In earlier blog posts, e-mails, and the fledgling Nitrogen User’s Manual we’ve described the setup of the U-Boot variables
bootargs for particular use cases. Because changing these requires access to the serial console and because the overwhelming majority of our customers are booting from SD card, we’re making a change to our process.
For those of you familiar with our PXA series of boards, this should be old hat to you, since we’ve been doing this for years on that platform. We’re essentially just swapping the file name of
init.scr for the new convention of
For those of you who aren’t familiar, we’ll try to walk through the essentials in this post.
One command-line for all boards
From this point forward, unless we’ve made arrangements with you for production needs, we’ll be shipping all of our devices with the same value of
fatload mmc 0 90008000 nitrogen_bootscript && source 90008000 ; errmsg='Error running bootscript!' ; lecho $errmsg ; echo $errmsg ;
In English, this says to try and load the file
nitrogen_bootscript from the first (FAT) partition on the SD card and run it. The
source command in U-Boot will evaluate a compiled script file in memory as if it were entered at the command-line (more on compilation later).
In normal use, the
nitrogen_bootscript script should never return. It should load the O/S of choice.
If either the script loading fails or the script runs to completion, the
bootcmd will display the string Error running bootscript! on the first LCD panel and the serial port.
Why this is useful
You may be asking yourself whether we’re just moving the decision about what to do at boot time from one place to another.
We are. We’re moving it to a place where it’s easier to change.
By doing this, the boot decisions can be made by removing the card, or by updating the card under either Linux or Windows CE.
It’s also much easier to edit the script when it’s not entered through the U-Boot command line.
As a final benefit, a script on the SD card can be larger than will fit into the command-line buffer in U-Boot.
Editing and compilation
I mentioned earlier that
nitrogen_bootscript must be a compiled script file. More specifically, a U-Boot script is a set of text with Unix-style line-ends using the
hush syntax. Refer to the U-Boot Manual for details, but if you’re familiar with
sh under Linux, you won’t find too many surprises.
The text file is compiled using the
mkimage tool, which is available for a number of platforms. On Debian-based hosts, you’ll find that there’s a package named
mkimage takes a number of parameters, but most of them have little meaning to a script.
The following short-hand should do it for you:
user@host:~$ mkimage -A arm -O linux -T script -n "Bootscript" -d bootscript.txt nitrogen_bootscript Image Name: Bootscript Created: Tue Sep 21 11:26:59 2010 Image Type: ARM Linux Script (gzip compressed) Data Size: 1888 Bytes = 1.84 kB = 0.00 MB Load Address: 00000000 Entry Point: 00000000 Contents: Image 0: 1880 Bytes = 1.84 kB = 0.00 MB
This example converts the text file
bootscript.txt into the compiled binary
Note that this isn’t true compilation: no syntax checking occurs. The
mkimage tool also doesn’t change the
format of line-ends. It simply adds a header with the name, description, type and length to the file.
To make it easier to do this, we’ve created a web-based tool that allows you to simply paste the text into a text control and receive the resulting binary.
Boot scripts in practice
The notes above cover the basics of what a boot script is and how we’ll be configuring the U-Boot environment variables on the boards. The following are some snippets of code that you’ll find inside the
nitrogen_bootscript files that we ship.
These are only a handful of examples of what you may find inside, but we’ve found each of them useful on at least one occasion
Displaying a splash screen
This example builds on the parts we describe in thepost about U-Boot’s display support. It will attempt to load a file named
logosomething.bmp from the first (FAT) partition on the SD card and display it on the screen.
if fatload mmc 0 92000000 logo*.bmp ; then bmp display 92000000 ; fi
Upgrading U-Boot itself:
This example will try to load
u-boot-nitrogen-something.bin from the first (FAT) partition on the SD card and compare it against the serial EEPROM. It builds upon the commands described in the Going serial post.
Note that this process may take a second or so to run if the file is actually present. You might consider a scheme to place the file onto the SD card only when an upgrade is needed and deleting it afterwards.
In some environments, our customers use separate upgrade SD cards to make sure there’s a person in front of a device when upgrades occur.
lecho "check U-Boot" ; if fatload mmc 0 92000000 u-boot-nitrogen*.bin ; then if sf probe 1 27000000 ; then if sf read 0x92400000 0x400 $filesize ; then if cmp.b 0x92000000 0x92400000 $filesize ; then lecho "..." ; else lecho "Need U-Boot upgrade" ; lecho "Program in 5 seconds" ; for n in 5 4 3 2 1 0 ; do lecho $n ; sleep 1 ; done sf erase 0 0x40000 ; sf write 0x92000000 0x400 $filesize if sf read 0x92400000 0x400 $filesize ; then if cmp.b 0x92000000 0x92400000 $filesize ; then while lecho "U-Boot upgraded. Cycle power" ; do sleep 120 done else lecho "Read verification error" ; fi else lecho "Error re-reading EEPROM" ; fi fi else lecho "Error reading boot loader from EEPROM" ; fi else lecho "Error initializing EEPROM" ; fi ; else lecho "No U-Boot image found on SD card" ; fi
Note that the file named
u-boot-nitrogen*.bin should be created from
ubl_ecspi.bin in the U-Boot build directory, not from u-boot.bin.
Loading and launching Windows CE:
This is probably the simplest form of O/S load and launch, since there is no kernel command line under Windows CE. This example simply reads a file named
NK6-nitrogensomething.nb0 from SD card and jumps to it.
if fatload mmc 0 90200000 nk6-nitrogen*.nb0 ; then lecho "Launching CE6" ; go 90200000 ; else lecho "No system image" ; fi
Changing a display setting
This is something we do a lot of at Boundary Devices. We’ll program boards at production time for one panel, but connect it up to another before shipment to a customer. It may also be useful to you if you have more than one display in common use.
Using a very minimal bootscript like the one below will allow you to simply change the display setting through the
The same idea of changing an environment variable and saving through a boot script is often useful for other reasons. You can use this to change
bootargs or even
bootcmd on devices you receive from us.
lcdpanel hitachi_hvga ; savee ; lecho Panel setting saved.
Another alternative is to set and save the panel conditionally in your production boot script like this:
if test $panel != hitachi_hvga ; then lcdp hitachi_hvga ; saveenv ; fi
Setting a GPIO pin
If you’re connecting GPIO outputs to a Nitrogen, you may want to set the pin state immediately at boot time. To do this, you can use the
mw (memory write) command in U-Boot to change the value of the i.MX51 registers.
This is totally hardware dependent, requires knowledge of the register set of the i.MX51 and the normal state of the rest of the bits in the
GPIO1_DR register, but the following will set GPIO bank 1/pin 5 high. It just so happens that this is an output connected to J17 pin 1 on the Nitrogen board and a command like this may be just the thing you need.
mw.l 0x73F84000 008000b8
Loading and launching Linux:
Linux is incredibly flexible. Because of the wide variety of ways in which it can be configured to boot, it’s impossible to list every option here. Instead, let’s look at the three key pieces involved in booting Linux:
- The Linux kernel
- RAM disk
- Kernel command-line arguments
The Linux kernel is generally loaded from a file named
uImageSomething to address
0x92000000 using a fragment like the following:
if fatload mmc 0 0x92000000 uImage* ; then echo "Linux kernel image loaded" ; fi
The address of the kernel is handed to U-Boot as a part of the
RAM disks are generally used in booting Android, Busybox, and Ubuntu Live images. They’re typically loaded at address
0x92400000, leaving 4MB for kernel image:
if fatload mmc 0 0x92400000 initrd*.u-boot ; then echo "RAM disk loaded" ; fi
If used, the address of the RAM disk is passed to the
bootm command as a second parameter:
bootm 0x92000000 0x92400000
The final piece of the puzzle, the kernel command-line has way more options. The Linux kernel tree has a set of common parameters, but that just scratches the surface. Each device driver may contain its own set of parameters, and user-space environments such as Android and Ubuntu also use the kernel command-line as a way for the boot loader to pass instructions about how to start up to their respective startup scripts.
The kernel command line is handed to the
bootm command indirectly through the use of the
bootargs environment variable.
The following is a short list of some common things we place into
bootargs for different boot scenarios:
(kernel).This option tells the kernel to use the first serial port as the default console. Without this, you’ll get the kernel boot messages on the display.
(kernel). This option tells the kernel’s networking stack to get an IP address through the
DHCPprotocol. It’s normally used when booting over NFS.
(kernel). This option tells the kernel to use NFS for its’ root filesystem.
(kernel). This option specifies the IP address of the NFS server and the path to the root filesystem on that server.
(kernel). This option tells the kernel to wait if the boot device isn’t immediately available. This is needed when not using a RAM disk to allow enumeration of SD card partitions or for an NFS connection to be established.
(kernel). Used to force a date and time into the real-time clock at boot time before a network time server is available. This is most useful when booting to an ext2 or ext3 filesystem since a ram-disk
may try to use a timestamp to determine if the filesystem should be checked.
(Android). Tells Android to use a touch screen calibration file.
(Debian, Ubuntu). Don’t display messages to the console during boot.
(Debian, Ubuntu). Show an animated graphic on the display instead of the progress text.
(Debian, Ubuntu). Don’t boot X-Windows.
(Debian, Ubuntu live images). Display detailed boot progress for the live startup on the console.
(Debian, Ubuntu). Display detailed boot progress for the core Ubuntu startup on the console.
(Ubuntu)– If your kernel is built without aufs support, specify union=unionfs
We certainly hope these notes help you to understand the power of the boot script and the details that you may see in shipments from us. If any of them are confusing, please let us know.