Electronic – Asynchronous write to EEPROM

eepromstm32

There is Stm32l052 with built-in EEPROM (2k). 4 ADC channels are used, data is collected by the trigger every 40 microseconds. Data from the ADC is processed in the interrupt (determined by the output of values beyond the boundaries). So, using the standard Hal libraries during recording in EEPROM points are lost (3 milliseconds standard write speed in EEPROM data), even if you write one byte from the ring buffer. Is there any way to get the controller to write to the EEPROM asynchronously without blocking the ADC interrupts?

Best Answer

STM32L052 appears to have a single bank NVM controller, therefore a write access to any EEPROM address would block data reads and fetches from flash.

It would work only if you can relocate all relevant code, except initialization, but including the vector table, to RAM. It would be quite a challenge to do in 8 kbytes, but it might work. Forget about HAL, it has too much overhead and complexity.

I'd recommend doing it this way:

  • Relocate NVIC to RAM
  • ADC interrupt handler in RAM, puts data in the ring buffer, invokes PendSV (SCB->ICSR=SCB_ICSR_PENDSVSET).
  • PendSV fault handler in RAM, as long as there is data to be written, puts a single 32 bit word† in EEPROM, and waits until the write completes. Do not return while NVM is still busy.
  • ADC handler should have higher priority as PendSV.
  • The rest of the code can be left in flash as long as the delay is acceptable. Interrupt handlers in flash should have lower priorities than PendSV.

This arrangement would prevent any code in flash from running as long as an EEPROM write is in progress, but lets higher priority handlers run as long as they do not touch nonvolatile memory.

To relocate a function to RAM

With gcc, use __attribute__((section(".data"))) in the function declaration. Do it recursively to each function it calls. Use -ffreestanding to prevent gcc from generating calls to library functions unexpectedly. The .data section will be copied from flash to RAM after reset, along with initialized variables, by the startup code.

To relocate the vector table

The vector table of the STM32L052 is 192 bytes long (Reference manual 12.3 Interrupt and exception vectors). I'd just move the beginning of RAM up by 192 bytes in the linker script

RAM (xrw) : ORIGIN = 0x200000C0, LENGTH = 8000 /* 8192 - 192 */

copy the vector table there, and set the vector table pointer

memcpy((void*)0x20000000, (void*)0x08000000, 192);
SCB->VTOR = 0x20000000;

before any interrupt is enabled.


Using STM32L072 instead, it would be possible to let the program run from Bank 1, and placing EEPROM data in Bank 2, they would not interfere with each other. Of course it would still take 3 ms (or 6 ms if it's not empty) to write a 32 bit word† into EEPROM, attempting to write more data before the first write is completed would still block program execution until the first one completes. Check the Reference manual for the bank layout (3.3.1 NVM Organization)


† AFAIK EEPROM data is written in 32 bit units, writing 1 or 2 bytes at a time takes just as much time as writing a full 4-byte word.