2025-09-04 2:32 AM
Hello,
we are using a STM32H5 with TZ disabled. In firmware, we are doing the following:
- set the product state to provisioning (0x17)
- provision the debug authentication
This already works fine. Afterwards, we can do a discovery an see the validity of the DA ( we read 0xeaeaeaea). Regression afterwards works fine.
However, we would like to check this validity from within the firmware.
1) where does this 0xeaeaeaea comes from? Can we also access it?
2) reading back the storage area of the DA (0x0ffd0100) is not reliable. Sometimes, we can read the data we just wrote, sometime we just read 0xff... This depends on the code we execute after writing. It is not a timing issue, should we maybe set a certain flag or something like that?
The code we used is based on the github project https://github.com/stm32-hotspot/STM32H5_DA_EmbeddedProvisioning
Best regards
Peter
2025-09-11 12:34 AM
Hello @peter7 ,
The 0xeaeaeaea code comes from STDA component that you activate when requesting a discovery.
This status is basically the result of the hash check done on DA OBK.
Regarding the reliability of writing the OBK from firmware, I have never seen any issue.
Especially, this is used by secure boot OEMiROT to write firmware hash and version.
What you see may be related to reading timing, I need to reproduce to understand what happens.
By the way, did you have any time a DA configuration written by firmware that couldn't be used to perform the regression ?
Best regards
Jocelyn
2025-09-15 5:20 AM
Hello Jocelyn,
thanks for the reply. I'm doing the following in firmware:
Please see the attached code. During my tests, provisioning always works.
When I execute certain code between the writing and the reading, I can directly read back the provisioned data. This behaviour is reproducible, some intermediate code works, some does not, but I could not narrow it down to a certain instruction. I have the impression that a function call is needed, so maybe it has something to do with the accessing other memory banks.
We would like to close the device on the first start of the firmware. This requires provisioning, setting to provisioned, checking the provisioned state first. Obviously, we don't want to close a device, before we are sure the the provisioning was successful.
The planned production process does not permit to do these steps with the flasher.
I'm hoping that you can help me figure out what to do to allow reading back without executing a reset.
/**********************************************************************************************************************/
/** Main function and initialization
**********************************************************************************************************************/
#include "stm32h5xx_hal.h"
#include "main.h"
extern "C" int main(void);
/**********************************************************************************************************************/
static void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct {};
RCC_ClkInitTypeDef RCC_ClkInitStruct {};
/** Configure the main internal regulator output voltage */
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE3);
while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}
/** Initializes the RCC Oscillators according to the specified parameters in the RCC_OscInitTypeDef structure. */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSIDiv = RCC_HSI_DIV1;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks */
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2
|RCC_CLOCKTYPE_PCLK3;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB3CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_3) != HAL_OK) {
Error_Handler();
}
}
/**********************************************************************************************************************/
static void MX_ICACHE_Init(void) {
if (HAL_ICACHE_ConfigAssociativityMode(ICACHE_1WAY) != HAL_OK) {
Error_Handler();
}
if (HAL_ICACHE_Enable() != HAL_OK) {
Error_Handler();
}
}
/**********************************************************************************************************************/
static void MX_GPIO_Init(void) {
GPIO_InitTypeDef GPIO_InitStruct {};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOE_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOF_CLK_ENABLE();
__HAL_RCC_GPIOH_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_GPIOG_CLK_ENABLE();
__HAL_RCC_USART3_CLK_ENABLE();
/*Configure GPIO pins : PD8 PD9 */
GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF7_USART3;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
// Initialize UART
UART_HandleTypeDef uartHandle;
uartHandle.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
uartHandle.Instance = USART3;
uartHandle.Init.BaudRate = 1000000;
uartHandle.Init.HwFlowCtl = UART_HWCONTROL_NONE;
uartHandle.Init.Mode = UART_MODE_TX;
uartHandle.Init.OverSampling = UART_OVERSAMPLING_16;
uartHandle.Init.Parity = UART_PARITY_NONE;
uartHandle.Init.StopBits = UART_STOPBITS_1;
uartHandle.Init.WordLength = UART_WORDLENGTH_8B;
uartHandle.Init.ClockPrescaler = UART_PRESCALER_DIV1;
uartHandle.Init.OneBitSampling = UART_ONEBIT_SAMPLING_DISABLED;
HAL_UART_Init(&uartHandle);
}
/**********************************************************************************************************************/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
if (htim->Instance == TIM3) {
HAL_IncTick();
}
}
/**********************************************************************************************************************/
void Error_Handler(void) {
__disable_irq();
while (1){}
}
/**********************************************************************************************************************/
static void PrintLn(uint8_t count, uint8_t * data) {
for(uint8_t pos = 0; pos < count; pos++) {
while((USART3->ISR & USART_ISR_TXE) == 0);
USART3->TDR = data[pos];
}
while((USART3->ISR & USART_ISR_TXE) == 0);
USART3->TDR = '\n';
}
/**********************************************************************************************************************/
static bool IsProvisioned() {
if ((*(uint32_t *)(0x0FFD0100)) != 0xFFFFFFFF) {
PrintLn(11,(uint8_t *)"provisioned");
return true;
}
else {
PrintLn(15,(uint8_t *)"not provisioned");
return false;
}
}
/**********************************************************************************************************************/
const unsigned char DA_Config[] = {
// addr
0x00, 0x01, 0xfd, 0x0f,
// size
0x60, 0x00, 0x00, 0x00,
// enc
0x00, 0x00, 0x00, 0x00,
// integrity
0x42, 0x09, 0x02, 0x43,
0x9c, 0x31, 0x95, 0x3b, 0x6a, 0x8b, 0xff, 0xdd, 0xab, 0x06, 0x19, 0x95, 0x81, 0x29, 0xe2, 0xb5,
0x2c, 0x51, 0xb0, 0x0f, 0x13, 0x91, 0x27, 0x4c, 0xe7, 0xdd, 0xb3, 0x53,
// sha256
0x18, 0x4a, 0xa4, 0x6d,
0x81, 0x34, 0x11, 0x72, 0x7d, 0xa0, 0xdc, 0x9e, 0x64, 0x18, 0x6b, 0xb9, 0x90, 0x72, 0x89, 0xb5,
0xaa, 0xb4, 0xb3, 0x20, 0xd2, 0x6f, 0xff, 0x5e, 0xa4, 0x5d, 0x8e, 0x3d,
// perm
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// reserved
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
/**********************************************************************************************************************/
static void OBKProvisioning_ProvisionDA(void) {
__HAL_RCC_SBS_CLK_ENABLE();
/* Unlock Flash area */
(void) HAL_FLASH_Unlock();
(void) HAL_FLASHEx_OBK_Unlock();
/* Force use of EPOCH_S value for DHUK */
WRITE_REG(SBS_S->EPOCHSELCR, (1U << SBS_EPOCHSELCR_EPOCH_SEL_Pos));
/* Erase OBKeys */
FLASH_EraseInitTypeDef FLASH_EraseInitStruct = {0U};
uint32_t sector_error = 0U;
FLASH_EraseInitStruct.TypeErase = FLASH_TYPEERASE_OBK_ALT;
if (HAL_FLASHEx_Erase(&FLASH_EraseInitStruct, §or_error) != HAL_OK) {
PrintLn(11, (uint8_t *)"Error Erase");
}
/* Program OBKeys */
for (uint32_t i = 0U; i < 0x60; i += 16) {
if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_QUADWORD_OBK_ALT, (0x0FFD0100 + i), ((uint32_t)&(DA_Config[12 + i]))) != HAL_OK) {
PrintLn(11, (uint8_t *)"Error Flash");
}
}
/* Swap all OBKeys */
if (HAL_FLASHEx_OBK_Swap(0x1FFU) != HAL_OK) {
PrintLn(10, (uint8_t *)"Error Swap");
}
/* Lock the User Flash area */
(void) HAL_FLASH_Lock();
(void) HAL_FLASHEx_OBK_Lock();
}
/** Main function *****************************************************************************************************/
int main(void)
{
// Reset of all peripherals, Initializes the Flash interface and the Systick.
HAL_Init();
/* Configure the system clock */
SystemClock_Config();
// Initialize all configured peripherals
MX_GPIO_Init();
MX_ICACHE_Init();
if(IsProvisioned() == false) {
// Write provisioning data
PrintLn(13,(uint8_t *)"do provision");
}
OBKProvisioning_ProvisionDA();
IsProvisioned();
while (true){}
}
Best regards,
Peter