linker script and changing the flash address - stm32

I would like to ask the following a question: im using stm32g0xx microcontroller and i want to change the flash address in linker script automatically and not be forced to changed manually every time i want to generate an apllication image to let it run from diffrent address. what im doing i wrote an application and i wrote it to tow different address"0x08001000 and 0x08004800" to have the apility to switch to other application incase one of them is updated or damaged. it worked fine but i need by every image to change the flash address manually and i would like to ask if it is possible to changed somewhere else out of the linker script like startup.s?
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 8K
FLASH (rx) : ORIGIN = 0x8001000, LENGTH = 32K
}
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 8K
FLASH (rx) : ORIGIN = 0x8004800, LENGTH = 32K
}

You can create two linker files and compile two times, each time with a different linker script and a different output binary. You will obtain the two necessary binaries. To integrate it on your project, it depends on your way of working (STM IDE, standalone Makefile...) which you did not mention.
As a side note, you should modify the LENGTH on your linker scripts, it will prevent the linker to place data where you have another application.
Your first application starts at 4KB (0x1000), and the second start at 18KB (0x4800), the lenght of the first application should be 18-4 = 16KB and the second LENGTH should be 32-18 = 14KB (if the FLASH total size is 32KB).

You can write two different linker script and apply one or the other in your building enviroment (with the -T linker flag) or you can use a variable for your ORIGIN and pass it with -Wl,--defsym=<VAR_NAME>=<VAR_VALUE>

Related

OSDev: OS fails when I deinit physical memory regions

I am currently running into problems. So, I am making my own OS, and currently have no problems except for one.
I don't know if it's with my linker script or what, but for some reason, when I attempt to deinit a region of physical memory, QEMU simply doesn't show anything on the screen.
But, as soon as I comment the function out, it works just fine. I tried packing the binary file full of random junk as well, OS still works fine, everything displays in QEMU. I tried doing hefty function calling for things that the OS doesn't even support yet, still runs. But, for some reason, when I call my function to de-init a region of used physical memory, the whole thing just crashes and doesn't work.
I am only including the linker script below, I will link my github page to the OS project for anyone to skim through it and possible help out. This is seriously super annoying.
SECTIONS {
.text 0x1F00 :
{
*(kernel_entry);
*(.text*);
}
.idt BLOCK(.) : ALIGN(.)
{
_idt = .;
. = . * 0x100;
}
.rodata :
{
*(.rodata*);
}
.bss :
{
*(.bss*);
}
end = .;
}
I did roll my own Bootloader as well. The github layout goes as so:
All bootloader content is in folder Bootloader, all kernel content(including linker script) is in folder Kernel.
GitHub page

External Flash Loader linker script file

I'm trying to make a custom external flash loader for my STM32F746 uC based board and i found some templates for this purpose from this link that is belongs to the ST workshop on this YouTube link. So when i dug into the corresponding files i saw that in a linker script file named linker.ld the RAM memory region is defined from base address 0x20000004 though i know that the RAM memory region in STM uCs starts from address 0x20000000:
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000004, LENGTH = 320K
}
I searched for many other templates file existing in this link and also they are using the same way for RAM memory region base address.
So the problem is why we must define RAM memory address from 0x20000004 for external flash loader algorithm to store in and not from 0x20000000 instead. Could anyone please help me to explain the reason and tell me that what will happen if we do the:
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 320K
}
instead of previous one and what errors might be occurred?
Thanks.

How can I change the start address on flash?

I'm using STM32F746ZG and FreeRTOS.
The start address of flash is 0x08000000. But I want to change it to 0x08040000. I've searched this issue through google but I didn't find the solution.
I changed the linker script like the following.
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 320K
/* FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 1024K */
FLASH (rx) : ORIGIN = 0x8040000, LENGTH = 768K
}
If I only change it and run the debugger, it has the problem.
If I change the VECT_TAB_OFFSET from 0x00 to 0x4000, it works fine.
/* #define VECT_TAB_SRAM */
#define VECT_TAB_OFFSET 0x40000 /* 0x00 */
SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET;
But if I don't use debugger, it doesn't work anything.
It means it only works when using ST-Linker.
Please let me know if you know the solution.
Thank you for in advance of your reply.
The boot address can be set in the option bytes.
You can set any address in the flash with 16k increments. There are two 16 bit registers in the option bytes area, one is used when the boot pin is low at reset, the other when the pin is high. Write the desired address shifted right by 14 bits, i.e. divided by 16384.
To boot from 0x08040000, write 0x2010 into the register as described in the Option bytes programming chapter of the reference manual.
You could also write a bootloader. Bootloader sits on the 0x0800 0000 address and loads your application firmware meaning jumps to it.
This is the other way to do it.
You need to place 8 bytes at the original beginning of the FLASH. Stm32 boots always from the address 0x00000000 which is aliased to the one of the memories (depending on the boot pins and options).
The first word contains the stack pointer the second one your reset handler. You never get to your code as it boots always from the same address.
You will need to modify your linker script and the startup files where vectors are defined

STM32 Boot from specific NOR block

I've ported an STM32F4 project from Keil uVision5 to Eclipse (GNU MCU Plugin).
In my Keil uVision5 project, I used to use 7th block (0x080E0000) for my boot code (I verify that using STM32 ST-LINK Utility tool that my boot code is really at 7th block) which I used to configure very easily using Keil uVision5 interface as shown below:
If I'm not mistaken, in my Keil uVision project (whose memory configuration is shown above), the MCU boots from 0th block (0x08000000) and then jumps immediately to 7th block (0x080E0000) to execute my code. Tell me if I'm wrong.
My problem is with my Eclipse project. As you might already know, we configure the memory map using a linker script file named mem.ld. I tried to imitate the same behavior using mem.ld but I suppose that I've failed. Whenever I flash the executable generated by Eclipse, my code doesn't run. Moreover, I couldn't find a way to indicate an area for startup in mem.ld file. Below is my memory configuration in mem.ld file:
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
CCMRAM (xrw) : ORIGIN = 0x10000000, LENGTH = 64K
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 16K
FLASHB1 (rx) : ORIGIN = 0x080E0000, LENGTH = 640K
EXTMEMB0 (rx) : ORIGIN = 0x00000000, LENGTH = 0
EXTMEMB1 (rx) : ORIGIN = 0x00000000, LENGTH = 0
EXTMEMB2 (rx) : ORIGIN = 0x00000000, LENGTH = 0
EXTMEMB3 (rx) : ORIGIN = 0x00000000, LENGTH = 0
MEMORY_ARRAY (xrw) : ORIGIN = 0x20002000, LENGTH = 32
}
Could you please help me to imitate the same behavior with Keil uVision5 using mem.ld file? What mistake do I do in mem.ld configuration? What should be the correct configuration?
Thanks a lot in advance.
The address of the code which is executed after the reset is taken from the 4-7 bytes of your vector table (it is called the reset vector).
In the gcc style linker script the ENTRY directive is important not your memory sections definitions.
you can change the entry to the address value or a symbol. For example
ENTRY(My_Startup_Function) or as it is in the standard linker scripts generated by the CubeMX ENTRY(Reset_Handler)
in keil as I remember you have couple of options:
command line
--entry=location
where location can be address or symbol
here is more information about the root region and the entry point. I do not use keil anymore and personally prefer gcc.

In Application Programming issue

I'm working on project on STM32L152RCT6, where i have to build a mechanism to self update the code from the newly gated file(HEX file).
For that i have implemented such mechanism like boot loader where it checks for the new firmware if there it it has to cross verify and if found valid it has to store on "Application location".
I'm taking following steps.
Boot loader address = 0x08000000
Application address = 0x08008000
Somewhere on specified location it has to check for new file through Boot loader program.
If found valid it has to be copy all the HEX on location(as per the guide).
Than running the application code through jump on that location.
Now problem comes from step 5, all the above steps I've done even storing of data has been done properly(verify in STM32 utility), but when i'm jump to the application code it won't work.
Is there i have to cross check or something i'm missing?
Unlike other ARM controllers that directly jump to address 0 at reset, the Cortex-M series takes the start address from a vector table. If the program is loaded directly (without a bootloader), the vector table is at the start of the binary (loaded or mapped to address 0). First entry at offset 0 is the initial value of the stack pointer, second entry at address 4 is called the reset vector, it contains the address of the first instruction to be executed.
Programs loaded with a bootloader usually preserve this arrangement, and put the vector table at the start of the binary, 0x08008000 in your case. Then the reset vector would be at 0x08008004. But it's your application, you should check where did you put your vector table. Hint: look at the .map file generated by the linker to be sure. If it's indeed at 0x08008000, then you can transfer control to the application reset vector so:
void (*app)(void); // declare a pointer to a function
app = *(void (**)(void))0x08008004; // see below
app(); // invoke the function through the pointer
The complicated cast in the second line converts the physical address to a pointer to a pointer to a function, takes the value pointed to it, which is now a pointer to a function, and assigns it to app.
Then you should manage the switchover to the application vector table. You can do it either in the bootloader or in the application, or divide the steps between them.
Disable all interrupts and stop SysTick. Note that SysTick is not an interrupt, don't call NVIC_DisableIRQ() on it. I'd do this step in the bootloader, so it gets responsible to disable whatever it has enabled.
Assign the new vector table address to SCB->VTOR. Beware that the boilerplate SystemInit() function in system_stm32l1xx.c unconditionally changes SCB->VTOR back to the start of the flash, i.e. to 0x08000000, you should edit it to use the proper offset.
You can load the stack pointer value from the vector table too, but it's tricky to do it properly, and not really necessary, the application can just continue to use the stack that was set up in the bootloader. Just check it to make sure it's reasonable.
Have you changed the application according to the new falsh position?
For example the Vector Table has to be set correctl via
SCB->VTOR = ...
When your bootloader starts the app it has to configure everything back to the reset state as the application may relay on the default reset values. Espessially you need to:
Return values of all hardware registers to its reset values
Switch off all peripheral clocks (do not forget about the SysTick)
Disable all enabled interrupts
Return all clock domains to its reset values.
Set the vector table address
Load the stack pointer from the beginning of the APP vector table.
Call the APP entry point.(vertor table start + 4)
Your app has to be compiled and linked using the custom linker script where the FLASH start point is 0x8008000
for example:
FLASH (rx) : ORIGIN = 0x8000000 + 32K, LENGTH = 512K - 32K
SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET;
where FLASH_BASE's value must be equal to the address of your IROM's value in KEIL
example:
#define FLASH_BASE 0x08004000
Keil configuration