Skip to main content
Associate
June 30, 2026
Question

How to Use STL(Self Test Library)

  • June 30, 2026
  • 0 replies
  • 10 views

 

/*
* Stl_Scheduler.c
*
* Created on: Jun 25, 2026
* Author: User
*/

#include <stl_user_api.h>
#include "stl_scheduler.h"
#include "main.h"
#include "app_threadx.h"
#include "APP_Log.h"

extern TIM_HandleTypeDef htim15;

/* RAM & FLASH Tests definitions */
#define FLASH_SECTION_SIZE 1024U
#define RAM_SECTION_SIZE 128U

#ifdef STL_DISABLE_RAM_BCKUP_BUF
#define RAM_BACKUP_BUFFER_SIZE 0
#else
#define RAM_BACKUP_BUFFER_SIZE 32
#endif

// STM32H523
#define TEST_RAM_START_ADDR (0x20000000U + RAM_BACKUP_BUFFER_SIZE)
#define TEST_ROM_START_ADDR 0x08000000U
//#define TEST_ROM_END_ADDR 0x0801A3FF
//#define TEST_ROM_END_ADDR 0x0801A00FU
#define TEST_ROM_END_ADDR 0x0801A3FFU
//#define TEST_ROM_END_ADDR 0x0807F7FFU


/*
#if (defined (__GNUC__) && !defined (__CC_ARM) && !defined (__ARMCC_VERSION))
extern void *_edata_load;
#define TEST_ROM_END_ADDR ( (uint32_t)&_edata_load + 3)
#endif
*/

// Runtime RAM test: 8 sections x 128 bytes = 1024 bytes
#define TEST_RAM_SECTION_NB_RUN 8 /* only 8 RAM sections are tested during runtime. */

// STM32H523 SRAM = 272 KB 0x20000000 + 0x44000 - 1 = 0x20043FFF
#define TEST_RAM_END_ADDR_FULL 0x20043FFFU

/////////////////////////////////////////////////////////////
/* Value of the system clock frequency at run time in Hz */
#define SYSTCLK_AT_RUN (uint32_t)(250000000uL)
/* Value of the Internal LSI oscillator in Hz */
#define LSI_Freq ((uint32_t)32000uL)
/* CLK frequency above this limit considered as harmonics in case of HSE */
#define CLK_LimitHigh(fcy) ((uint32_t)(((fcy)/LSI_Freq)*4u*5u)/4u) /* (Value + 25%) */
/* CLK frequency below this limit considered as sub-harmonics in case of HSE */
#define CLK_LimitLow(fcy) ((uint32_t)(((fcy)/LSI_Freq)*4u*3u)/4u) /* (Value - 25%) */
/* if SYSCK is derived from HSI, the upper fixed clock limits can be set more severe
e.g., ...*2u*6u)/5 resp. ...*2u*4u)/5 (~ value +/- 20%) but such a severe restriction
can require including some adaptive flow to compensate possible temperature drift
of HSI by making acceptable window defined by these limits variable in time */

/* uncomment following lines when simulating artificial failing of particular modules
during execution of either full or run test */
/* #define ARTI_FAILING_CPU_TM */
/* #define ARTI_FAILING_FLASH_TM */
//#define ARTI_FAILING_RAM_TM
/* #define ARTI_FAILING_CLK_TM */
/* #define ARTI_FAILING_DURING_FULL_TEST */


/* variables to keep user configuration and status of all the test modules
- can be handled as local and/or changed dynamically inside the STL_RunStep procedure
- set of global variables is applied here to keep overall overview when debug STL */
static STL_TmStatus_t StlCpuTm1LStatus;
static STL_TmStatus_t StlCpuTm7Status;
static STL_TmStatus_t StlCpuTmCBStatus;
static STL_TmStatus_t StlFlashStatus;
static STL_TmStatus_t StlRamStatus;
static STL_TmStatus_t StlClkStatus;

/* following variables have to be static due to separation of configuration and run procedures */
/* Flash & RAM configurations: */
static STL_MemSubset_t FlashSubsetRunTime;
static STL_MemSubset_t RamSubsetRunTime;
static STL_MemConfig_t FlashConfigRunTime;
static STL_MemConfig_t RamConfigRunTime;


/* internal variables for clock cross check measurement */
volatile uint16_t tmpCC1_last;
volatile uint32_t PeriodValue;
volatile uint32_t PeriodValueInv;
volatile uint32_t LSIPeriodFlag;

/* structure to handle artificial failing */
#if defined(ARTI_FAILING_CPU_TM) || defined(ARTI_FAILING_FLASH_TM) || defined(ARTI_FAILING_RAM_TM)
STL_ArtifFailingConfig_t ArtifFailing = {{ STL_PASSED, STL_PASSED, STL_PASSED }, STL_PASSED, STL_PASSED };
#endif /* ARTI_FAILING */


extern uint32_t __stl_ram_test_start__;
extern uint32_t __stl_ram_test_end__;

static STL_MemSubset_t MyRamSubsetRunTime = {
.StartAddr = (uint32_t)&__stl_ram_test_start__,
.EndAddr = (uint32_t)&__stl_ram_test_end__ - 1U,
.pNext = NULL
};

static STL_MemConfig_t MyRamConfigRunTime = {
.NumSectionsAtomic = UINT32_MAX,
.pSubset = &MyRamSubsetRunTime
};


void FailSafe_Handler(uint32_t fail_code)
{
/* Here, user has to add an action to setup & keep the application in safe state.
The fail_code input parameter together with TM dedicated user status value
can be used to identify detected issue and adopt specific action */
while (1)
{
HAL_GPIO_WritePin(LED_ON2_GPIO_Port, LED_ON2_Pin, GPIO_PIN_SET); //RED
HAL_Delay(100U);
HAL_GPIO_WritePin(LED_ON2_GPIO_Port, LED_ON2_Pin, GPIO_PIN_RESET); //RED
HAL_Delay(100U);
Log_Printf("FailSafe_Handler=%u", fail_code);
/*
if(fail_code < DEF_PROG_OFFSET)
{
HAL_Delay(1900);
}
else
{
HAL_Delay(3900);
}
*/
}
}


void Thread_FailSafe_Handler(uint32_t fail_code)
{
/* Here, user has to add an action to setup & keep the application in safe state.
The fail_code input parameter together with TM dedicated user status value
can be used to identify detected issue and adopt specific action */
while (1)
{
HAL_GPIO_WritePin(LED_ON2_GPIO_Port, LED_ON2_Pin, GPIO_PIN_SET); //RED
tx_thread_sleep(100U);
HAL_GPIO_WritePin(LED_ON2_GPIO_Port, LED_ON2_Pin, GPIO_PIN_RESET); //RED
tx_thread_sleep(100U);

Log_Printf("Thread_FailSafe_Handler=%u", fail_code);
/*
if(fail_code < DEF_PROG_OFFSET)
{
HAL_Delay(1900);
}
else
{
HAL_Delay(3900);
}
*/
}
}



static STL_Status_t STL_InitClock_Xcross_Measurement(void)
{
TIM_IC_InitTypeDef sConfigIC = {0};

/* TIMx Peripheral clock enable */
// __TIM15_CLK_ENABLE();
__HAL_RCC_CSI_ENABLE();
while (__HAL_RCC_GET_FLAG(RCC_FLAG_CSIRDY) == RESET)
{
}

__HAL_RCC_TIM15_CLK_ENABLE();


/* Configure the NVIC for TIM12 */
HAL_NVIC_SetPriority(TIM15_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(TIM15_IRQn);

htim15.Instance = TIM15;
htim15.Init.Prescaler = 0;
htim15.Init.CounterMode = TIM_COUNTERMODE_UP;
htim15.Init.Period = 65535;
htim15.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim15.Init.RepetitionCounter = 0;
htim15.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim15) != HAL_OK)
{
return (STL_KO);
}
if (HAL_TIM_IC_Init(&htim15) != HAL_OK)
{
return (STL_KO);
}
sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
sConfigIC.ICPrescaler = TIM_ICPSC_DIV4;
sConfigIC.ICFilter = 0;
if (HAL_TIM_IC_ConfigChannel(&htim15, &sConfigIC, TIM_CHANNEL_1) != HAL_OK)
{
return (STL_KO);
}
if (HAL_TIMEx_TISelection(&htim15, TIM_TIM15_TI1_CSI_128, TIM_CHANNEL_1) != HAL_OK)
{
return (STL_KO);
}
/* Start the TIM Input Capture measurement in interrupt mode */
if(HAL_TIM_IC_Start_IT(&htim15, TIM_CHANNEL_1) != HAL_OK)
{
return (STL_KO);
}
return (STL_OK);
}

void STL_Init(void)
{

/* FLASH test Config
*****************
In this example, single continuous area (subset) is tested under unique configuration setting.
User can apply wider set of subsets tested sequentially to cover separated memory areas
as well as different configurations to be applied for selected subset(s) - see UM */
FlashSubsetRunTime.StartAddr = TEST_ROM_START_ADDR;
FlashSubsetRunTime.EndAddr = TEST_ROM_END_ADDR;
FlashSubsetRunTime.CrcTableIdx = STL_CRC_TABLE_NO_TZ;
FlashSubsetRunTime.pNext = NULL;
FlashConfigRunTime.pSubset = &FlashSubsetRunTime;
FlashConfigRunTime.NumSectionsAtomic = 1; /* split test into sections of 1kB */

/* RAM test Config
***************
In this example, single continuous area (subset) is tested under unique configuration setting.
User can apply wider set of subsets tested sequentially to cover separated memory areas
as well as different configurations to be applied for selected subset(s) - see UM */
RamSubsetRunTime.StartAddr = TEST_RAM_START_ADDR;
RamSubsetRunTime.EndAddr = TEST_RAM_START_ADDR + TEST_RAM_SECTION_NB_RUN * RAM_SECTION_SIZE - 1;
RamSubsetRunTime.pNext = NULL;
RamConfigRunTime.pSubset = &RamSubsetRunTime;
RamConfigRunTime.NumSectionsAtomic = 1; /* split test into sections of 128 bytes */
/* RamConfig.NumSectionsAtomic = (2 * TEST_RAM_SECTION_NB); */ /* - use this setting for one shot */


/* test status initialization */
StlCpuTm1LStatus = STL_NOT_TESTED;
StlCpuTm7Status = STL_NOT_TESTED;
StlCpuTmCBStatus = STL_NOT_TESTED;
StlFlashStatus= STL_NOT_TESTED;
StlRamStatus= STL_NOT_TESTED;

if (STL_SCH_Init() != STL_OK)
{
FailSafe_Handler(SCH_ERR_CODE + DEF_PROG_OFFSET);
}


// Clock test Config
if(STL_InitClock_Xcross_Measurement() != STL_OK)
{
FailSafe_Handler(CXM_ERR_CODE + DEF_PROG_OFFSET);
}
// Wait for two subsequent LSI periods measurements to perform initial crosscheck computation
LSIPeriodFlag = 0u;
while (LSIPeriodFlag == 0u)
{

}
LSIPeriodFlag = 0u;
while (LSIPeriodFlag == 0u)
{

}

}
STL_Status_t STL_RunClockTest(STL_TmStatus_t *clk_sts)
{
STL_Status_t tst_res;

*clk_sts = STL_PARTIAL_PASSED;
/* next line can produce compilation warning due to accessing of two volatile
variables making single result value integrity pair. The pair is changed
simultaneously exclusively at TIM16 IRQ and its integrity is verified here
before the clock measurement is compared if it fits within expected range */
if (((PeriodValue ^ PeriodValueInv) == 0xFFFFFFFFuL)\
&& (LSIPeriodFlag == 0xAAAA5555u) )
{
#ifndef ARTI_FAILING_CLK_TM
*clk_sts = STL_PASSED;
if (PeriodValue < CLK_LimitLow(SYSTCLK_AT_RUN))
{
*clk_sts = STL_FAILED; /* Sub-harmonics: HSE -25% below expected */
}
if (PeriodValue > CLK_LimitHigh(SYSTCLK_AT_RUN))
{
*clk_sts = STL_FAILED; /* Harmonics: HSE +25% above expected */
}
#else
*clk_sts = STL_FAILED;
#endif /* ARTI_FAILING_CLK_TM */

/* clear flag here to ensure the latest LSI measurement result will be taken into account at next check */
LSIPeriodFlag = 0u;
tst_res = STL_OK;
}
else
{
tst_res = STL_KO; /* Clock measurement flow error */
}
return(tst_res);
}

void STL_RunFullTest(void)
{
/* Example of complete device self-test
************************************
This function executes all the provided CPU, flash, RAM, and clock test modules in this order. Test
of both the memories is performed in one shot in their entirety here. The function should be called
prior to the main application entry, but can also be re-called by the application at any later point.
Configuration structures for handling tests of the memories are declared locally, therefore they
cannot be referenced outside of the function which is supposed to be executed as a whole.
*/

/********************/
/* CPU Test modules */
/********************/

#if defined(ARTI_FAILING_CPU_TM) && defined(ARTI_FAILING_DURING_FULL_TEST)
/* Artificial failing feature -
when activated, it forces the STL outputs to predefined values */
ArtifFailing.aCpuTmStatus[0] = STL_PASSED;
ArtifFailing.aCpuTmStatus[1] = STL_PASSED;
ArtifFailing.aCpuTmStatus[2] = STL_FAILED;
STL_SCH_StartArtifFailing(&ArtifFailing);
#endif /* ARTI_FAILING_CPU_TM */

/* CPU TM1L */
if (STL_SCH_RunCpuTM1L(&StlCpuTm1LStatus) != STL_OK)
{
FailSafe_Handler(TM1L_ERR_CODE + DEF_PROG_OFFSET);
}
if (StlCpuTm1LStatus != STL_PASSED)
{
FailSafe_Handler(TM1L_ERR_CODE);
}
/* CPU TM7 */

if (STL_SCH_RunCpuTM7(&StlCpuTm7Status) != STL_OK)
{
FailSafe_Handler(TM7_ERR_CODE + DEF_PROG_OFFSET);
}
if (StlCpuTm7Status != STL_PASSED)
{
FailSafe_Handler(TM7_ERR_CODE);
}
/* CPU TMCB */
if (STL_SCH_RunCpuTMCB(&StlCpuTmCBStatus) != STL_OK)
{
FailSafe_Handler(TMCB_ERR_CODE + DEF_PROG_OFFSET);
}
if (StlCpuTmCBStatus != STL_PASSED)
{
FailSafe_Handler(TMCB_ERR_CODE);
}

#if defined(ARTI_FAILING_CPU_TM) && defined(ARTI_FAILING_DURING_FULL_TEST)
STL_SCH_StopArtifFailing();
#endif /* ARTI_FAILING_CPU_TM */


/*********************/
/* FLASH Test Module */
/*********************/

#if defined(ARTI_FAILING_FLASH_TM) && defined(ARTI_FAILING_DURING_FULL_TEST)
/* forced STL_FAILED status simulates the TM configuration error and
STL_NOT_TESTED status simulates TM run error */
ArtifFailing.FlashTmStatus = STL_FAILED;
STL_SCH_StartArtifFailing(&ArtifFailing);
#endif /* ARTI_FAILING_FLASH_TM */

/* The following configuration tests the entire program in the flash, in one shot */
STL_MemSubset_t FlashSubsetFullTest = {
.StartAddr = TEST_ROM_START_ADDR,
.EndAddr = TEST_ROM_END_ADDR,
.CrcTableIdx = STL_CRC_TABLE_NO_TZ,
.pNext = NULL
};
STL_MemConfig_t FlashConfigFullTest = {
.NumSectionsAtomic = UINT32_MAX,
.pSubset = &FlashSubsetFullTest
};
if (STL_SCH_InitFlash(&StlFlashStatus) != STL_OK)
{
FailSafe_Handler(TMF_ERR_CODE + DEF_PROG_OFFSET);
}

if (STL_SCH_ConfigureFlash(&StlFlashStatus, &FlashConfigFullTest) != STL_OK)
{
FailSafe_Handler(TMF_ERR_CODE + DEF_PROG_OFFSET);
}
else if (StlFlashStatus != STL_NOT_TESTED)
{
FailSafe_Handler(TMF_ERR_CODE);
}

/*
STL_Status_t ret;

ret = STL_SCH_RunFlashTM(&StlFlashStatus);

if (ret != STL_OK)
{
volatile STL_Status_t debug_ret = ret;
volatile STL_TmStatus_t debug_flash_status = StlFlashStatus;
FailSafe_Handler(TMF_ERR_CODE + DEF_PROG_OFFSET);
}
*/

if (STL_SCH_RunFlashTM(&StlFlashStatus) != STL_OK)
{
FailSafe_Handler(TMF_ERR_CODE + DEF_PROG_OFFSET);
}
else if (StlFlashStatus != STL_PASSED)
{
FailSafe_Handler(TMF_ERR_CODE);
}

StlFlashStatus = STL_NOT_TESTED;

#if defined(ARTI_FAILING_FLASH_TM) && defined(ARTI_FAILING_DURING_FULL_TEST)
STL_SCH_StopArtifFailing();
#endif /* ARTI_FAILING_FLASH_TM */


/********************/
/* RAM Test module */
/********************/

#if defined(ARTI_FAILING_RAM_TM) && defined(ARTI_FAILING_DURING_FULL_TEST)
/* forced STL_FAILED status simulates the TM configuration error and
STL_NOT_TESTED status simulates TM run error */
ArtifFailing.RamTmStatus = STL_NOT_TESTED;
STL_SCH_StartArtifFailing(&ArtifFailing);
#endif /* ARTI_FAILING_RAM_TM */

/* The following configuration tests the entire user-defined range of the RAM used by the program */
/* RAM subset: */
STL_MemSubset_t RamSubsetFullTest = {
.StartAddr = TEST_RAM_START_ADDR,
.EndAddr = TEST_RAM_END_ADDR_FULL,
.pNext = NULL
};
STL_MemConfig_t RamConfigFullTest = {
.NumSectionsAtomic = UINT32_MAX,
.pSubset = &RamSubsetFullTest
};

if (STL_SCH_InitRam(&StlRamStatus) != STL_OK)
{
FailSafe_Handler(TMR_ERR_CODE + DEF_PROG_OFFSET);
}
if (STL_SCH_ConfigureRam(&StlRamStatus, &RamConfigFullTest) != STL_OK)
{
FailSafe_Handler(TMR_ERR_CODE + DEF_PROG_OFFSET);
}
else if (StlRamStatus != STL_NOT_TESTED)
{
FailSafe_Handler(TMR_ERR_CODE);
}
if (STL_SCH_RunRamTM(&StlRamStatus) != STL_OK)
{
FailSafe_Handler(TMR_ERR_CODE + DEF_PROG_OFFSET);
}
else if (StlRamStatus != STL_PASSED)
{
FailSafe_Handler(TMR_ERR_CODE);
}
StlRamStatus = STL_NOT_TESTED;

#if defined(ARTI_FAILING_RAM_TM) && defined(ARTI_FAILING_DURING_FULL_TEST)
STL_SCH_StopArtifFailing();
#endif /* ARTI_FAILING_RAM_TM */

/************/
/* Clock TM */
/************/
StlClkStatus = STL_NOT_TESTED;
if (STL_RunClockTest(&StlClkStatus) != STL_OK)
{
FailSafe_Handler(CLK_ERR_CODE + DEF_PROG_OFFSET);
}
if (StlClkStatus != STL_PASSED)
{
FailSafe_Handler(CLK_ERR_CODE);
}
}



void STL_RunStep(void)
{
/* Example of the test sequence execution
**************************************
In this example, a unique sequence performing all the tests in one shot is applied.
Note it is fully upon user to define order and repetition frequency of all the API calls.
The same sequence of the calls can be repeated regularly or few different sequences can be
applied at different time slots. All the tests can be repeated without any limitation
except for clock test which can not be called earlier than 8 LSI periods to prepare new clock
computation result in between two comparisons (otherwise the clock API call fails). */

/********************/
/* CPU Test modules */
/********************/

#ifdef ARTI_FAILING_CPU_TM
/* Artificial failing feature -
when activated, it forces the STL outputs to predefined values */
ArtifFailing.aCpuTmStatus[0] = STL_PASSED;
ArtifFailing.aCpuTmStatus[1] = STL_PASSED;
ArtifFailing.aCpuTmStatus[2] = STL_FAILED;
STL_SCH_StartArtifFailing(&ArtifFailing);
#endif /* ARTI_FAILING_CPU_TM */

/* CPU TM1L */
if (STL_SCH_RunCpuTM1L(&StlCpuTm1LStatus) != STL_OK)
{
Thread_FailSafe_Handler(TM1L_ERR_CODE + DEF_PROG_OFFSET);
}
if (StlCpuTm1LStatus != STL_PASSED)
{
Thread_FailSafe_Handler(TM1L_ERR_CODE);
}
/* CPU TM7 */
#if 0
if (STL_SCH_RunCpuTM7(&StlCpuTm7Status) != STL_OK)
{
Thread_FailSafe_Handler(TM7_ERR_CODE + DEF_PROG_OFFSET);
}
if (StlCpuTm7Status != STL_PASSED)
{
Thread_FailSafe_Handler(TM7_ERR_CODE);
}
#endif
/* CPU TMCB */
if (STL_SCH_RunCpuTMCB(&StlCpuTmCBStatus) != STL_OK)
{
Thread_FailSafe_Handler(TMCB_ERR_CODE + DEF_PROG_OFFSET);
}
if (StlCpuTmCBStatus != STL_PASSED)
{
Thread_FailSafe_Handler(TMCB_ERR_CODE);
}

#ifdef ARTI_FAILING_CPU_TM
STL_SCH_StopArtifFailing();
#endif /* ARTI_FAILING_CPU_TM */


/************/
/* Flash TM */
/************/

#ifdef ARTI_FAILING_FLASH_TM
/* forced STL_FAILED status simulates the TM configuration error and
STL_NOT_TESTED status simulates TM run error */
ArtifFailing.FlashTmStatus = STL_FAILED;
STL_SCH_StartArtifFailing(&ArtifFailing);
#endif /* ARTI_FAILING_FLASH_TM */

if (StlFlashStatus == STL_NOT_TESTED)
{
/* Init & configure Flash TM */
if (STL_SCH_InitFlash(&StlFlashStatus) != STL_OK)
{
Thread_FailSafe_Handler(TMF_ERR_CODE + DEF_PROG_OFFSET);
}
if (STL_SCH_ConfigureFlash(&StlFlashStatus, &FlashConfigRunTime) != STL_OK)
{
Thread_FailSafe_Handler(TMF_ERR_CODE + DEF_PROG_OFFSET);
}
else if (StlFlashStatus != STL_NOT_TESTED)
{
Thread_FailSafe_Handler(TMF_ERR_CODE);
}
}
/* run partial atomic test */

if (STL_SCH_RunFlashTM(&StlFlashStatus) != STL_OK)
{
Thread_FailSafe_Handler(TMF_ERR_CODE + DEF_PROG_OFFSET);
}
if (StlFlashStatus != STL_PARTIAL_PASSED)
{
if (StlFlashStatus == STL_PASSED)
{
// test completed successfully - to be restarted
StlFlashStatus= STL_NOT_TESTED;
}
else
{
Thread_FailSafe_Handler(TMF_ERR_CODE);
}
}

#ifdef ARTI_FAILING_FLASH_TM
STL_SCH_StopArtifFailing();
#endif /* ARTI_FAILING_FLASH_TM */


/**********/
/* RAM TM */
/**********/

#ifdef ARTI_FAILING_RAM_TM
/* forced STL_FAILED status simulates the TM configuration error and
STL_NOT_TESTED status simulates TM run error */
ArtifFailing.RamTmStatus = STL_NOT_TESTED;
STL_SCH_StartArtifFailing(&ArtifFailing);
#endif /* ARTI_FAILING_RAM_TM */


if (StlRamStatus == STL_NOT_TESTED)
{
/* Initialize & configure Flash TM */
if (STL_SCH_InitRam(&StlRamStatus) != STL_OK)
{
Thread_FailSafe_Handler(TMR_ERR_CODE + DEF_PROG_OFFSET);
}
if (STL_SCH_ConfigureRam(&StlRamStatus, &MyRamConfigRunTime) != STL_OK)
{
Thread_FailSafe_Handler(TMR_ERR_CODE + DEF_PROG_OFFSET);
}
else if (StlRamStatus != STL_NOT_TESTED)
{
Thread_FailSafe_Handler(TMR_ERR_CODE);
}
}
/* run partial atomic test */
if (STL_SCH_RunRamTM(&StlRamStatus) != STL_OK)
{
Thread_FailSafe_Handler(TMR_ERR_CODE + DEF_PROG_OFFSET);
}
if (StlRamStatus != STL_PARTIAL_PASSED)
{
if (StlRamStatus == STL_PASSED)
{
/* test completed successfully - to be restarted */
StlRamStatus= STL_NOT_TESTED;
}
else
{
Thread_FailSafe_Handler(TMR_ERR_CODE);
}
}

#ifdef ARTI_FAILING_RAM_TM
STL_SCH_StopArtifFailing();
#endif /* ARTI_FAILING_RAM_TM */

/************/
/* Clock TM */
/************/
/* When artificial failing is activated for clock module, the failure status is
forced by the API module itself available as open source code */
StlClkStatus = STL_NOT_TESTED;
if (STL_RunClockTest(&StlClkStatus) != STL_OK)
{
Thread_FailSafe_Handler(CLK_ERR_CODE + DEF_PROG_OFFSET);
}
if (StlClkStatus != STL_PASSED)
{
Thread_FailSafe_Handler(CLK_ERR_CODE);
}
}

I am developing a firmware using the STM32H523VET6 MCU. I downloaded and am applying the sample below, but the `StlFlashStatus` value returned by the `STL_SCH_RunFlashTM(&StlFlashStatus)` function inside the `STL_RunFullTest()` function is `STL_FAILED`. I would like to know the reason for this. I understand that this example file supports all STM32H5 models; is that not the case?​

Post-Build Steps Command: echo "\"STM32_Programmer_CLI.exe\" -sl \"%CD%\${BuildArtifactFileName}\" 0x08000000 0x08080000 0x400" > call_prg.bat && cmd /c call_prg.bat && arm-none-eabi-objcopy -O binary --gap-fill 0xFF "${BuildArtifactFileBaseName}.elf" "${BuildArtifactFileBaseName}.bin"

Sample : stm32cubeexpansion-x-cube-classb-h5-v4.0.0.zip