2018-03-09 09:47 AM
Dear all,
I'm using the Nucelo-144 board with a STM32H743ZI, with the GCC+Makefile toolchain, and am trying to get the RAM in the D2 domain to work.
I generated a Makefile-project with CubeMX and added the following to the linker file:
/* used by the startup to initialize data */
_siRAM_D2 = LOADADDR(.RAM_D2.data);/* Initialized data sections goes into RAM_D2, load LMA copy after code */
.RAM_D2.data : { . = ALIGN(4); _sRAM_D2 = .; /* create a global symbol at data start */ *(.RAM_D2.data) /* .data sections */ *(.RAM_D2.data*) /* .data* sections */. = ALIGN(4);
_eRAM_D2 = .; /* define a global symbol at data end */ } >RAM_D2 AT> FLASH/* Uninitialized data section */
. = ALIGN(4); .RAM_D2.bss (NOLOAD) : { /* This is used by the startup in order to initialize the .bss secion */ _sbss_RAM_D2 = .; /* define a global symbol at bss start */ *(.RAM_D2.bss) *(.RAM_D2.bss*). = ALIGN(4);
_ebss_RAM_D2 = .; /* define a global symbol at bss end */ } >RAM_D2.RAM_D2 : {*(.RAM_D2)} >RAM_D2 AT> FLASH
Also, to initialize .
RAM_D2.data and zero the .RAM_D2.bss segment I added the following to the startup assembly file:
/* Copy the data segment initializers from flash to RAM_D2 */
movs r1, #0 b LoopCopyDataInit_RAM_D2CopyDataInit_RAM_D2:
ldr r3, =_siRAM_D2 ldr r3, [r3, r1] str r3, [r0, r1] adds r1, r1, #4LoopCopyDataInit_RAM_D2:
ldr r0, =_sRAM_D2 ldr r3, =_eRAM_D2 adds r2, r0, r1 cmp r2, r3 bcc CopyDataInit_RAM_D2 ldr r2, =_sbss_RAM_D2 b LoopFillZerobss_RAM_D2/* Zero fill the bss segment. */FillZerobss_RAM_D2: movs r3, #0 str r3, [r2], #4LoopFillZerobss_RAM_D2:
ldr r3, = _ebss_RAM_D2 cmp r2, r3 bcc FillZerobss_RAM_D2Now, everything compiles and objdump shows the sections with correct length, position and attributes, and I can place variables in the D2 RAM using __attribute__((section('.RAM_d1.data')) directives.
However, it looks like these memory regions are neither initialized (for .RAM_D2.data) nor zeroed out (for .RAM_D2.bss), that is, the initialization code in the startup assembly does not work. The interesting thing is that using exactly the same code and linker script but for the D1 and D3 RAM works perfectly fine?!
Also, I tried initializing the memory in C with the following code (only for .RAM_D2.data, .RAM_D2.bss is similar):
extern uint32_t _siRAM_D2;
extern uint32_t _sRAM_D2;
extern uint32_t _eRAM_D2;
void__initialize_data(uint32_t* flash_begin, uint32_t* data_begin, uint32_t* data_end){
uint32_t *p = data_begin;
while(p < data_end){
*p++=*flash_begin++;
}
}
In main():
__initialize_data(&_siRAM_D2,&_sRAM_D2,&_eRAM_D2);
Here the interesting thing is that when I place the call to __initialize_data immediately at the beginning of main(), it does not work, but at some later point in time (after HAL and board init) it does indeed work!
Does anyone have an idea what the problem could be here? Especially, is there a difference between the D1, D2, and D3 RAMs that could be causing this? Because, as I wrote above, everything is 100% fine for D1 and D3, just not for D2 RAM...
Thanks a lot!
Michael
Solved! Go to Solution.
2018-03-13 05:56 PM
,
,
One of the purposes of SystemInit() in the CMSIS model is to initialize the clocks and memory subsystems BEFORE initializing the statics into them.
The GNU startup.s files don't do this, whereas Keil calls SystemInit before __main, and in this case __main is the code that initializes the statics and unpacks the load regions described by the linker before calling the user's main() function.
Having the SP in the vector table point to an uninitialized memory can be problematic too. The value in the vector table could be set to a convenient IRAM address and then changed in the early execution after clocks are brought up.
See Ibrahim's post here
https://community.st.com/0D70X000006SzASSA0
,2018-03-10 01:41 PM
After some more investigation it seems that for D2 RAM one needs to initialize the clock first. Adding the following at the beginning of main does work:
__HAL_RCC_D2SRAM1_CLK_ENABLE();
__HAL_RCC_D2SRAM2_CLK_ENABLE();
__HAL_RCC_D2SRAM3_CLK_ENABLE();
__initialize_data(&_siRAM_D2, &_sRAM_D2, &_eRAM_D2);
__initialize_bss(&_sbss_RAM_D2, &_ebss_RAM_D2);
So the remaining question is: is there anything similar I have to do for D1 and D3 RAMs? I was expecting CubeMX to generate these sort of init routines for me but it seems it doesn't (why?). Also, initializing D2 RAM in the startup assembly file will not work because at that point in time the clocks aren't enabled yet. However, the CubeH7 MDMA example does it that way, am I missing something here or is that example simply wrong?
Best
Michael
2018-03-13 05:56 PM
,
,
One of the purposes of SystemInit() in the CMSIS model is to initialize the clocks and memory subsystems BEFORE initializing the statics into them.
The GNU startup.s files don't do this, whereas Keil calls SystemInit before __main, and in this case __main is the code that initializes the statics and unpacks the load regions described by the linker before calling the user's main() function.
Having the SP in the vector table point to an uninitialized memory can be problematic too. The value in the vector table could be set to a convenient IRAM address and then changed in the early execution after clocks are brought up.
See Ibrahim's post here
https://community.st.com/0D70X000006SzASSA0
,2018-03-15 12:21 PM
Thanks for the clarification Clive, that makes a lot of sense! Is there a way to notify ST about these problems so that they can be fixed in future CubeMX/CubeHAL versions? I think having such a fundamental issue in all projects generated for the GNU toolchain is quite severe and should probably be addressed in a more principled way then the hacky work-around I'm doing right now...
2018-06-19 11:52 PM
Yes, the same issue realized by me:
D2 RAMs are NOT (!!) powered on/enabled during reset. You had to enable the CLK for D2 RAMs, specifically.
The 'only' problem:if you create project and linker script which should place code, data ... on D2 RAMs - it generates entries in a table which are used by startup.s assembly code (e.g. to copy .data from flash to D2 SRAMs, or do zero-init for .bss).But D2 is still disabled. If you just call these CLK enable function later in main() - it is too late (startup.s, ResetVector was running already before and nothing was written due to D2 was off).It is not a problem, it is a feature (save power, enable just what you need, keep D2 down to save power ...).
Just a need to understand the system: the datasheet is pretty clear on this D2 reset/startup behavior (that it needs explicit enable is the conclusion).
You have two options:
a) add the D2 clock enable into startup.s code, before any .data, .bss is copied, initialized - very messy and ugly!
b) do not use D2 for memory which must be initialized at start-up (assuming D2 SRAM is ready when main() runs - it is NOT!!!!):
if you use D2 SRAM locations for buffers, for mem-pools, for heap (malloc), after main() was running (and you enableD2 in main() ) - it works fine, just to bear in mind when D2 is available and that after CLK enable it will have randomcontent, not cleared with zeros or any startup data loaded!You c
annot
pre-load data into D2 on reset and system start-up (during power on)(even not with a debugger, because it will not enable D2 for you before it will release system and startup.s will run).Change your linker script
NOT
to map .data, .bss etc. to D2.