Teensy 4.0 EEPROM data overwritten after power off/on VIN pin

cyboff

Member
Hello, when I try to migrate a project from Teensy 3.2 to Teensy 4.0, the EEPROM is somehow not keeping correctly the stored values.

I use the simple functions EEPROM.update() and EEPROM.read() to store 20 uint16_t values of configuration that can be changed via Modbus ...

On Teensy 3.2 the code worked without any problems. But on Teensy 4.0 everything works properly only until I turn the power off and on again . Teensy is powered externally via 5VDC on the VIN pin... I double check the stored values by printing the written values, then printing the values directly read from EEPROM and all values are correct as long as Teensy is running without power interruption.
When the Teensy 4.0 is powered on, some values in the EEPROM are overwritten, but most remain correct...
I also tried to software reset the Teensy via writing to SCB_AIRCR = 0x05FA0004; and the EEPROM then holds all values correctly ... But only until I turn power off.
I also tried to change the EEPROM address from 0 - 40 to 100-140 , to check if there's any problem with the flash region, but it acts the same...
However, if I do not write anything to the EEPROM, the values in the EEPROM will not change even after the power is turned off.


Is there something I forgot to do before or after writing to EEPROM to make sure the values are stored correctly in Teensy 4.0? Or is it better to use EEPROM.put() and EEPROM.get() ?

Here is an example part of the code with functions I'm calling from loop() to store the uint16_t variables I'm getting from Modbus, but code have some interrupt routines too...

Code:
// EEPROM Addresses for signature code and version of firmware
#define EE_ADDR_OFFSET 100                           // EEPROM address offset for debug

#define EE_ADDR_MODEL_TYPE EE_ADDR_OFFSET+0          // WORD 
#define EE_ADDR_MODEL_SERIAL_NUMBER EE_ADDR_OFFSET+2 // WORD
#define EE_ADDR_FW_VERSION EE_ADDR_OFFSET+4          // WORD

// EEPROM Addresses for config
#define EE_ADDR_modbus_ID EE_ADDR_OFFSET+6     // WORD
#define EE_ADDR_modbus_Speed EE_ADDR_OFFSET+8  // WORD  
#define EE_ADDR_modbus_Format EE_ADDR_OFFSET+10 // WORD
 
// etc... 
volatile uint16_t modbusID = 0;



// EEPROM
// read a unsigned int (two bytes) value from eeprom
uint16_t eeprom_readInt(uint16_t address)
{
  return EEPROM.read(address) | (EEPROM.read(address + 1) << 8);

#if defined(__IMXRT1062__) // Teensy 4.0
  asm("DSB");
#endif
}

// Write a unsigned int (two bytes) value to eeprom
void eeprom_writeInt(uint16_t address, uint16_t value)
{
  __disable_irq();

  EEPROM.write(address, value & 0xFF);   // LSB
  EEPROM.write(address + 1, value >> 8); // MSB
#if defined(SERIAL_DEBUG)
  Serial.printf("EEwr a: %u w: %u r: %u\n", address, value, eeprom_readInt(address));

  // print all used EEPROM words

  for (int p=EE_ADDR_OFFSET+0; p <EE_ADDR_OFFSET+42; p=p+2) 
  {
    Serial.printf("%2u:%5u|", p, EEPROM.read(p) | EEPROM.read(p + 1) << 8);
  }
  Serial.println();
#endif

  __enable_irq();

#if defined(__IMXRT1062__) // Teensy 4.0
  asm("DSB");
#endif
}

void eeprom_updateInt(uint16_t address, uint16_t value)
{
  __disable_irq();

  EEPROM.update(address, value & 0xFF); // LSB
  EEPROM.update(address + 1, value >> 8);
#if defined(SERIAL_DEBUG)
  Serial.printf("EEupd a: %u w: %u r: %u\n", address, value, eeprom_readInt(address));

  // print all used EEPROM words

  for (int p=EE_ADDR_OFFSET+0; p <EE_ADDR_OFFSET+42; p=p+2) 
  {
    Serial.printf("%2u:%5u|", p, EEPROM.read(p) | EEPROM.read(p + 1) << 8);
  }
  Serial.println();
#endif

  __enable_irq();

#if defined(__IMXRT1062__) // Teensy 4.0
  asm("DSB");
#endif
}


void loop()
{

// check changes made via ModBus - if values are valid, save them in EEPROM

    if ((holdingRegs[MODBUS_ID] != modbusID) && (holdingRegs[MODBUS_ID] > 0) && (holdingRegs[MODBUS_ID] < 248))
    {
      modbusID = holdingRegs[MODBUS_ID];
      eeprom_updateInt(EE_ADDR_modbus_ID, modbusID);
    }
}
 
Starting from your code, I made a short working program that reads your 20 x 2-byte locations, increments and writes them back. This test works for me, with the data shown below. Note that it also works fine if I comment out all of the disable/enable interrupts and asm("DSB") statements. Can you try this program and show the output if it doesn't work as expected?

Code:
READ:     5   5   5   5   5   5   5   5   5   5   5   5   5   5   5   5   5   5   5   5 
WRITE:   6   6   6   6   6   6   6   6   6   6   6   6   6   6   6   6   6   6   6   6

Code:
#include <EEPROM.h>

// EEPROM Addresses for signature code and version of firmware
#define EE_ADDR_OFFSET 100   // EEPROM address
volatile uint16_t data[20];  // EEPROM data

// read a unsigned int (two bytes) value from eeprom
uint16_t eeprom_readInt(uint16_t address)
{
  return EEPROM.read(address) | (EEPROM.read(address + 1) << 8);
  asm("DSB");
}

// Write a unsigned int (two bytes) value to eeprom
void eeprom_writeInt(uint16_t address, uint16_t value)
{
  __disable_irq();
  EEPROM.write(address, value & 0xFF);   // LSB
  EEPROM.write(address + 1, value >> 8); // MSB
  __enable_irq();
  asm("DSB");
}

void eeprom_updateInt(uint16_t address, uint16_t value)
{
  __disable_irq();
  EEPROM.update(address, value & 0xFF); // LSB
  EEPROM.update(address + 1, value >> 8);
  __enable_irq();
  asm("DSB");
}

void setup() {
  Serial.begin( 9600 );
  while (!Serial) {}
  // read data[]
  Serial.print( "READ:  " );
  for (int i=0; i<20; i++) {
    data[i] = eeprom_readInt( EE_ADDR_OFFSET+i*2 );
    Serial.printf( "%3hu ", data[i] );
  }
  Serial.println();
  // increment and write data[]
  Serial.print( "WRITE: " );
  for (int i=0; i<20; i++) {
    eeprom_updateInt( EE_ADDR_OFFSET+i*2, ++data[i] );
    Serial.printf( "%3hu ", data[i] );
  }
  Serial.println();
}

void loop() {
}
 
Hi Joe, thanks for your time, your code is working as it should, of course... Not sure what is happening in my case...

Just to test the issue I'm trying to read EEPROM at the beginnig of the setup(), and then periodicaly in the loop(), when writing something to EEPROM I print it...

Code:
// read a unsigned int (two bytes) value from eeprom
uint16_t eeprom_readInt(uint16_t address)
{
  return EEPROM.read(address) | (EEPROM.read(address + 1) << 8);
  asm("DSB");
}

// Write a unsigned int (two bytes) value to eeprom
void eeprom_writeInt(uint16_t address, uint16_t value)
{
  __disable_irq();
  EEPROM.write(address, value & 0xFF);   // LSB
  EEPROM.write(address + 1, value >> 8); // MSB

  Serial.printf("EEwr a: %u w: %u r: %u\n", address, value, eeprom_readInt(address));

  __enable_irq();
  asm("DSB");
}


void setup()
{
#if defined(SERIAL_DEBUG)
  Serial.begin(9600);
  while (!Serial && millis() < 5000)
    ;
  Serial.println("Starting");

  // print all used EEPROM words
  Serial.print("EEread: ");
  for (int i=0; i<21; i++) 
  {
    Serial.printf("%2u:%5hu|",i*2, EEPROM.read(i*2) | EEPROM.read(i*2 + 1) << 8); 
  }
  Serial.println();
#endif

  //  continuing initialize I/O etc... 

}

void loop()
{

#if defined(SERIAL_DEBUG)
  // print all used EEPROM words
  Serial.print("EEread: ");
  for (int i=0; i<21; i++) 
  {
    Serial.printf("%2u:%5hu|",i*2, EEPROM.read(i*2) | EEPROM.read(i*2 + 1) << 8);
  }
  Serial.println();
#endif

  // continue doing stuff and checking data to write to EEPROM e.g.:

if ((holdingRegs[POSITION_MODE] != positionMode) && (holdingRegs[POSITION_MODE] < 5))
  {
    positionMode = holdingRegs[POSITION_MODE];
    eeprom_writeInt(EE_ADDR_position_mode, holdingRegs[POSITION_MODE]);
  }

// continuing...
}


but output looks like this:

Code:
Starting

EEread:  0:   50| 2:23001| 4:  234| 6:    1| 8:  192|10:    0|12:    2|14:   16|16:   50|18:   32|20:   50|22:   20|24:   80|26:    1|28: 1281|30:  250|32:    6|34:    0|36:    0|38:   60|40:   13|
EEread:  0:   50| 2:23001| 4:  234| 6:    1| 8:  192|10:    0|12:    2|14:   16|16:   50|18:   32|20:   50|22:   20|24:   80|26:    1|28: 1281|30:  250|32:    6|34:    0|36:    0|38:   60|40:   13|
EEwr a: 12 w: 3 r: 3
EEread:  0:   50| 2:23001| 4:  234| 6:    1| 8:  192|10:    0|12:    3|14:   16|16:   50|18:   32|20:   50|22:   20|24:   80|26:    1|28: 1281|30:  250|32:    6|34:    0|36:    0|38:   60|40:   13|
EEread:  0:   50| 2:23001| 4:  234| 6:    1| 8:  192|10:    0|12:    3|14:   16|16:   50|18:   32|20:   50|22:   20|24:   80|26:    1|28: 1281|30:  250|32:    6|34:    0|36:    0|38:   60|40:   13|
EEread:  0:   50| 2:23001| 4:  234| 6:    1| 8:  192|10:    0|12:    3|14:   16|16:   50|18:   32|20:   50|22:   20|24:   80|26:    1|28: 1281|30:  250|32:    6|34:    0|36:    0|38:   60|40:   13|
EEread:  0:   50| 2:23001| 4:  234| 6:    1| 8:  192|10:    0|12:    3|14:   16|16:   50|18:   32|20:   50|22:   20|24:   80|26:    1|28: 1281|30:  250|32:    6|34:    0|36:    0|38:   60|40:   13|

  // SWITCHED POWER OFF
Reconnecting to COM9     Connected!
Starting
EEread:  0:   50| 2:23001| 4:  234| 6:    1| 8:  192|10:    0|12:    0|14:   16|16:   50|18:   32|20:   50|22:   20|24:   80|26:    1|28: 1281|30:  250|32:    6|34:    0|36:    0|38:   60|40:   13|
EEread:  0:   50| 2:23001| 4:  234| 6:    1| 8:  192|10:    0|12:    0|14:   16|16:   50|18:   32|20:   50|22:   20|24:   80|26:    1|28: 1281|30:  250|32:    6|34:    0|36:    0|38:   60|40:   13|
EEread:  0:   50| 2:23001| 4:  234| 6:    1| 8:  192|10:    0|12:    0|14:   16|16:   50|18:   32|20:   50|22:   20|24:   80|26:    1|28: 1281|30:  250|32:    6|34:    0|36:    0|38:   60|40:   13|

As you can see, I wrote a value of 3 to address 12 , which was periodically read correctly in loop() ..... But after turning Teensy off and on again, I got a value of 0 at address 12 ...
 
Here is another example - I wrote 4 at address 26, but after turning Teensy off and on, I got a value of 0 at address 12 ... Then I just turned Teensy off and on again without any write and I got a random value of 6577 at address 36 ...

Code:
EEread:  0:   50| 2:23001| 4:  234| 6:    1| 8:  192|10:    0|12:    3|14:   16|16:   50|18:   32|20:   50|22:   20|24:   80|26:    0|28: 1281|30:  250|32:    6|34:    0|36:    0|38:   60|40:   13|
EEread:  0:   50| 2:23001| 4:  234| 6:    1| 8:  192|10:    0|12:    3|14:   16|16:   50|18:   32|20:   50|22:   20|24:   80|26:    0|28: 1281|30:  250|32:    6|34:    0|36:    0|38:   60|40:   13|
EEwr a: 26 w: 4 r: 4
EEread:  0:   50| 2:23001| 4:  234| 6:    1| 8:  192|10:    0|12:    3|14:   16|16:   50|18:   32|20:   50|22:   20|24:   80|26:    4|28: 1281|30:  250|32:    6|34:    0|36:    0|38:   60|40:   13|
EEread:  0:   50| 2:23001| 4:  234| 6:    1| 8:  192|10:    0|12:    3|14:   16|16:   50|18:   32|20:   50|22:   20|24:   80|26:    4|28: 1281|30:  250|32:    6|34:    0|36:    0|38:   60|40:   13|
EEread:  0:   50| 2:23001| 4:  234| 6:    1| 8:  192|10:    0|12:    3|14:   16|16:   50|18:   32|20:   50|22:   20|24:   80|26:    4|28: 1281|30:  250|32:    6|34:    0|36:    0|38:   60|40:   13|
EEread:  0:   50| 2:23001| 4:  234| 6:    1| 8:  192|10:    0|12:    3|14:   16|16:   50|18:   32|20:   50|22:   20|24:   80|26:    4|28: 1281|30:  250|32:    6|34:    0|36:    0|38:   60|40:   13|

// SWITCHED POWER OFF
Reconnecting to COM9     Connected!
Starting
EEread:  0:   50| 2:23001| 4:  234| 6:    1| 8:  192|10:    0|12:    0|14:   16|16:   50|18:   32|20:   50|22:   20|24:   80|26:    4|28: 1281|30:  250|32:    6|34:    0|36:    0|38:   60|40:   13|
EEread:  0:   50| 2:23001| 4:  234| 6:    1| 8:  192|10:    0|12:    0|14:   16|16:   50|18:   32|20:   50|22:   20|24:   80|26:    4|28: 1281|30:  250|32:    6|34:    0|36:    0|38:   60|40:   13|
EEread:  0:   50| 2:23001| 4:  234| 6:    1| 8:  192|10:    0|12:    0|14:   16|16:   50|18:   32|20:   50|22:   20|24:   80|26:    4|28: 1281|30:  250|32:    6|34:    0|36:    0|38:   60|40:   13|
EEread:  0:   50| 2:23001| 4:  234| 6:    1| 8:  192|10:    0|12:    0|14:   16|16:   50|18:   32|20:   50|22:   20|24:   80|26:    4|28: 1281|30:  250|32:    6|34:    0|36:    0|38:   60|40:   13|
// SWITCHED POWER OFF
Reconnecting to COM9 ...         Connected!
Starting
EEread:  0:   50| 2:23001| 4:  234| 6:    1| 8:  192|10:    0|12:    0|14:   16|16:   50|18:   32|20:   50|22:   20|24:   80|26:    4|28: 1281|30:  250|32:    6|34:    0|36: 6577|38:   60|40:   13|
EEread:  0:   50| 2:23001| 4:  234| 6:    1| 8:  192|10:    0|12:    0|14:   16|16:   50|18:   32|20:   50|22:   20|24:   80|26:    4|28: 1281|30:  250|32:    6|34:    0|36: 6577|38:   60|40:   13|
EEread:  0:   50| 2:23001| 4:  234| 6:    1| 8:  192|10:    0|12:    0|14:   16|16:   50|18:   32|20:   50|22:   20|24:   80|26:    4|28: 1281|30:  250|32:    6|34:    0|36: 6577|38:   60|40:   13|
EEread:  0:   50| 2:23001| 4:  234| 6:    1| 8:  192|10:    0|12:    0|14:   16|16:   50|18:   32|20:   50|22:   20|24:   80|26:    4|28: 1281|30:  250|32:    6|34:    0|36: 6577|38:   60|40:   13|
 
So actually I don't need to write to EEPROM at all, but EEPROM changes randomly on every restart when my code is running... Here, first at address 30 the value 250 is zeroed after a reboot, then at address 32 value 6 is zeroed, then at address 36 the value 6577 is zeroed ...

Code:
EEread:  0:   50| 2:23001| 4:  234| 6:    1| 8:  192|10:    0|12:    0|14:   16|16:   50|18:   32|20:   50|22:   20|24:   80|26:    4|28: 1281|30:  250|32:    6|34:    0|36: 6577|38:   60|40:   13|
EEread:  0:   50| 2:23001| 4:  234| 6:    1| 8:  192|10:    0|12:    0|14:   16|16:   50|18:   32|20:   50|22:   20|24:   80|26:    4|28: 1281|30:  250|32:    6|34:    0|36: 6577|38:   60|40:   13|
 
Starting
EEread:  0:   50| 2:23001| 4:  234| 6:    1| 8:  192|10:    0|12:    0|14:   16|16:   50|18:   32|20:   50|22:   20|24:   80|26:    0|28: 1281|30:    0|32:    6|34:    0|36: 6577|38:   60|40:   13|
EEread:  0:   50| 2:23001| 4:  234| 6:    1| 8:  192|10:    0|12:    0|14:   16|16:   50|18:   32|20:   50|22:   20|24:   80|26:    0|28: 1281|30:    0|32:    6|34:    0|36: 6577|38:   60|40:   13|
EEread:  0:   50| 2:23001| 4:  234| 6:    1| 8:  192|10:    0|12:    0|14:   16|16:   50|18:   32|20:   50|22:   20|24:   80|26:    0|28: 1281|30:    0|32:    6|34:    0|36: 6577|38:   60|40:   13|
EEread:  0:   50| 2:23001| 4:  234| 6:    1| 8:  192|10:    0|12:    0|14:   16|16:   50|18:   32|20:   50|22:   20|24:   80|26:    0|28: 1281|30:    0|32:    6|34:    0|36: 6577|38:   60|40:   13|
EEread:  0:   50| 2:23001| 4:  234| 6:    1| 8:  192|10:    0|12:    0|14:   16|16:   50|18:   32|20:   50|22:   20|24:   80|26:    0|28: 1281|30:    0|32:    6|34:    0|36: 6577|38:   60|40:   13|
EEread:  0:   50| 2:23001| 4:  234| 6:    1| 8:  192|10:    0|12:    0|14:   16|16:   50|18:   32|20:   50|22:   20|24:   80|26:    0|28: 1281|30:    0|32:    6|34:    0|36: 6577|38:   60|40:   13|
EEread:  0:   50| 2:23001| 4:  234| 6:    1| 8:  192|10:    0|12:    0|14:   16|16:   50|18:   32|20:   50|22:   20|24:   80|26:    0|28: 1281|30:    0|32:    6|34:    0|36: 6577|38:   60|40:   13|
EEread:  0:   50| 2:23001| 4:  234| 6:    1| 8:  192|10:    0|12:    0|14:   16|16:   50|18:   32|20:   50|22:   20|24:   80|26:    0|28: 1281|30:    0|32:    6|34:    0|36: 6577|38:   60|40:   13|
EEread:  0:   50| 2:23001| 4:  234| 6:    1| 8:  192|10:    0|12:    0|14:   16|16:   50|18:   32|20:   50|22:   20|24:   80|26:    0|28: 1281|30:    0|32:    6|34:    0|36: 6577|38:   60|40:   13|

Starting
EEread:  0:   50| 2:23001| 4:  234| 6:    1| 8:  192|10:    0|12:    0|14:   16|16:   50|18:   32|20:   50|22:   20|24:   80|26:    0|28: 1281|30:    0|32:    0|34:    0|36: 6577|38:   60|40:   13|
EEread:  0:   50| 2:23001| 4:  234| 6:    1| 8:  192|10:    0|12:    0|14:   16|16:   50|18:   32|20:   50|22:   20|24:   80|26:    0|28: 1281|30:    0|32:    0|34:    0|36: 6577|38:   60|40:   13|
EEread:  0:   50| 2:23001| 4:  234| 6:    1| 8:  192|10:    0|12:    0|14:   16|16:   50|18:   32|20:   50|22:   20|24:   80|26:    0|28: 1281|30:    0|32:    0|34:    0|36: 6577|38:   60|40:   13|
EEread:  0:   50| 2:23001| 4:  234| 6:    1| 8:  192|10:    0|12:    0|14:   16|16:   50|18:   32|20:   50|22:   20|24:   80|26:    0|28: 1281|30:    0|32:    0|34:    0|36: 6577|38:   60|40:   13|
EEread:  0:   50| 2:23001| 4:  234| 6:    1| 8:  192|10:    0|12:    0|14:   16|16:   50|18:   32|20:   50|22:   20|24:   80|26:    0|28: 1281|30:    0|32:    0|34:    0|36: 6577|38:   60|40:   13|
EEread:  0:   50| 2:23001| 4:  234| 6:    1| 8:  192|10:    0|12:    0|14:   16|16:   50|18:   32|20:   50|22:   20|24:   80|26:    0|28: 1281|30:    0|32:    0|34:    0|36: 6577|38:   60|40:   13|
EEread:  0:   50| 2:23001| 4:  234| 6:    1| 8:  192|10:    0|12:    0|14:   16|16:   50|18:   32|20:   50|22:   20|24:   80|26:    0|28: 1281|30:    0|32:    0|34:    0|36: 6577|38:   60|40:   13|
EEread:  0:   50| 2:23001| 4:  234| 6:    1| 8:  192|10:    0|12:    0|14:   16|16:   50|18:   32|20:   50|22:   20|24:   80|26:    0|28: 1281|30:    0|32:    0|34:    0|36: 6577|38:   60|40:   13|
EEread:  0:   50| 2:23001| 4:  234| 6:    1| 8:  192|10:    0|12:    0|14:   16|16:   50|18:   32|20:   50|22:   20|24:   80|26:    0|28: 1281|30:    0|32:    0|34:    0|36: 6577|38:   60|40:   13|
EEread:  0:   50| 2:23001| 4:  234| 6:    1| 8:  192|10:    0|12:    0|14:   16|16:   50|18:   32|20:   50|22:   20|24:   80|26:    0|28: 1281|30:    0|32:    0|34:    0|36: 6577|38:   60|40:   13|
EEread:  0:   50| 2:23001| 4:  234| 6:    1| 8:  192|10:    0|12:    0|14:   16|16:   50|18:   32|20:   50|22:   20|24:   80|26:    0|28: 1281|30:    0|32:    0|34:    0|36: 6577|38:   60|40:   13|
EEread:  0:   50| 2:23001| 4:  234| 6:    1| 8:  192|10:    0|12:    0|14:   16|16:   50|18:   32|20:   50|22:   20|24:   80|26:    0|28: 1281|30:    0|32:    0|34:    0|36: 6577|38:   60|40:   13|
EEread:  0:   50| 2:23001| 4:  234| 6:    1| 8:  192|10:    0|12:    0|14:   16|16:   50|18:   32|20:   50|22:   20|24:   80|26:    0|28: 1281|30:    0|32:    0|34:    0|36: 6577|38:   60|40:   13|
EEread:  0:   50| 2:23001| 4:  234| 6:    1| 8:  192|10:    0|12:    0|14:   16|16:   50|18:   32|20:   50|22:   20|24:   80|26:    0|28: 1281|30:    0|32:    0|34:    0|36: 6577|38:   60|40:   13|
EEread:  0:   50| 2:23001| 4:  234| 6:    1| 8:  192|10:    0|12:    0|14:   16|16:   50|18:   32|20:   50|22:   20|24:   80|26:    0|28: 1281|30:    0|32:    0|34:    0|36: 6577|38:   60|40:   13|
EEread:  0:   50| 2:23001| 4:  234| 6:    1| 8:  192|10:    0|12:    0|14:   16|16:   50|18:   32|20:   50|22:   20|24:   80|26:    0|28: 1281|30:    0|32:    0|34:    0|36: 6577|38:   60|40:   13|
EEread:  0:   50| 2:23001| 4:  234| 6:    1| 8:  192|10:    0|12:    0|14:   16|16:   50|18:   32|20:   50|22:   20|24:   80|26:    0|28: 1281|30:    0|32:    0|34:    0|36: 6577|38:   60|40:   13|

Starting
EEread:  0:   50| 2:23001| 4:  234| 6:    1| 8:  192|10:    0|12:    0|14:   16|16:   50|18:   32|20:   50|22:   20|24:   80|26:    0|28: 1281|30:    0|32:    0|34:    0|36:    0|38:   60|40:   13|
EEread:  0:   50| 2:23001| 4:  234| 6:    1| 8:  192|10:    0|12:    0|14:   16|16:   50|18:   32|20:   50|22:   20|24:   80|26:    0|28: 1281|30:    0|32:    0|34:    0|36:    0|38:   60|40:   13|
EEread:  0:   50| 2:23001| 4:  234| 6:    1| 8:  192|10:    0|12:    0|14:   16|16:   50|18:   32|20:   50|22:   20|24:   80|26:    0|28: 1281|30:    0|32:    0|34:    0|36:    0|38:   60|40:   13|
EEread:  0:   50| 2:23001| 4:  234| 6:    1| 8:  192|10:    0|12:    0|14:   16|16:   50|18:   32|20:   50|22:   20|24:   80|26:    0|28: 1281|30:    0|32:    0|34:    0|36:    0|38:   60|40:   13|
EEread:  0:   50| 2:23001| 4:  234| 6:    1| 8:  192|10:    0|12:    0|14:   16|16:   50|18:   32|20:   50|22:   20|24:   80|26:    0|28: 1281|30:    0|32:    0|34:    0|36:    0|38:   60|40:   13|
 
Last edited:
It's really not possible to help without seeing a complete program, so please try to reduce what you're doing to a small, working program that shows the issue. With that said, does "Int" stand for interrupt in these function names, and does that mean you are calling these functions from ISR's? Are you printing to Serial from an ISR?
 
Thanks for trying to help me, Joe... That Int in the name was actually meant as eeprom_readInteger(), eeprom_writeInteger()... But I have a few ISR in the code, that's why I'm disabling and re-enabling interrups, when writing to EEPROM..
I will first try to find the problem by commenting my rather huge and ugly code ...
 
But I have a few ISR in the code, that's why I'm disabling and re-enabling interrups, when writing to EEPROM.

It feels like something related to what you're doing in your ISRs, but that's just a guess. You don't need to disable interrupts when reading/writing EEPROM, so as a quick test, you could try commenting out those lines and also the "DSB" statements, which is something you might need in a very short ISR, based on what I've read on this forum.
 
I actually added those lines because it wasn't working properly, just in case... I let Teensy run over the weekend and there was no change in EEPROM values (nothing was written), so I assume there is no problem in the ISR... Looking at the Teensy 4.0 memory map image, I rather suspect that I have too many variables that may somehow leak into the EEPROM area during initialization after power up ... but I have no idea how to verify this...
 
I actually added those lines because it wasn't working properly, just in case... I let Teensy run over the weekend and there was no change in EEPROM values (nothing was written), so I assume there is no problem in the ISR... Looking at the Teensy 4.0 memory map image, I rather suspect that I have too many variables that may somehow leak into the EEPROM area during initialization after power up ... but I have no idea how to verify this...

After the Arduino build completes, the amount of RAM and FLASH used are displayed. You might have to turn on verbose output.
 
Hard to really know what is going on. As we may not know the whole setup including the setup code, what else is connected...

But code too large: you would normally think that would behave the same for reboot versus power up runs.
I know not necessarily, but... For example is all of the memory fully cleared when you reboot or do some of the un-itialized variables now have values.

Or maybe when you reboot you already have a Serial monitor open and when you do a power up you don't so maybe it waits longer for the monitor?
And maybe hardware is powering up and, that does something different.

It is unlikely that your code would overwrite the actual eeprom area. Which on T4 starts at: 0x601F0000, you can easily read from that area, but writing to that area requires calls to things like: eepromemu_flash_write, which has to do lots of stuff, like use the FLEXSPI subsystem to do the actual write. Each write, the address is split into a sector number and a logic offset number. And it appends on a new index/value pair into that sector. If that sector fills, it then takes the sector and compresses out all of the old values from it and then has to do an erase of the sector and then a write. So again unlikely that part was corrupted.

During T4 beta testing had sketch that would print out all of the logical eeprom locations, plus dump the different sectors showing which value should win. Have not run it in awhile. But included it here in case you would like to see what is stored in your eeprom area.

However there are a couple of other static variables within eeprom.c
Code:
static uint8_t initialized=0;
static uint16_t sector_index[FLASH_SECTORS];
That could potentially be overwritten.

Again I know I am just throwing darts at the problem
 

Attachments

  • t4_eeprom_test.ino
    3.9 KB · Views: 16
Thank you all for the help, I added a few conditions to make sure that I don't overflow the uint8_t value in the EEPROM.write() function (which is a bit weird for me), but it seems to have helped a lot... I need to test it longer, but so far it works...

It's still interesting that the code always worked correctly for long periods of time, e.g. overnight, but the EEPROM values were only overwritten when I switched Teensy off... Although I thought that the voltage from the external power supply might be dropping slowly due to the capacitors, so maybe some values still just get written to the EEPROM incorrectly...
Is there any way to verify that Teensy is about to shutdown? So that I can block the writing to the EEPROM in time?

Code:
void eeprom_write(uint16_t address, uint16_t value)
{
  __disable_irq();
  EEPROM.write(address, value & 0xFF);   // LSB
  EEPROM.write(address + 1, (value >> 8) & 0xFF); // MSB
  __enable_irq();
}

// example from the code
#define EE_ADDR_max_temperature  
uint16_t temperature = 0, max_temperature = 0;

temperature = (uint16_t)tempmonGetTemp();

if (temperature > max_temperature)
  {
    max_temperature = temperature & 0xFFFF;
    eeprom_write(EE_ADDR_max_temperature, max_temperature);
  }
 
Just thought I'd chime in here, because I have the same issue as cyboff on T4.0. I will do a few more tests before sending you simplified code. Basically, I write to address 1010 in EEPROM and read it back , and it is correct. Then I power cycle the Teensy, and immediately read that location, and it has changed.
Cyboff did you ever fix this issue?
 
Just thought I'd chime in here, because I have the same issue as cyboff on T4.0. I will do a few more tests before sending you simplified code. Basically, I write to address 1010 in EEPROM and read it back , and it is correct. Then I power cycle the Teensy, and immediately read that location, and it has changed.
Cyboff did you ever fix this issue?

Do you get similar (mis)behavior if you run the EEPROM example sketches (e.g. eeprom_put & eeprom_get) ??

Mark J Culross
KD5RXT
 
Do you get similar (mis)behavior if you run the EEPROM example sketches (e.g. eeprom_put & eeprom_get) ??

Mark J Culross
KD5RXT


Mark, I was able to get it to work by using lower memory locations, namely at 450 bytes onwards, I write 32 bytes. That works. Before I had it starting at 1010 bytes, on the basis that that is below the limit of 1080 bytes for the EEPROM shown in the Help Docs. Can we read/write to all EEPROM up to location 1079? Or is it 511 only? The example sort of sounds like we can only access to 512.
Thanks for any info...
 
Cyboff did you ever fix this issue?
Not, yet, I thought that by writing only uint8_t values I had solved it, but after longer testing the errors appeared again... I still haven't figured out what's going on... I think I'd rather use the external I2C EEPROM 24LC256... I don't like the other limitations, like I can't read the program and I have to wait until the EEPROM is written...
 
Last edited:
Mark, I was able to get it to work by using lower memory locations, namely at 450 bytes onwards, I write 32 bytes. That works. Before I had it starting at 1010 bytes, on the basis that that is below the limit of 1080 bytes for the EEPROM shown in the Help Docs. Can we read/write to all EEPROM up to location 1079? Or is it 511 only? The example sort of sounds like we can only access to 512.
Thanks for any info...

I don't see anywhere in any of the EEPROM examples that indicate a limit of 512 (did you actually run any of the T4.0 EEPROM examples in the Arduino IDE ?? What example are you referring to ??).

Although I haven't used right up to the very last EEPROM location in any of my projects, I've certainly used the EEPROM in the T4.x to store groups of configuration settings well past location 511 in some of my Teensy projects. In my original TeensyMIDIPolySynth project (using the T4.0 + hardware pots & LEDs for all of the controls), I stored 16 configurations of 55 bytes each, for a total of 880 bytes stored in EEPROM. Currently, in the latest version of my TeensyMIDIPolySynth project (using the T4.1 + 7" RA8875 800x480 TFT touchscreen, with on-screen visual sliders for all of the controls), I am storing 16 different configurations of 232 bytes each (plus one byte for a global setting), for a total of 3713 bytes stored in EEPROM.

By calling the "EEPROM.length()" function, you can determine the exact usable length of the EEPROM in any of the Teensy processors (and probably any of the Arduinos in general as well).

If you encountered an error when using 1010 as your starting location, you may have had some kind of coding mistake (it would be much easier to provide you meaningful help with this if you post your code so that others can try to reproduce the problem that you are seeing . . . see the Forum Rule: at the top of every forum page), for instance, maybe you were writing something other than bytes (are you using EEPROM.write() or EEPROM.put() ??), etc.

Hope this helps . . .

Mark J Culross
KD5RXT
 
Here's a "quick & dirty" program that you can use to test your EEPROM reads/writes in a predictable & repeatable way:

Code:
USAGE NOTES:

1) WRITE known (random) byte values to the EEPROM
   a) uncomment the line that reads "OP_TYPE op_type = OP_TYPE_WRITE;"
   b) comment out the line that reads "OP_TYPE op_type = OP_TYPE_READ;"
   c) uncomment the line that reads "TEST_TYPE test_type = TEST_TYPE_UINT8_T;"
   d) comment out the line that reads "TEST_TYPE test_type = TEST_TYPE_UNSIGNED_INT;"
   e) comment out the line that reads "TEST_TYPE test_type = TEST_TYPE_FLOAT;"
   f) compile & run the program

2) READ & confirm known (random) byte values from the EEPROM
   a) comment out the line that reads "OP_TYPE op_type = OP_TYPE_WRITE;"
   b) uncomment the line that reads "OP_TYPE op_type = OP_TYPE_READ;"
   c) compile & run the program
   d) unplug & plug the Teensy repeatedly to confirm that the same (correct) byte data is read from EEPROM each time

3) WRITE known (random) unsigned integer values to the EEPROM
   a) uncomment the line that reads "OP_TYPE op_type = OP_TYPE_WRITE;"
   b) comment out the line that reads "OP_TYPE op_type = OP_TYPE_READ;"
   c) comment out the line that reads "TEST_TYPE test_type = TEST_TYPE_UINT8_T;"
   d) uncomment the line that reads "TEST_TYPE test_type = TEST_TYPE_UNSIGNED_INT;"
   e) comment out the line that reads "TEST_TYPE test_type = TEST_TYPE_FLOAT;"
   f) compile & run the program

4) READ & confirm known (random) unsigned integer values from the EEPROM
   a) comment out the line that reads "OP_TYPE op_type = OP_TYPE_WRITE;"
   b) uncomment the line that reads "OP_TYPE op_type = OP_TYPE_READ;"
   c) compile & run the program
   d) unplug & plug the Teensy repeatedly to confirm that the same (correct) unsigned integer data is read from EEPROM each time

5) WRITE known (random) float values to the EEPROM
   a) uncomment the line that reads "OP_TYPE op_type = OP_TYPE_WRITE;"
   b) comment out the line that reads "OP_TYPE op_type = OP_TYPE_READ;"
   c) comment out the line that reads "TEST_TYPE test_type = TEST_TYPE_UINT8_T;"
   d) comment out the line that reads "TEST_TYPE test_type = TEST_TYPE_UNSIGNED_INT;"
   e) uncomment the line that reads "TEST_TYPE test_type = TEST_TYPE_FLOAT;"
   f) compile & run the program

2) READ & confirm known (random) float values from the EEPROM
   a) comment out the line that reads "OP_TYPE op_type = OP_TYPE_WRITE;"
   b) uncomment the line that reads "OP_TYPE op_type = OP_TYPE_READ;"
   c) compile & run the program
   d) unplug & plug the Teensy repeatedly to confirm that the same (correct) float data is read from EEPROM each time


You can also change the "seed" variable to any value other than '0' to force the EEPROM reads/writes to start at a different location to make sure that reading/writing the values are independent of the byte/word alignment.

Monitor progress of the reads/writes to EEPROM in the serial monitor.

This was tested and confirmed to work properly on both Teensy 4.0 & Teensy 4.1.

Hope that helps . . .


Code:
#include <EEPROM.h>

typedef enum
{
   OP_TYPE_WRITE = 0, OP_TYPE_READ
}  OP_TYPE;

// uncomment only one of the following lines to select which kind of operation ("write" or "read") that you'd like to run
//OP_TYPE op_type = OP_TYPE_WRITE;
OP_TYPE op_type = OP_TYPE_READ;

typedef enum
{
   TEST_TYPE_UINT8_T = 0, TEST_TYPE_UNSIGNED_INT, TEST_TYPE_FLOAT
}  TEST_TYPE;

// uncomment only one of the following lines to select which kind of variable ("uint8_t" or "unsigned int" or "float") to test storing in the EEPROM
// NOTE: the first time thru after changing between test types, the read values will not be correct since the values stored will be from the run of the previous test type
//       & as a result, any read comparisons perfomed the first time thru after changing between test types will very likely fail...this is to be expected

//TEST_TYPE test_type = TEST_TYPE_UINT8_T;
TEST_TYPE test_type = TEST_TYPE_UNSIGNED_INT;
//TEST_TYPE test_type = TEST_TYPE_FLOAT;

unsigned int seed = 1;  // NOTE: must be something other than '0'

uint8_t put_value_uint8_t;
uint8_t get_value_uint8_t;

uint8_t seed_uint8_t;

unsigned int put_value_unsigned_int;
unsigned int get_value_unsigned_int;

unsigned int seed_unsigned_int;

float put_value_float;
float get_value_float;

float seed_float;


void print_integer_value(unsigned int value, unsigned int places)
{
   places--;

   while (places > 0)
   {
      if (value < (unsigned int)pow(10, places))
      {
         Serial.print(' ');
      }

      places--;
   }

   Serial.print(value, DEC);
}


void print_hex_value(unsigned int value, unsigned int places)
{

   places--;

   while (places > 0)
   {
      if (value < (unsigned int)pow(16, places))
      {
         Serial.print('0');
      }

      places--;
   }

   Serial.print(value, HEX);
}


void setup() {
   unsigned int eeAddress;   //Location we want the actual data to be put into

   EEPROM.get(seed, seed_uint8_t);
   EEPROM.get(seed, seed_unsigned_int);
   EEPROM.get(seed, seed_float);

   Serial.begin(9600);

   unsigned long check_time = millis();
   while (!Serial && ((millis() - check_time) <= 3000));

   Serial.print("testing ");
   Serial.print(EEPROM.length());
   Serial.println(" EEPROM locations...\n\n");

   randomSeed(seed);

   switch (op_type)
   {
      case OP_TYPE_READ:
         {
            switch (test_type)
            {
               case TEST_TYPE_UINT8_T:
                  {
                     eeAddress = seed + sizeof(uint8_t);

                     if ((uint8_t)seed == seed_uint8_t)
                     {
                        while (eeAddress <= (unsigned int)(EEPROM.length() - sizeof(uint8_t)))
                        {
                           put_value_uint8_t = random();

                           EEPROM.get(eeAddress, get_value_uint8_t);

                           if (put_value_uint8_t == get_value_uint8_t)
                           {
                              Serial.print("Read CORRECT get_value_uint8_t '0x");
                              print_hex_value(get_value_uint8_t, 2);
                              Serial.print("' (");
                              print_integer_value(get_value_uint8_t, 3);
                              Serial.print(") at location 0x");
                              print_hex_value(eeAddress, 4);
                              Serial.print(" (");
                              print_integer_value(eeAddress, 4);
                              Serial.print(")");
                              Serial.println("...");
                           } else {
                              Serial.print("Read BAD get_value_uint8_t '0x");
                              print_hex_value(get_value_uint8_t, 2);
                              Serial.print("' (");
                              print_integer_value(get_value_uint8_t, 3);
                              Serial.print(") at location 0x");
                              print_hex_value(eeAddress, 4);
                              Serial.print(" (");
                              print_integer_value(eeAddress, 4);
                              Serial.print(")");
                              Serial.print("...");
                              Serial.print("expected put_value_uint8_t '0x");
                              print_hex_value(put_value_uint8_t, 2);
                              Serial.print("' (");
                              print_integer_value(put_value_uint8_t, 3);
                              Serial.println(")...");
                           }

                           eeAddress += sizeof(uint8_t); //Move address to the next starting byte location based upon the size of the variables being stored
                        }
                     }
                  }
                  break;

               case TEST_TYPE_UNSIGNED_INT:
                  {
                     eeAddress = seed + sizeof(unsigned int);

                     if ((unsigned int)seed == seed_unsigned_int)
                     {
                        while (eeAddress <= (unsigned int)(EEPROM.length() - sizeof(unsigned int)))
                        {
                           put_value_unsigned_int = random();

                           EEPROM.get(eeAddress, get_value_unsigned_int);

                           if (put_value_unsigned_int == get_value_unsigned_int)
                           {
                              Serial.print("Read CORRECT get_value_unsigned_int '0x");
                              print_hex_value(get_value_unsigned_int, 8);
                              Serial.print("' (");
                              print_integer_value(get_value_unsigned_int, 10);
                              Serial.print(") at location 0x");
                              print_hex_value(eeAddress, 4);
                              Serial.print(" (");
                              print_integer_value(eeAddress, 4);
                              Serial.print(")");
                              Serial.println("...");
                           } else {
                              Serial.print("Read BAD get_value_unsigned_int '0x");
                              print_hex_value(get_value_unsigned_int, 8);
                              Serial.print("' (");
                              print_integer_value(get_value_unsigned_int, 10);
                              Serial.print(") at location 0x");
                              print_hex_value(eeAddress, 4);
                              Serial.print(" (");
                              print_integer_value(eeAddress, 4);
                              Serial.print(")");
                              Serial.print("...");
                              Serial.print("expected put_value_unsigned_int '0x");
                              print_hex_value(put_value_unsigned_int, 8);
                              Serial.print("' (");
                              print_integer_value(put_value_unsigned_int, 10);
                              Serial.println("'...");
                           }

                           eeAddress += sizeof(unsigned int); //Move address to the next starting byte location based upon the size of the variables being stored
                        }
                     }
                  }
                  break;

               case TEST_TYPE_FLOAT:
                  {
                     eeAddress = seed + sizeof(float);

                     if ((float)seed == seed_float)
                     {
                        while (eeAddress <= (unsigned int)(EEPROM.length() - sizeof(float)))
                        {
                           put_value_float = random() / 1000.0;

                           EEPROM.get(eeAddress, get_value_float);

                           if (put_value_float == get_value_float)
                           {
                              Serial.print("Read CORRECT get_value_float '");
                              Serial.print(get_value_float, 4);
                              Serial.print("' at location 0x");
                              print_hex_value(eeAddress, 4);
                              Serial.print(" (");
                              print_integer_value(eeAddress, 4);
                              Serial.print(")");
                              Serial.println("...");
                           } else {
                              Serial.print("Read BAD get_value_float '");
                              Serial.print(get_value_float, 4);
                              Serial.print("' at location 0x");
                              print_hex_value(eeAddress, 4);
                              Serial.print(" (");
                              print_integer_value(eeAddress, 4);
                              Serial.print(")");
                              Serial.print("...");
                              Serial.print("expected put_value_float '");
                              Serial.print(put_value_float, 4);
                              Serial.println("'...");
                           }

                           eeAddress += sizeof(float); //Move address to the next starting byte location based upon the size of the variables being stored
                        }
                     }
                  }
                  break;
            }
         }
         break;

      case OP_TYPE_WRITE:
         {
            switch (test_type)
            {
               case TEST_TYPE_UINT8_T:
                  {
                     EEPROM.put(seed, (uint8_t)seed);

                     eeAddress = seed + sizeof(uint8_t);

                     while (eeAddress <= (unsigned int)(EEPROM.length() - sizeof(uint8_t)))
                     {
                        put_value_uint8_t = random();

                        EEPROM.put(eeAddress, put_value_uint8_t);

                        Serial.print("Wrote put_value_uint8_t '0x");
                        print_hex_value(put_value_uint8_t, 2);
                        Serial.print("' (");
                        print_integer_value(put_value_uint8_t, 3);
                        Serial.print (") at location 0x");
                        print_hex_value(eeAddress, 4);
                        Serial.print(" (");
                        print_integer_value(eeAddress, 4);
                        Serial.print(")");
                        Serial.println("...");

                        eeAddress += sizeof(uint8_t); //Move address to the next starting byte location based upon the size of the variables being stored
                     }
                  }
                  break;

               case TEST_TYPE_UNSIGNED_INT:
                  {
                     EEPROM.put(seed, (unsigned int)seed);

                     eeAddress = seed + sizeof(unsigned int);

                     while (eeAddress <= (unsigned int)(EEPROM.length() - sizeof(unsigned int)))
                     {
                        put_value_unsigned_int = random();

                        EEPROM.put(eeAddress, put_value_unsigned_int);

                        Serial.print("Wrote put_value_unsigned_int '0x");
                        print_hex_value(put_value_unsigned_int, 8);
                        Serial.print("' (");
                        print_integer_value(put_value_unsigned_int, 10);
                        Serial.print (") at location 0x");
                        print_hex_value(eeAddress, 4);
                        Serial.print(" (");
                        print_integer_value(eeAddress, 4);
                        Serial.print(")");
                        Serial.println("...");

                        eeAddress += sizeof(unsigned int); //Move address to the next starting byte location based upon the size of the variables being stored
                     }
                  }
                  break;

               case TEST_TYPE_FLOAT:
                  {
                     EEPROM.put(seed, (float)seed);

                     eeAddress = seed + sizeof(float);

                     while (eeAddress <= (unsigned int)(EEPROM.length() - sizeof(float)))
                     {
                        put_value_float = random() / 1000.0;

                        EEPROM.put(eeAddress, put_value_float);

                        Serial.print("Wrote put_value_float '");
                        Serial.print(put_value_float, 4);
                        Serial.print ("' at location 0x");
                        print_hex_value(eeAddress, 4);
                        Serial.print(" (");
                        print_integer_value(eeAddress, 4);
                        Serial.print(")");
                        Serial.println("...");

                        eeAddress += sizeof(float); //Move address to the next starting byte location based upon the size of the variables being stored
                     }
                  }
                  break;
            }
            break;
         }
   }
}

void loop()
{
   /* Empty loop */
}

Hope that helps . . .

Mark J Culross
KD5RXT
 
Each teensy type has a different number of EEPROM locations, as you can see on the page:

https://www.pjrc.com/teensy/td_libs_EEPROM.html
Teensy 4.0 1080 bytes

If for example you write to location 1010, The system breaks this into which of the 15 flash sectors that are dedicated to EEPROM on T4, to write to:

Code:
	sector = (addr >> 2) % FLASH_SECTORS; 
	offset = (addr & 3) | (((addr >> 2) / FLASH_SECTORS) << 2);

Sector: (1010 >> 2) %15 = 12 (if my quick math worked)
And the logical offset index would be:

offset = 2 + 64 = 66

For reads, it scans from the start of the page, for: the two byte pair, where the index byte is 66, and remembers the last value with this index number,
it will continue until it finds a word of 0xffff marking the first uunused location

For writes
It then walks through the memory page, from the end of it back, looking for the first memory location that is not 0xffff (reading words at a time). if the new value is equal to the
current value, it will return without needing to do anything.

If new value and the sector is already full, then it needs to build a compress out all of the duplicates in the page and then erases that page and writes out the compressed
version of it. Otherwise, it simply writes out (eepromemu_flash_write) the two bytes for the index and the new value.

As I mentioned in previous post, the code tries to spread out the EEPROM locations, through all of the pages (15 in this case). The first 4 (0-3) to page 0, 4-7 page 1, 8-11 page 2,
page 14 probably (56-59)... And then EEPROM.write(60, 100); would go back to page 0...

So if you run into error cases, you maybe should try to dump out the cooresponding page of memory and legally walk the data and see if your expected value is there or not.

Also are you doing anything special?

Like are you running the Teensy at default speed? Optimization? ...

Kurt
 
Thanks Kurt and all for the help. I tested that the basic functionality of the EEPROM for each location was there from 0 to 1079 address locations, and that worked. And after 1079 if you try to read you just get 65535 or other large number so you know you are off the limit. It also worked aok through resets and power cycles.

The situation I had was that we 'upgraded' from the Teensy 3.2 to 4.0 which has less EEPROM so the memory locations I was using were out of bounds. But once I brought them back in for my uses to 1010 that caused conflicts. I then went back and guessed at what might be being stored by other parts of the code (we have a rather large code base and it was not clear how much of EEPROM was being used) and was able to find a part that was untaken.

So, basic user error. Thanks all.
 
Back
Top