cancel
Showing results for 
Search instead for 
Did you mean: 

How to run code in RAM?

fb
Associate III

I have a project with a STM32H7 part generated with CubeMX, but I want to copy the code to RAM after reset and then run it from RAM, because I want to change the flash where the code is running. How can I do this?

I noticed there is a linker file STM32H723ZGTX_RAM.ld generated. I've used this in the build settings instead of the STM32H723ZGTX_FLASH.ld, but looks like it is still running the code from flash. Do I have to change or add something else or in the startup code?

9 REPLIES 9

The job of the startup.s code is to unpack the work done by the linker and as directed by the linker script.

The ST implementation of this is a bit lackluster. I've seen some Arduino based GNU/GCC implementations that build a table, much like Keil and IAR, which allows the startup code to unpack things to their final destinations without symbols and code for every region.

For code in RAM to run it needs to be copied there, and other code branch or jump to it, usually that's the linkers job to manage. One problem is calling subroutines, library code, or helper functions outside the scope of the elements copied into RAM, and also to copy the vector table there, otherwise you're likely to touch FLASH and either stall, or jump to code you have potentially erased.

I would tend to a) have the RAM code be its own independent application, or b) code a clean, linear, self-relative/referencing, code fragment in assembler and situated in the startup.s, and then copy and execute that in RAM when the system is in a well controlled/defined state (no interrupts, or other noise), and managing a flash update operation.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

The chip for which I'm planning it is the STM32H750ZBT6. It has plenty of RAM, 1 MB, but only 128 kB flash, and unfortunately 128 kB flash sector size as well, and I can only erase a whole sector. So I don't care if everything is copied to RAM and executed from there. It helps with speed as well, because no flash latency needed.

I'm testing it with my STM32H723 board at the moment, and looks like the startup_stm32h723zgtx.s code doesn't include any copy function for the program from flash to RAM. But I'm not an ARM assembly expert. Would be nice if someone has already done it. I would guess others have the problem as well to want to store user data in the flash with the H750 chip.

Pavel A.
Evangelist III

> startup_stm32h723zgtx.s code doesn't include any copy function for the program from flash to RAM

To copy code from flash to internal RAM just use memcpy or whatever. Only make sure that the size of copied block is rounded up to 4 bytes,

because the RAM of STM32H7 does not like incomplete 32-bit units (TL;DR).

No assembly required, just use C.

By the way, the closest relative of STM32H750 is STM32H753, not 723.

​--pa

Nikita91
Lead II

Have a look at this post. An example of C startup code and a linker script with RAM code sections.

Design a generic startup file and a linker script - AdAstra-Soft

To modify for your configuration.

fb
Associate III

Thanks. So looks like it is a bit more work than just writing one memcpy line. Is there a full sample project, working with STM32CubeMX?

Would be nice, if STM32CubeMX would have just a checkbox to generate everything to execute all from RAM.

Hhtgf.1
Associate

The ST implementation of this is a chunk lackluster. I've seen a few Arduino based GNU/GCC implementations that construct a table, similar to Keil and IAR, which lets in the startup code to unpack things to their final locations without symbols and page code for each vicinity.

fb
Associate III

Meanwhile I solved the problem with a macro:

#define RAMCODE attribute ((long_call, section (".data")))

For every function that needs to be in RAM, I just use this macro in front of the function:

RAMCODE HAL_StatusTypeDef FLASH_EraseSector(uint8_t sector)

{

...

The only problem is that when I call a library function in the HAL layer, this function has to be defined with the same macro, otherwise I get lots of "relocation truncated to fit" errors, because branching from flash to RAM and vice versa is not possible with the usual code which is generated, which is limited to a certain distance. So after regenerating the code with CubeMX, I have to add the macros after it manually (or do a diff/apply step).

The startup copies automatically the code from flash to RAM for every function where I use this macro, but I also need to specify the "-fPIC" compiler flag, to create position independent code.

This is also interesting for functions that need to run fast, because there is no flash latency when the code is executed from RAM. But doesn't matter if you have the instruction cache enabled for the bigger microcontrollers which have it.

tempdeltavalue
Associate II

@fb Hi. Can you share any docs which will help to understand you macro ?

Sure, start here:
https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-section-function-attribute
then read about how the GCC linker works, and for the details, read the startup assembly code.