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-bootloader2014-09-10 08:26 PM
As indicated in the other thread the biggest issue with Cortex-Mx related to position dependence is the vector table. If you want flexibility you're probably going to want to send a firmware image in a relocatable form, either one you've created or as a standard ELF relocatable object.
You're going to need to get an understanding of the object format, the features which are important to you, and the options the linker, and to a lesser extent the compiler, provide to make position independent code, and relocatable code.2014-09-11 12:25 AM
I guess one way to avoid the relocation issue would be to build 2 versions of the image - one for the 'A' space; the other for the 'B' space.
Then your download protocol would need to include some way to specify/decide which space...2014-09-11 01:50 AM
Hi
First the simple answers to your questions : ''Can anyone shed some more light on how I can generate position-independent code (PIC)? (Perhaps this is a question better directed at Atollic?)'' The Linker generates the output which will be in fixed or relocatable form. It is set by a linker (possibly compiler) switch. Since Atollic simply wrap the GNU compiler/linker - just look up the GNU documentation (Atollic actually provide it - they simply brand it with their logo) ''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,'' Yes and No. Yes, the banking feature can be used to update the binary in a selected bank. No, because of the code location issue - it is not a simple case of the bootloader vectoring to one back. The issue with fixed and relocatable code : Normally, in Flash the code must be located to fixed addresses. Relocatable code must first be fixed to physical addresses before it is loaded into memory some where for execution. This is for all the jumps (jumps cannot jump to offsets, they must jump to physical addresses). The 'locating' for relocatable code is normally done by the OS - eg when you load a program off disk to execute on a PC the OS will do that for you. To do what you want : You must set the linker to generate relocatable code You must send the code in this form to the bootloader The bootloader must do the conversion from relocatable to fixed addresses, based on which bank (relative to start address) The bootloader must write the now fixed address binary into Flash. One of your big issues will be RAM space - do you have enough space to load the parts of the image and do the offset to address conversion? I have never done anything like this before. It will definitely be a challenge. Good luck2014-09-15 04:10 PM
First off, thanks to everyone for your very informative and timely replies - I appreciate all the input.
While the solution may not be nearly as elegant as the alternative, I'm inclined to move forward with Neil's suggestion of creating two essentially identical images, one for ''A'' region and one for ''B'' region. It seems that much of the difficulty in the process I described pertains to relocatable code. If I can get my task done more efficiently through using two images, this is acceptable for final implementation of the OTA FW update (and unlike an option with relocatable code, I'm comfortable implementing this solution). Thanks again! clive1 - Totally unrelated, but I have to ask after seeing so many of your posts over the past few months. Is that Bill Adama in your profile picture? I've debated making a ''so say we all'' reference becauseI'm struggling to recall an episode in which Olmos wears a necktie :)2014-09-15 07:13 PM
Randall Duk Kim
2015-08-20 08:17 AM
Hi,
Just curious, where would I find the recipe for doing the conversion from relocatable code to fixed addresses? I may be in a situation where I have sufficient RAM to accomplish such a task! Thanks, Bob2015-08-20 11:13 AM
In the general sense one would get a CS text they like on ''Linkers and Loaders''
The ELF format is documentedhttp://flint.cs.yale.edu/cs422/doc/ELF_Format.pdf
, and probably in other newer forms, I started with x86, but the format extends to SPARC, MIPS and ARM. I've used ELF as a starting point, because it's usually easier to transcode objects output from a linker, than write a linker, but I've done both.One could undoubtedly condense the relocation information into much simpler forms using a custom object format that meets specific needs.On a Cortex-Mx, the trick with the Vector Table is just to rebase the 32-bit words to point at the new location, provided the rest of your image didn't contain any address dependent code. If the image were built for an 0x08000000 base, and you wanted it to function at 0x08004000, you'd go add +0x4000 to all 0x080xxxxx addresses in the vector table.One can confirm that an object/binary is address agnostic by linking it for different addresses and doing a compare to understand where the differences are, or by analyzing the objects output from the linker, and the presence and types of relocation entries. If the differences are contained wholly within the vector table, then mission accomplished!2015-08-20 12:35 PM
I tried to create two images at different addresses, 0x08000000 and 0x08020000 using the --apcs=/fpic option on the compiler and the linker (not sure if that is what I am supposed to do). I also used the same VECT_TAB_OFFSET of 0x00 in the system_stm32f4xx.c file for both compiles (Not sure if that was the right thing to do as well). I did a binary compare and there are a very small number of differences throughout the image. Most of the differences are '00' being replaced by '02' but there are a few 'FF' replaced with 'FD'. Seems that I am very close unless some of my assumptions above are incorrect.
2015-08-20 05:19 PM
Ok, have tried using /ropi and now I can see the majority of the differences are in the vector table entries, but there are still a small number sprinkled all through the code. Not sure if it is possible to get those out? Is there something that might be defined in the code that might be doing this? Should I enable the option to locate the vector table in SRAM?