- Blackfin device: CM-BF537E from Bluetechnix
- Bootloader: Das U-Boot (blackfin.uClinux project site)
- OS: uClinux (blackfin.uClinux project site)
The goal is a controller for various mechanical devices (move motors, read sensors via GPIO) with a web interface (HTML and web-services).
I spent some time organizing a safe method for deploying application updates to a remote blackfin device. There were a couple restrictions that led to my final plan.
- If the update process fails, the device should still boot and be accessible via internet.
- Updating needs to be done remotely via internet.
- Bootloader (u-boot) – 2 sectors 0x20000000-0x2003FFFF
- Flash filesystem (jffs2) – 6 sectors 0x20040000-0x200FFFFF
- uClinux compressed image (uImage) – 24 sectors 0x20100000-0x203FFFFF
I originally placed the uImage parition directly after the u-boot partition, with the jffs2 partition at the end. The flash device on the CM-BF537E splits the flash into two halves addressable by toggling a GPIO pin (pf4). Some tools handled the addressing and toggling of pf4 for me, others didn’t. It turned out easier to move the jffs2 parition into the first half of flash and let the uImage parition straddle the flash halves.
Setting Up U-Boot
On the first boot, I wanted u-boot to download the uImage (via TFTP) and write it to flash memory. However, we did not want the device to always netboot, so u-boot would then alter itself to boot from the flashed uImage.
U-boot also needs to erase the jffs2 paritions on a fresh CM-BF537E so the filesystem can mount.
Here is the important section from cm-bf537e.h
"erasejffs2=" "protect off 0x20040000 0x200FFFFF;" "erase 0x20040000 0x200FFFFF;" "protect on 0x20040000 0x200FFFFF;" "" "tftpupdate=" "run erasejffs2;" "tftp $(loadaddr) $(imagename);" "protect off 0x20100000 0x203FFFFF;" "erase 0x20100000 0x203FFFFF;" "cp.b $(loadaddr) 0x20100000 0x300000;" "protect on 0x20100000 0x203FFFFF;" "setenv bootcmd run localboot;" "saveenv;" "reset" "" "localboot=" "ping 172.16.5.1;" "pf4 set;" "cp.b 0x20100000 $(loadaddr) 100000;" "pf4 clear;" "cp.b 0x20000000 0x1100000 200000;" "pf4 set;" "bootm" ""
Again, on first boot, the device auto-runs tftpupdate. Here is what happens:
- Jffs2 parition is erased
- uImage is downloaded into memory (address 0x1000000)
- Unprotect flash sectors where uImage will be stored
- Erase flash sectors where uImage will be stored
- Copy uImage into flash
- Protect flash sectors where uImage is now stored
- Change default startup command to localboot (described below)
- Save setting change
- Reset device
When the device comes back up, here is what happens:
- Ping a server (the only thing this does is write the u-boot MAC Address to the network device so uClinux will use the same MAC Address and not assign a random one)
- Set the GPIO pin to use the first half of flash (mentioned above)
- Copy uImage from first half of flash into memory (0x1000000)
- Clear GPIO pin to use second half of flash
- Copy remainder of uImage in upper half of flash to memory (offset from previous copy)
- Re-set GPIO pin
- Boot uImage from memory
From here, the device is now running!
Upgrades to the uImage stored in flash are possible, but the u-boot console is needed to halt the autoboot and run the tftpupdate macro again.
This post is actually just the setup of U-Boot and uClinux to boot a blackfin device from a stored uImage (i.e. NOT netboot). Part 2 will explain the scheme for updating the device remotely – without netboot!