cancel
Showing results for 
Search instead for 
Did you mean: 

Using and correctly configuring ITCM RAM for data on STM32H7 within STM32CubeIDE

NSR
Associate III

I'm using a Nucleo STM32H743ZI2 and reallocating variables to different domains to leverage the maximum availability and as such have made changes to both STM32H7ZITX_FLASH.ld and STM32H7ZITX_RAM.ld. This is shown below as:

.
.
.
.
 .myD2memory :
 {  
  . = ALIGN(4);
   *(.myD2memory)
  . = ALIGN(4);
 } >RAM_D2
  
 .myD3memory :
 {  
  . = ALIGN(4);
   *(.myD3memory)
  . = ALIGN(4);
 } >RAM_D3
  
 .myDTCmemory :
 {  
  . = ALIGN(4);
   *(.myDTCmemory)
  . = ALIGN(4);
 } >DTCMRAM
 
 .myITCmemory :
 {  
  . = ALIGN(4);
   *(.myITCmemory)
  . = ALIGN(4);
 } >ITCMRAM
 
 /* Remove information from the compiler libraries */
 /DISCARD/ :
 {
  libc.a ( * )
  libm.a ( * )
  libgcc.a ( * )
 }
 
 .ARM.attributes 0 : { *(.ARM.attributes) }
}

I then apply the designations to the variables as:

uint16_t varDTC[sizeDTC] __attribute__ ((section(".myDTCmemory")));
uint32_t varITC[sizeITC] __attribute__ ((section(".myITCmemory")));
uint32_t varD2[sizeD2] __attribute__ ((section(".myD2memory")));
uint32_t varD3[sizeD3] __attribute__ ((section(".myD3memory")));
 
.
.
int main(void)
{
 /* Initialise prior to use just in case */
 memset(varITC[0], sizeof(varITC), 0);
.
.
}

I'm using STM32CubeIDE to develop my application and in the CORTEX_M7 section, both CPU ICACHE and DCACHE are disabled, as is the MPU. I'm not using MDMA but I do use DMA.

Everything works fine once I've reflashed the program on to the Nucleo board and run it, using the reset button as and when needed. I can also confirm the allocation of memory to the respective areas from the Build Analyzer.

However, if I power-cycle the board, then it appears that I can no longer use ITCM_RAM as it seems to producing pseudo garbage results, as if there's noise on the bus. The area in the TCM areas are used as processor only access; I use this area to process data (graphics) stored in other areas and subsequently store the processed data into D2_RAM domain where I can use timed DMA to shift it to peripherals. While I've tried mitigating existing garbage / noise with memset, this has no affect and is not required on any of the other memory areas; memory in any domain other than AXI_SRAM (default D1_RAM) is read in externally and is not prestored in any way. If I rebuild / reflash the chip using the IDE then full functionality is restored.

I've read through https://www.st.com/resource/en/reference_manual/dm00314099-stm32h742-stm32h743-753-and-stm32h750-value-line-advanced-arm-based-32-bit-mcus-stmicroelectronics.pdf and https://www.st.com/resource/en/application_note/dm00306681-stm32h72x-stm32h73x-and-singlecore-stm32h74x75x-system-architecture-and-performance-stmicroelectronics.pdf but cannot see anything the appears relevant to this, other than while the DTCM is for data only while ITCM can be used for both data and instructions.

The only thing I can think of is that when the unit is being flashed by the IDE tool / onboard debugger, it's configuring the ITCM in such a way that it allows the functionality I want. However, when the unit is power cycled, this configuration is lost as it's not being stored as a configuration within the program.

I also note that for using the D2_RAM domain their respective SRAM {1, 2, 3} clocks should be pre-enabled (as documented in my second link), this has not been done by my program yet still works regardless; albeit there are no pre-configured variables in this area. However, I cannot find similar instruction for the ITCM.

Any help and suggestions how to move this forward would be greatly appreciated.

4 REPLIES 4
NSR
Associate III

While I've managed to reorganize my memory structure, I've noticed that moving from the ITCM to D3 RAM area produces the same results. The only thing I can think of is that there's some configuration of the bus that's causing this to fail after a power up; works fine when freshly compiled and uploaded otherwise.

I've therefore managed to mitigate some of this by swapping the memory areas of some variables and putting others in ITCM / D3 and the problematic (which didn't have any DMA or associated peripherals) into D2. Not really the result I wanted but still moving forward.

If your startup.s code does not specifically address the issue the memories will contain entirely random data at startup, the processor is not responsible for clearing them. Enabling the RAM clocks in startup.s has also been covered here before. ITCM/DTCM RAM shouldn't need additional clock settings.

Check the .ELF to confirm these RAM sections are "NOLOAD", and perhaps do that in your linker scripts also.

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

Hi Clive

Thanks for your reply, I appreciate the effort.

I have no data to preload into those areas as they are used for buffers only. I've also gone further to partition the D2 RAM into three smaller pieces according to their respective SRAM{1, 2, 3} sizes as I want to firmly ensure that my arrays won't span. I've tried starting the clocks as suggested, modifying startup_stmh743zitx.s as:

.section  .text.Reset_Handler
  .weak  Reset_Handler
  .type  Reset_Handler, %function
Reset_Handler:  
/* Enable SRAM clocks */
  ldr r0,=0x580244dc
  ldr r3,[r0]
  orr r3, r3, #3758096384 /* 0xE0000000 */
  str r3,[r0]

to no avail. I've gone further by uncommenting the define at line 81 of system_stm32h7xx.c

/************************* Miscellaneous Configuration ************************/
/*!< Uncomment the following line if you need to use initialized data in D2 domain SRAM (AHB SRAM) */
#define DATA_IN_D2_SRAM

that now implements further in the same file:

which now implements
#if defined (DATA_IN_D2_SRAM)
  /* in case of initialized data in D2 SRAM (AHB SRAM) , enable the D2 SRAM clock (AHB SRAM clock) */
#if defined(RCC_AHB2ENR_D2SRAM3EN)
  RCC->AHB2ENR |= (RCC_AHB2ENR_D2SRAM1EN | RCC_AHB2ENR_D2SRAM2EN | RCC_AHB2ENR_D2SRAM3EN);

that pretty much does the same thing....RCC->AHB2ENR is at 0x580244DC with RCC_AHB2ENR_D2SRAM1EN, RCC_AHB2ENR_D2SRAM2EN and RCC_AHB2ENR_D2SRAM3EN being bits 29, 30 and 31 respectively.

Having checked the .ELF file, whether or not I use (NOLOAD) at the end of each definition in the linker file, I still get the following program header definitions (snipped forthwith for brevity):

Program Headers:
  Type           Offset   VirtAddr   PhysAddr
  LOAD           0x010000 0x00000000 0x00000000
  LOAD           0x010000 0x08000000 0x08000000
  LOAD           0x030000 0x24000000 0x080179a4
  LOAD           0x030208 0x24000208 0x08017ba8
  LOAD           0x03ee28 0x2401ee28 0x08017ba8
  LOAD           0x040000 0x20000000 0x20000000
  LOAD           0x040000 0x30000000 0x30000000
  LOAD           0x040000 0x30020000 0x30020000
  LOAD           0x040000 0x30040000 0x30040000
  LOAD           0x040000 0x38000000 0x38000000

The only difference I see is whether I don't use NOLOAD:

.myD2Amemory :
  {  
    . = ALIGN(4);
     *(.myD2memory)
    . = ALIGN(4);
  } >RAM_D2_1
etc
 
  [Nr] Name              Type            Addr     Off
  [ 9] .data             PROGBITS        24000000 040000
  [10] .bss              NOBITS          24000208 040208
  [11] ._user_heap_stack NOBITS          2401ee28 04ee28
  [12] .myD2Amemory      PROGBITS        30000000 060000
  [13] .myD2Bmemory      PROGBITS        30020000 070000
  [14] .myD2Cmemory      PROGBITS        30040000 090000
  [15] .myD3memory       PROGBITS        38000000 0a0000
  [16] .myDTCmemory      PROGBITS        20000000 050000
  [17] .myITCmemory      PROGBITS        00000000 010000

or I do use it:

.myD2Amemory (NOLOAD):
  {  
    . = ALIGN(4);
     *(.myD2memory)
    . = ALIGN(4);
  } >RAM_D2_1
etc
 
  [Nr] Name              Type            Addr     Off
  [ 9] .data             PROGBITS        24000000 030000
  [10] .bss              NOBITS          24000208 030208
  [11] ._user_heap_stack NOBITS          2401ee28 03ee28
  [12] .myD2Amemory      NOBITS          30000000 040000
  [13] .myD2Bmemory      NOBITS          30020000 040000
  [14] .myD2Cmemory      NOBITS          30040000 040000
  [15] .myD3memory       NOBITS          38000000 040000
  [16] .myDTCmemory      NOBITS          20000000 040000
  [17] .myITCmemory      NOBITS          00000000 010000

The only difference I see is that if I power cycle with the NOLOAD directive in then I can no longer reflash the board to get it working, I have to remove the NOLOAD directives, recompile and then reflash.

Anyway, clocks aside from the D2 memory domain, is there anything that the flashing/debugging utility could be doing to the board/ITCM RAM area that allows everything to function as intended that is otherwise being missed from the board start-up procedures during a cold (re)start? There are other variables that I can put into this domain but the intended array is exactly 64kB. I've also noted a similar behaviour with a particular variable within the D3 domain; they work after flashing until subject to a cold (re)start. I note that the clocks in the D3 are always running for SRAM4 and while a little more complex to move data around, I focus the use for low priority data.