Arduino Longterm

I am building an Arduino product. Its kinda like a scheduler thing with LCD, relays and all. I was wondering before I launch it as product what are the additions or precautions I must take for a long time use. I mean like would I require a watchdog timer? Or will there be any long running time problems associated with it(I am using LCDs) or something similar to those which I should keep in mind while designing a complete package.

I am hoping some of the experienced users who have made products with this can help me out. :slight_smile:

I suppose that depends what you mean by 'long term use'. If you mean it can be treated like an appliance and assumed to work for years, then I guess you will need to make sure any electrical inputs and outputs are buffered effectively, make sure your sketch doesn't use any dynamic memory allocation and ensure you have edalt with the issue of counter overflow and number overflow in general throughout. Also make sure it is possible to do a hard reset somehow - perhaps via a pushbutton behind a small hole.

@peterH
Thanx for the info :slight_smile:

If you mean it can be treated like an appliance and assumed to work for years

Yes this is what I have in my mind.

U mean dynamic memory allocation as in variables used in programs?? I use very few.

counter overflow and number overflow

How do I solve this? Maybe a software reset every 2 days or something?

And I do provide a hard reset button. Is watchdog timers necessary?

Dynamic allocation like malloc() and such, where there's a fair chance you didn't free the memory properly, and eventually run out.

Overflows, like millis() -- the runtime counter that resets every ... what was it, 49 days? What happens if you check the time between two events and it's a huge negative number, for example... You solve this by watching anything that continuously increments, and handling the case where it rolls from max to 0. Or negative-max.

As for providing a means to reset, a push-button, barrel jack DC adapter that can be yanked... just some way. Any way will suit just fine.

Most(?) of the AVR chips have a watchdog timer you can enable. You tell it to reset the chip after so much time of no communication, then you make sure you reset the timer in your code within that window of time. When it stops being reset by your code, the watchdog assumes it crashed and resets the CPU. There's a tutorial from the playground:

http://tushev.org/articles/electronics/48-arduino-and-watchdog-timer

SirNickity:
Overflows, like millis() -- the runtime counter that resets every ... what was it, 49 days? What happens if you check the time between two events and it's a huge negative number, for example... You solve this by watching anything that continuously increments, and handling the case where it rolls from max to 0. Or negative-max.

I disagree. You solve this by designing your code so that counters either don't overflow, or so that the logic is not affected by an overflow. There is a classic example of this in the code usually used to implement the 'blink without delay' example. This version handles overflow correctly:

unsigned long lastMillis;
...
if((millis() - lastMillis) > interval)
{
    lastMillis += interval;
    ...

This version doesn't:

if(millis() > nextMillis)
{
    nextMillis += interval;

Although you should provide some way to reset the device, you should design it so that this is never expected to be needed.

Good point Peter! The solution is simple as you illustrated. Most people will not see the difference in your 2 examples.

If there are no bugs in your software (or hardware), you should be fine.

I built an alarm system for my 1994 van when it was less than a year old. (Of course with a different microcontroller.) It's been running 24/7 for over 15 years! It's powered-up, turned-on, and running full-time, even when it's not armed.... Only the inputs & "state" changes when you turn it "on" or "off". There is no "reset", except for when the car-battery dies & gets replaced every 4 or 5 years...

I disagree. You solve this by designing your code so that counters either don't overflow, or so that the logic is not affected by an overflow.

I think my meaning was misunderstood. millis() will overflow. There's nothing you can do about that, thus proper design handles this accordingly. Your example, for example, is predicated on the understanding that the integer value (returned by millis()) will eventually increment beyond its limits, and handles that.

One of the other fellows here is building an assembly line counter. Eventually, that could very well overflow the count variable. How would you prevent that from ever happening? Use a larger integer? Well, eventually, a 2048-byte integer could overflow (in theory -- buuuut probably not in practice), and that's every byte of SRAM on a 328, so it can't be made bigger. (Not even that big, of course, but you get the point.) The "best" way to handle that depends entirely on the circumstance.

My point was only to illustrate that such things happen, and if you don't anticipate it, you'll end up with things you didn't expect -- such as a large negative number (assuming you use signed integers) when you only ever expected to see a small, positive, difference. I never intended to provide a workaround, as there are many valid approaches, and an engineer will ultimately have to find the one best suited to their own application. :slight_smile:

All the above is known as "defensive coding". At every point in your program you look at the assumptions being made and ask yourself "But what happens if...?".

Depending on the application you can spend a lot of time doing this, placing guard bands around arrays, monitors to keep an eye on the stack etc etc. If you get really serious you probably have to look at the MTBF of all the hardware components :slight_smile:

It is essentially the difference between some code knocked up for fun in the home and a professional product.


Rob

Or sometimes the difference between a quality device that no one ever complains about and a cheap piece that is only bought once before people realize its crap

Oyii Lots of activity since I last logged in... :smiley: Thanks for all the replies.. :slight_smile:

@SirNickity
I am not using any dynamic initialization so thats out of the window... :slight_smile:
I know millis will overflow in around 50days or so. So will it be a good idea to reset (I mean software reset) every 4-5 days and restart the sketch?

@DVDdoug

If there are no bugs in your software (or hardware), you should be fine.

I was thinking on same lines... :smiley: Thanx for letting me know that its possible :smiley:

@winner10920

Or sometimes the difference between a quality device that no one ever complains about and a cheap piece that is only bought once before people realize its crap

I would like to be in first category... :wink:

Let me thank everyone once again for your responses... :slight_smile: Is there anything else I could have missed?? If so please do tell... :slight_smile:

Are you using a rtc for timekeeping or the arduino's millis()? The millis isn't that accurate over large amount of time, a software reset isn't needed if your code can handle the millis rollover

Yeah, what he said. :slight_smile:

milis() is useful as a quick "how long has it been since I've done some maintenance task" thing. Or for debouncing, or backlight timeouts, or what-have-you.

As winner said, and like we were discussing above, if the code you write to calculate differences between samples taken from millis() expects and properly handles the rollover case, then there's no need to worry about it. The overflow is completely harmless. All it means is that you can't blindly assume the value will always be higher than the last time you checked it. At some point it goes back to zero and starts counting up again.

Along the lines of the defensive coding thing, you should probably ALWAYS expect counters of any kind will eventually overflow.

SirNickity:
All it means is that you can't blindly assume the value will always be higher than the last time you checked it.

Or to get really picky, you can't blindly assume the computed time even if you handle rollover correctly was less than 49 days :-).

It was mentioned that an RTC can help address the time accuracy. How does an RTC work? Does it track the actual time (so you'd have to set it some how...), or is it also just milliseconds, but can count more accurately, and we'd do to the match to calculate the proper time?

An RTC has a full calendar (normally 200 years), you do have to set it up of course but once done as long as you keep the power to the chip all you have to do is read the time and date.

but can count more accurately

That depends on the chip used. Bottom line is an RTC and the Arduino are both dependant on the quality of the crystal used and the temperature. In general they will have about the same accuracy but it's possible to get RTCs with internal temperature-compensated oscillators (TCXO), these are a lot more accurate (2-3ppm) than the standard RTCs and Arduinos (maybe 20-50ppm).


Rob

Sounds neat. If the project has an Ethernet shield included anyways, is there an (dis)advantage of using an network time service (NTS) instead of an RTC, say, if the script needs to execute at the same time each day?

My guesses:
NTS won't need a battery backup if power is lost, since the code can reset/retrieve the time on next boot up.
Looping code could even periodically check the NTS to resynch it's internal time.

RTS avoids the dependency on an external service and a internet connection
I assume there's lower overall power consumption with this IC.
Reduced code complexity

Any others?

(hoping not to hijack the OP's thread, as this does seem relevant to good Longterm programming decisions and practice)

I've not used NTS but all the pros and cons you mention are correct I would say.

if power is lost

It's easy to battery back an RTC.

One thing is that an Enet shield uses a lot of power AFAIK, for battery supplied gadgets that would be a problem, an RTC uses two fifths of five eights of half a fempto watt.

Also RTCs are now included in the modern 32-bit chips, so you don't even have to add anything except a 32kHz crystal (unless you need the super accuracy of a TCXO).


Rob

I would definitely not use NTP as a replacement for an onboard clock, if what you need is a clock.

With an RTC, you always have a running date/time. It has a coin-cell backup battery to make sure it keeps ticking even when the power's off, or your code locks up, or whatever.

Without the RTC, your code will need to keep track of time somehow. Usually, this is by setting an interrupt timer to fire once a (e.g.) second and increment a seconds-since-epoch counter, or do date math on the fly to increment minutes, hours, days, months, years. The accuracy of this method depends on how reliable that interrupt timer is (which is in turn dependent on the crystal driving the timer -- already covered adequately here), and of course how quickly you can respond to that interrupt and update your time variables.

This is inherently sloppy as compared to a dedicated RTC chip. But, it's plenty good enough for a lot of projects. If your project is reliant on time enough that you're considering either an RTC or NTP, you should probably go with the RTC. If you're already using the Ethernet shield for some other aspect of your project, maybe adding NTP isn't such a big deal, but it's a huge waste if your primary point of network connectivity is to get the time from your network. And less accurate, due to the software clock implementation described above.

Plus, what do you do before NTP is available? Does it matter if the time is not known for some period? What if NTP is down, or the network is misconfigured? NTP doesn't seem too difficult, but it's not exactly trivial. Far easier to query an RTC.

Now, if precision time is essential to your project, maybe it's worth having both the RTC to keep the time consistent, and NTP to keep it accurate.

@SirNickity
I have used millis very less in the program. Now that I think of it I guess RTC could be a better option :smiley: Not much heavy work. Changing a few lines of code should do the trick... :slight_smile: