Random delay in setup() without using delay()

Hi,

I have an Arduino project where I need the Atmega328 to start randomly between 0 and 16 seconds as soon as the power is applied. My first attempt using this code didn't work:

void setup() {
randomSeed(analogRead(1));
delay(random(1,16000));
...
}

The program freezes after some seconds. Since I'm using the watchdog timer for different timings I'm unable to use the serial connection to see what's really happening, but all I know is, that the problem comes from the delay-command.

Is there any other way how to stop the Atmega executing the program directly?

Best regards
Cornelius

(deleted)

I'm getting closer. Thanks! It still freezes, but the watchdog works. The only problem, what remains is that the freezing takes approx. 1-10 seconds till it restarts...

void setup() {
randomSeed(analogRead(1));
int b;
int c = random(1,16000);
for (b = 0; b < c; b++){
delay(1);
noInterrupts();
MCUSR &= ~_BV(WDRF);
WDTCSR = _BV(WDCE) | _BV(WDE);
WDTCSR = 0;
interrupts();
}
}

Any ideas?

  for (b = 0; b < c; b++){
    delay(1);
    noInterrupts();
    MCUSR  &= ~_BV(WDRF);
    WDTCSR  =  _BV(WDCE) | _BV(WDE);
    WDTCSR  = 0;   
    interrupts();
  }

How many times do you need to set up the watchdog? Any answer other than one is WRONG.

Why do you need to delay() some variable amount of time? Why do you need to delay at all?

If you REALLY must delay some random amount of time, why can't you do that BEFORE you set up the watchdog?

The whole project will be a set of candles, showing a semi-realistic flame on a LED matrix. Since every candle runs the same program they should not all start at the same frame. One could either choose a random starting frame or simply start the candles one after another but randomly between 0 and the end of the animation (16s). I personally like the second option more, since it may look really cool, when the candles lights up one after another.

firlefranz:
The whole project will be a set of candles, showing a semi-realistic flame on a LED matrix. Since every candle runs the same program they should not all start at the same frame. One could either choose a random starting frame or simply start the candles one after another but randomly between 0 and the end of the animation (16s). I personally like the second option more, since it may look really cool, when the candles lights up one after another.

OK. So, what is the watchdog doing, and why can't you start it snarling after the initial delay?

The watchdog is used on the one hand as interrupt to wake up the Atmega and send a new frame via I2C to the LED driver and on the other hand to restart the Atmega if the sending failed. This happens sometimes, causing the program to freeze.

As a side note: I tried different I2C libraries, but the watchdog was at the end the only solution for this problem. The driver is a IS31FL3731.

Putting the watchdog-definition in the for-statement at the beginning is the first solution I found, where the atmega not keeps freezing.

What PaulS is getting at is that you don't need the watchdog running at all during the initial startup delay. Wait until AFTER you run the start-up delay to enable it.

OR, if you want to go with the solution in reply #1, then first take the code that starts the watchdog out of the for loop, you only need to do that once. Put in the for loop only the line to reset the watchdog, that's the only part you have to do over and over. And make the delay in the for loop almost as long as the watchdog setting. No sense in patting the dog every 1ms if he's not going to bite until 8 seconds.

Surprisingly putting the watchdog definition inside the for statement is the only way that the watchdog works. I really don't know why, but that's what I see here.

This one works:

void setup() {
randomSeed(analogRead(1));
int b;
int c = random(1,10000);
for (b = 0; b < c; b++){
delay(1);
noInterrupts();
MCUSR &= ~_BV(WDRF);
WDTCSR = _BV(WDCE) | _BV(WDE);
WDTCSR = 0;
interrupts();
}
}

This one doesn't:

void setup() {
randomSeed(analogRead(1));
int b;
int c = random(1,10000);
for (b = 0; b < c; b++){
delay(1);
}
noInterrupts();
MCUSR &= ~_BV(WDRF);
WDTCSR = _BV(WDCE) | _BV(WDE);
WDTCSR = 0;
interrupts();
}

Any ideas?

What does the second code actually do? The for loop really isn't necessary. delay(c); will work just fine.

When the program runs it can happen from time to time, that the LED driver did not send a proper response that it got the data through the I2C. When this happens the whole program stops. The watchdog then kills it and everything starts by the first frame.
Without putting the watchdog definition inside the for-statement the program does not start from the beginning and just keeps freezing. It freezes because the matrix will just keep the last frame of the animation until it gets a new one.

Here is the complete setup:

void setup() {
randomSeed(analogRead(1));
int b;
int c = random(1,10000);
for (b = 0; b < c; b++){
delay(1);
noInterrupts();
MCUSR &= ~_BV(WDRF);
WDTCSR = _BV(WDCE) | _BV(WDE);
WDTCSR = 0;
interrupts();
}
uint8_t i, j, p, byteCounter, byteCounterB;
uint8_t array13[13] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0};
uint8_t array36[36] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};

power_all_disable();
power_twi_enable();
DIDR0 = 0x0F;
pinMode(3, INPUT);

I2c.setSpeed(1);
I2c.pullup(0);
I2c.timeOut(28); // Set timeout to 28 ms
I2c.begin();

pageSelect(0x0B);
I2c.write(I2C_ADDR1, 0, array13, 13);
for (p = 0; p < 2; p++) {
pageSelect(p);
I2c.write(I2C_ADDR1, 0, array36, 36);
I2c.write(I2C_ADDR1, 0x24, img, 144);
}
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
noInterrupts();
MCUSR &= ~_BV(WDRF);
WDTCSR = _BV(WDCE) | _BV(WDE);
WDTCSR = _BV(WDIE) | _BV(WDP0);
interrupts();
}