Greetings!
One hardware related issue I have been puzzling with is how to make simple configuration changes, at boot-time, without having to either edit the /boot configuration files and/or change SD cards to effect each change.
Or, how to fit more than one O/S on a single SD card, since current SD cards are massively huge compared to the size of these operating system images.
For example, I might want to try running Raspbian for Robots with either a 32 bit or 64 bit kernel. Or, I might want to try running different versions of either Raspbian for Robots, or a new release of the GoPiGo O/S that’s being developed by the good people at Modular Robotics, without having to fiddle with and try to swap-out a tiny and fragile SD card.
Normally, you’d have to either stop what you’re doing, edit something in /boot like the config.txt file, (and run the risk of not editing it back, making yourself CRAZY!!! ), or having to use tweezers - or pliers!! - to remove and replace a tiny and delicate SD card.
My idea is to develop a way to use little jumper-clips or jumper wires to connect GPIO pins to force a change in configuration at the next boot.
For example, if I want to try a particular version of GoPiGo O/S, (or, Raspbian for Robots), with the experimental 64 bit preemptive kernel, I’d have to edit the config.txt file and either add in, (or comment out), an arm_64bit=1 line. Not hugely difficult, but it could be easier.
What if I could do this without editing anything? Perhaps just by connecting two GPIO pins together with a jumper or dip-switch, and then rebooting?
In cases like Charlie’s, where things are already a bit complex, or Carl which is even more complicated, or (God help me!), Derik’s’bot, which is entirely enclosed, trying to fiddle with SD cards and stuff can be complex to the point of disaster.
A better way would be to be able to add a jumper or a dip-switch that lets me connect or disconnect individual GPIO pins, (perhaps through a small plug-in header), that brings the selections out to where they can be conveniently manipulated without disassembling the 'bot and potentially damaging things.
All that would need to be done to change something would be to flip, (or un-flip), a particular dip-switch and reboot.
Issue:
In the course of experimenting or testing, I may want to make some kind of configuration change, (i.e. Trying something with the 64 bit kernel, changing a display option, or even booting a different version of an operating system), that would normally require either editing something in the /boot directory or physically swapping SD cards. This is especially problematic since swapping SD cards in the GoPiGo can be challenging at best or possibly damage the 'bot or SD card at worst.
Concept:
The idea here is that you can have a 'bot, or a Raspberry Pi, with multiple possible fixed configurations simultaneously available, such that one or more combinations of configurations can be selected by hardware jumpers or dip-switches when booting.
Note the emphasis on “when booting” - these are boot-time configuration selections. Being able to dynamically re-configure the robot at run-time is a totally different topic!
For example:
- Two different monitors with two different display resolutions, individually selectable at boot-time.
- Selecting the 32 or 64 bit kernel at boot time.
- Selecting one of several different O/S’s to boot at boot time.
- This is doable, but there are additional considerations, and additional research needs to be done.
- Select one of several camera configurations.
- Etc.
The requirements I wanted to establish;
- Specific configuration changes should be selectable by GPIO pins connected to ground. (i.e. via hardware jumpers or dip-switches)
- Configuration changes should not require removing the SD card.
- Configuration changes should not require special pre-compiled configuration files like custom firmware overlays or device-tree files that may be difficult to maintain or troubleshoot.
- Ideally, the alternate configurations should be defined by easily edited files like config.txt or an alternative cmndline.txt
- Ideally, the configuration should be defined once and then selected by jumpers or dip-switches when rebooting the 'bot.
The Setup:
Ref: The GPIO pin layout.
Note: Pin numbers are the Broadcomm internally defined GPIO pin numbers, not the external physical pin number on the header.
- I used pins beyond the original 26 pin GPIO set used by the GoPiGo3 controller board, (i.e. Everything to the right of the vertical “I2C0” block is fair game), because I didn’t remember which of the original 26 pins are or are not being used by the GoPiGo controller board itself.
- I wanted to use pins that did not have potentially pre-defined uses and might be set by the OS at run-time as they are likely to remain tied to ground if selected.
- I’m a bit confused by pin “12”, (PWM0), as that’s also assigned to pin “18” in the original 26 pin block too. Are they shorted together? I’ll have to investigate this further.
- Pin “26” might be a better choice as it doesn’t seem to have a pre-defined use, but it was hidden in the “back row” and was difficult to get to. If I do something with dip-switches and a header, I’ll probably use pin 26 instead of 12.
- Pin definitions are the Broadcomm pin numbers, (the numbers next to the pins), not the physical pin header numbers, (1-40).
- For the sake of testing, I selected pins 12 and 16 as they’re easily reachable on the outside edge of the GPIO pins, being the third and fifth pins from the end of the connector.
- Pin “12” is the fifth pin in.
- Pin “16” is the third pin in.
- Each of these pins is immediately adjacent to a convenient ground pin to connect it to if I want to use it.
How to do this:
- First, select what you want to change, and how to make the change happen:
- In my case, I wanted to be able to make two selections:
(a) Select between the 32 and 64 bit kernel image.
This can be done via a selection in the config.txt file by selecting arm_64bit=11 to select the 64 bit kernel image.
(b)Select between two different operating system images.
This can be done by selecting a different, custom, command-line file that selects the partition to boot into.
- In my case, I wanted to be able to make two selections:
- Decide which GPIO hardware pins you want to use:
- As I mentioned before, I decided to use pins “12” and “16”.
(a) I use pin “12” to select the kernel image.
(b) I use pin “16” to select the operating system to boot.
- As I mentioned before, I decided to use pins “12” and “16”.
- Modify the config.txt file to reserve and configure the two GPIO pins.
- Near the top of the config.txt file, add two lines to assign and configure the GPIO pins you’re going to be using.
In this case “gpio=12=ip.pu” means “set Broadcomm GPIO pin 12 as an input, pulled high to +3 using an internal software pull-up resistor”. You want the pin to be pulled high so that you can tie it to ground to set the alternate state.
If you don’t specify a specific pull-up/down state for the pin, it can float if disconnected and do weird things. Specifying a software pull-up and then tying the pin to ground is the safest way as you don’t risk frying delicate GPIO pins.
The second line says the exact same thing, but for pin “16” instead of pin “12”.
- Once you’ve set up the pins you want to use, you can test for them later on in the config.txt file by using “gpioxx” pin test statement blocks.
- For example, later on in the config.txt file, I test for the alternate kernel selection by the following:
This says that if pin “12” is shorted to ground, (pulled low), then select “arm_64bit=1”, otherwise skip it and use the default.
- Likewise,
says that if pin “16” is pulled low, execute the custom cmdline.txt file specified to boot a different O/S.
Note that all of these things, including things already in the config.txt and combined together - if you set something more than once, the last setting wins - so these selections should go toward the end of the file - you define default behaviors first, then exceptions toward the end.
For example, my modified config.txt file looks something like this:
====================
Notes about booting an alternate operating system.
This is the “default” cmdline.txt file as-shipped.
(I eliminated the “quiet splash” as I want to see boot-time messages)
To add an additional operating system image, I copied the “rootfs” partition from a working image to a third partition on the SD card I wanted the image to be on. (Gparted is your friend, it can create additional partitions, AND copy them!)
When I did this, I needed to create a special “cmdline.txt” file that points to the third partition instead of the second one, so I created a “cmdlinep3.txt” file that contains:
Note the difference:
- The original cmdline.txt file has root=PARTUUID=ca78f9f0-02 - which specifies booting from the second partition.
- The modified, and renamed cmdline.txt file has root=PARTUUID=ca78f9f0-03 - which specifies booting from the third partition.
- Also note that the PARTUUID has to be the actual UUID for the disk volume you’re using - if it boots, its the one in the original cmdline.txt file.
Additionally, prior to booting the new partition, you have to go to the /etc/fstab for the new partition and make sure both /boot and / (root) specify the correct UUID, (it can be different if copied from somewhere else), and that root specifies the correct partition, in this case “03”. Failure to do this will result in a system that gets entirely tangled up on itself when it tries to boot.
So far, I can get both operating systems to boot, but the operating system booting from the alternate partition never quite works correctly - and there may be other fixups needed that I have not yet discovered.
Summary:
- Decide what changes you want to be able to select between.
- Decide what has to happen to make the changes work.
- A change in kernel definition?
- A change in a config.txt parameter?
- A different cmdline.txt file?
- Something else?
- Experiment with the changes, and the commands needed to select them before trying to get fancy. Test to make sure the changes - and how to select them - actually work.
-
i.e. Does selecting “arm_64bit=1” in the config.txt load the correct 64 bit kernel?
Hint: Type “uname -a” in a terminal window, and if things like “PREEMPT” and “arm64” show up, you’re golden! - i.e. Does selecting a custom cmdline.txt, (by renaming and substituting a new one), boot properly?
- You need to get all the selections and changes you might want to do working in a “standard” configuration - by editing the config.txt/cmdline.txt files - before trying to get fancy.
-
i.e. Does selecting “arm_64bit=1” in the config.txt load the correct 64 bit kernel?
- Once everything is working when done by hand. . .
Then select the GPIO pins you want to use and configure them.- gpio=NN=ip.pu - where “NN” is the pin you want to use.
You select the pin by shorting it to a “black” (ground) GPIO pin.
- gpio=NN=ip.pu - where “NN” is the pin you want to use.
- Then, select the pin and test it in your modified config.txt file
- Create a section
[gpioNN=0]
which selects what to do when the pin is pulled low, (the “alternate” behavior), such as “boot an alternate kernel” by specifying something like arm_64bit=1 - Viz.:
[gpioNN=0]
arm_64bit=1
- Create a section
- Test, test, test, and continue testing until you get it right.
Credits:
- Huge credit goes to the people on the Raspberry Pi forums who provided links, advice, (lots of good advice!), and a number of different suggestions on how to do this, both in hardware and software. If my hardware-centric method doesn’t quite fit your needs, you would do well to look at some of the alternate methods proposed. All are good and all are worthy of a careful read.
- Everybody here on the Dexter Industries / Modular Robotics forums.
It’s people like you who give me the inspiration and, (let’s be honest here), the courage to try something, publish results, and not fear being torn to shreds if it’s not quite ready for prime time.
- The people at Dexter/Modular Robotics who came up with the idea for a robot like the GoPiGo. Without that, God Himself only knows what I’d be doing otherwise.
- Special mention goes to Nicole, (@cleoqc), for being the GoPiGo champion she is, and being an example for all of us. I for one vote that she change her username to st.cleoqc. She should be sainted!
Notes about booting into the 64 bit kernel:
- Theoretically, you could boot into a 64 bit kernel simply by specifying the kernel to boot, in this case the “kernel8.img” kernel. However, there’s more to this than simply changing kernels.
By default, the Broadcomm SoC, (System on a Chip), that implements the Raspberry Pi is configured internally in a number of ways to behave as a 32 bit system even though it has the potential to run as a full-bore 64 bit system.
In order for the Raspberry Pi to run correctly in a 64 bit environment, several different internal states and registers need to be changed prior to booting the kernel for it to work properly.
The correct way to select “64 bit kernel mode” is to execute the statement arm_64bit=1 within the config.txt file. This allows the Raspberry Pi SoC to make the needed internal configuration changes and then automatically load and run the “kernel8.img” kernel.
Thanks!