It works! I was able to reprogram a remote Moteino over the air with a blinky sketch!
Definitely not a ground breaking achievement, but it really felt like “Hello World” all over again! 🙂
I didn’t expect to overcome this so soon but I managed to get past what I thought would be the biggest hurdle: customizing Optiboot for wireless programming. Actually it’s just reading the new flash image from the external flash chip and transferring it into the internal flash memory. The “wireless” part happens in Step 1.
Here’s a snapshot of the transmission in progress. The first picture is the start of the HEX file transfer, second image is the transmission end, and reprogramming by my modified version of Optiboot.
The modified Optiboot now takes 1016 bytes, about 500 more than the original Optiboot. Not too bad considering it contains all the extra code to read from the external SPI flash chip and some basic serial output for debugging. I had to modify where the bootloader gets flashed on the ATMega328 (last 1k instead of last 512b). Here is an excellent article on AVR bootloaders: http://blog.schicks.net/wp-content/uploads/2009/09/bootloader_faq.pdf
One part I don’t like right now is that the serial communication between Python and the MAIN Moteino is rather slow (it takes ~15 seconds to transmit a blinky sketch). The reflashing by the bootloader is almost instant (second picture, the [FL***…***EFXA] part). It’s because of delay()s I added in Python and while using Serial.readline() to make sure I am reading whole messages and avoid any truncation. I will probably try to rewrite that logic to use getCh() instead of Serial.readline(). If anyone has suggestions please let me know.
Here’s a summary of all that happens:
- Python script talks to MAIN Moteino. An optional -f blah.hex argument will hand over the HEX image to Moteino for transmission to remote Moteino.
- Main Moteino intercepts handshake from Python host, attempts to contact the remote Moteino for wireless HEX image transmission.
- Remote Moteino responds to the request and begins a wireless handshake transmission of the new HEX image to the external flash memory. When done it reboots via Watchdog.
- Bootloader detects the new flash image and begins reprogramming the internal flash memory. When done it deletes the image to avoid an endless loop and reboots.
Some extra assumptions:
- in addition to the HEX image being valid, the HEX image bytes have to be in order, and without gaps. The compiled sketch HEX file (intel format) contains the addresses where the bytes go. The image I’m storing does only contain the bytes (without addresses and unHEXified to save space), assuming they are all in sequential order. I’ve never seen this not being true but thought I’d mention it anyway.
- The HEX file addresses start from 0. The bootloader lives at the end of the Atmega328 flash memory, and sketches start at address 0. So this is assuming any sketch being wirelessly reprogrammed is starting at 0.
- The remote Moteino should be well within range to avoid wireless packet loss. The code will allow for up to 3 seconds of retries in such cases, after which it will abort and any HEX data stored will be erased.
- a challenge will be to make this all work with battery operated nodes that sleep most of the time. The current code has timed retry attempts to reach the remote node (a few seconds), if no handshake ACK is received the transmission is aborted
There are several code files for this whole thing to work. Right now it’s a bit messy and I won’t include the files here to avoid confusion. I am mainly trying to get a feel if people are interested in this, and if so I will work on getting the files organized and into a Github repo.
- Python code that talks to MAIN Moteino
- Arduino code on MAIN Moteino listening on the serial stream for a reflash request and handling the wireless HEX file transmission
- Arduino code on REMOTE Moteino listening to a wireless reflash request, and handling the wireless HEX file reception and storage on external memory chip. To allow continuous wireless programming, the new sketch should contain the same code in this step 3 to handle further wireless programming requests.
- Custom Optiboot that detects the HEX image on external memory chip and can reprogram the Atmega328 internal flash memory with it
Any feedback and ideas appreciated.