Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 7 of 7

Thread: Battery backed NV RAM

  1. #1
    Junior Member
    Join Date
    Mar 2017
    Posts
    9

    Battery backed NV RAM

    Hello,

    Using the Teensy 3.5.

    We're working on a sequencing system that requires us to pick up the sequence after a power failure.
    This means we need to make a note of the current sequence number (small amount of data) somewhere at least every 15 seconds but worse case every sec. That's a lot of writing which is not suitable for EEPROM or SD Cards.

    NVSRAM seems to be the best bet.

    We're looking at a system lifetime of 5 to 10 years so although the system will be powered 99.99% of the time, the battery obviously has to remained charged for when the power does fail.

    Just wanted some views on what others had used with the Teensy to achieve this type of goal.

    Many thanks
    Gary

  2. #2
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    22,116
    Teensy 3.5 (and all 3.x boards) have a small 32 byte memory located at 0x4003E000, which stays alive if you connect a 3V coin cell to the VBAT pin. The startup code uses the last 4 bytes as part of its RTC initialization process. You can use the other 28 bytes for storing your sequence number or other frequently changed data. If you *really* want all 32 bytes, you could also edit the startup code.

    You can make use of it like this:

    #define NVRAM_INTEGER (*(uint32_t *)0x4003E000)

    Then just read or write NVRAM_INTEGER. It's RAM so you can write as often as you like. If you're concerned about the compiler actually performing your writes immediately, adding "volatile" to the definition might be a good idea.

  3. #3
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    11,828
    Cool. I did this and it works with 3V cell across GND<>VBat across unplugging - survives reset without battery.

    As used I pulled the extra '*' from NVRAM_INTEGER in post #2, but just set up a pointer to use like this (avoiding the 8th uint32_t the RTC code uses):
    Code:
    #define NVRAM_INTEGER ((uint32_t *)0x4003E000)
    volatile uint32_t *NVR_8 = NVRAM_INTEGER; // (uint32_t *) 0x4003E000;
    
    void setup() {
      Serial.begin(57600);
      for ( int ii = 0; ii < 7; ii++ ) {
        Serial.println( NVR_8[ii] );
        NVR_8[ii] += ii*ii;
      }
    }

  4. #4
    Senior Member+ Frank B's Avatar
    Join Date
    Apr 2014
    Location
    Germany NRW
    Posts
    6,910
    @Paul, there's an old pull-request by me, you might want to add it to the core..
    The name "NVRAM" might be a better choice for the name

    https://github.com/PaulStoffregen/cores/pull/212

  5. #5
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    11,828
    Maybe my 'C' is poor - or maybe I just like the ARRAY[] indexing method - but I can't get the compiler to use the provided definition with the extra *
    #define NVRAM_INTEGER (*(uint32_t *)0x4003E000)
    to access the way I would see it used.

    Code:
    #define NVRAM_UINT32 ((uint32_t *)0x4003E000)
    
    void setup() {
      Serial.begin(57600);
      for ( int ii = 0; ii < 7; ii++ ) {
        Serial.println( NVRAM_UINT32[ii] );
        NVRAM_UINT32[ii] += ii*ii;
      }
    }
    And that definition allows me to have 14 uint16_t's instead:
    Code:
    #define NVRAM_UINT32 ((uint32_t *)0x4003E000)
    #define NVRAM_UINT16 ((uint16_t *)NVRAM_UINT32)
    
    void setup() {
      Serial.begin(57600);
      for ( int ii = 0; ii < 14; ii++ ) {
        Serial.println( NVRAM_UINT16[ii] );
        NVRAM_UINT16[ii] += ii*ii;
      }

  6. #6
    Junior Member
    Join Date
    Mar 2017
    Posts
    9
    Quote Originally Posted by PaulStoffregen View Post
    Teensy 3.5 (and all 3.x boards) have a small 32 byte memory located at 0x4003E000, which stays alive if you connect a 3V coin cell to the VBAT pin. The startup code uses the last 4 bytes as part of its RTC initialization process. You can use the other 28 bytes for storing your sequence number or other frequently changed data. If you *really* want all 32 bytes, you could also edit the startup code.

    You can make use of it like this:

    #define NVRAM_INTEGER (*(uint32_t *)0x4003E000)

    Then just read or write NVRAM_INTEGER. It's RAM so you can write as often as you like. If you're concerned about the compiler actually performing your writes immediately, adding "volatile" to the definition might be a good idea.
    Hi Paul,

    This is REALLY useful - thanks. 28 bytes will be plenty for what we need. I note your recommended for the volatile. I just wondered if there is any chance of data corruption of half written data if say the power goes off during the writing of the 28 bytes. I suppose we could as a checksum as one of the end bytes so when reading the data on power restore we can be sure of clean data. Thoughts?

    Many thanks
    Gary

  7. #7
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    3,379
    or write 2 vars with crc, upon reboot the one with valid crc will be taken

    write first volatile A with crc
    write second volatile B with crc

    A is the main one, if crc fails it copies last valid from B, which wasnt written to as shutdown happened in A

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •