2014-09-10 05:05 PM
I'm trying attempting to wrap my head around a rather complex problem and am seeking a little guidance to get me started.
I'm developing a platform based on the STM32F405 and FreeRTOS with Atollic as the IDE of choice. I am currently investigating various ''over the air'' (OTA) firmware update methodologies. There are a few options I have considered, and I think the simplest (and most reliable) would be something like this: 1. Write a bootloader which is capable of ''choosing'' between two applications/firmware images, say app ''A'' and ''B'', both of which live in the 1MB internal flash (obviously the bootloader + ''A'' + ''B'' would be <= 1MB in size in order to fit in the internal flash). Note that ''B'' would essentially represent an updated version of ''A''. 2. The device would initially ship with bootloader and ''A'' on the internal flash (with ample space reserved for a subsequent update - this allows reversion to ''A'' should OTA FW update to ''B'' fail, if ''B'' is corrupted, etc.). 3. Some time later, a newer version of firmware, ''B'', is available. The application code (both ''A'' and ''B'') are capable of writing a new FW version to flash. That is to say, ''A'' receives ''B'' over the air and writes ''B'' to its respective home in internal flash. 4. Based on some magic value, the bootloader determines that we should now boot to ''B'' instead of ''A''. Note that ''A'' is still retained in flash, and the bootloader is capable of reverting to ''A'' should we encounter an issue with ''B''. 5. As additional updates roll out (''C'', ''D'', etc.) this process is repeated. Obviously the normal update cycle would go ''A'' -> ''B'' -> ''C'' -> ''D''... but its possible that if ''A'' -> ''B'' update fails (or user simply never gets ''B'' before ''C'' is available) we may see updates like ''A'' -> ''C'' (a firmware version is skipped, thus we cannot make any assumption about the absolute address where ''C'' may be placed) From what I've read I believe what I've described is possible - I'm essentially replicating the ''dual bank'' feature that is present in other STM32s except the application code handles the flash update. That is, a bootloader can be used to select which FW version to boot, and each FW version should be capable of updating the sector(s) of flash it does not occupy. Can someone confirm if, in general, this methodology is sound? Second, I've come across a few posts in this forum that discuss this process in general; [DEAD LINK /public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Flat.aspx?RootFolder=/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/STM32F4%20Dual%20images%20for%20firmware%20update%20-%20remapping%20interrupts&FolderCTID=0x01200200770978C69A1141439FE559EB459D7580009C4E14902C3CDE46A77F0FFD06506F5B¤tviews=2331]this post in particular seems to capture a lot of what I'm hoping to implement. However, I need some clarification on what special considerations are needed to accomplish this. Beyond the need for a bootloader which can adequately jump to another image (and properly relocate the vector table) I understand there is the issue of position-independent vs position-dependent code. Can anyone shed some more light on how I can generate position-independent code (PIC)? (Perhaps this is a question better directed at Atollic?) Is there any reason to prefer one over the other? I would venture to guess that PIC likely consumes more code space than its ''dependent'' alternative? Other than what I've listed here (bootloader that can properly jump to a new image, PIC vs. non-PIC), are there any other caveats to be aware of? #bootloader #multi-firmware #multi-image-bootloader2015-08-20 10:53 PM
Have you considered a two-stage approach instead?
Have a tiny stage1 loader that just copies either A or B from flash to SRAM, and transfers control to it, same way as happens with the initialised data section in normal startup code. A and B are then both linked to reside at the fixed SRAM address, no need for relocation. And both a and B can overwrite B in flash without any special considerations, as the code is running from SRAM.2015-08-21 06:41 AM
Yes of course! I hadn't considered that approach since we weren't using any external SDRAM in the past. Now that will change things as our hardware guys are planning to provide an extra 32 MB. It is hard sometimes to forget we only had 192KB of RAM to play with in the past! RAM does provide options! Our application images had been around 500KB so we normally ran from flash and used the RAM for our variables. We had reached 80% utilization on the heap. Thanks for the insight!
2015-08-21 07:10 AM
The step to move the vector table into RAM needs to be done manually (ie not by C runtime library code, or linker helper code) where you fix it for the base the rest of the code is residing in, and the SCB->VTOR needs to reflect the RAM address where your table has been moved. In needs to be at 512 byte boundary. You could use 0x20000000 RAM, and advance/shrink the IRAM section in the linker script, or scatter file, to carve out this space.
If you have differences outside the vector table you need to disassemble and examine the code to understand exactly what was created.