2025-02-10 11:18 PM - edited 2025-02-10 11:21 PM
Hi all,
i have an issue with an STM32-H7A3, which is going into hard fault, when calling a function, which is moved to the ITCM-RAM.
I have defined a section for ITCM-RAM in the Linker-Script:
_siitcmram = LOADADDR(.itcmram); /* size of ITCM-RAM */
.itcmram : { /* ITCM-RAM Section */
. = ALIGN(4); /* Alignment: 4 Bytes - "Word" - u32 */
_sitcmram = .; /* define a global symbols at itcmram start */
*(.itcmram)
*(.itcmram*)
. = ALIGN(4);
_eitcmram = .; /* define a global symbols at itcmram end */
} >ITCMRAM AT> FLASH /* reseve memory in flash for this section */
I copy the code from the flash to the ITCM-RAM in the startup
// BEGIN MODIFICATION - STM-CubeMX Code above
/* Copy from flash to ITCMRAM */
ldr r0, = _sitcmram // start: itcmram start
ldr r1, = _eitcmram // end: itcmram end
ldr r2, = _siitcmram // size
movs r3, #0
b LoopCopyCCMInit
CopyCCMInit:
ldr r4, [r2, r3]
str r4, [r0, r3]
adds r3, r3, #4
LoopCopyCCMInit:
adds r4, r0, r3
cmp r4, r1
bcc CopyCCMInit
/* End of copy to ITCMRAM */
// END MODIFICATION - STM-CubeMX Code below
basically the code above is just a "Copy & Paste" of the section above, where the data get copied from Flash to RAM. I Just edited the names and symbols.
I got the same ruinning - with the same functions - in a Test Project without any issues. The only issue I had at the beginning in the test project was, that I did not copy the code from flash to the ITCM-RAM, but when I did that it worked as intended.
But in this case i can litterally see, that somthing is wrong, because when I step through my code in the debugger, I can not jump (with "step into (F5)") into the function. The debugger simply steps over and quickly goes into hard fault. So my asumption is: for some reason the code is not copied into the ITCMRAM, and the copied functions seem to have the address 0x00 - which is the reason why it goes into hard fault quickly.
Obviously I am missing something. But I don't know what. Can anyone help me out?
Additional Info:
In the CubeIDE Memory Details, I can see the code that should be in the ITCM-RAM is allocated in the ITCM-RAM. There is also a ITCM-RAM section in the flash, where the code that gets copied is stored.
2025-02-11 12:19 AM
2025-02-11 12:47 AM
thanks for the input. It's a nice tutorial to explain how to use the ITCM-RAM.
If it is your tutorial I have 2 comments:
a) typo the 3rd line, the ITCM RAM has 16 kB not 16 MB
b) i wonder how the tutorial works without copying the flash contents into the ITCM-RAM? AFAIK this is "mandatory" to copy the ITCM-Code from the Flash into the ITCM-RAM at the startup ...
but I used your input to check the Memory in the Memory Viewer. And the result is: the whole ITCM-RAM starting at 0x00 seems to be full with random data. This means my code in the startup script somehow has no effect. The same code is working in another project on the same Nucleo, and I wonder why it works in one build but not in another? Thats weird ...
2025-02-11 01:00 AM
I don't have a H7 device, nor I'm really experienced with this variants.
However, two points you might consider.
First, I assume the code you copy is linked for this address, or PIC.
And second, the issues might be related to clock / system setup. I had similiar issues with external RAM, which is of course a different matter.
But perhaps you can try to copy the code after the setup.
Another possible reason might be the MPU, if you use it in your application.
2025-02-11 05:02 AM
Thanks @Ozone
what do you mean with
First, I assume the code you copy is linked for this address, or PIC.
What I do is:
if I have e.g. the function void MyFunction(void) and I want this function to run from the ITCM-RAM, I take the following steps:
a) i create a symbol for the ITCM-RAM in the linker file - as described in my initial post
b) I add code to the startup_stm32xxxxx.s file - as shown in my initial post - that copies the code from the flash memory to the ITCM-RAM at startup
c) I add a __attribute__((section(".itcmram"))) to the function, e.g.
__attribute__((section(".itcmram"))) void MyFunction(void) {
do_some_stuff();
}
and this works normaly. It just won't work in my current project. So I wonder if I forgot something or whatever it might be? It also looks like the startup_stm32xxxx.s does not get compliled every time?
I assumed It might be I had to declare variables for the symbols created in the linker file, because those exists for the other symbols from the linker file:
/* start address for the initialization values of the .data section.
defined in linker script */
.word _sidata
/* start address for the .data section. defined in linker script */
.word _sdata
/* end address for the .data section. defined in linker script */
.word _edata
/* start address for the .bss section. defined in linker script */
.word _sbss
/* end address for the .bss section. defined in linker script */
.word _ebss
/* stack used for SystemInit_ExtMemCtl; always internal RAM used */
so I created .word entries for _siitcmram, _sitcmram and _eitcmram. But that did nothing first. But after a "Project Clean" it lead to a hard fault, even before the first breakpoint in the main.c was reached. After I removed them, cleaned the project, recompiled and started it again, the issue was gone ...
Is there anyone out there who could write me a few lines of assembler, that fill the ITCM-RAM with zeros? I have no assembler skills, I don't know how to do that.
I want to fill the ITCM with zeros (or 0xff, whatever) so I can check in the Memory Viewer, if the init code is working. ATM I can only compare the contents of the memory from Project A (working) and Project B (hard fault) and the look the same. But It is just a bunch of hex values, so it's hard to tell if it is correct or not ...
2025-02-11 05:31 AM
> What I do is: ...
> ...
> c) I add a __attribute__((section(".itcmram"))) to the function, e.g.
I assume you talk about the CubeIDE, which I don't use.
But I suppose it does the trick. Unless you force position-independant code, the linker binds every object (function, variable) to a specific address. This of course only works if the address is correct. In your case, function execution would only work in RAM, not the Flash address you have copied it from.
The map file should show reflect the correct addresses of all objects.
Although I'm not sure how you create it in CubeIDE, and where it is located. But this is standard functionality of basically all modern (and not so modern) toolchains.
> It also looks like the startup_stm32xxxx.s does not get compliled every time?
I would assume a Cube issue. A "clean" should help.
If not, startup_stm32xxxx.o might not be included in list of files to "clean".
> Is there anyone out there who could write me a few lines of assembler, that fill the ITCM-RAM with zeros? I have no assembler skills, I don't know how to do that.
That would be one option.
But you could write a C function somewhere else in your project, and call it from within the startup code.
I think the startup code already contains examples of such calls to external C function.
If not, you could try something like "gcc -c myfile.c", and re-use the compiler-generated assembler code.
2025-02-11 05:32 AM - edited 2025-02-11 05:34 AM
some additional info: it looks like the copy function is working.
This is the content of the Flash
Code in Flash
and this is the content of the ITCM-RAM after startup:
ITCM-RAM
a visual comparison tells me the contents are almost identical, except one word (3rd line) which i marked red.
In the Build Analyzer it looks like it should look like - according to the tutorial @ahsrabrifat linked in his post, with sections for the .itcmram in "FLASH" as well as "ITCMRAM"
When I remove the code to copy the memory contents and restart the Nucleo (remove power, wait 30) seconds, the memory contents look different ...
2025-02-11 05:37 AM
thanks for the hint with the C-file, I'll try that ...
2025-02-11 06:13 AM
Looks like something else may be modifying that space due to the inconsistency you see. Probably an uninitialized pointer or other bad reference. Set a hardware watchpoint to figure out when and where it gets changed. It should get hit once during initialization and once again when the rogue instruction modifies it.
Otherwise it should work. Works for me on H7.
To initialize that space with 0s, use the same code but replace the inner chunk with this:
CopyCCMInit:
movs r4, #0
str r4, [r0, r3]
adds r3, r3, #4
2025-02-11 06:47 AM
Thanks @TDK
i tried your code and that worked. I can see the ITCM-RAM is filled with 0x00 in the memory viewer.
This means: when I revert that change and copy the flash contents again, the ITCM is filled correctly. I guess I have to search the root cause for my hard faults somewhere else.