2020-05-02 06:03 PM
I am writing a USB MSD bootloader for an STM32L4 processor with 2MB of Flash. The bootloader code will reside in Flash as will the application code. The application code will most likely be larger than 1MB so I’m thinking to have only a single bank. I will thus need to copy the pertinent routines that access Flash for erasing and programming from Flash to RAM. I can put all the pertinent routines into one file. I would like some help in writing the linker script so that I can specify that file separately for ROM to RAM copying. I’ve been looking at the linker script manual but I’m still unclear about the exact syntax. Any help would be greatly appreciated!
Thanks
2020-05-02 07:19 PM
In your function:
__attribute__ ((section (".code_in_ram")))
void function_to_overwrite_flash() {
...
};
In your linker script:
/* Initialized data sections goes into RAM, load LMA copy after code */
.data :
{
. = ALIGN(4);
_sdata = .; /* create a global symbol at data start */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
. = ALIGN(4);
*(.code_in_ram)
*(.code_in_ram*)
. = ALIGN(4);
_edata = .; /* define a global symbol at data end */
} >RAM AT> FLASH
And in your startup code:
/* Copy the data segment initializers from flash to SRAM */
movs r1, #0
b LoopCopyDataInit
CopyDataInit:
ldr r3, =_sidata
ldr r3, [r3, r1]
str r3, [r0, r1]
adds r1, r1, #4
LoopCopyDataInit:
ldr r0, =_sdata
ldr r3, =_edata
adds r2, r0, r1
cmp r2, r3
bcc CopyDataInit
Note that you can use variables on the stack within that function, but any variables/constants stored in ROM will no longer be valid once you erase it.
2020-05-02 11:57 PM
Calls to built-in functions would too cease to work.
2020-05-03 12:48 AM
> I will thus need to copy the pertinent routines that access Flash for erasing and programming from Flash to RAM.
No, you don't need to. Flash programming works fine from the same bank.
> I can put all the pertinent routines into one file.
They must be linked separately from the application. Put them into a separate project.
Best practice is to locate the bootloader at the beginning of the flash. If a flag is set a certain way, and the reset source is software, then start the bootloader process, otherwise jump to the application. The application sets the flag and calls NVIC_SystemReset() to start the bootloader. When the bootloader finishes updating the flash, resets the flag and calls NVIC_SystemReset() to reset all peripherals before jumping to the application. The flag should be at a fixed memory location which is excluded in the linker scripts of both projects.
2020-05-03 01:37 PM
I am confused by your statement that you can program in the same bank where the code is running. I was interpreting section 3.3.8 of the reference manual to mean that you cannot either program or erase sectors (pages) from one bank while executing code from the same bank. And I would assume the same if there is only one bank. So you’re saying that I don’t need to have the routines that program or erase pages be put into RAM. That was true for the Kinetis processor I was using which had a separate Flash control module. I am planning to have the bootcode at the beginning of Flash which will jump to the application code unless it sees that a USB host has been connected. After the app file has been copied from the host and programmed into Flash, the bootcode will jump to the application.
2020-05-03 03:07 PM
No, it's the other way round. You cannot execute code (or read data) from the same bank while a flash write or erase is in progress.
Flash write or erase operations block reading from the same bank. The core will wait patiently for the operation to finish, and continue.
Just keep in mind that erasing a flash sector can take a few seconds (listed somewhere in the datasheet), during that time everything is blocked.
2020-05-03 03:20 PM
Great! Thanks so much for the help!