cancel
Showing results for 
Search instead for 
Did you mean: 

STM32H743ZIT6 random startup problems when D-Cache enabled

DWeng.1
Associate II

Hello,

I am about to improve the execution speed of an existing code base on a NUCLEO-H743ZI2 board.

So far, I have the following memory setup:

Instruction Memory:

  • ITCM for time-critical functions
  • FLASH (+ I-Cache) for remaining instructions

Data Memory:

  • AXI_SRAM for two DMA-buffers (Peripheral to Memory)
  • SRAM1 for another DMA buffer (Memory to Peripheral)
  • DTCM for everything else (including ISR table)

My program with the above setup works fine.

Now I want to check whether enabling the D-Cache can actually further improve execution speed. My intention is, to use this Cache solely for a faster reading/processing of the DMA-Buffers in AXI_SRAM. Their reading happens upon a DMA half- or full-complete interrupt and the D-Cache is always invalidated before accessing any DMA-Buffer data. SRAM1 stays non-cacheable.

This is my new setup:

Instruction Memory:

  • ITCM for time-critical functions
  • FLASH (+ I-Cache) for remaining instructions

Data Memory:

  • AXI_SRAM (+ D-Cache) for two DMA-buffers (Peripheral to Memory)
  • SRAM1 for another DMA buffer (Memory to Peripheral)
  • DTCM for everything else (including ISR table)

MPU:

  • Region 0 = SRAM1 (non-cacheable)
  • Region 1 = AXI_SRAM


_legacyfs_online_stmicro_images_0693W00000bjNzKQAU.pngHere I am facing a weird problem.

When I download the program to the nucleo, it often does not start and instead goes to the error handler. However, when I press the reset button a couple of times, it suddenly starts and runs perfectly fine.

Has anybody faced a similar problem? Can somebody help me debugging?

1 ACCEPTED SOLUTION

Accepted Solutions
DWeng.1
Associate II

I think I found the problem now! The reason for the Error Handler lies in this section of Code that is called by MX_USB_OTG_FS_PCD_Init().

/**
  * @brief  Reset the USB Core (needed after USB clock settings change)
  * @param  USBx  Selected device
  * @retval HAL status
  */
static HAL_StatusTypeDef USB_CoreReset(USB_OTG_GlobalTypeDef *USBx)
{
  uint32_t count = 0U;
 
  /* Wait for AHB master IDLE state. */
  do
  {
    if (++count > 200000U)
    {
      return HAL_TIMEOUT;	/* This timeout causes Error_Handler() when building in release mode */
    }
  } while ((USBx->GRSTCTL & USB_OTG_GRSTCTL_AHBIDL) == 0U);
 
  /* Core Soft Reset */
  count = 0U;
  USBx->GRSTCTL |= USB_OTG_GRSTCTL_CSRST;
 
  do
  {
    if (++count > 200000U)
    {
      return HAL_TIMEOUT;
    }
  } while ((USBx->GRSTCTL & USB_OTG_GRSTCTL_CSRST) == USB_OTG_GRSTCTL_CSRST);
 
  return HAL_OK;
}

Apparently the counter value increases much faster when building in release mode (-ofast) and when D/I-Caches + D/I-TCMs are used in addition.

Increasing the counter threshold from 200'000 to 400'000'000 fixed the problem.

Now everything works perfectly fine 🙂

Is there somewhere a bug report portal where I can report this?

View solution in original post

6 REPLIES 6
SofLit
ST Employee

Hello,

First try to disable the access to non valid memory regions using MPU:

void MPU_Config(void)

{

 MPU_Region_InitTypeDef MPU_InitStruct;

 /* Disable the MPU */

 HAL_MPU_Disable();

 /* Configure the MPU as Strongly ordered for not defined regions */

 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;

 MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;

 HAL_MPU_ConfigRegion(&MPU_InitStruct);

 /* Enable the MPU */

 HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);

}

and add your MPU regions after.

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.
DWeng.1
Associate II

Thank you for your answer. Unfortunately, the problem remains.

This is my MPU config now:

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.Number = MPU_REGION_NUMBER0;
  MPU_InitStruct.BaseAddress = 0x0;
  MPU_InitStruct.Size = MPU_REGION_SIZE_4GB;
  MPU_InitStruct.SubRegionDisable = 0x87;
  MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
  MPU_InitStruct.AccessPermission = MPU_REGION_NO_ACCESS;
  MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;
  MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;
  MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
  MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
 
  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 = 0x24000000;
  MPU_InitStruct.Size = MPU_REGION_SIZE_512KB;
  MPU_InitStruct.SubRegionDisable = 0x0;
  MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
  MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
 
  HAL_MPU_ConfigRegion(&MPU_InitStruct);
  /** Initializes and configures the Region and the memory to be protected
  */
  MPU_InitStruct.Number = MPU_REGION_NUMBER2;
  MPU_InitStruct.BaseAddress = 0x30000000;
  MPU_InitStruct.Size = MPU_REGION_SIZE_128KB;
  MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
 
  HAL_MPU_ConfigRegion(&MPU_InitStruct);
  /* Enables the MPU */
  HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
 
}

I have removed anything from main now, such that just an LED is going to blink:

int main(void)
{
  /* USER CODE BEGIN 1 */
  SCB_CleanInvalidateDCache();
  /* USER CODE END 1 */
 
  /* MPU Configuration--------------------------------------------------------*/
  MPU_Config();
 
  /* Enable I-Cache---------------------------------------------------------*/
  SCB_EnableICache();
 
  /* Enable D-Cache---------------------------------------------------------*/
  SCB_EnableDCache();
 
  /* MCU Configuration--------------------------------------------------------*/
 
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();
 
  /* USER CODE BEGIN Init */
  /* USER CODE END Init */
 
  /* Configure the system clock */
  SystemClock_Config();
 
/* Configure the peripherals common clocks */
  PeriphCommonClock_Config();
 
  /* USER CODE BEGIN SysInit */
 
  /* USER CODE END SysInit */
 
  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_ETH_Init();
  MX_USART3_UART_Init();
  MX_USB_OTG_FS_PCD_Init();
  MX_SPI1_Init();
  MX_SPI3_Init();
  MX_SPI4_Init();
  MX_I2C1_Init();
  MX_I2C2_Init();
  MX_I2C4_Init();
  MX_SPI2_Init();
  MX_SPI5_Init();
  MX_UART4_Init();
  MX_UART5_Init();
  MX_UART7_Init();
  MX_USART2_UART_Init();
  MX_USART6_UART_Init();
  MX_ADC1_Init();
  MX_ADC2_Init();
  MX_ADC3_Init();
  MX_DAC1_Init();
  MX_TIM1_Init();
  MX_TIM6_Init();
  MX_TIM15_Init();
  MX_TIM7_Init();
  /* USER CODE BEGIN 2 */
  /* USER CODE END 2 */
 
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
	while (1)
	{
		cnt++;
		if (cnt > 60000000) {
			HAL_GPIO_TogglePin(LD1_GPIO_Port, LD1_Pin);
			cnt = 0;
		}
    /* USER CODE END WHILE */
 
    /* USER CODE BEGIN 3 */
	}
  /* USER CODE END 3 */
}

It seems, that I cannot reproduce the problem when building in debug mode.

In release mode (-ofast) the problem remains. Most of the time, I end up in the error handler but sometimes it works.

DWeng.1
Associate II

I think I found the problem now! The reason for the Error Handler lies in this section of Code that is called by MX_USB_OTG_FS_PCD_Init().

/**
  * @brief  Reset the USB Core (needed after USB clock settings change)
  * @param  USBx  Selected device
  * @retval HAL status
  */
static HAL_StatusTypeDef USB_CoreReset(USB_OTG_GlobalTypeDef *USBx)
{
  uint32_t count = 0U;
 
  /* Wait for AHB master IDLE state. */
  do
  {
    if (++count > 200000U)
    {
      return HAL_TIMEOUT;	/* This timeout causes Error_Handler() when building in release mode */
    }
  } while ((USBx->GRSTCTL & USB_OTG_GRSTCTL_AHBIDL) == 0U);
 
  /* Core Soft Reset */
  count = 0U;
  USBx->GRSTCTL |= USB_OTG_GRSTCTL_CSRST;
 
  do
  {
    if (++count > 200000U)
    {
      return HAL_TIMEOUT;
    }
  } while ((USBx->GRSTCTL & USB_OTG_GRSTCTL_CSRST) == USB_OTG_GRSTCTL_CSRST);
 
  return HAL_OK;
}

Apparently the counter value increases much faster when building in release mode (-ofast) and when D/I-Caches + D/I-TCMs are used in addition.

Increasing the counter threshold from 200'000 to 400'000'000 fixed the problem.

Now everything works perfectly fine 🙂

Is there somewhere a bug report portal where I can report this?

Hello,

Is it possible to declare the counter as volatile __IO uint32_t count and tell us if it does fix the issue?

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.
DWeng.1
Associate II

Yes changing the variable from uint32_t to volatile __IO uint32_t and leaving the counter threshold at 200'000 works too.

Pavel A.
Evangelist III

To avoid changing the ST library, maybe better is to make a small change in the user code.

Instead of the (lame) counter, check for timeout in ms, which is independent of clock rate and cache (need to test and find the max. required time).

HAL_StatusTypeDef st;
for (unsigned n=10;  n > 0; n--) {
  st = USB_CoreInit(....);
  if (st == OK) break;
  HAL_Delay(1);
}
 
if (st != HAL_OK) {
 // fail
}