2025-04-22 1:45 PM - last edited on 2025-04-23 6:06 AM by Amel NASRI
I’m using the Class B Flash self‑test on an STM32F407. My post‑build step injects CRCs with:
STM32_Programmer_CLI -sl Firmware.elf 0x08000000 0x08100000 0x400
I Inspected the CRC of the first section via
arm-none-eabi-objdump -s -j "CRCs area" Firmware.elf | head -n2
After this I re‑computed the CRC to verify which method it used. I used srec_cat and I used the following method:
arm-none-eabi-objcopy -O binary Firmware.elf full_flash.bin
dd if=full_flash.bin of=region.bin bs=1 count=1024
srec_cat region.bin -Binary \
-CRC32_Little_Endian 0x400 \
-crop 0x400 0x404 \
-output - -binary \
| hexdump -e '1/4 "CRC32: 0x%08X\n"'
After this I figured out that the CRC checksum stored in the memory for the first 0x400 section matched with the srec_cat output.
However at runtime, when STL_SCH_RunFlashTM() (compiled with both -DSTL_SW_CRC and without it) computes the CRC over the exact same 0x400 bytes which is different than the expected value. As a result, StlFlashStatus returns STL_Failed I end up in the FailSafe_Handler with error code 13.
Key finding:
The built‑in STM32F4 CRC peripheral has no bit reflections, initial bit is 0xFFFFFFFF, no final XOR. Whereas -CRC32_Little_endian (same as STM_Programmer_CLI) uses reflected input and output, consistent with the standard CRC-32 definition. A final XOR of 0xFFFFFFFF is applied always injects the reflected CRC32 (input+output bit‑reversal), so the two algorithms cannot match on F4 hardware.
The whole method of CRC calculation seems unusual to me. Maybe it's my lack of knowledge too. Any guidance or best‑practice example for aligning the runtime CRC with the CLI‑injected table on STM32F4 would be greatly appreciated.
2025-04-22 2:17 PM
srecord does have the STM32-specific CRC implemented, see it's manual.
JW
2025-04-22 3:11 PM - edited 2025-04-22 3:11 PM
>>The whole method of CRC calculation seems unusual to me.
The HW is super awkward, it does 32-bit word level processing, reads the words small-endian and then processes left-ward with the high order bit first.
Most online calculators will choke if fed bytes in memory order.
https://github.com/cturvey/RandomNinjaChef/blob/main/stm32crc.c
2025-04-23 5:25 AM
Hey @waclawek.jan , yes I've seen that too and tried it. It results in a different checksum from what is stored in the CRCs area of the memory. Which leads me to believe that STM_Programmer_CLI uses -CRC32_Little_Endian configurations (which is different than STM32F407's hardware CRC engine).
2025-04-23 5:37 AM
In X-Cube-ClassB-F4, all the safety functions including the checksum calculation function is under STL_Lib.a library. According to the documentation, all I know is that the flash test STL_SCH_RunFlashTM() calls the CRC calculation function CRC_Handle_32_HW(). I don't have the visibility of what's inside. It likely calls the HAL function to calculate the CRC but I don't know.
The issue is it's a pre-certified library and I shouldn't modify any core logic. That's why wanted to figure out if anyone in the community faced similar issues or not.
Maybe an ST employee can answer this? @Petr Sladecek @Amel NASRI
2025-05-05 7:30 AM
Hello all,
STL use no HAL functions and simply apply default setting of the embedded CPU HW CRC unit to calculate the checking patterns. The CRC result descriptor field is made by CLI of the STM32 Cube Programmer at the end of the flash area. To make the CRC calculations working correctly, user must ensure required alignments of the binary area start and end and the area must be continuous (any gaps between sections could make a trouble due to their different default filling by different programmers). Anyway, customer can develop and certify own method to check the program memory integrity at his responsibility.
Best regards,
Petr
2025-05-06 6:14 AM
Thanks for your reply Petr,
But can you further explain to me how do I verify the start and the end area of the binary is continuous? This is my linker file FYI:
/*
******************************************************************************
**
** @file : LinkerScript.ld
**
** @author : Auto-generated by STM32CubeIDE
**
** @brief : Linker script for STM32F407ZGTx Device from STM32F4 series
** 1024KBytes FLASH
** 64KBytes CCMRAM
** 128KBytes RAM
**
** Set heap size, stack size and stack location according
** to application requirements.
**
** Set memory bank area and size if external memory is used
**
** Target : STMicroelectronics STM32
**
** Distribution: The file is distributed as is, without any warranty
** of any kind.
**
******************************************************************************
** @attention
**
** Copyright (c) 2025 STMicroelectronics.
** All rights reserved.
**
** This software is licensed under terms that can be found in the LICENSE file
** in the root directory of this software component.
** If no LICENSE file comes with this software, it is provided AS-IS.
**
******************************************************************************
*/
/* Entry Point */
ENTRY(Reset_Handler)
/* Highest address of the user mode stack */
_estack = ORIGIN(RAM) + LENGTH(RAM); /* end of "RAM" Ram type memory */
_Min_Heap_Size = 0x200; /* required amount of heap */
_Min_Stack_Size = 0x400; /* required amount of stack */
/* Memories definition */
MEMORY
{
CCMRAM (xrw) : ORIGIN = 0x10000000, LENGTH = 64K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 1024K
}
/* Sections */
SECTIONS
{
/* The startup code into "FLASH" Rom type memory */
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(4);
} >FLASH
/* The program code and other data into "FLASH" Rom type memory */
.text :
{
. = ALIGN(4);
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.glue_7) /* glue arm to thumb code */
*(.glue_7t) /* glue thumb to arm code */
*(.eh_frame)
KEEP (*(.init))
KEEP (*(.fini))
. = ALIGN(4);
_etext = .; /* define a global symbols at end of code */
} >FLASH
/* Constant data into "FLASH" Rom type memory */
.rodata :
{
. = ALIGN(4);
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
. = ALIGN(4);
} >FLASH
.ARM.extab (READONLY) : /* The "READONLY" keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
{
. = ALIGN(4);
*(.ARM.extab* .gnu.linkonce.armextab.*)
. = ALIGN(4);
} >FLASH
.ARM (READONLY) : /* The "READONLY" keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
{
. = ALIGN(4);
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
. = ALIGN(4);
} >FLASH
.preinit_array (READONLY) : /* The "READONLY" keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
{
. = ALIGN(4);
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
. = ALIGN(4);
} >FLASH
.init_array (READONLY) : /* The "READONLY" keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
{
. = ALIGN(4);
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
. = ALIGN(4);
} >FLASH
.fini_array (READONLY) : /* The "READONLY" keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
{
. = ALIGN(4);
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
. = ALIGN(4);
} >FLASH
/* reserved space at the beginning of RAM to be used by STL RAM test */
backup_buffer_section (NOLOAD): { *(backup_buffer_section) } >RAM
/* Used by the startup to initialize data */
_sidata = LOADADDR(.data);
/* Initialized data sections into "RAM" Ram type memory */
.data :
{
. = ALIGN(4);
_sdata = .; /* create a global symbol at data start */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
*(.RamFunc) /* .RamFunc sections */
*(.RamFunc*) /* .RamFunc* sections */
. = ALIGN(4);
_edata = .; /* define a global symbol at data end */
_edata_load = LOADADDR(.data) + SIZEOF(.data) -4; /* Define address of the last word of this section, which is also the last word in the flash. */
} >RAM AT> FLASH
_siccmram = LOADADDR(.ccmram);
/* CCM-RAM section
*
* IMPORTANT NOTE!
* If initialized variables will be placed in this section,
* the startup code needs to be modified to copy the init-values.
*/
.ccmram :
{
. = ALIGN(4);
_sccmram = .; /* create a global symbol at ccmram start */
*(.ccmram)
*(.ccmram*)
. = ALIGN(4);
_eccmram = .; /* create a global symbol at ccmram end */
} >CCMRAM AT> FLASH
/* Uninitialized data section into "RAM" Ram type memory */
. = ALIGN(4);
.bss :
{
/* This is used by the startup in order to initialize the .bss section */
_sbss = .; /* define a global symbol at bss start */
__bss_start__ = _sbss;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end */
__bss_end__ = _ebss;
} >RAM
/* User_heap_stack section, used to check that there is enough "RAM" Ram type memory left */
._user_heap_stack :
{
. = ALIGN(8);
PROVIDE ( end = . );
PROVIDE ( _end = . );
. = . + _Min_Heap_Size;
. = . + _Min_Stack_Size;
. = ALIGN(8);
} >RAM
/* Remove information from the compiler libraries */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
.ARM.attributes 0 : { *(.ARM.attributes) }
}
2025-05-15 6:18 AM
Hello,
you can use Cube IDE embedded Build Analyzer to check ends and begins of all the sections inside the binary. Discontinuity can be observed easily by inspection of the HEX file, too. Anyway, if you program your code by Cube Programmer (not by any IDE itself) you eliminate the problem as the programmer forces the occasional gaps by the same default values as applied during the computation and build of the CRC descriptor field. Usually the problem is with the test end address configuration because it must match with the last address of the binary while aligned to the last 32-bit word end. Binary start must be aligned with 1KB section start.
Best regards,
Petr
2025-11-21 1:47 AM
Hello,
I'm facing similar problems to the ones introduced by @NafiurRahman. I'm using the Nucleo equipped with STM32H563ZI, and I'm running the tests for this board download from the ST official website (STL_Single_Tests_Nucleo_H563ZI).
I didn't do any modification to the original code, but the call to STL_SCH_RunFlashTM() returns STL_Failed.
The process I followed is this:
1) I have built the test using STM32CubeIde
2) I have injected the CRC using STM32_Programmer_CLI in the binary obtained from the step 1. I had to use as end_address a multiplier of 0x400 in order to get a correct injection.
3) I have uploaded the firmware using STM32CubeProgrammer GUI application.
I have some doubts regarding the padding provided by STM32_Programmer_CLI in order to reach a correct size for the tool. Moreover, I don't know if the CRCTable used by the Nucleo tests coincides with the one used by the STM32_Programmer_CLI.
Any help or suggestion would be really appreciated, probably I make some dumb mistakes.
I think that the STlib together with its tests could be really useful, but I'm worried about spending a lot of effort to make this tests work without having full control on them.
Thank you,
Giulio
p.s. @NafiurRahman: did you succeed on fixing those tests for you specific case?
2025-11-21 2:53 AM
A little update: I tried to use the full flash size in order to avoid padding issues. I also tried to force the same CRCTable by forcing STL_CRC_TABLE_NO_TZ_DEF in stl_user_api.h to 0x04C11DB7, that is the polynomial I suspect STM32_Programmer_CLI is using.
However, I'm still receiving the same STL_Failed error in the flash test.
Giulio