SpenceKonde / DxCore

Arduino core for AVR DA, DB, DD, EA and future DU-series parts - Microchip's latest and greatest AVRs. Library maintainers: Porting help and adviccee is available.
Other
189 stars 50 forks source link

How to do OTA? AVR128DB64 #511

Closed bgersmann closed 10 months ago

bgersmann commented 10 months ago

Hi, if I understand corretly, I could update the appcode by writing a new firmware directly in flash starting 0x0200?

But if I have an error while writing my program is broken and the chip will stop working?

Is there any example how to do OTA the right way? Should I use a bootloader and ArudinoOTA library or so?

I have an AVR128DB64 + Sim7080 LTE Module.

Thanks for any tips!

MX682X commented 10 months ago

The whole thing is a bit tricky. I'd say the most reliable thing would be to write a custom bootloader. Like this: AppCode sets a flag and does a Software Reset. Bootloader examines the Flag. The flag indicates a software download. It sends a "ready for programming" command to the LTE module. The remote programmer, upon receiving the command sends initiates the programming procedure. The bootloader on the DB writes the data automatically to the Flash.

The BOOT secton can be Write protected, this makes sure that one part of you Program will remain operational. The 0x0200 Section can be increased, to accomodate for a bigger bootloader, neccessary to have the LTE Interface communication.

SpenceKonde commented 10 months ago

This has "time sink" written all over it... OTA f/w updates are hard.

I think ESPs take the copout option (some bootloaders for them sure do), sacrificing half of the flash (on an external chip, hence space is no problem), and have one half marked as the active one which the bootloader jumps to, and the second one is the upload partition, and the bootloader writes code to and verifies it from there. Once once it's verified does it flip the switch, and start jumping to the other partition.

Of course, this doesn't work unmodified on an AVR because code is not freely relocatable - the compiler has to be told where the image starts to correctly generate code (i've looked at what the problem is like if we were to modify the code on the fly - that looks like a rabbithole that will lead to glory - but it's just a rathole. You'll just end up where you started 4-48 hours later, dirty and fleabitten. (the wide time range because it doesn't look that bad until you realize you need to be able to deal with ld/ldd/st/std, and depending on where the values in the pointer register came from and what they point to, figure out how. if at all, they must be modified. That sounds like it borders impossibility - it means working back from every single ld or st to figure out where it will be accessing, what type of memory that is, but often it's not clear from whence come the values in the pointer registers. So to implement an analogous thing, I think you'd need to double-up the linking step, generating two s, one with each of the addresses, and have the OTA uploader, after talking to the chip, determine if the upload partition was the high or low one, and upload the appropriate binary... but nope, even then, it won't work, because you can't change fuses when uploading via bootloader, and at runtime you only get two options for the start of vectors - they either start at 0x0000 (in the bootloader, no good!), or they start at 0x200 BOOTSIZE (this is what we want, at the start of the app - but if we had two app "partitions" we would have no way to tell the chip to change the BOOTSIZE except via a updi programmer. So not only is that rathole a dead end, see all those holes burrowed into the hillside there? They're all* dead ends!

Any scheme with hope of working (as must have the bootloader trash it's old active partition after verifying, and then write all the data to the flash, then go through the uploaded code for a third time, copying the upload partition to the active one. This also bypasses that near impossible relocation task and the need for workarounds for that, though it produces twice the flash wear. I don't think you can get around persisting at least a byte of auxilliary data probably in eeprom so it knows what state it's in and whether it should run the app, or if it was reset into bootloader to copy the new firmware from the second partition to the first (since we can only run it from the first as discussed above), so that if an upload fails while in progress, either the app is still there because it failed to make it past opening (or trying to) the connection over which the chip, bootloader eventually times out if it was ever activated, and app still runs. A partially completed upload will not be run, and won't harm the app in the active partition. But that burns half your flash - and it's a ton of code to write, and not easy code.

You can do the same thing with an external EEPROM chip too - app receives new code and writes it to eeprom, verifies, then resets itself into your custom bootloader (giving itself the power to write to the appcode section) that loads a firmware image from the external eeprom and writes it to flash