An alternative to "nvram_save/restore" using the SD card?

  • I know that this might sound like a question that has already been discussed before. However I haven't found an answer in the forums saying "no, it is not possible".

    I have a fleet of devices that will be commissioned out there in the field powered by an accumulator and a small energy harvesting circuit.
    The logic dictates that the devices need to go into deep sleep mode for 5 minutes, wake up, transmit and deep sleep again.

    After doing some maths and considering the max number of read/write cycles of the NVRAM is 100.000, my devices will have an expected life time of less than a year:

    1440 total minutes per day

    1440 / 5 = 288 Read-Write cycles per day

    100000 cycles / 288 cycles = 347 days!

    I was therefore thinking if there is a way to use the SD card to store/restore the relevant LoRaWAN parameters(joined status, network keys, packet counters, etc) instead of using NVRAM on each cycle and thus increase the lifetime of the sensors.


  • @d-alvrzx Looking deeper in the code, it seems that these are on different name spaces. Strange. Normally I test before posting.

  • @robert-hh Hey, just checking, this is not yet implemented, right? Because I attempted to run pycom.nvs_get("DEVADDR") for example, after an ABP join, and it just returned ValueError: No matching object for the provided key... Having direct access to these parameters (including the fCnt) would be a godsend...

  • Other options are external :

    Both can be used with Peter Hinch MicroPython driver module, with advanced features, like many equal IC in parallel (seen as unique in MicroPython), optional use of FAT or LittleFS, etc :

  • @jcaron hi! thanks for joining the topic.

    • Waking up every 5 minutes? You'd better have a pretty good source of energy to harvest from
      Yes, I have already considered that point and my energy source seem to cope with that quite well within the conditions of operation.

    • During deep sleep, you'll use a bit over 10 µA minimum (again, depends on your setup).
      I have also already considered this in my design and I am disconnecting everything when going into deepsleep.

    I am aware of the fair use policy of ttn. Where this sensor are intended to be deployed, the coverage is quite good so the planned SF of operation will be 7.
    I will be transmitting 8 bytes of data, according to TTN a good practice is to stay below 12.

    • Are you sure you need to transmit that often?
      5 minutes period might also be an adjustable parameter.

    Thanks for the useful reminders, I will make sure I maintain good practices in order to make an efficient and effective use of the network.

    How do you suggest to store lorawan parameters in sd instead of using internal flash?

  • @snorkman Waking up every 5 minutes? You'd better have a pretty good source of energy to harvest from...

    A wake-read-send-sleep cycle using LoRaWAN on a LoPy takes at the very least 4 seconds, possibly a lot more depending on what you need to do (e.g. wait for a sensor to settle), the data rate you are using (SF12 means over 1 second for the TX phase) or if the network you are connected to as a RX delay longer than the default 1 second. Let's say it's 5 seconds.

    The average power draw during those 5 seconds will be at the very least 50 mA, possibly up to 100 mA (again, depends on a lot of factors such as your sensor, what work you have to do, data rate...).

    During deep sleep, you'll use a bit over 10 µA minimum (again, depends on your setup).

    At 5 seconds awake time per 500 seconds, that's:

    ( 5 * 50 + 295 * 0.01)  / 300 = 0.843 mA

    If you rely solely on a battery, a 2500 mAh battery will last about 4 months.

    For your energy harvesting to be useful (i.e. prevent the battery from ever going flat), it needs to be able to harvest a few watts on average. You'd better be outside in a sunny location if you want to get that.

    Also, depending on region, network and data rate, you may hit limits. TTN for instance doesn't allow over 30 seconds of uplink airtime per device per day, which at SF12 means about 20 packets per day, less than one per hour.

    Are you sure you need to transmit that often? Depending on your exact use case, you may be a lot better off recording data locally and sending less often, of instance. Or just waking up a lot less often.

  • Hello @robert-hh and thanks for the quick reply,
    I am glad to know that wear levelling is already coping with this issue in the background.

    I think it also worths to be mentioned, that in my application I already do the exact sequence you mention:

    1. Join (only once if using OTAA)

    2. Transmit

    3. nvram_save (to keep track of the packet counter)

    4. deep sleep 5 mins

    5. nvram_restore

    6. repeat from step 2)

    Regarding the possibility of storing the current LoRaWAN data on an external source such as an SD card (also with the con of a higher power consumption) and modifying the underlying behaviour sounds to me like a large additional effort just to achieve it when LittleFS and NVS are already in charge of that.

  • @snorkman NVS is told to have some wear leveling. So the total cycles you can use shall be higher, if you use just a small fraction of the 28k reserved for it.
    Besides that you should be able to write at least some of the data to an SD card. Device joining consists of a) synchronization of the key material, and b) setting the packet counter to an initial value. Joining happens ideally only once in lifetime, and for instance ABP join does not even require communication between the device and the network. It just sets the respective keys locally. As far as I recall, the only value that cannot be retrieved and set to an arbitrary value by python scripts is the packet counter. But since the Lora module uses the standard nvs functions to store & retrieve them, you may be able to set & get them that way. The keys for the values are defined in esp32/mods/modlora.c lines 260 ff.

    static const char *modlora_nvs_data_key[E_LORA_NVS_NUM_KEYS] = { "JOINED", "UPLNK", "DWLNK", "DEVADDR",
                                                                     "NWSKEY", "APPSKEY", "NETID", "ADRACK",
                                                                     "MACPARAMS", "CHANNELS", "SRVACK", "MACNXTTX",
                                                                     "MACBUFIDX", "MACRPTIDX", "MACBUF", "MACRPTBUF",
                                                                     "REGION", "CHANMASK", "CHANMASKREM" };

    So after having stored these values by lora.nvs_save once after a OTAA join, you can retrieve the key material via pycom.nvs_get commands, and then use ABP join fur further session initiation, unless you go anyhow for APB-join. So the only thing that's missing is an API for getting/setting the packet counters on-the-fly.

Log in to reply

Pycom on Twitter