FOTA/Wireless Programming for Funky V3
WIKI describes how to setup FOTA on Funky.
I wanted to have FOTA/Wireless programming capability for my project. Unfortunately RFM69 library does not fit 4KB bootloader area therefore I could not follow standard self-programming mechanism (store data coming from a serial stream to internal flash). I wanted to reuse Felix's wireless programming library however Funky V3 does not have external spi flash. Therefore I had to change layout of the internal 32KB flash. I was influenced by video: Intermediate memory bootloaders.
- The application section (aps) 0x0000-0x6FFF (28KB) and
- bootloader section (bls) 0x7000-0x7FFF (4KB).
I split aps into two equal areas. First is an app area 0x0000-0x37FF (14KB) and the rest 0x3800-0x7FFF (14KB) is something like external spi flash area, let's call it temp area. The first disadvantage is clear we have only 14KB instead of 28KB for our application code. To be honest it is even worst. 13406B out of 14336B is occupied by RFM69 driver and wireless programming code. The bottom line is that we have around 1KB for our app. It may seem to be ridiculously small but it is sufficient for my app that is supposed to count led flashes on my watt-meter and send them via RFM69 to RFM69PI V3 gateway for further processing. Later on I would like to measure other things such as temperature voltage of battery, … moreover I don't have easy access to Funky node therefore FOTA is needed.
Changes in Caterina Bootloader
- I modified Caterina bootloader to expose a function that wraps SPM instruction. I found inspiration in video arduinos (and other avrs) write to own flash. Btw there is an interesting trick how to invoke SPM without wrapping function, src code.
- I added function that updates the app area with code stored in temp area. More or less what DualOptiboot does.
The only remaining piece is the update of temp area with firmware coming over the air.
Changes in Wireless Programming Library
Modified wireless programming library writes firmware coming from the air into temp area instead of external spi flash. I removed all debugging messages to shrink size of this library in favor of space for application code.
Layout of Flash Memory
|Start address||Stop address||Size||Description|
|0x0000||0x37FF||14KB=14336B||Application code (app area)|
|0x3800||0x3801||2B||Length of data in temp area (Length >14334 means temp area contains invalid data)|
|0x7000||0x7FFF||4KB=4096||Bootloader area (bls)|
Complete Flow of FOTA Process
- Let’s power on Funky (we assume that Temp area contains invalid data)
- Bootloader is active
- Is there a new code in Temp area (check value at address 0x3800)? No, therefore pass control to application, ie. jmp 0x0000
- Application is active and processing requests or sending data via RFM69
- Application checks if there is a request to update firmware. (if not go to 4)
- Write firmware to Temp area (using externalized wrapper function for SPM instruction) and reboot Funky via watchdog.
- Bootloader is active
- Are there valid data in Temp area (value at 0x3800 contains length of data and is < 14334)
- Copy content of Temp area to app area
- Erase page at 0x3800, this set length to 0xFFFF, ie invalidates content of Temp area
- Pass control to application, ie. jmp 0x0000
- verification of checksum of firmware prior to update of app area.
- more space in the app area, there are several techniques how to get there
- Shrink RFM69 library and Wireless programming library
- Compression that would shrink temp area in favor of app area. The app and temp area sizes have to be aligned to SPM_PAGESIZE (128B).
- Squeeze RFM69 driver into 4KB. This could eliminate necessity of temp area because bootloader could flash data directly to app area. This seems to be best approach but the most complicated one.
- introduce faster mode that increases transfer rate
- allow Arduino IDE to update firmware over the air