Boron / Xenon / Argon Carrier for Outdoor Applications

@peekay123,

Wow, did not know that wear leveling was built in. Can I assume that in addition to the wear leveling writes will use “update” so they only write if there is a change?

I don’t see any issue with saving hourly or daily data as even without wear leveling, these would last for years.

My question is in trying to judge the life of the device when I store the current state.

If I have a device that stores its “state” including the current counts and would be an object like this:

  • Control register (byte)
  • hourly count (2xbyte)
  • daily count (2xbyte)
  • time stamp of last count (4xbyte)
  • alerts (byte)
  • resets (byte)

For a busy park this object would be updated about 2,000 times a day. Without understanding the effectiveness of the wear leveling program is, how can I estimate the useful life?

That said, I have interacted enough with you on the forum to trust what you say. If there is no easy answer other than “trust the algorithm” I can be OK with that since Flash storage is quite mature and the wear leveling issue must be much more of an impact on devices such as PCs and Servers.

Thanks, Chip

@chipmc, the current EEPROM emulation uses a wear-leveling algorithm thus using more flash than what is presented to the user. The current library used by the DeviceOS for its flash operations is LittleFS which provides power-failure resistance and wear-leveling. I’m not sure if LittleFS will be replaced in future versions but you get the idea.

That said, I am not aware of any “update” capability since writes are done at the page level (typically 256 bytes) and not the byte level per say. Regardless, with wear leveling, you would not have to worry about the lifetime of the flash in your design IMO. However, @rickkas7 and @ScruffR may want to chime in :wink:

1 Like

I would keep the FRAM ind the design, it can always be changed to (do not mount) status, when the unlocked flash has proved itself to be in existence and reliable.

Could be some users may want to save large amounts of varying data often, in a way that minimise the effect of wear leveling (camera output?).

(Super nice boards!)

2 Likes

Yes, as peekay123 pointed out, you probably should not attempt to use SPI flash in direct sector access mode. Not only does it cause wear, but you are very limited in what you can write. You basically have to erase and write a whole 512 byte sector every time which is a pain and inefficient.

Using SPIFFS or LittleFS on the SPI flash essentially eliminates the wear issue as the data keeps moving around the flash, at least as long as you leave some empty space.

2 Likes

How about ($0,08)

https://lcsc.com/product-detail/Toggle-Switches_XKB-Enterprise-SS-3235S-L3_C381098.html

1 Like

@shanevanj,

OK, so after a fair bit of research and analysis, I have come to the conclusion that you are right.

First, I tried reaching out to the TI folks on their forum.

  • Petting the Watchdog does not reset the timer
  • Power cycling the watchdog will not work as it asserts the reset pin when power cycled
  • No, they don’t have another part number to suggest

Then, I started looking at the ATTINY and found a new part, the $0.40 ATTINY 202 / 402 which can consume less than 1uA of power. One bummer is that you have to use a UPDI programmer so, need to see if the savings justify the complexity.

So, I will order a couple and start testing. I need to validate this approach and determine the best programming header but, I am now thinking that this might be the best approach.

Thanks for pointing this out to me.

Chip

2 Likes

Thanks for the follow up on this, Chip. As you know my board is largely based on your original 3G design. I use the TPL5010 chip too. I did not know however that “feeding” the watchdog did not reset the timer. Good to know. I had been contemplating the ATtiny and will look at the chips you referenced.

I just took a look at this range - the issues around the UPDI and the toolset requirements are going to be expensive - the current attiny45/85 are much simpler right now (I am used to the Arduino environment to program these guys) - so I am going to use these for now.

@shanevanj,

It turns out you can make a UPDI programmer with an Arduino (or small cheap Pro Mini) as described here.

I also am comfortable with the ATTINY85 so that would be easier. Question is how low power can the ATTINY85 go? I have these at home so I can test - 1MHz internal clock and minimal components.

Let’s see.

Chip

Don’t forget to disable the ADC before sleep… save a lot of power.

1 Like

OK, so here is the simple sketch I made for my “dream watchdog timer”. I have built this and, so far so good. More testing tomorrow but, you can see where I am going from this sketch.

// ATtiny85 Watchdog Timer
// Author: Chip McClelland
// Date: 12-11-19
// License - GPL3

// ATMEL ATTINY 25/45/85 / ARDUINO
//
//                           +-\/-+
//  Reset - Ain0 (D 5) PB5  1|    |8  Vcc
//  Wake  - Ain3 (D 3) PB3  2|    |7  PB2 (D 2) Ain1 - Reset uC
//  Done  - Ain2 (D 4) PB4  3|    |6  PB1 (D 1) pwm1 - MISO
//                     GND  4|    |5  PB0 (D 0) pwm0 - MOSI
//                           +----+
// Interrupt code: https://gammon.com.au/forum/?id=11488&reply=9#reply9

/*
This is my dream Watchdog timer. It will function exactly as I want it - unlike the TPL5010.
First - You can set the interval in the header - wakeIntervalSeconds
Second - At the end of the interval, it will bring WAKE HIGH
Third - It will start a timer to reset which you can set in the header - resetIntervalSeconds
Finally - It will either Reset the device or restart the interval if it received a HIGH / LOW on Debounce
Version 1.0 - Minimally Viable Product - No Sleep
*/

#define adc_disable() (ADCSRA &= ~(1<<ADEN)) // disable ADC (before power-off)

#include <avr/power.h>    // Power management

enum State {INITIALIZATION_STATE, IDLE_STATE, INTERRUPT_STATE, DONE_WAIT_STATE, RESET_STATE};
State state = INITIALIZATION_STATE;

// Pin assignments will for the ATTINY85
const int resetPin  =   2;              // Pin to reset the uC - Active LOW
const int wakePin   =   3;              // Pin that wakes the uC - Active HIGH
const int donePin   =   4;              // Pin the uC uses to "pet" the uC

// Timing Variables
const int wakeIntervalSeconds = 20;   // One Hour and one minute
const int resetIntervalSeconds = 5;    // You have one minute to pet the watchdog
unsigned long lastWake = 0;
unsigned long resetWait = 0;

// Program Variables
volatile bool donePinInterrupt = false;

void setup() {
  pinMode(resetPin,OUTPUT);             // Pin to reset the uC
  pinMode(wakePin,OUTPUT);              // Pin to wake the uC
  pinMode(donePin,INPUT);               // uC to Watchdog pin

  digitalWrite(resetPin, HIGH);
  digitalWrite(wakePin, HIGH);
  delay(10000);

  digitalWrite(resetPin, HIGH);
  digitalWrite(wakePin, LOW);

  adc_disable();

  PCMSK  |= bit (PCINT4);               // Pinchange interrupt on pin D4 / pin 3
  GIFR   |= bit (PCIF);                 // clear any outstanding interrupts
  GIMSK  |= bit (PCIE);                 // enable pin change interrupts

  state = IDLE_STATE;
}

void loop() {
  switch (state) {
    case IDLE_STATE:
      if (millis() - lastWake >= wakeIntervalSeconds * 1000) {
        state = INTERRUPT_STATE;
      }
      if (donePinInterrupt) {           // This is where we can reset the wake cycle using the Done pin
        lastWake = millis();
        donePinInterrupt = false;
      }
    break;

    case INTERRUPT_STATE:              // In this state, we will take the average of the non-event pressures and compute an average
      digitalWrite(wakePin, HIGH);
      resetWait = millis();
      state = DONE_WAIT_STATE;
    break;
    
    case DONE_WAIT_STATE:
      if (millis() - resetWait >= resetIntervalSeconds *1000) {
        digitalWrite(wakePin,LOW);
        state = RESET_STATE;
      }
      else if (donePinInterrupt) {
        donePinInterrupt = false;
        digitalWrite(wakePin,LOW);
        lastWake = millis();
        state = IDLE_STATE;
      }

    break;

    case RESET_STATE:
      digitalWrite(resetPin, LOW);      // Reset is active low
      delay(5000);                       // Need to see how long this should be
      digitalWrite(resetPin, HIGH);     // Need to bring high for device to reset
      lastWake = millis();
      state = IDLE_STATE;
    break;
  }
}

ISR (PCINT0_vect) {
  donePinInterrupt = true;
}

Here is the circuit:

ATTINY85 is not my strong suit so, suggestions welcome.

Chip

I like your thinking - I have baked one into my carrier as well, however I will use the I2C library, make it a slave (0x07) and use that to set the intervals - leaves the SPI alone in Gen3 so I can use ETH as well if required.

Close to my dream watchdog too, not finding a similar one chip solution.

Agree with i2c option to change timeouts. With a changing OS, it is safer than without.

5s reset should be fine, but cutting power setups need around 15s + margin from experiments earlier this year, with devices stuck that need cloud re-sync. I believe @rickkas7 use 30s in a HW watchdog setup with the Enable pin.

Agree on the timing part. These values are too small but are helping me complete testing faster…

I will do more testing today to see what those values need to be with my Boron.

Thanks

Thanks for taking a look and, as always, for your thoughts.

I like your suggestion about i2c for the intervals. But, I have a significant concern as well, this is supposed to be an external watchdog. Adding i2c increases the complexity of the code, forces two-way communication between the Particle device and the watchdog. What if the event that you want your watchdog to save you from is the i2c bus locking up? What if a i2c lockup locks your watchdog as well?

You have been right so far on this topic and may be here as well. But, can you say more about how you might reduce these risks?

Thanks, Chip

1 Like

Hi Chip, on the topic, please have a look at this article.
The article talks about many cases and what to want (and not want) in a watchdog.
I enjoyed and learned a lot reading it, and perhaps, it can help you too.
Cheers,
Gustavo.
PS: thank you for posting about your experiments. I enjoy it every bit.

2 Likes

So I have given that aspect a lot of thought. The WD on the AVR chips has been really good in my use cases so far. I’ll enable on the 85, as per your code and this will bounce the 85, if the I2C hangs up and when restarts it will take last time value from eeprom and (re)start the timer cycle. In the meantime, if the Gen3 has hung on the same I2C and it’s WD (which in my case will be on a 60s cycle) has not bounced it - then when the 85 times out it will reset the Gen3. I won’t use the I2C as the “pat the dog” I will still use an I/O just in case something else has hung the I2C bus. I still need to write some code and test this logic…

Folks, excellent work. You may want to consider the situation where you want the '85 to kill the power to the Gen3 device entirely since RESET doesn’t reset the other devices like the SARA modem or the ESP32. With clever programming and I2C connectivity, the '85 could be configured to act as a Windowed Watchdog as well and could reset the nRF52 and/or cycle power on the device. Writing to “registers” on the '85 to “pet” it would prevent the scenario where the simple GPIO “petting” would continue in spite of the main software going into a crazy state.

@gusgonnet, that article you linked to is great. Thanks!

@peekay123, @shanevanj, @gusgonnet, @thrmttnw,

Thanks for the suggestions. I can see that this Watchdog Timer thing is a bit of a big deal (thanks @gusgonnet for the article) and worth putting more time into.

Thing is that I need to get this board out the door if I am ever going to move from Electron to Boron. So, I will focus on the board and work on the software features while OSHPark is building the next round:

  • i2c slave to get watchdog timing from the Particle device
  • Windowed watchdog to prevent simple toggling

I can see two issues on the board layout that I need to figure out (and would, of course, be open to any help or suggestions).

  1. The pins that the ATTINY85 uses for i2c are the same MISO / MOSI pins used for programming. If I connect these pins to the i2c bus, they get the pull ups and will affect the other i2c devices. Unless I want to pay the $$$ to get these pre-programmed, how can I wire these onto the board without losing the ability to re-program them?

  2. If I toggle the EN pin, it will power cycle the board and the peripherals (good thing) but, it will also cut power to the watchdog. Do I need to add a RC filter / or by-pass cap so the watchdog stays powered long enough (about 100mSec has worked in the past) to keep the power off long enough to reset the device?

Thanks,

Chip

I’m not an ATTINY85 expert but my understanding is that you must disconnect the I2C bus before you can program (or reprogram) it. The easiest way to do this (that I’ve seen) is to add 2 jumpers between the ATTINY and the I2C bus. It’s important that the MISO/MOSI lines aren’t pulled up by I2C resistors. When you’re ready to program the ATT, disconnect the jumpers first before connecting to the programmer interface. And make sure you disconnect the programmer before you connect the I2C bus. When you’re done programming, just reconnect the I2C bus. I’ve never tried this but it makes sense to my feeble brain. Hope it helps or spurs more ideas.