STM32H7xx: Driver for internal flash memory partially uses a fixed flash program word size, which doesn't fit for all STM32H7xx SOCs (e.g. STM32H7A3, STM32H7B0, STM32H7B3) leading to potential flash data corruption #45568
Labels
bug
The issue is a bug, or the PR is fixing a bug
platform: STM32
ST Micro STM32
priority: low
Low impact/importance bug
Milestone
Describe the bug
When running an adapted version of the Zephyr littlefs example on a Nucelo-H7A3ZI-Q board it fails to create and format the littlefs filesystem placed in an internal flash partition.
The UART log output shows that littlefs cannot successfully create the filesystem and fails to create superblock 0 with error code -28
(see log output further down)
Unfortunately the meaning of the error code is a bit misleading here.
Please also mention any information which could help others to understand
the problem you're facing:
What target platform are you using?
The Zephyr board name is
nucleo_h7a3zi_q
.It uses an STM32H7A3ZI-Q microcontroller (ARM Cortex-M7).
What have you tried to diagnose or workaround this issue?
I tried various things to examine the issue, mainly log analysis and debugging with gdb.
Actually I think that the issue originates from the stm32h7xx specific low-level flash driver write routine
flash_stm32_write_range()
. More on that further down.To Reproduce
Steps to reproduce the behavior:
zephyr\samples\subsys\fs\littlefs\boards
to add support for the nucleo_h7a3zi_q board to the littlefs example project. Remove the .txt file extension that was added because of github.(see section 'Additional context' for attached files)
CONFIG_APP_WIPE_STORAGE=y
inprj.conf
of the example project.This ensures, that the flash partition is always getting erased and that the littlefs filesystem is recreated.
west build -p -b nucleo_h7a3zi_q zephyr\samples\subsys\fs\littlefs
west flash
Expected behavior
The littlefs filesystem initialization shouldn't fail and the example program should be able to execute in the intended way and do it's file operations (e.g. incrementing and writing boot counter to file). No errors should be reported in the log output by littlefs, the file system or flash driver.
File Systems API calls should work as expected.
Impact
I'm rather new to Zephyr and it took me several hours to track down and to locally fix the issue.
Initially I expected that the example project builds and would work as-is out of the box for the used Nucleo board, as support was added for it and littlefs.
So it looked like a showstopper in the beginning, but was in the end luckily more of a learning experience in debugging and working with Zephyr and about filing this bug report.
The issue does probably not only affect littlefs write operations, but potentially affects all internal flash writes on STM32H7xx SOCs that have a flash program word size that is different from 256 bits.
Logs and console output
In the described error situation the UART log output is the following:
The log shows how littlefs tries to format the partition, but fails to write Superblock 0 correctly and then fails with error code -28.
Environment (please complete the following information):
Additional context
nucleo_h7a3zi_q.conf.txt
nucleo_h7a3zi_q.overlay.txt
Proposed fix
Change the code in zephyr\drivers\flash\flash_stm32h7x.c:376 to:
for (i = 0; i < len && i + nbytes <= len; i += nbytes, offset += nbytes) {
This essentially replaces the constant
32
by the already calculated number of bytes innbytes
.The calculated number fits to the flash program word size of the used STM32H7xx SOC type, as it is based on a SOC type specific definition of the flash program word size.
Explanation
Original Code
In the shown code part, with each execution of the for loop the number of dwords (64 bits / 8 bytes) is written to flash that is needed to match the flash program word size.
Most STM32H7xx SOCs seem to have 256 bits / 32 bytes flash program word size. This results in
ndwords
being equal to 32 / 8 = 4That's the reason why the hard-coded constant 32 is used to increment the byte offset in the for loop too.
Unfortunately some (newer) STM32H7xx SOC types use only a flash program word size of 128 bits / 16 bytes (e.g. STM32H7A3, STM32H7B0, STM32H7B3 types).
As
ndwords
andnbytes
are calculated based on definitions from the SOC type specific header file they are correct and fitting.However the constant
32
in the for loop is not, as it would need to be set to 16 in this case.The issue is caused by the fact, that only two dwords are written via the
write_ndwords()
call each loop, so 16 bytes, but the byte offset in the for loop is still incremented by 32 bytes.When checking the flash content, one can see that a block of 16 bytes of data is followed by an erased block of 16 bytes in an alternating fashion.
Proposed solution: The code can be fixed by replacing the constant
32
by the calculated constantnbytes
, as this constant respects the definition from the SOC type specific header file from themodules\hal\stm32\stm32cube\stm32h7xx\soc
directory.See the definition for
FLASH_NB_32BITWORD_IN_FLASHWORD
in those header files.Log output via UART after applying the proposed solution
Littlefs detects a corrupted filesystem, as the flash partition got erased by the application.
But this time it succeeds with formatting and the freshly created filesystem can be mounted afterwards.
The file operations of the example application work without errors, too.
The text was updated successfully, but these errors were encountered: