May 30, 2013

Displaying a Splash Screen with U-Boot

2014-02-22: N.B. Some of this post has flaws

At least with a GCC 4.7 cross compiler and the latest U-Boot sources, it is necessary to align bitmaps on a memory address with an offset of an odd multiple of +2, since the use of a four-byte alignment will cause alignment exceptions at run-time.
  • If you’re using an un-compressed bitmap, you should use an address like 0x10000002, and
  • If you’re using a gzipped image, you’ll also need a patch like this one
Refer to these documents for details:

Original post

We’ve recently had several customers contact us asking about using splash screens with U-Boot. We added display support to U-Boot a while back as described here and with it we got a nice Tux logo and the version information but didn’t have a way to customize it. Now we do and we’ll explain how it works in this post.

For the impatient

The process to set it up is the following:
U-Boot > ext2load mmc 1 10000000 /water-conservation1024x600.bmp.gz
745898 bytes read in 219 ms (3.2 MiB/s)
U-Boot > sf probe
SF: Detected SST25VF016B with page size 4 KiB, total 2 MiB
U-Boot > sf erase c2000 +${filesize}
U-Boot > sf write 10000000 c2000 ${filesize}
U-Boot > setenv splashimage 12000000
U-Boot > setenv splashpos m,m
U-Boot > setenv splashsize ${filesize}
U-Boot > saveenv
  • The image is copied into SPI flash so it is tied to the board and won’t change with different boot devices.
  • For splashimage, pick somewhere in the valid range.
  • The variable splashpos is optional and setting it to m,m will center the image.
  • SPI NOR flash is 2 MiB so your max image size is 1302528 bytes, 2 MiB – c2000 bytes.
  • It can handle most bmp formats as well as gzipped versions as show above.

Background

U-Boot provides the bmp command for working with bitmaps. You can load an image from an SD card and display them like this:
U-Boot > ls mmc 1
<DIR>       4096 .
<DIR>       4096 ..
<DIR>      16384 lost+found
...
         1152138 water2.bmp
         1843338 water1.bmp
         1152138 water-conservation800x480.bmp
         1843338 water-conservation1024x600.bmp
         1843338 splash.bmp
          134538 boundarydevicesx240.bmp
          745898 water-conservation1024x600.bmp.gz
U-Boot > ext2load mmc 1 10000000 /water-conservation1024x600.bmp.gz
745898 bytes read in 219 ms (3.2 MiB/s)
U-Boot > bmp i 10000000
Image size    : 1024 x 600
Bits per pixel: 24
Compression   : 0
U-Boot > bmp d 10000000
With this capability we could do something like adding the following line to the top of 6x_bootscript (or to the bootcmd environment variable), will cause u-boot to look for a bitmap image named splash.bmp in the root directory of the filesystem from whatever you’re booting from.

${fs}load ${dtype} ${disk}:1 10000002 /splash.bmp && bmp d 10000002 ;

See this post for more details about the bootscript and bootcmd

There are 2 major downsides with this method. One, if there’s no boot media attached to the board you get Tux. Two, it’s slow and fleeting. You still see Tux and the version info for a second or 2 because it only runs once the bootcmd has been called after the 1 second boot delay and if you continue to boot into Linux or something else which has it’s own splash screen or simply clears the screen, you’ll only see your image for a second anyway.

SPI NOR and splashimage

We want displaying the splash screen to work regardless of whether there’s an SD card or anything else plugged in to boot from and we want it displayed immediately on boot up (without seeing Tux or U-Boot output).

The first part can be solved using flash. Our boards have 2 MiB of non-volatile SPI NOR flash, part of which we use to store U-Boot and the environment variables. We can store an image here with U-Boot’s sf commands. Assuming you’ve just loaded an image to RAM at address 10000000 (see above), the process looks like this:

U-Boot > sf probe
SF: Detected SST25VF016B with page size 4 KiB, total 2 MiB
U-Boot > sf erase c2000 +${filesize}
U-Boot > sf write 10000000 c2000 ${filesize}
U-Boot > sf read 12000000 c2000 ${filesize}
U-Boot > bmp d 12000000
The filesize environment variable is automatically set to the size of the file just loaded (in hex which is what we need). Why did we write to SPI location c2000 besides that’s where loadsplash expects it? The SPI NOR memory map looks like this:
0..bffff                - U-Boot
0xc0000..0xc1fff        - environment

The free space in flash is from c2000 to the end, so that’s where we put the image.

The second part, displaying immediately at bootup, is covered by taking advantage of the CONFIG_SPLASH_SCREEN option in U-Boot. When U-Boot is compiled with this enabled, immediately on startup it will look for an environment variable named splashimage and read an address out of it. It’ll then try to load and display a bmp image from that location in RAM.

Sounds easy enough, but now we have another problem. U-Boot’s splash screen feature is expecting the image in RAM and our image is stored in NOR flash. To solve this we’ve committed some code changes to the staging branch. This key change is an added default environment variable loadsplash:

loadsplash=if sf probe ; then sf read ${splashimage} c2000 ${splashsize} ; fi
Obviously, when run it will copy an image from c2000 in flash to the location in splashimage, the place where U-Boot will look for it. You can try running it manually using the run command:
U-Boot > run loadsplash
SF: Detected SST25VF016B with page size 4 KiB, total 2 MiB
U-Boot > bmp d ${splashimage}
So, at startup, if splashimage and splashsize and loadsplash exist, U-Boot will try to run loadsplash. Splashimage, is as we mentioned the address that U-Boot will look for the splash screen bmp so we load it there and splashsize is the size in hex of the image you copied to SPI NOR. You’ll have to set those 2 variables using setenv:
U-Boot > setenv splashimage 12000000
U-Boot > setenv splashpos m,m
U-Boot > setenv splashsize ${filesize}
U-Boot > saveenv

After setting these variables appropriately, you’re done. Reset and you should see your image displayed instantly.

Conclusion

I admit that it does seem like quite a process going on behind the scenes for something as simple as displaying a splash image but we’ve aimed for it to be as easy to use (or ignore) as possible from the your perspective