Closed chrihell closed 2 years ago
@chrihell , Thanks for reporting this issue, and welcome to Zephyr community. Thank you also for your analysis, which is very detailed, and further more exact, And finally thanks for the fix you proposed, and the test you performed, it looks good.
So you made all the job, thus I propose you to continu the Zephyr experience, and push, on your own, the fix that you proposed in a Pull Request.
@ABOSTM Thanks for the quick and welcoming reply. I'll try to do the PR then. It can't be that hard to change a line of code, right? ;)
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:
nucleo_h7a3zi_q
. It uses an STM32H7A3ZI-Q microcontroller (ARM Cortex-M7).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 constant32
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 forFLASH_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.