EEPROM write sometimes takes too much time

Post here all questions related to STM32 core if you can't find a relevant section!
GonzoG
Posts: 403
Joined: Wed Jan 15, 2020 11:30 am
Answers: 27
Location: Prudnik, Poland

Re: EEPROM write sometimes takes too much time

Post by GonzoG »

mcu8484 wrote: Tue Oct 20, 2020 4:23 pm ... should really have explicit warning at the top about the risk of greatly reducing flash lifespan.
Have you read this ??
https://github.com/stm32duino/wiki/wiki ... -Emulation
Emulation is made in Flash, with all constraints related to Flash operation:

* whole sector/page erased and written for each write operation.
Can be very long depending on sector/page size
* limited Flash life cycle write operation
mcu8484
Posts: 13
Joined: Tue Oct 20, 2020 1:11 am

Re: EEPROM write sometimes takes too much time

Post by mcu8484 »

GonzoG wrote: Tue Oct 20, 2020 5:22 pm
mcu8484 wrote: Tue Oct 20, 2020 4:23 pm ... should really have explicit warning at the top about the risk of greatly reducing flash lifespan.
Have you read this ??
https://github.com/stm32duino/wiki/wiki ... -Emulation
Emulation is made in Flash, with all constraints related to Flash operation:

* whole sector/page erased and written for each write operation.
Can be very long depending on sector/page size
* limited Flash life cycle write operation
Unfortunately no. Good to have the link in this thread now but the warnings should really be in the main documentation page for the library itself.
mrburnette
Posts: 633
Joined: Thu Dec 19, 2019 1:23 am
Answers: 7

Re: EEPROM write sometimes takes too much time

Post by mrburnette »

mcu8484 wrote: Tue Oct 20, 2020 5:55 pm ...
Unfortunately no. Good to have the link in this thread now but the warnings should really be in the main documentation page for the library itself.
Well, it is a generally known fact to us old-timers from the original (Roger's STM32duo forum) as it was discussed in length. But that forum copy crashed (what could be recovered is on stm32duinoforum.com)

The problem as I see it is that Arduino.cc folks are jumping over to STM32duino to gain speed, SRAM, and extra flash; they think the STM32 uC's are fat Arduino and in the loosest of terms they are correct. But, STM32 is new cores (at least 3 commonly used ones), new rules, and new libraries ... not all 100% compatible with the Arduino 8-bit microcontrollers. You are welcome to come in and learn, but your mind needs to be open to the differences and the need to 1) perform extra experimenting and 2) extra reading and research.

I was a forum admin in the old forum and I advised new members that STM32duino was "advanced Arduino" and while the ArduinoIDE is unchanged, almost everything else was different... similar, but different.

I see you have discovered some of the differences in a painful manner: there are likely many more uncomfortable differences ahead.

Good place to start reading: viewtopic.php?f=2&t=301


Ray
GonzoG
Posts: 403
Joined: Wed Jan 15, 2020 11:30 am
Answers: 27
Location: Prudnik, Poland

Re: EEPROM write sometimes takes too much time

Post by GonzoG »

mcu8484 wrote: Tue Oct 20, 2020 5:55 pm Unfortunately no. Good to have the link in this thread now but the warnings should really be in the main documentation page for the library itself.
Well, it looks like you haven't read it carefully enough.
At the top there's a fragment that should make you think twice:
Th EEPROM library provides an easy to use interface to interact with the internal non-volatile storage found in AVR based Arduino boards. This library will work on many AVR devices like ATtiny and ATmega chips.
There's no mention of STM32.

And you have link to wiki on top of descrition:
https://github.com/stm32duino/Arduino_Core_STM32
mcu8484
Posts: 13
Joined: Tue Oct 20, 2020 1:11 am

Re: EEPROM write sometimes takes too much time

Post by mcu8484 »

mrburnette wrote: Tue Oct 20, 2020 8:17 pm
mcu8484 wrote: Tue Oct 20, 2020 5:55 pm ...
Unfortunately no. Good to have the link in this thread now but the warnings should really be in the main documentation page for the library itself.
Well, it is a generally known fact to us old-timers from the original (Roger's STM32duo forum) as it was discussed in length. But that forum copy crashed (what could be recovered is on stm32duinoforum.com)

The problem as I see it is that Arduino.cc folks are jumping over to STM32duino to gain speed, SRAM, and extra flash; they think the STM32 uC's are fat Arduino and in the loosest of terms they are correct. But, STM32 is new cores (at least 3 commonly used ones), new rules, and new libraries ... not all 100% compatible with the Arduino 8-bit microcontrollers. You are welcome to come in and learn, but your mind needs to be open to the differences and the need to 1) perform extra experimenting and 2) extra reading and research.

I was a forum admin in the old forum and I advised new members that STM32duino was "advanced Arduino" and while the ArduinoIDE is unchanged, almost everything else was different... similar, but different.

I see you have discovered some of the differences in a painful manner: there are likely many more uncomfortable differences ahead.

Good place to start reading: viewtopic.php?f=2&t=301


Ray
Thanks for the background. I certainly made the mistake of thinking stm32 as "fat Arduino" and will be much more careful going forward.
mcu8484
Posts: 13
Joined: Tue Oct 20, 2020 1:11 am

Re: EEPROM write sometimes takes too much time

Post by mcu8484 »

GonzoG wrote: Tue Oct 20, 2020 8:42 pm
mcu8484 wrote: Tue Oct 20, 2020 5:55 pm Unfortunately no. Good to have the link in this thread now but the warnings should really be in the main documentation page for the library itself.
Well, it looks like you haven't read it carefully enough.
At the top there's a fragment that should make you think twice:
Th EEPROM library provides an easy to use interface to interact with the internal non-volatile storage found in AVR based Arduino boards. This library will work on many AVR devices like ATtiny and ATmega chips.
There's no mention of STM32.

And you have link to wiki on top of descrition:
https://github.com/stm32duino/Arduino_Core_STM32
I certainly could have been more careful but the library documentation could certainly be improved to help newbies avoid nasty surprises. Even the supplemental API documentation is not totally clear in stating "whole sector/page erased and written for each write operation." which could be interpreted as calling EEPROM.put method once would result in one whole sector/page erase but based on looking at the source code this is not correct if you call it to write multi-byte data (e.g. float, struct, etc.). Ultimately this is an open source project and I am only pointing out a small improvement that could have helped me.
mrburnette
Posts: 633
Joined: Thu Dec 19, 2019 1:23 am
Answers: 7

Re: EEPROM write sometimes takes too much time

Post by mrburnette »

mcu8484 wrote: Tue Oct 20, 2020 10:37 pm ...
I certainly could have been more careful but the library documentation could certainly be improved to help newbies avoid nasty surprises. Even the supplemental API documentation is not totally clear in stating "whole sector/page erased and written for each write operation." which could be interpreted as calling EEPROM.put method once would result in one whole sector/page erase but based on looking at the source code this is not correct if you call it to write multi-byte data (e.g. float, struct, etc.). Ultimately this is an open source project and I am only pointing out a small improvement that could have helped me.
Point taken.
But consider that feedback to the author(s) is how documentation gets "purified" and old timers like myself often read documentation completely differently than a newbie (when I even read docs, which is seldom.) So, for github.com code, give the author feedback if possible.

You may also wish to consult official documentation, https://www.st.com/content/ccc/resource ... 165693.pdf
Last edited by mrburnette on Tue Oct 20, 2020 11:10 pm, edited 1 time in total.
mcu8484
Posts: 13
Joined: Tue Oct 20, 2020 1:11 am

Re: EEPROM write sometimes takes too much time

Post by mcu8484 »

After looking the EEPROM library source code and the lower level API buffered example, I decided not to make all the source code changes required to use the lower level API. Instead I decided to write a new library based on the existing EEPROM library but with option for buffered operation to avoid erase/write cycle for every byte written to flash. The new library has option to commit writes to flash after each write method call (similar to existing EEPROM library) or require explicit commit after write calls which in my case results in much faster and much less wear on flash. The auto-commit default is off on H7xx (my case) but on for other stm32 families as I am not familiar with their flash structure. I named the new library class STM32EEPROM to avoid confusion with the core EEPROM library. The only changes to my AVR source code is the include statement and an added call to EEPROM.commit() and all EEPROM related functions seems to be working well so far.


The new library source is below for anyone interested.

Code: Select all



#ifndef STM32EEPROM_h
#define STM32EEPROM_h

#include "Arduino.h"

/***
    STM32EERef class.

    This object references an EEPROM cell.
    Its purpose is to mimic a typical byte of RAM, however its storage is the EEPROM.
    This class has an overhead of two bytes, similar to storing a pointer to an EEPROM cell.
***/

struct STM32EERef {

  STM32EERef(const int index)
  : index(index) {}


  //Access/read members.
  uint8_t operator*() const
  {
    return eeprom_buffered_read_byte(/*(uint8_t*)*/ index);
  }
  operator uint8_t() const
  {
    return **this;
  }

  //Assignment/write members.
  STM32EERef &operator=(const STM32EERef &ref)
  {
    return *this = *ref;
  }
  STM32EERef &operator=(uint8_t in)
  {    
    eeprom_buffered_write_byte(/*(uint8_t*)*/ index, in);
    return *this;
  }
  STM32EERef &operator +=(uint8_t in)
  {
    return *this = **this + in;
  }
  STM32EERef &operator -=(uint8_t in)
  {
    return *this = **this - in;
  }
  STM32EERef &operator *=(uint8_t in)
  {
    return *this = **this * in;
  }
  STM32EERef &operator /=(uint8_t in)
  {
    return *this = **this / in;
  }
  STM32EERef &operator ^=(uint8_t in)
  {
    return *this = **this ^ in;
  }
  STM32EERef &operator %=(uint8_t in)
  {
    return *this = **this % in;
  }
  STM32EERef &operator &=(uint8_t in)
  {
    return *this = **this & in;
  }
  STM32EERef &operator |=(uint8_t in)
  {
    return *this = **this | in;
  }
  STM32EERef &operator <<=(uint8_t in)
  {
    return *this = **this << in;
  }
  STM32EERef &operator >>=(uint8_t in)
  {
    return *this = **this >> in;
  }

  STM32EERef &update(uint8_t in)
  {
    return  in != *this ? *this = in : *this;
  }

  /** Prefix increment/decrement **/
  STM32EERef &operator++()
  {
    return *this += 1;
  }
  STM32EERef &operator--()
  {
    return *this -= 1;
  }

  /** Postfix increment/decrement **/
  uint8_t operator++ (int)
  {
    uint8_t ret = **this;
    return ++(*this), ret;
  }

  uint8_t operator-- (int)
  {
    uint8_t ret = **this;
    return --(*this), ret;
  }

  int index; //Index of current EEPROM cell.
};

/***
    STM32EEPtr class.

    This object is a bidirectional pointer to EEPROM cells represented by STM32EERef objects.
    Just like a normal pointer type, this can be dereferenced and repositioned using
    increment/decrement operators.
***/

struct STM32EEPtr {

  STM32EEPtr(const int index)
    : index(index)                {}

  operator int() const
  {
    return index;
  }
  STM32EEPtr &operator=(int in)
  {
    return index = in, *this;
  }

  //Iterator functionality.
  bool operator!=(const STM32EEPtr &ptr)
  {
    return index != ptr.index;
  }
  STM32EERef operator*()
  {
    return index;
  }

  /** Prefix & Postfix increment/decrement **/
  STM32EEPtr &operator++()
  {
    return ++index, *this;
  }
  STM32EEPtr &operator--()
  {
    return --index, *this;
  }
  STM32EEPtr operator++ (int)
  {
    return index++;
  }
  STM32EEPtr operator-- (int)
  {
    return index--;
  }

  int index; //Index of current EEPROM cell.
};

/***
    EEPROMClass class.

    This object represents the entire EEPROM space.
    It wraps the functionality of STM32EEPtr and STM32EERef into a basic interface.
    This class is also 100% backwards compatible with earlier Arduino core releases.
***/

#if defined(STM32H7xx)
#define STM32EEPROM_AUTOCOMMIT_DEFAULT      false
#else
#define STM32EEPROM_AUTOCOMMIT_DEFAULT      true
#endif


struct STM32EEPROMClass {

  STM32EEPROMClass(): autoCommit(STM32EEPROM_AUTOCOMMIT_DEFAULT), bufDirty(false), bufEmpty(true) {}

  void enableAutoCommit() {
    if(autoCommit!=true) {
      commit();
      autoCommit=true;
    }

  }
  void disableAutoCommit() {
    if(autoCommit==true) {
      autoCommit=false;
      bufDirty=false;
    }
  }

  bool isAutoCommitOn() {
    return autoCommit;
  }

  void commit() {
    if(bufDirty==true) {
      eeprom_buffer_flush();
      bufDirty=false;
    }
  }

  void load() {
    if(bufEmpty==true) {
      eeprom_buffer_fill();
      bufEmpty=false;
    }
  }

  //Basic user access methods.
  STM32EERef operator[](const int idx)
  {
    load();
    return idx;
  }
  uint8_t read(int idx)
  {
    load();
    return STM32EERef(idx);
  }
  void write(int idx, uint8_t val)
  {
    load();
    if(bufDirty!=true) {
      bufDirty= (eeprom_buffered_read_byte(idx) != val);
    }

    (STM32EERef(idx)) = val;
    if(autoCommit==true) {
      commit();
    }
  }
  void update(int idx, uint8_t val)
  {
    load();
    if(bufDirty!=true) {
      bufDirty= (eeprom_buffered_read_byte(idx) != val);
    }

    STM32EERef(idx).update(val);
    if(autoCommit==true) {
      commit();
    }
  }

  //STL and C++11 iteration capability.
  STM32EEPtr begin()
  {
    return 0x00;
  }
  STM32EEPtr end()
  {
    return length();  //Standards requires this to be the item after the last valid entry. The returned pointer is invalid.
  }
  uint16_t length()
  {
    return E2END + 1;
  }

  //Functionality to 'get' and 'put' objects to and from EEPROM.
  template< typename T > T &get(int idx, T &t)
  {
    load();
    STM32EEPtr e = idx;
    uint8_t *ptr = (uint8_t *) &t;
    for (int count = sizeof(T) ; count ; --count, ++e) {
      *ptr++ = *e;
    }
    return t;
  }

  template< typename T > const T &put(int idx, const T &t)
  {
    load();
    STM32EEPtr e = idx;
    const uint8_t *ptr = (const uint8_t *) &t;
    for (int count = sizeof(T) ; count ; --count, ++e) {
       if(bufDirty!=true) {
	bufDirty= (*e != *ptr);
      }
      (*e).update(*ptr++);
    }
    return t;
  }


  bool autoCommit;
  bool bufDirty;
  bool bufEmpty;
};

static STM32EEPROMClass EEPROM;
#endif


Post Reply

Return to “General discussion”