cancel
Showing results for 
Search instead for 
Did you mean: 

STM32H743: Moving Heap to SDRAM using TouchGFX

heyo
Senior

So Im trying to move heap to my external SDRAM and the problem is that it hardfaults after 3s and do not know why.
In startup file before__libc_init_array i call fmc function which init SDRAM.Fmc function looks like this: 

void fmc(void)
{
	HAL_Init();
	SystemClock_Config();
	PeriphCommonClock_Config();
	MX_GPIO_Init();
	MX_FMC_Init();
	MPU_Config();         // mark SDRAM cacheable
	SCB_EnableICache();
	SCB_EnableDCache();
}


Im using TouchGFX, STM32H743ZIT6 and IS42S16400J-6TLI SDRAM. Ive already changed my sbrk, linker and MPU. I add code fragments:

/*
******************************************************************************
**
**  File        : LinkerScript.ld
**
**  Author      : STM32CubeIDE
**
**  Abstract    : Linker script for STM32H7 series
**                2048Kbytes FLASH and 1056Kbytes RAM
**
**                Set heap size, stack size and stack location according
**                to application requirements.
**
**                Set memory bank area and size if external memory is used.
**
**  Target      : STMicroelectronics STM32
**
**  Distribution: The file is distributed as is, without any warranty
**                of any kind.
**
*****************************************************************************
** @attention
**
** Copyright (c) 2023 STMicroelectronics.
** All rights reserved.
**
** This software is licensed under terms that can be found in the LICENSE file
** in the root directory of this software component.
** If no LICENSE file comes with this software, it is provided AS-IS.
**
****************************************************************************
*/

/* Entry Point */
ENTRY(Reset_Handler)

/* Highest address of the user mode stack */
_estack = ORIGIN(RAM_D1) + LENGTH(RAM_D1);    /* end of RAM */
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Stack_Size = 0x1200; /* required amount of stack */
/* Heap in SDRAM */
__heap_start = 0xC0000000;
__heap_limit = 0xC0200000;
/* Specify the memory areas */
MEMORY
{
  /*FLASH (rx)     : ORIGIN = 0x08040000, LENGTH = 1792K*/
  FLASH (rx)     : ORIGIN = 0x08000000, LENGTH = 2048K
  DTCMRAM (xrw)  : ORIGIN = 0x20000000, LENGTH = 128K
  RAM_D1 (xrw)   : ORIGIN = 0x24000000, LENGTH = 512K
  RAM_D2 (xrw)   : ORIGIN = 0x30000000, LENGTH = 288K
  RAM_D3 (xrw)   : ORIGIN = 0x38000000, LENGTH = 64K
  ITCMRAM (xrw)  : ORIGIN = 0x00000000, LENGTH = 64K
  QUADSPI (r)    : ORIGIN = 0x90000000, LENGTH = 16M
  SDRAM   (xrw)  : ORIGIN = 0xC0000000, LENGTH = 8M
}
/* Define output sections */
SECTIONS
{
  /* The startup code goes first into FLASH */
  .isr_vector :
  {
    . = ALIGN(4);
    KEEP(*(.isr_vector)) /* Startup code */
    . = ALIGN(4);
  } >FLASH

  /* The program code and other data goes into FLASH */
  .text :
  {
    . = ALIGN(4);
    *(.text)           /* .text sections (code) */
    *(.text*)          /* .text* sections (code) */
    *(.glue_7)         /* glue arm to thumb code */
    *(.glue_7t)        /* glue thumb to arm code */
    *(.eh_frame)

    KEEP (*(.init))
    KEEP (*(.fini))

    . = ALIGN(4);
    _etext = .;        /* define a global symbols at end of code */
  } >FLASH

  /* Constant data goes into FLASH */
  .rodata :
  {
    . = ALIGN(4);
    *(.rodata)         /* .rodata sections (constants, strings, etc.) */
    *(.rodata*)        /* .rodata* sections (constants, strings, etc.) */
    . = ALIGN(4);
  } >FLASH

  .ARM.extab   : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH
  .ARM : {
    __exidx_start = .;
    *(.ARM.exidx*)
    __exidx_end = .;
  } >FLASH

  .preinit_array     :
  {
    PROVIDE_HIDDEN (__preinit_array_start = .);
    KEEP (*(.preinit_array*))
    PROVIDE_HIDDEN (__preinit_array_end = .);
  } >FLASH

  .init_array :
  {
    PROVIDE_HIDDEN (__init_array_start = .);
    KEEP (*(SORT(.init_array.*)))
    KEEP (*(.init_array*))
    PROVIDE_HIDDEN (__init_array_end = .);
  } >FLASH

  .fini_array :
  {
    PROVIDE_HIDDEN (__fini_array_start = .);
    KEEP (*(SORT(.fini_array.*)))
    KEEP (*(.fini_array*))
    PROVIDE_HIDDEN (__fini_array_end = .);
  } >FLASH

  /* used by the startup to initialize data */
  _sidata = LOADADDR(.data);

  /* Initialized data sections goes into RAM, load LMA copy after code */
  .data :
  {
    . = ALIGN(4);
    _sdata = .;        /* create a global symbol at data start */
    *(.data)           /* .data sections */
    *(.data*)          /* .data* sections */
    *(.RamFunc)        /* .RamFunc sections */
    *(.RamFunc*)       /* .RamFunc* sections */

    . = ALIGN(4);
    _edata = .;        /* define a global symbol at data end */
  } >RAM_D1 AT> FLASH

  /* Uninitialized data section */
  . = ALIGN(4);
  .bss :
  {
    /* This is used by the startup in order to initialize the .bss section */
    _sbss = .;         /* define a global symbol at bss start */
    __bss_start__ = _sbss;
    *(.bss)
    *(.bss*)
    *(COMMON)

    . = ALIGN(4);
    _ebss = .;         /* define a global symbol at bss end */
    __bss_end__ = _ebss;
  } >RAM_D1

  /* User_heap_stack section, used to check that there is enough RAM left */
._user_stack :
{
  . = ALIGN(8);
  PROVIDE(_stack_start = .);
  . = . + _Min_Stack_Size;
  PROVIDE(_stack_end = .);
  . = ALIGN(8);
} >RAM_D1

/* Heap in SDRAM */
._user_heap (NOLOAD):
{
  . = ALIGN(8);
  __heap_start = .;
  . = . + 0x200000;
  __heap_limit = .;
} >SDRAM

  /* Remove information from the standard libraries */
  /DISCARD/ :
  {
    libc.a ( * )
    libm.a ( * )
    libgcc.a ( * )
  }

  .ARM.attributes 0 : { *(.ARM.attributes) }
  /*.sdram_section (NOLOAD) : { *(.sdram_section) }> SDRAM*/
    FontFlashSection (NOLOAD): /*DELETE (NOLOAD) IF U WANT TO UPDATE QSPI FLASH*/
  {
    *(FontFlashSection FontFlashSection.*)
    *(.gnu.linkonce.r.*)
    . = ALIGN(0x4);
  } >QUADSPI

  TextFlashSection (NOLOAD):/*DELETE (NOLOAD) IF U WANT TO UPDATE QSPI FLASH*/
  {
    *(TextFlashSection TextFlashSection.*)
    *(.gnu.linkonce.r.*)
    . = ALIGN(0x4);
  } >QUADSPI

  ExtFlashSection (NOLOAD):/*DELETE (NOLOAD) IF U WANT TO UPDATE QSPI FLASH*/
  {
    *(ExtFlashSection ExtFlashSection.*)
    *(.gnu.linkonce.r.*)
    . = ALIGN(0x4);
  } >QUADSPI
}

 

 

#include <errno.h>
#include <stdint.h>
#include <sys/types.h>

extern char __heap_start;
extern char __heap_limit;

caddr_t _sbrk(int incr)
{
    static char *heap_end = NULL;
    char *prev_heap_end;

    if (heap_end == NULL)
        heap_end = &__heap_start;

    /* Align increment to 8 bytes (prevent unaligned access faults) */
    incr = (incr + 7) & ~7;

    if ((heap_end + incr) > &__heap_limit)
    {
        errno = ENOMEM;
        return (caddr_t)-1;
    }

    prev_heap_end = heap_end;
    heap_end += incr;

    return (caddr_t)prev_heap_end;
}
void MPU_Config(void)
{
  MPU_Region_InitTypeDef MPU_InitStruct = {0};

  /* Disables the MPU */
  HAL_MPU_Disable();

  /** Initializes and configures the Region and the memory to be protected
  */
  MPU_InitStruct.Enable = MPU_REGION_ENABLE;
  MPU_InitStruct.BaseAddress = 0xC0000000;
  MPU_InitStruct.Size = MPU_REGION_SIZE_8MB;
  MPU_InitStruct.Number = MPU_REGION_NUMBER0;
  MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
  MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
  MPU_InitStruct.IsCacheable  = MPU_ACCESS_CACHEABLE;
  MPU_InitStruct.IsShareable  = MPU_ACCESS_NOT_SHAREABLE;
  MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;
  MPU_InitStruct.SubRegionDisable = 0x00;
  MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;

  HAL_MPU_ConfigRegion(&MPU_InitStruct);

  /** Initializes and configures the Region and the memory to be protected
  */
  MPU_InitStruct.Number = MPU_REGION_NUMBER1;
  MPU_InitStruct.BaseAddress = (uint32_t)RxData;
  MPU_InitStruct.Size = MPU_REGION_SIZE_4KB;
  MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;
  MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;

  HAL_MPU_ConfigRegion(&MPU_InitStruct);
  /* Enables the MPU */
  HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);

}

 Does someone sees where is the problem? Or what to check?

15 REPLIES 15
mƎALLEm
ST Employee

Hello,

I have a doubt that this configuration is an undefined MPU encoding (TEX=1, C=1, B=0, S=0):

  MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
  MPU_InitStruct.IsCacheable  = MPU_ACCESS_CACHEABLE;
  MPU_InitStruct.IsShareable  = MPU_ACCESS_NOT_SHAREABLE;
  MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;

Try to use this config (TEX=0, C=1, B=1, S=0): write-back/no write allocate:

  MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;
  MPU_InitStruct.IsCacheable  = MPU_ACCESS_CACHEABLE;
  MPU_InitStruct.IsShareable  = MPU_ACCESS_NOT_SHAREABLE;
  MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;

:

 

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.

Same. It hardfault after 2-3s start. I see that it uses heap in sdram bet when hardfault. Ive changed so many thing and need more ideas what can i do.
Adding fmc init, maybe something wrong is here:

void MX_FMC_Init(void)
{
  /* USER CODE BEGIN FMC_Init 0 */

  /* USER CODE END FMC_Init 0 */

  FMC_SDRAM_TimingTypeDef SdramTiming = {0};

  /* USER CODE BEGIN FMC_Init 1 */

  /* USER CODE END FMC_Init 1 */

  /** Perform the SDRAM1 memory initialization sequence
  */
  hsdram1.Instance = FMC_SDRAM_DEVICE;
  /* hsdram1.Init */
  hsdram1.Init.SDBank = FMC_SDRAM_BANK1;
  hsdram1.Init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_8;
  hsdram1.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_12;
  hsdram1.Init.MemoryDataWidth = FMC_SDRAM_MEM_BUS_WIDTH_16;
  hsdram1.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4;
  hsdram1.Init.CASLatency = FMC_SDRAM_CAS_LATENCY_2;
  hsdram1.Init.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE;
  hsdram1.Init.SDClockPeriod = FMC_SDRAM_CLOCK_PERIOD_2;
  hsdram1.Init.ReadBurst = FMC_SDRAM_RBURST_ENABLE;
  hsdram1.Init.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_1;
  /* SdramTiming */
  SdramTiming.LoadToActiveDelay = 2;
  SdramTiming.ExitSelfRefreshDelay = 7;
  SdramTiming.SelfRefreshTime = 5;
  SdramTiming.RowCycleDelay = 6;
  SdramTiming.WriteRecoveryTime = 3;
  SdramTiming.RPDelay = 2;
  SdramTiming.RCDDelay = 2;

  if (HAL_SDRAM_Init(&hsdram1, &SdramTiming) != HAL_OK)
  {
    Error_Handler( );
  }

  /* USER CODE BEGIN FMC_Init 2 */
   FMC_SDRAM_CommandTypeDef Command;
   /* Step 1 and Step 2 already done in HAL_SDRAM_Init() */
   /* Step 3: Configure a clock configuration enable command */
    Command.CommandMode            = FMC_SDRAM_CMD_CLK_ENABLE; /* Set MODE bits to "001" */
    Command.CommandTarget          = FMC_SDRAM_CMD_TARGET_BANK1; /* configure the Target Bank bits */
    Command.AutoRefreshNumber      = 1;
    Command.ModeRegisterDefinition = 0;
    HAL_SDRAM_SendCommand(&hsdram1, &Command, 0xfff);
    HAL_Delay(1); /* Step 4: Insert 100 us minimum delay - Min HAL Delay is 1ms */
    /* Step 5: Configure a PALL (precharge all) command */
    Command.CommandMode            = FMC_SDRAM_CMD_PALL; /* Set MODE bits to "010" */
    HAL_SDRAM_SendCommand(&hsdram1, &Command, 0xfff);
    /* Step 6: Configure an Auto Refresh command */
    Command.CommandMode            = FMC_SDRAM_CMD_AUTOREFRESH_MODE; /* Set MODE bits to "011" */
    Command.AutoRefreshNumber      = 2;
    HAL_SDRAM_SendCommand(&hsdram1, &Command, 0xfff);
    /* Step 7: Program the external memory mode register */
    Command.CommandMode            = FMC_SDRAM_CMD_LOAD_MODE;/*set the MODE bits to "100" */
    Command.ModeRegisterDefinition =  (uint32_t)0 | 0<<3 | 2<<4 | 0<<7 | 1<<9;
    HAL_SDRAM_SendCommand(&hsdram1, &Command, 0xfff);
    /* Step 8: Set the refresh rate counter - refer to section SDRAM refresh timer register in RM0455 */
    /* Set the device refresh rate
     * COUNT = [(SDRAM self refresh time / number of row) x  SDRAM CLK] – 20
             = [(64ms/4096) * 100MHz] - 20 = 1562.5 - 20 ~ 1542 */
    HAL_SDRAM_ProgramRefreshRate(&hsdram1, 1542);
  /* USER CODE END FMC_Init 2 */
}
heyo
Senior

When I using this sbrk it starts and working fine until I go to another screen view.

caddr_t _sbrk(int incr)
{
    extern char __heap_start;
    extern char __heap_limit;

    static char *heap_end = NULL;
    char *prev_heap_end;

    if (heap_end == NULL)
        heap_end = &__heap_start;

    prev_heap_end = heap_end;

    // Check overflow
    if ((heap_end + incr) > &__heap_limit)
    {
        errno = ENOMEM;
        return (caddr_t)-1;
    }

    heap_end += incr;

    return (caddr_t)prev_heap_end;
}

Better to validate your SDRAM access first: read/write to the SDRAM config + the MPU config before without any middleware (TouchGFX, FreeRTOS etc ..) at list to validate your SDRAM/MPU configs. Try to read/write all the SDRAM address range. I think this is the first step to do before adding more complexity to your application.

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.

Dump the HardFault state so you at least understand what the MCU dislikes.

Don't use the  Stack Pointer / SP as any reference or high water mark for the HEAP in SDRAM. The stack should be in Internal SRAM

I'd probably be more cautious about what you call from SystemInit() as the BSS is not initialized.

Couple of second is an age in MCU ticks, what is actually occurring then? A lot of malloc/free stuff?

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

+ I also recommend to add the default MPU config to prevent the CM7 speculative access as the background MPU config (the first region to declare):

  MPU_InitStruct.Enable = MPU_REGION_ENABLE;
  MPU_InitStruct.BaseAddress = 0x00;
  MPU_InitStruct.Size = MPU_REGION_SIZE_4GB;
  MPU_InitStruct.AccessPermission = MPU_REGION_NO_ACCESS;
  MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
  MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
  MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;
  MPU_InitStruct.Number = MPU_REGION_NUMBER0;
  MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
  MPU_InitStruct.SubRegionDisable = 0x87;

Then add the MPU config for SDRAM and other regions (QSPI if it is used). Don't forget to increment the MPU region number.

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.

I call fmc here:

heyo_0-1759916825734.png

Yes, as I said when I upload code it start up and if I do not go to another screen it works perfectly fine, but when Im trying to do that it hardfault after uploading next screen view. During loading screen it creating objects 

MemoryPool<Selections> pool_AlarmSelection;
vector<Selections*> dynamicAlarmSelection;
and load widgets and etc and after 2s hardfaults. Maybe its something with memory managment.

 

SDRAM is already checked because when Heap was in internal RAM everything works perfect.


@heyo wrote:

SDRAM is already checked because when Heap was in internal RAM everything works perfect.


I meant you need to check the SDRAM access not to validate the heap config. 

So did you run a simple test with read/write to SDRAM (the full SDRAM range)?

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.