I am using a micro-controller with ARM Cortex M4 processor and developing a bootloader application on it.
- Compiler : GCC- GNU ARM compiler
- Code flash size : 1MB
- Interface for application code download : USB CDC ACM class
- One application software at PC to transfer the application code binary file to MCU o USB
- I have two codes : a. main code(boot code), b. Application code
- In application code, run_my_app() function is written.
-
Flow of main code is as follow :
reset-> initialize MCU initialize USB boot status = CLEAR; while(1) { wait for command from USB : write/ erase if(boot status == BOOT_COMPLETE) { call a function name run_my_app() from application code; } } if erase command received : erase the application code at a flash location 0x0020000 if write command received : Write the application code to flash location 0x0020000 after completion successful write, boot status == BOOT_COMPLETE;
My question is how should i map the run_my_app() function from application code to boot code?
How can i get the address of run_my_code() function so that using function pointer i can call that function?
Hello everyone, I have to modify the entry point of application code to location 0x0020000 in flash from location 0x0000000 using linker script. Currently generated linker script file is :
MEMORY
{
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x0100000 /* 1M */
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x0030000 /* 192K */
DATA_FLASH (rx) : ORIGIN = 0x40100000, LENGTH = 0x0004000 /* 16K */
QSPI_FLASH (rx) : ORIGIN = 0x60000000, LENGTH = 0x4000000 /* 64M, Change in QSPI section below also */
}
ENTRY(Reset_Handler)
SECTIONS
{
.text :
{
__ROM_Start = .;
/* Even though the vector table is not 256 entries (1KB) long, we still allocate that much
* space because ROM registers are at address 0x400 and there is very little space
* in between. */
KEEP(*(.vectors))
__Vectors_End = .;
__Vectors_Size = __Vectors_End - __Vectors;
__end__ = .;
/* ROM Registers start at address 0x00000400 */
. = __ROM_Start + 0x400;
KEEP(*(.rom_registers*))
/* Reserving 0x100 bytes of space for ROM registers. */
. = __ROM_Start + 0x500;
*(.text*)
KEEP(*(.init))
KEEP(*(.fini))
/* .ctors */
*crtbegin.o(.ctors)
*crtbegin?.o(.ctors)
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
*(SORT(.ctors.*))
*(.ctors)
/* .dtors */
*crtbegin.o(.dtors)
*crtbegin?.o(.dtors)
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
*(SORT(.dtors.*))
*(.dtors)
*(.rodata*)
KEEP(*(.eh_frame*))
__ROM_End = .;
} > FLASH = 0xFF
.............
..........
Adding some details to my implementation:
A structure 'CodeInfoStruct' is defined in both boot and application code.
struct CodeInfoStruct
{
uint32_t RunCodeFunctionAddress;
};
In Application code :
Here, a instance of structure is created at a fixed location '0x0020100' and address of the function 'run_my_app' is stored there.
const struct CodeInfoStruct CodeInformation __attribute__((section(".ARM.__at_0x0020100")));
const struct CodeInfoStruct CodeInformation =
{
(uint32_t)run_my_app
};
Also, in linker file, the ROM start address is modified to 0x0020000:
MEMORY
{
FLASH (rx) : ORIGIN = 0x00020000, LENGTH = 0x0100000 /* 1M */
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x0030000 /* 192K */
DATA_FLASH (rx) : ORIGIN = 0x40100000, LENGTH = 0x0004000 /* 16K */
QSPI_FLASH (rx) : ORIGIN = 0x60000000, LENGTH = 0x4000000 /* 64M, Change in QSPI section below also */
}
In boot code:
the structure pointer of 'COdeInfoStruct' is defined.
struct CodeInfoStruct* pCodeInfo = 0x0020100;
And then, the function 'run_my_code' is called from boot code as follow:
void (*trgt_fnc)(void);
trgt_fnc = (void (*)())(pCodeInfo->RunCodeFunctionAddress);
trgt_fnc();
But, i get zero value in this 'trgt_fnc'.
Is it a correct way to share address of function run_my code?
What is wrong here?
Best Answer
The way we do it in one of our products is like this (code is based on IAR compiler, so pragmas might differ for you):
We defined a structure which contains important information of the application part (which is called mainpart in our projects):
This contains among other things the
uint32_t startFunctionAddress
. Now for this structure to be useful, you have to do several things:const
so it can be placed in flashIn the application part:
To share the location, we created a header-file which is included in both parts with a simple define:
In a
.cpp
file of our application we create an instance of the structure which is placed accordingly:Several things happen here:
#pragma location = MAIN_INFO_MEMORY_POSITION
tells the linker where to place the next structure.The
__root
tells our linker that this symbol must be kept, even if it is not referenced by the application code (which it isn't). It has to beconst
otherwise it would not get placed in flash (if it doesn't end up in flash try adding astatic
).So with this we have done everything in the application.
In the boot part:
The boot part needs access to the application part info structure. We wrapped a class around this whole thing, but basically a pointer will be enough:
We use
volatile
here to make sure, that the compiler will not optimize the access to the flash away. With this you can now jump into the application code with an ugly cast:Notes:
In our application we do a CRC check over the whole application part which includes the mainInfoStruct, so we don't jump into nirvana is something went wrong with the update.
The first thing we do in our application is to set the stackpointer to the value it is expected to start with (you can get that from the linker configuration file or your interrupt vector table). Otherwise you might end up with a stack overflow and corrupting your other data.
This is not a minimal example, but might give some hint on what might be useful in a shared structure as well.
We use C++, sorry for the
reinterpret_cast
s.