We have a multi-app bootloader. The application starts with bootloader.uvprojx and then switches to one of the two applications namely: fw2000 and fw3000. So we have 3 binaries/executables on our controller at following addresses of the flash program/code memory space: bootloader at 0x0, fw2000 at 0x2000 and fw3000 at 0x3000 . fw2000 and fw3000 are the same code but these two app firmwares here are compiled using absolute ROM addresses to create fw2000.bin and fw3000.bin. This is done in Keil by setting the address in "Options for target"->"Target"->"IROM1:" -> "Start" address to respective start address .
We have this architecture to update firmware. For that creating bin/hex specific to absolute address is not desirable.
Is there a way to compile a fwXXXX which can be relocatable at both the addresses? Such that, fwXXXX is compiled and the .bin ot .hex can be written at any address (in this case 0x2000 or 0x3000).
Not sure Keil is well suited to that, but when I've do this sort of thing in the past I've used relocatable .ELF files, or a custom executable format. The .ELF format is well documented, and has a lot of GNU tools behind it.
I thought Keil had this in built because in the "Options for Target" -> C/C++ there are two check boxes "Read-Only Position Independent" and "Read-Write Position Independent". I thought these options had something to do with my objective.
Perhaps if you're using a non-eval version of the tools, and making position independent objects.
You're problem at the linking level with the Cortex-Mx parts is the Vector Table contains absolute values, earlier ARM parts used relative branches. You could build everything as address independent, and then link for address zero, and then fudge the vector table values as you write into a specific area of flash to account for the new offset basis.
Hi Pier, I'm not sure which options to check out of the two: "Options for Target" -> C/C++ there are two check boxes "Read-Only Position Independent" and "Read-Write Position Independent". I'm gonna give this a try: compile the code with Read-Only Position Independent checked. Then write this bin file at 0x3000 and then reboot from the bootloader and switch to 0x3000... see if it executes from there...
When I say 'switch to 0x3000', I mean the bootloader does this: 1) force re-map assigned flash page (in this case 0x3000) to CPU address 0x0 . This is a feature of the microcontroller and not common to Cortex M0 arch. 2) Assign a function pointer to the base address of the firmware (in this case 0x3000). 3) Use the CMSIS function __set_MSP() to the base address of the firmware (in this case 0x3000). 4) Call the funtion which was set in step (2).
So your concern of the vector table being called from an absolute address is handled by the micro-controller's feature of force remap.
Thanks
How do I know which options need to checked? In my case, the controller's internal flash is divided into bootloader, fw2000, fw3000 and the remaining latter portion of the flash is used for storing persistent data like an eprom or data flash. So, the fw2000 and fw3000 access absolute addresses from this region to access persistent data using absolute addresses which remain the same for both application firmwares.
The interrupt vector table relocation feature is quite common.
All it does, is to make a piece of flash be mapped to the address range where the actual hardware expects to find it.
But it doesn't take care of how the processor - when activating an interrupt - will be able to jump from the vector and into the relocated service routine.
The normal way this is done is that the build tools knows the interrupt vector table will be mapped on top of address zero - but also knows about the exact address where the ISR code is. So the linker produces code that correctly jumps to the ISR. But if you load your code to some other address than what the linker prepared the code for, then this jump will fail.
So the vector remapping fixes the jump into the table but not the jump out of the table and into the ISR. That's something your boot loader needs to fix. If the processor architecture uses absolute or relative jumps, affects how the boot loader needs to modify the interrupt vector table content.
"So your concern of the vector table being called from an absolute address is handled by the micro-controller's feature of force remap."
Umh, no.
The Cortex-M3/M4 have SCB->VTOR, the Cortex-M0 requires an alternate shadowing at address zero to achieve a similar effect.
STILL, the vectors IN THE TABLE point to ABSOLUTE addresses. Which, by definition, is NOT address-independent. If the rest of your code/data is address-independent you can fudge/patch the vector table entries as you write them to FLASH or RAM to account for the specific address they are now situated at.
Thanks! I got what what u were telling about the absolute address entries in the vector table. I'll figure out a way to fix that.
I did NOT understand : "If the rest of your code/data is address-independent". How do I know this? Doesn't checking the "Read-Only Position Independent" box ensure that?
Hi Pier, I tried shifted the vector table to the RAM in the firmware. The ISR funtion pointers are copied in the vector table in RAM. The program runs through the init and then stops working. I'm not able to debug this code.
The reason could be that when the fw2000 is running, it is provided with fw3000.bin . The fw2000 copies the .bin file in the internal flash @ 0x3000. After fw2000 is done writing and veryfying the firmware, the MCU restarts and the bootloader will now boot only fw3000. fw3000 runs though init, I get a few led blinks as expected and then I can't tell what's happening. Is there a way to debug the fw3000 using Keil?
Hi Pier, Out of curiosity I compiled 3 bin files: 1)IROM1 0x2000 2)IROM1 0x3000 3)IROM1 0x3000, I checked the ROPI box in C/C++ tab.
The bin files created using 2) and 3) are identical.
I was thinking that: checking ROPI would make the bin position independent and then even if it is loaded at any address in the flash, it should work.
Correct me if I'm wrong.
The source level debugger should work if a) the right project file is loaded, and b) it's at the address the linker created it. The disassembly view should work regardless, and should be adequate to diagnose what's happening. Use the .MAP file to navigate if you need too.
I'd augment that with output via USART or SWV channels, and by having an effective Hard Fault handler, and other diagnostics, so I could see what was happening internally.
If you built all your firmware with the assumption they load at zero, then you'd fix up the vector table so that the ODD code address had +0x2000 and +0x3000 added to them respectively if you wrote them at 0x2000 and 0x3000 instead of 0x0000
I'd also walk the code generated by the compiler/linker until I was comfortable that it was actually address independent. Believe me people get very irritated if you commit bad code to a Masked ROM, even if it's the tool chain's fault, they can't fire, shout or throw things at the tools. You learn to understand how the processor and the tools function.