Replies: 4 comments
-
Another issue is that NvmDataMgmtStore() doesn't handle failures of NvmmWrite(). |
Beta Was this translation helpful? Give feedback.
-
Thanks for reporting it here (we use real EEPROM chips), helpful for the LoRaWAN community. |
Beta Was this translation helpful? Give feedback.
-
In this project we just use the libraries provided by ST with a specific version. Maybe in the mean time ST has produced newer versions of the library which is able to support newer MCU variants. In our examples we use the EEPROM emulation just as an example. The reason being that the produced firmware binary will work out of the box for the given evaluation kit. No need to have external components. As @pieterdemil pointed out one should use external real NVM devices (EEPROM, FRAM, etc). The biggest advantage being the maximum number of MCU FLASH erase/write cycles which is much lower than for a real NVM memory. In the future it would be nice if you could post this kind of questions on the project Discussions tab. It is a better place to engage discussions and then we can agree if it is an issue or not. |
Beta Was this translation helpful? Give feedback.
-
It is lovely when the product requirements allow the use of external real NVM devices (EEPROM, FRAM, etc.), but those add space and cost. As a result, it is incredibly common in low-cost embedded products (the sorts of things LoRaMac-node is intended for) to use flash for NV persistence. Since the reference stack does exactly that, I think it is reasonable to address this here rather than just suggest that users not use flash for persistence. There are many successful software strategies for limiting erase/write cycles to stay within the 10K-100K limits typical of most flash memories including spreading usage across multiple sectors (the approach used by the ST EEPROM emulation library) or caching the data in RAM and flushing to flash periodically and/or when necessary (e.g. before a reset). Because the reference stack incorporates the ST EEPROM library explicitly rather than by reference, and because what I'd mentioned above is clearly a bug (I've also filed it against the EEPROM library), and because the fix is so easy, I'm mystified as to why anyone would want to intentionally leave a serious bug buried deep in the code base for each unsuspecting user to find on their own. It's obviously your call, but I respectfully suggest that this be left as an issue rather than a discussion. The issue of how to handle NV errors rather than failing silently is another topic (with another easy fix) and I will start a separate discussion about it. |
Beta Was this translation helpful? Give feedback.
-
When used on STM32L4xx platforms (and possibly others), with flash configured for single-bank mode, the EEPROM emulation library miscalculates flash sectors which causes silent erase failures.
The stack uses the ST EEPROM emulation library for persistence on ST targets; this uses flash on the target to emulate EEPROM. When porting the stack to a new ST target, the emulated EEPROM must be given a place in the flash memory map; this is done by setting START_PAGE_ADDRESS in boards/myBoard/eeprom_emul_conf.h. In my case, I am using a 512K flash processor (STM32L471) with the flash memory configured as a single contiguous bank so I set the emulated EEPROM start page address to to 0x0806E000 (flash page 220).
This results in a subtle, silent failure. I think this is a bug in the ST EEPROM emulation library that first manifests when the emulated EEPROM is initialized (EEPROM_Emul/Core/eeprom_emul.c: EE_Init(). This calls EEPROM_Emul/Porting/STM32L4/flash_interface.c: Page_Erase() which calls GetBankNumber(). That function should consider whether flash is configured in single or dual bank mode, but simply assumes dual-bank mode resulting in the wrong sector(s) being erased.
The EEPROM emulation library: src/boards/mcu/stm32/EEPROM_Emul/Core/eeprom_emul.h defines:
#define PAGE(__ADDRESS__) (uint32_t)((((__ADDRESS__) - FLASH_BASE) % BANK_SIZE) / FLASH_PAGE_SIZE)
#define PAGE_ADDRESS(__PAGE__) (uint32_t)(FLASH_BASE + (__PAGE__) * PAGE_SIZE + ((START_PAGE_ADDRESS - FLASH_BASE) / BANK_SIZE) * BANK_SIZE)
Although that works for most cases, it doesn't fix a subtle problem when Core/eeprom_emul.c calls PageErase(page, 1U) in Porting/STM32L4/flash_interface.c and passes in the page number to erase. PageErase() uses the reversing macro to calculate the address. This gets back to the correct address, but then GetBankNumber() is called to determine which bank that address is in and determines that it is in Bank 2. The actual flash erase operation then tries to erase sector 92 in bank 2 instead of sector 220 in bank 1. This works out to a page in the second 512K of flash...which doesn't exist on this processor - at least not officially (see below) and as a result, the erase sort of "works", but not on the appropriate sector.
The real issue (at least for the EEPROM emulation library) is that BANK_SIZE (which evaluates to FLASH_BANK_SIZE defined in HAL) needs to evaluate to the size of flash when in single-bank mode and half of flash when in dual-bank mode. I think the fix is to:
#define BANK_SIZE ((FLASH->OPTR & FLASH_OPTR_DUALBANK)?FLASH_BANK_SIZE:FLASH_SIZE)
I realize this is really a bug in the ST EEPROM emulation library, but because it is included in this code base, I thought it important to report the issue here so others are aware. This may affect more dual-bank-capable ST processors than the one mentioned here.
Why the erase works (but on the wrong sector): ST has a huge number of processor variants and almost certainly doesn't produce that many different types of wafer. So the STM32L471 is likely an STM32L476 with some fuses burnt to identify it as the smaller flash variant and packaging marked accordingly. The STM32L471 parts correctly report their flash size as 512K, but seem to contain 1MB of flash: when you write data to the upper 512K, it will be there after a power cycle and hasn't overwritten anything in the lower 512K. Erasing pages in the upper 512K also seems to work and returns an OK status. However, you can't count on a free 512K...ST may later make wafers that really only have 512K flash or otherwise disable access so you have to code assuming flash matches what is reported by the FLASH_SIZE register.
Beta Was this translation helpful? Give feedback.
All reactions