Skip to main content
Associate
October 5, 2026
Question

How to define safe and non-safe zone banks without using STMCubeProgrammer software

Hello everyone,

I'm developing an application using the STM32H563 with TrustZone enabled. Online tutorials first show configuring the fuse bits using the STMCubeProgrammer software:
TZEN
SECWM1_STRT
SECWM1_END
SECWM2_STRT
SECWM2_END

Then, the application is installed in the STMCubeIDE, where it is saved and executed correctly.

However, if the developer tries to install the application without going through the first step, the code is unable to exit the safe zone, resulting in a hard fault error. This is because the IDE, when TrustZone is enabled, assumes that all FLASH memory is in the safe zone.

I would like to change these fuse bits without using STMCubeProgrammer. I believe it's possible, but I haven't found any information where the result is satisfactory. Could someone help me?

3 replies

ST Technical Moderator
October 7, 2026

Hello ​@Anderson Santos 

In STM32H5, option byte programming is done using HAL_FLASHEx_OBProgram() from your secure project 

The general sequence requires:

  • Unlocking Flash and Option Bytes via HAL_FLASH_Unlock() and HAL_FLASH_OB_Unlock().
  • Populating FLASH_OBProgramInitTypeDef with OptionType = OPTIONBYTE_WMSEC and calling HAL_FLASHEx_OBProgram().
  • Applying the changes via HAL_FLASH_OB_Launch() (which generates a system reset) or through a power-on reset.
  • Locking the Flash configuration.

 

Example
FLASH_OBProgramInitTypeDef OBInit;

/* Unlock the Flash control register and Option Bytes */
HAL_FLASH_Unlock();
HAL_FLASH_OB_Unlock();

/* Configure Bank 1 Secure Watermark (e.g., all Bank 1 secure) */
OBInit.OptionType = OPTIONBYTE_WMSEC;
OBInit.Banks = FLASH_BANK_1;
OBInit.WMSecStartSector = 0x00;
OBInit.WMSecEndSector = 0x7F;
HAL_FLASHEx_OBProgram(&OBInit);

/* Configure Bank 2 Secure Watermark (e.g., non-secure: Start > End) */
OBInit.OptionType = OPTIONBYTE_WMSEC;
OBInit.Banks = FLASH_BANK_2;
OBInit.WMSecStartSector = 0x01;
OBInit.WMSecEndSector = 0x00;
HAL_FLASHEx_OBProgram(&OBInit);

/* Launch Option Bytes to apply settings (triggers a reset) */
HAL_FLASH_OB_Launch();

HAL_FLASH_OB_Lock();
HAL_FLASH_Lock();

 

In order to give better visibility on the answered topics, please click on 'Best answer' on the reply which solved your issue or answered your question. Saket_Om
Associate
October 7, 2026

I tried using your code.
It compiles but doesn't save. If I read the settings using HAL_FLASHEx_OBGetConfig, I can see that there were no changes to the settings.

Hai
ST Employee
October 10, 2026

Hello ​@Anderson Santos 

Yes, it is possible to configure the secure watermark without STM32CubeProgrammer, but there are two important conditions:

  • The secure watermark config is applicable only when TrustZone is already active (TZ_STATE = 0xB4)
  • SECWMx_STRT/SECWMx_END can be modified only by secure firmware

So in your case, the first point to verify is that the code calling HAL_FLASHEx_OBProgram() is really executed from the Secure project.

In the STM32CubeIDE verify that the generated TrustZone project structure and memory layout:

  • CubeIDE should normally generate two projects: one Secure and one NonSecure
  • In the .ioc, TZ should be enabled and generated as Secure + NonSecure
  • The secure linker must place secure code in the flash sectors covered by SECWMx
  • The non-secure linker script must place the non-secure vector table and code outside the secure watermark area
  • GTZC/SAU config must also be consistent with this split

Also, please note the secure watermark behavior from RM0481:

  • SECWMx_STRT > SECWMx_END: no secure area in that bank
  • SECWMx_STRT = SECWMx_END: one secure sector
  • SECWMx_STRT < SECWMx_END: secure area from start to end

If the programmed values seem not to be saved, please check:

  • return status of HAL_FLASH_Unlock() function
  • return status of HAL_FLASH_OB_Unlock() function
  • return status of HAL_FLASHEx_OBProgram() function
  • HAL_FLASH_GetError() function
  • and verify the readback after reset, because HAL_FLASH_OB_Launch() reloads the option bytes and triggers a reset

If you can share:

  • the Secure and NonSecure linker memory regions and the SECWM1/2 values read after reset
  • the non-secure start address used by the Secure project

then it should be possible to confirm whether the CubeIDE TZ config matches the programmed flash security layout.