Shop OBEX P1 Docs P2 Docs Learn Events
Saving P2 program state when the power goes off? — Parallax Forums

Saving P2 program state when the power goes off?

Very often, the state of a P2 based module requires saving at switch-off and restoring at switch on. We have several good libraries for flash or sd card file management now. However, that begs the question - how to save those critical project variables with the least amount of effort? Saving individual variables would seem to be more work than saving one structure of variables. A smartpin can be made to monitor the unregulated power voltage and the capacitor across the regulated supply ensures there's enough time to save and close the file before the P2 stops. Any hints and tips?
Cheers, bob

Comments

  • RaymanRayman Posts: 16,263

    Interesting question ….

    Maybe save entire hub to nonvolatile every so often and restore if reboot detected ?

    That’d be easy but not sure if would be ok

  • roglohrogloh Posts: 6,316

    If these "variables" don't change much and are acting more like configuration settings then possibly keep them stored in some i2c or SPI accessible NVRAM / EEPROM to begin with and read them back into RAM at run time and update the NVRAM whenever they change. If they change too much then the device may start to wear however, depending on the HW chosen.

  • RaymanRayman Posts: 16,263

    If it’s just a few bytes., some new i2c rtc have user ram…

  • If all the variables that need saving at power-off are collected together in a structure in the top level object, @mystructure gives you the start address and sizeof(mystructure) gives you the byte count. Not too difficult to write that out to a file and read it back in on start-up.

  • JonnyMacJonnyMac Posts: 9,795

    If it’s just a few bytes., some new i2c rtc have user ram…

    I'm doing that in a game piece; every time the score or game time changes we save it to a battery-backed RTC module. On power-up (e.g., after a battery change in the middle of an 8-hour Airsoft game) the code looks for a running flag in the RAM. If that is set the scoring and game timer is copied from the RAM and the game auto starts, otherwise the game is reset to defaults and waits for a start single from the referee.

  • @bob_g4bby said:
    Very often, the state of a P2 based module requires saving at switch-off and restoring at switch on. We have several good libraries for flash or sd card file management now. However, that begs the question - how to save those critical project variables with the least amount of effort? Saving individual variables would seem to be more work than saving one structure of variables. A smartpin can be made to monitor the unregulated power voltage and the capacitor across the regulated supply ensures there's enough time to save and close the file before the P2 stops. Any hints and tips?
    Cheers, bob

    I have done this a couple of ways.
    1. FRAM memory, writes quick, virtually no wear. If the additional access time doesn't slow things down too much, you can work from it for critical values, states, etc.
    2. Exactly as you describe, monitoring actual power and using capacitive 'hang time' to write. I place the critical variables in a section where I can just copy the entire block of data to a file on power loss, and restore it over the block on power up. Know that capacitors age and you can't always control the drain. you might find someday that the hang time isn't enough. Corrupt data can be worse than no data.

  • RaymanRayman Posts: 16,263

    Suppose to be 100% safe, should cycle through two copies of this data just to guard against the off chance that power is lost in the middle of a write …

  • A good excuse for a checksum?

  • RaymanRayman Posts: 16,263

    You’d want something to make sure error was good you’d think…

    But maybe the odds of bad write are so low, would depend on application ..

  • @Rayman said:
    But maybe the odds of bad write are so low, would depend on application ..

    Anything that CAN happen, WILL happen, in a highly visible and embarrassing way, with cringingly expensive pyrotechnics, with the highest number of the most important witnesses, at the WORST time possible. Every. Single. Time.

    Don't ask how I know...

  • Saving variables to flash ROM triggered by a power-good signal seems to be a good idea. In a perfect world this would avoid writing too often which could cause storage wear. But in the real world I'd argue that leaving the system in an inconsistent state (RAM content doesn't match flash content) for a longer than neccessary time means asking for trouble. I had too much bad experience with software that only saves when shutting down, for example Mach3 and Code::Blocks. If something unexpected happens you loose the last input and possibly a lot of work.

    I think it's better to save as soon as possible after anything has changed. Chip made a power fail safe file system that supports wear levelling. Please also consider using a file format that supports up- and downward compatibility so that newer software can still read the files from the older version after an update. IFF (developed on the Amiga) is a good example. It was mainly used for pictures but is not limited to.

  • @bob_g4bby said:
    A good excuse for a checksum?

    indeed.

  • Mm - yes, saving on variable change sounds like a very good idea. Also, if saving to sd-card, multiple copies would be a drop in the ocean. Attempting to load most recent copy and iterating back in time if a checksum fails would add more resilience to project initialise.

  • ke4pjwke4pjw Posts: 1,312
    edited 2026-04-07 17:50

    I save and load configuration variables directly to the SD card.

    VAR
            long PIXELCONFIG[144]
            long E131CONFIG[432]
            byte MACADDRESS[6]  ' Must be unique per layer 2 network
            byte IPADDRESS[4]
            byte SUBNETMASK[4]
            byte GATEWAY[4]
            byte DHCP 'Non zero
            byte BRIGHTNESS
            byte DNS[4]
            byte SPEEDDUPLEX
            long SCREENTIMEOUT
            long DMXENABLED
            byte HOSTNAME[32]
            nametype OUTPUTNAME[32]
            long ENDOFCONFIG ' End of the loadable config
    

    Later in the program.....

      handle := sd.openFileRead(string("blitzen.cfg"))
      sd.readHandle(handle, @PIXELCONFIG, (@ENDOFCONFIG + 3) - @PIXELCONFIG + 1)
    
    

    Just make sure you only add to that memory structure and keep it in the same order.

  • RaymanRayman Posts: 16,263

    @ke4pjw Doesn't Spin rearrange bytes and longs in VAR when compiling? Or, maybe that was fixed?

    Maybe compiler dependent, think prop tool does this but maybe SpinTools doesn't...

  • JonnyMacJonnyMac Posts: 9,795
    edited 2026-04-07 19:09

    Doesn't Spin rearrange bytes and longs in VAR when compiling? Or, maybe that was fixed?

    P1/Spin1, yes. P2/Spin2, no. In Spin2 you can treat a block of variables like a structure. I did this early on with the WAV header. Back then FlexProp did rearrange by size, even in the P2. I don't know if that has changed.

    A few minutes later....

    FlexProp does layout as defined, too. Perhaps I'm mistaken and it always did.

    Works in Spin Tools, too.

  • ke4pjwke4pjw Posts: 1,312
    edited 2026-04-07 20:20

    @Rayman so far, Prop-Tool, Spin-Tools, and PNUT all work the same. If that changes, I will abstract the config, but so far, so good.

    Not sure if this works with flexprop.

    Looks like Jon verified it works too.

  • RaymanRayman Posts: 16,263

    Ok, good to refresh memory on this. Personally, just do all longs, so don't have to think about it...

  • JonnyMacJonnyMac Posts: 9,795
    edited 2026-04-07 21:39

    If I have control, I do longs, but there are times when getting packed information from another device that the mixed variable sizes is nice. Here are the header variables for a WAV:

    ' wav header
    ' -- do not modify
    
      long  chunkid
      long  chunksize
      long  format
      long  subchunk1id
      long  subchunk1size
      word  audioformat
      word  numchannels
      long  samplerate
      long  byterate
      word  blockalign
      word  bitspersample
      long  subchunk2id
      long  subchunk2size
    

    The file can be checked with

    pub validate(p_str) : result | n
    
    '' Return true for 16-bit, mono, PCM, canonical WAV
    '' -- http://soundfile.sapp.org/doc/WaveFormat/
    '' -- returns OK (0) if file is valid
    ''    * error codes are negative
    
      if (has_file(p_str) <> OK)
        return EOF
    
      n := rd_buf(@chunkid, 44)                                     ' get header structure
      if (n <> 44)
        return -2
    
      if (chunkid <> RIFF)
        return -3
    
      if (format <> WAVE)
        return -4
    
      if (audioformat <> 1)
        return -5
    
      if (numchannels <> 1)
        return -6
    
      if (samplerate < 1000) || (samplerate > 48_000)
        return -7
    
      if (bitspersample <> 16)
        return -8
    
      return OK
    

    In my P1 code I have to read the header into a separate buffer and then use bytemove() to extract individual variables to be checked.

  • RaymanRayman Posts: 16,263

    Guess we have the new Spin2 structure stuff...

Sign In or Register to comment.