Skip to main content
Associate II
July 6, 2026
Solved

STM32H573 TZ-EN - RCC Access When CPU NS Causing Hardfault

  • July 6, 2026
  • 1 reply
  • 59 views

Hello,

 

I have an STM32H573 project with TrustZone enabled. After the CPU goes into non-secure mode and during execution of the HAL_Init() function (more specifics below) a hard fault occurs. There is only a hard fault during the execution from a non-secure state. In the secure state (at boot) the HAL_Init() function successfully runs.

 

Is there a configuration for the RCC not enabled by default that I a missing, allowing it to be accessed by both Secure and Non-Secure CPU states?

Within GTZC_S TZSC - Privilegeable peripherals I cannot enable it. I see no relevant settings (I have tested a few that might be loosely related but no solved) in RCC.

 

In the code below I have used an arrow (<--) to denote exactly where the hard fault occurs (Verified with debugger)

Non-Secure Entry Code (CubeMX Generated):

int main(void)
{

/* USER CODE BEGIN 1 */

/* USER CODE END 1 */

/* MCU Configuration--------------------------------------------------------*/

/* MPU Configuration--------------------------------------------------------*/
MPU_Config();

/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init(); <-- Hard fault within this function

/* USER CODE BEGIN Init */

/* USER CODE END Init */

/* GTZC initialisation */
MX_GTZC_NS_Init();
...

HAL_Init Code (CubeMX Generated):

HAL_StatusTypeDef HAL_Init(void)
{
/* Configure Flash prefetch */
#if (PREFETCH_ENABLE != 0U)
__HAL_FLASH_PREFETCH_BUFFER_ENABLE();
#endif /* PREFETCH_ENABLE */

/* Set Interrupt Group Priority */
HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);

/* Update the SystemCoreClock global variable */
SystemCoreClock = HAL_RCC_GetSysClockFreq() >> AHBPrescTable[(RCC->CFGR2 & RCC_CFGR2_HPRE) >> RCC_CFGR2_HPRE_Pos]; <-- Hard fault here (Specifically inside the HAL_RCC_GetSysClockFreq() function)

/* Select HCLK as SysTick clock source */
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);

/* Use systick as time base source and configure 1ms tick (default clock after Reset is HSI) */
if (HAL_InitTick(TICK_INT_PRIORITY) != HAL_OK)
{
return HAL_ERROR;
}

/* Init the low level hardware */
HAL_MspInit();

/* Return function status */
return HAL_OK;
}

HAL_RCC_GetSysClockFreq Code (CubeMX Generated):

uint32_t HAL_RCC_GetSysClockFreq(void)
{
uint32_t pllsource;
uint32_t pllp;
uint32_t pllm;
uint32_t pllfracen;
uint32_t sysclockfreq;
uint32_t hsivalue;
float_t fracn1;
float_t pllvco;

if (__HAL_RCC_GET_SYSCLK_SOURCE() == RCC_SYSCLKSOURCE_STATUS_CSI) <-- Hardfault occurs here
{
/* CSI used as system clock source */
sysclockfreq = CSI_VALUE;
}
else if (__HAL_RCC_GET_SYSCLK_SOURCE() == RCC_SYSCLKSOURCE_STATUS_HSI)
{
/* HSI used as system clock source */
if (__HAL_RCC_GET_FLAG(RCC_FLAG_HSIDIVF) != 0U)
{
sysclockfreq = (uint32_t)(HSI_VALUE >> (__HAL_RCC_GET_HSI_DIVIDER() >> RCC_CR_HSIDIV_Pos));
}
else
{
sysclockfreq = (uint32_t) HSI_VALUE;
}
}

and even more specifically this is the last instruction in that function before execution jumps to the hardfault

ldr r3, [pc, #556]

 

Best answer by Jocelyn RICARD

Hello ​@cjackson ,

First, your zip is missing gcc-arm-none-eabi.cmake

I still managed to build after understanding that you separated the 2 projects.

I’m not sure how you managed to do that, but you missed one important point:

the secure application has to be build with -mcmse flag to tell compiler you run in secure. This flag impact the selection of the memory alias that are used to access peripheral.

This flag is actually set in your 2 projects : secure and non secure.

So, when your non secure project tries to access RCC it uses the secure alias (starting by 0x5 … instead of 0x4..) which generates a secure fault transformed into a hardfault.

Removing this -mcmse flag from your non secure build solves the issue.

As a general rule, I would recommend having a working setup with default code generated first and then make your adaptation. In such way you would have been able to figure our the difference in the compilation flags.

Besides, I noticed one option byte configuration enabling the flash data, probably reason why you changed the size of the secure app (no in the code shared but in your previous comment). You should also change non secure app size to avoid overlapping the flash data area also enabled in the second bank.

Best regards

Jocelyn

1 reply

Jocelyn RICARD
ST Employee
July 6, 2026

Hello ​@cjackson ,

When you say “There is only a hard fault during the execution from a non-secure state. In the secure state (at boot) the HAL_Init() function successfully runs.”, do you mean the HAL_Init of the secure part is executing correctly ?

Did you generate both projects using CubeMX?

Are you sure non secure application is running after secure application ? Debugger may run directly non secure are startup.

Best regards

Jocelyn

cjacksonAuthor
Associate II
July 7, 2026

@Jocelyn RICARD  thanks for the quick response.

 

When you say “There is only a hard fault during the execution from a non-secure state. In the secure state (at boot) the HAL_Init() function successfully runs.”, do you mean the HAL_Init of the secure part is executing correctly ?

Yes.

 

Did you generate both projects using CubeMX?

I generated a single New Project in CubeMX ticking ‘with TrustZone activated?’, creating two separate projects for each state but a single .ioc file.

 

Are you sure non secure application is running after secure application ? Debugger may run directly non secure are startup.

Yes. Within GDB I set a breakpoint on main, and it would stop execution on the secure side first followed by the non-secure side. Additionally, I have a USART peripherals that output in the main function for both (Non-Secure has USART1, Secure has USART3).

 

I have created a new project with the same result. There are the steps I took:

  1. Create the new project in STM32CubeMX with TZ enabled
  2. In project manager tab: Name project, Toolchain to CMake, in Code Generator toggle on ‘Generate peripheral initialization as a pair of ‘.c/.h’ files per peripheral.
  3. Enable SAU
  4. Disable not needed peripherals: ADC, TIM1, All connectivity except USART1 & USART 3, SAI, BSP.
  5. Generate Code button in STM32CubeMX.
  6. Add UART output code to secure main.c, stm32h5xx_it.c & non-secure main.c.
  7. Modify secure and non-secure cmake
  8. Build and flash.

 

All UART code mentioned in step 6 looks very similar to this (only changed content and variables names)

const static char startup_output[] = "\n\r***** Output Text *****\n\r";
HAL_UART_Transmit(&huart1, (uint8_t *)startup_output, sizeof(startup_output), 100);

 

The CMake files mentioned in step 7 are here:

// This is the secure project CMakeLists.txt file

cmake_minimum_required(VERSION 3.22)

set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(CMAKE_C_COMPILER arm-none-eabi-gcc)
set(CMAKE_CXX_COMPILER arm-none-eabi-g++)
set(CMAKE_ASM_COMPILER arm-none-eabi-gcc)
set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY")

# Setup compiler settings
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_EXTENSIONS ON)

if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Debug")
endif()
message("Build type: " ${CMAKE_BUILD_TYPE})

set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE)

# Set the project name
set(CMAKE_PROJECT_NAME SecurityKey_S)
project(${CMAKE_PROJECT_NAME} LANGUAGES C ASM)

set(STM32_MCU_FLAGS "-mcpu=cortex-m33 -mthumb -mfpu=fpv5-sp-d16 -mfloat-abi=hard -mcmse")

set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${STM32_MCU_FLAGS}")
set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} ${STM32_MCU_FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${STM32_MCU_FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--print-memory-usage")

# Create the executable target
add_executable(${CMAKE_PROJECT_NAME})

# Ensure the output directory for the NSC library exists before linking
execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_CURRENT_SOURCE_DIR}/../Secure_nsclib")

include("mx-generated.cmake")

target_link_options(${CMAKE_PROJECT_NAME} PRIVATE
"-T${CMAKE_CURRENT_SOURCE_DIR}/STM32H573xx_FLASH_s.ld"
"-Wl,--cmse-implib"
"-Wl,--out-implib=${CMAKE_CURRENT_SOURCE_DIR}/../Secure_nsclib/secure_nsclib.o"
)

set(CMAKE_CXX_COMPILER_FORCED "true")

target_compile_definitions(${CMAKE_PROJECT_NAME} PRIVATE
STM32H573xx
)

# Include paths
target_include_directories(${CMAKE_PROJECT_NAME} PRIVATE
"Core/Inc"
"${CMAKE_CURRENT_SOURCE_DIR}/../NonSecure/Core/Inc"
"[Redacted]/STM32Cube/Repository/Packs/STMicroelectronics/X-CUBE-FREERTOS/1.5.0/Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM33/secure"
)

if("ob" IN_LIST CMAKE_C_IMPLICIT_LINK_LIBRARIES)
list(REMOVE_ITEM CMAKE_C_IMPLICIT_LINK_LIBRARIES ob)
endif()

if((CMAKE_C_STANDARD EQUAL 90) OR (CMAKE_C_STANDARD EQUAL 99))
message(ERROR "Generated code requires C11 or higher")
endif()
// This is the Non-Secure CMakeLists.txt

cmake_minimum_required(VERSION 3.22)

set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(CMAKE_C_COMPILER arm-none-eabi-gcc)
set(CMAKE_CXX_COMPILER arm-none-eabi-g++)
set(CMAKE_ASM_COMPILER arm-none-eabi-gcc)
set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY")

# Setup compiler settings
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_EXTENSIONS ON)

# Define the build type
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Debug")
endif()

message("Build type: " ${CMAKE_BUILD_TYPE})

set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE)

# Compiler options
set(STM32_MCU_FLAGS "-mcpu=cortex-m33 -mthumb -mcmse -mfpu=fpv5-sp-d16 -mfloat-abi=hard")

set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${STM32_MCU_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${STM32_MCU_FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--print-memory-usage")

set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -mcpu=cortex-m33 -mthumb -mcmse")

#Linker options
set(STM32_LINKER_SCRIPT STM32H573xx_FLASH_ns.ld)
set(STM32_LINKER_OPTION)

# Set the project name
set(CMAKE_PROJECT_NAME SecurityKey_NS)
project(${CMAKE_PROJECT_NAME})

# Create an executable object type
add_executable(${CMAKE_PROJECT_NAME})

# Include mx-generated
include("mx-generated.cmake")

target_link_options(${CMAKE_PROJECT_NAME} PRIVATE
"-T${CMAKE_CURRENT_SOURCE_DIR}/${STM32_LINKER_SCRIPT}"
"-mcpu=cortex-m33"
"-mthumb"
"-mcmse"
"-mfpu=fpv5-sp-d16"
"-mfloat-abi=hard"
"--specs=nano.specs"
)

# In order to use CMake for cross-compiling
set(CMAKE_CXX_COMPILER_FORCED "true")

# Add project symbols (macros)
target_compile_definitions(${CMAKE_PROJECT_NAME} PRIVATE
# Add user defined symbols
)

# Enable CMake support for ASM and C languages
enable_language(C ASM)

# Add include paths
target_include_directories(${CMAKE_PROJECT_NAME} PRIVATE
# Add user defined include paths
)

# Add sources to executable
target_sources(${CMAKE_PROJECT_NAME} PRIVATE
# Add user sources here
)

# Link directories setup
target_link_directories(${CMAKE_PROJECT_NAME} PRIVATE
# Add user defined library search paths
)

# Add linked libraries
target_link_libraries(${CMAKE_PROJECT_NAME}
# Add user defined libraries
"${CMAKE_CURRENT_SOURCE_DIR}/../Secure_nsclib/secure_nsclib.o"
)

list(REMOVE_ITEM CMAKE_C_IMPLICIT_LINK_LIBRARIES ob)

# Validate that STM32CubeMX code is compatible with C standard
if((CMAKE_C_STANDARD EQUAL 90) OR (CMAKE_C_STANDARD EQUAL 99))
message(ERROR "Generated code requires C11 or higher")
endif()

 

Some additional information (not sure of its usefulness):

  • ICACHE is disabled
  • Memory Regions (As defined in .ld files)
    • Secure
      • RAM    (xrw)    : ORIGIN = 0x30000000,    LENGTH = 320K
      • FLASH    (rx)    : ORIGIN = 0xC000000,    LENGTH = 256K
      • FLASH_NSC    (rx)    : ORIGIN = 0xC040000,    LENGTH = 16K
    • Non-Secure
      • RAM    (xrw)    : ORIGIN = 0x20050000,    LENGTH = 320K
      • FLASH    (rx)    : ORIGIN = 0x8100000,    LENGTH = 1024K
  • SAU Regions (As defined in partition_stm32h573xx.h)
    • SAU_INIT_CTRL_ALLNS = 0
    • Region 0
      • Start: 0x0C040000
      • End: 0x0C041FFF
      • SAU_INIT_NSC0 = 1 (Secure, Non Secure Callable)
    • Region 1
      • Start: 0x08100000
      • End: 0x081FFFFF
      • SAU_INIT_NSC1 = 0 (Non Secure)
    • Region 2
      • Start: 0x20050000
      • End: 0x200CFFFF
      • SAU_INIT_NSC2 = 0 (Non Secure)