cancel
Showing results for 
Search instead for 
Did you mean: 

How to avoid a HardFault when ICACHE is enabled on the STM32H5 series

Sarra.S
ST Employee

Introduction

This article presents a quick guidance on how to prevent HardFault occurrences when the ICACHE is enabled on the STM32H5 MCU. 

1. Summary and description  

This article explains why a HardFault may occur when accessing the following:

  • Internal reference voltage (VREFINT)
  • Internal temperature sensor (VSENSE)
  • Unique device ID
  • Package ID data
  • How the CACHE intervenes in accessing data on the STM32H5 series. 

2. Root cause 

The internal reference voltage (VREFINT), the internal temperature sensor (VSENSE), the unique device ID, and the package ID data are located in RO and OTP areas. 

By default, all the AHB memory range is cacheable. For OTP and RO regions, caching is not practical and MPU has to be used to disable local cacheability. 

3. RO and OTP areas

The embedded flash memory offers a 2-Kbyte memory area to store read-only data. This area is mapped as described in the below table: 

SarraS_0-1705673287748.png

* VREFINT_CAL_ADR, TEMPSENSOR_CAL1_ADDR, and TEMPSENSOR_CAL2_ADDR are located in reserved information

OTP data is organized as 32 blocks of 32 OTP words, as shown in the below table:

SarraS_1-1705661477396.png

It is also important to note that for 8-bit accesses, an AHB bus error is generated. For OTP and RO sectors in memory, a 6-bit ECC code is associated with each 16-bit data flash word. So, the embedded flash memory supports only16-bit or 32-bit write operations. Therefore, the burst access is not supported for these regions. 

4. MPU configuration 

You can refer to the following MPU configuration to disable cacheability for OTP and RO regions

 

 

 

#include "stm32h5xx_hal.h"

void MPU_Config(void);

/* MPU attribute setting */
#define  DEVICE_nGnRnE          0x0U  /* Device, noGather, noReorder, noEarly acknowledge. */
#define  DEVICE_nGnRE           0x4U  /* Device, noGather, noReorder, Early acknowledge.   */
#define  DEVICE_nGRE            0x8U  /* Device, noGather, Reorder, Early acknowledge.     */
#define  DEVICE_GRE             0xCU  /* Device, Gather, Reorder, Early acknowledge.       */

#define  WRITE_THROUGH          0x0U  /* Normal memory, write-through. */
#define  NOT_CACHEABLE          0x4U  /* Normal memory, non-cacheable. */
#define  WRITE_BACK             0x4U  /* Normal memory, write-back.    */

#define  TRANSIENT              0x0U  /* Normal memory, transient.     */
#define  NON_TRANSIENT          0x8U  /* Normal memory, non-transient. */

#define  NO_ALLOCATE            0x0U  /* Normal memory, no allocate.         */
#define  W_ALLOCATE             0x1U  /* Normal memory, write allocate.      */
#define  R_ALLOCATE             0x2U  /* Normal memory, read allocate.       */
#define  RW_ALLOCATE            0x3U  /* Normal memory, read/write allocate. */

#define OUTER(__ATTR__)        ((__ATTR__) << 4U)
#define INNER_OUTER(__ATTR__)  ((__ATTR__) | ((__ATTR__) << 4U))

/**
  * @brief  Configure the MPU attributes.
  * @note   The Base Address is RO area
  *   None
  * @retval None
  */
void MPU_Config(void)
{
  MPU_Attributes_InitTypeDef   attr;
  MPU_Region_InitTypeDef       region;

  /* Disable MPU before perloading and config update */
  HAL_MPU_Disable();

  /* Define cacheable memory via MPU */
  attr.Number             = MPU_ATTRIBUTES_NUMBER0;
  attr.Attributes         = INNER_OUTER(NOT_CACHEABLE);
  HAL_MPU_ConfigMemoryAttributes(&attr);

  /* BaseAddress-LimitAddress configuration */
  region.Enable           = MPU_REGION_ENABLE;
  region.Number           = MPU_REGION_NUMBER0;
  region.AttributesIndex  = MPU_ATTRIBUTES_NUMBER0;
  region.BaseAddress      = 0x08FFF800;
  region.LimitAddress     = 0x08FFFFFF;
  region.AccessPermission = MPU_REGION_ALL_RW;
  region.DisableExec      = MPU_INSTRUCTION_ACCESS_DISABLE;
  region.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
  HAL_MPU_ConfigRegion(&region);

  /* Enable the MPU */
  HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
}


void MX_ICACHE_Init(void)
{

  /* USER CODE BEGIN ICACHE_Init 0 */

  /* USER CODE END ICACHE_Init 0 */

  /* USER CODE BEGIN ICACHE_Init 1 */

  /* USER CODE END ICACHE_Init 1 */
  /** Enable instruction cache in 1-way (direct mapped cache)
  */
  if (HAL_ICACHE_ConfigAssociativityMode(ICACHE_1WAY) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_ICACHE_Enable() != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN ICACHE_Init 2 */

  /* USER CODE END ICACHE_Init 2 */

}

 

 

 

5. How does the cache intervene in access to data in the STM32H5 series?

The STM32H503xx microcontrollers features an integrated ICACHE that combines instructions and data into a single cache. This cache is introduced on the C-AHB code bus of the Cortex®-M33 processor. This is to improve performance when fetching instructions (or data) from internal memories (SRAM1 and SRAM2).

SarraS_0-1705662028907.png

The STM32H562xx, STM32H563xx, and STM32H573xx microcontrollers features:

  • A DCACHE S-bus that connects the system bus of the Cortex®-M33 core to the BusMatrix via the data cache. This bus targets the external memories (FMC and OCTOSPI)
  • An ICache that is connected via the fast C-bus to the internal flash memory and the internal SRAMs (SRAM1, SRAM2 and SRAM3), and it is connected via the slow bus to the external memories (FMC and OCTOSPI)

SarraS_0-1705670800035.png

Related links 

RM0492: STM32H503 line Arm®-based 32-bit MCUs

RM0481: STM32H563/H573 and STM32H562 Arm®-based 32-bit MCUs

Comments

Using the term "ICACHE" for this was a quintessentially horrible idea.  Thanks for the permanent confusion!

Pavel A.
Evangelist III

I've read this 3 times back and forth but still cannot understand ((

So, does the ICACHE in H503xx mean Integrated or Instruction cache?

And why exactly it causes a fault when accessing the RO & OTP area?

The "128-bit cacheline refill" probably is the burst operation mentioned in the article. But how is it related to 8-bit access vs. 16 or 32 bit? Does it mean that any access, even 32 bit, to this area triggers the cacheline load?

How about the main flash array - is cacheline refill OK there?

Finally why in the example code access is RW and not RO? are we going to write there? 

 region.AccessPermission = MPU_REGION_ALL_RW;

 

I'm pretty sure it's "integrated".  Beyond that it looks like an integrated mess.

Version history
Last update:
‎2024-06-27 01:01 AM
Updated by: