Compile-Time vs. Run-Time Flag

I need a way for setup() to determine if it is being run for the first time after a compile/upload, or is being run after a power-on/restart. The compiler needs to set a value, that my program can then change at run-time.

I thought about using the flash memory, but at run-time, it really is READ-ONLY! >:(

I'm going to look at using EEPROM for this, but, at present, I don't know of anyway to have the compiler set a value in EEPROM.

Any ideas?

BTW, I'm using an Arduino UNO.

It would be useful to know why you want to make that distinction - there might be a different solution.

I can't recall if the EEPROM memory gets erased when you upload a program but if it does that could be a solution.

...R

Optiboot provides no access to the EEPROM.

@stecoop, which board?

In the OP its an Uno

...R

A work-around might be for the Arduno to assume it is in repeat mode unless a certain I/O pin is grounded or a certain EEPROM value is XX. Then, after programming you could ground the I/O pin temporarily with a piece of wire and power up the Arduino when it will automatically write some value to the EEPROM so that the next start (without the grounded pin) will be considered the first start.

...R

DATE and TIME embedded in the uploaded image. If the values do not match the values stored in EEPROM then it is a fresh upload.

You are actually in the territory I'm working. I want the TinyRTC to be set to the DATE TIME after an upload, but NOT after a power outage. Unfortunatly, the DATE TIME values are read only, so I can't change them at run-time. I need something the compiler sets, that I can change at run-time. The compiler won't set EEPROM, so, unless the uploader erases the EEPROM, I don't see that working.

stecoop:
You are actually in the territory I'm working. I want the TinyRTC to be set to the DATE TIME after an upload, but NOT after a power outage. Unfortunatly, the DATE TIME values are read only, so I can't change them at run-time. I need something the compiler sets, that I can change at run-time. The compiler won't set EEPROM, so, unless the uploader erases the EEPROM, I don't see that working.

The compiler can load the date and time when the compile took place. If that does not match the date and time in the EEPROM treat it as the first run after compiling and write the matching values into the EEPROM. Next time the Arduino starts the values will match.

...R

I think the DATE and TIME solution is great, but since you brought it up, the latest version of the Optiboot bootloader does allow you to write to flash at runtime.

The easiest way to get this bootloader on your Uno is via MiniCore:

which provides a demonstration sketch for this feature:

Your Uno is already using the optiboot bootloader, but an older version from before the feature was added.

Robin2:
The compiler can load the date and time when the compile took place. If that does not match the date and time in the EEPROM treat it as the first run after compiling and write the matching values into the EEPROM. Next time the Arduino starts the values will match.

...R

Okay, I see what you're suggesting...it's the reverse logic of what I'm looking for. I think it could work; I'll give it a try as soon as I can and post here the results.

Thank you, everyone, for your suggestions.

pert:
I think the DATE and TIME solution is great, but since you brought it up, the latest version of the Optiboot bootloader does allow you to write to flash at runtime.

The easiest way to get this bootloader on your Uno is via MiniCore:
GitHub - MCUdude/MiniCore: Arduino hardware package for ATmega8, ATmega48, ATmega88, ATmega168, ATmega328 and ATmega328PB
which provides a demonstration sketch for this feature:
GitHub - MCUdude/MiniCore: Arduino hardware package for ATmega8, ATmega48, ATmega88, ATmega168, ATmega328 and ATmega328PB

Your Uno is already using the optiboot bootloader, but an older version from before the feature was added.

Does the compiler know this? My first idea was to zero-out the DATE_ & TIME strings, but the compiler wouldn't allow it because it knew I was trying to write to read-only memory.

byte x = 10;
int address = 0;

void setup()
{
  if (EEPROM.read(address) == x)
  {
    // code has run before
  }
  else
  {
    // code has not run before
    EEPROM.write (address, x);// write x to address so we know code has now been run
  }
}// End setup

Why bother? Assuming a proper battery-backed RTC you have to set it only once, after that you're good for many years to come.

So upload a sketch that sets the RTC (using the DATE and TIME incorporated in the sketch) once, when that's done upload your main code and the RTC just keeps it time.

If after a few years you want to adjust the RTC (they tend to lose or gain a few seconds a year) you upload the set sketch, run it once, immediately after you put back your original sketch.

Hutkikz:

byte x = 10;

int address = 0;

void setup()
{
 if (EEPROM.read(address) == x)
 {
   // code has run before
 }
 else
 {
   // code has not run before
   EEPROM.write (address, x);// write x to address so we know code has now been run
 }
}// End setup

Thank you. That's even simpler than saving the DATE and TIME strings. I just need to remember to change the value of 'x' each time I upload.

Hutkikz:

byte x = 10;

int address = 0;

void setup()
{
 if (EEPROM.read(address) == x)
 {
   // code has run before
 }
 else
 {
   // code has not run before
   EEPROM.write (address, x);// write x to address so we know code has now been run
 }
}// End setup

Unless you change x for every new version of your code (you're bound to forget this), this code will only run the one time it's a fresh upload on a fresh Arduino. Subsequent uploads see x in that EEPROM address and act as if it's run before.

wvmarle:
Why bother? Assuming a proper battery-backed RTC you have to set it only once, after that you're good for many years to come.

So upload a sketch that sets the RTC (using the DATE and TIME incorporated in the sketch) once, when that's done upload your main code and the RTC just keeps it time.

If after a few years you want to adjust the RTC (they tend to lose or gain a few seconds a year) you upload the set sketch, run it once, immediately after you put back your original sketch.

As a matter of fact, the TinyRTC DS1307 I'm using gains 10 to 12 seconds a DAY; I'm disappointed in the lack of accuracy. I suppose it's possible I received a defective or counterfeit TinyRTC because I've run into other problems with it; for instance, when I stop the clock, and later restart it, the seconds are ALWAYS set to 48, regardless of the value I try to set. Obviously, I can buy a different RTC breakout from Adafruit, but for now, trying to work around the problems is a good programming exercise.

A quick search on "DS1307 calibration" turns out that this is normal, that's indeed about as poor as or even worse than the internal timekeeping of the Arduino. Probably back in the day the RTC designs weren't that good yet (it's an oldie). This post gives an idea on how to correct for this drift programmatically.

The best solution is of course to get a better RTC. Such as the popular but admittedly less cheap DS3231, known for high accuracy out of the box. Or if you want low cost and small size, an MCP7940 (it can be calibrated, but even without calibration the drift will be less).

wvmarle:
A quick search on "DS1307 calibration" turns out that this is normal, that's indeed about as poor as or even worse than the internal timekeeping of the Arduino. Probably back in the day the RTC designs weren't that good yet (it's an oldie). This post gives an idea on how to correct for this drift programmatically.

The best solution is of course to get a better RTC. Such as the popular but admittedly less cheap DS3231, known for high accuracy out of the box. Or if you want low cost and small size, an MCP7940 (it can be calibrated, but even without calibration the drift will be less).

For the final project build I will get a DS3231. There are several 'aspects' to this project; I've been testing and "playing with" the various aspects for now to get some ideas for the final project.

With the DS3231 RTC you shouldn't need any adjustment, set it once and be happy - it's specs say 2 ppm accuracy, that's <16 seconds a year drift for 0-40°C conditions. So if you can put up with the inaccuracy during the testing phase it's a waste of time to try and set it time and again this way.

If you don't use a bootloader and you don't set fuses to lock flash then you should be able to write flash in runtime.

A bootloader on an ATtiny seems a waste anyway.

OTOH you could write to EEPROM with one sketch and then load your job sketch that reads and modifies EEPROM if the byte is say 0b10101010 to 0b01010101.