CubeCell-Arduino
CubeCell-Arduino copied to clipboard
Timer Wakeup not happening "on time"
I am using the Timer package as shown in LowPower_WakeUpByTimer.ino. Running on the CubeCell AB02 model, I am getting curious results as to when the timer wakeup interrupt happens from deep sleep (set by lowPowerHandler().
Time of 350 wakes up in 350 msec. Time of 10000 wakes up in 10000 msec. Time of 2345 wakes up in 2000 msec. (!) Time of 10100 wakes up in 10000 msec. (!) Time of 9500 wakes up in 8000 msec. (!!)
At first it appears to round down to the closest multiple of 1000 but the last example proved me wrong.
Bottom line: why doesn't TimerSetValue( &wakeUp, timetillwakeup ); wake up from deep sleep at timetillwakeup +/- 1 msec?
How did you measure this difference? Using the internal millis()
/ micros()
or did you use some kind of external "stopwatch"?
used code like old = millis(); lowPowerHandler(); timeused = millis()-old;
I can create a mini-sketch to demo the problem if need be.
Would be cool if you share that script. I can verify your findings with several boards.
static TimerEvent_t wakeUp;
void onWakeUp() { return; }
void setup() {
Serial.begin(115200); delay(50);
TimerInit(&wakeUp,onWakeUp);
}
void loop() { int sleepTime[] = {123,2345,9500,10000}; for (int i=0; i<4; i++) { int st = sleepTime[i]; TimerSetValue(&wakeUp,st); TimerStart(&wakeUp); int now = millis(); lowPowerHandler(); Serial.printf("Sleep for %d; Slept for %d.\n",st,millis()-now); delay(50); } while(1); //stop } OUTPUT: Sleep for 123; Slept for 124. Sleep for 2345; Slept for 2000. Sleep for 9500; Slept for 8000. Sleep for 10000; Slept for 10000.
Using Heltec HTC-AB02 on Windows; Arduino IDE 2.0
I find the same problem when I use this sort of timing: int oldTime = TimerGetCurrentTime(); ....sleep.... sleptFor = TimerGetElapsedTime(oldTime);
Timer is very busted.
Using the code you provided above I can reproduce your measured Timings using several CubeCell Boards.
What I noticed before is that you'll have to call lowPowerHandler()
at least 6 times for the board to go into low power mode (see this post on the forum). However, they claim this behavior to be fixed. But just to be sure you can use a simple flag and loop to achieve "exact" wakeup timings.
static TimerEvent_t wakeUp;
volatile uint8_t lowpower=0;
void onWakeUp() {
lowpower=0;
}
void setup() {
Serial.begin(115200);
delay(50);
TimerInit(&wakeUp, onWakeUp);
}
void loop() {
uint32_t sleepTime[] = {123, 2345, 9500, 10000};
for (int i = 0; i < 4; i++) {
int st = sleepTime[i];
TimerSetValue(&wakeUp, st);
TimerStart(&wakeUp);
uint32_t startTimeMs = millis();
uint32_t startTimeUs = micros();
// this loop will run 6 times
lowpower=1;
while(lowpower) {
lowPowerHandler();
}
TimerStop(&wakeUp);
Serial.printf("Sleep for %dms;\t Slept for %dms,\t %dus.\n", st, millis() - startTimeMs, micros() - startTimeUs); delay(50);
}
while (1); //stop
}
Output:
02:38:34.137 -> Sleep for 123ms; Slept for 123ms, 124346us.
02:38:36.564 -> Sleep for 2345ms; Slept for 2346ms, 2347024us.
02:38:46.090 -> Sleep for 9500ms; Slept for 9501ms, 9502023us.
02:38:56.154 -> Sleep for 10000ms; Slept for 10000ms, 10000342us.
Slight differences could be caused by the time it takes to print/evaluate the functions. But I think you're already satisfied with that level of accuracy, right?
Because I was also interested in what exactly is going wrong here, I connected the Board to my Otii Arc. I then ran my code from above and measured the power consumption. Apparently, the board wakes up, for a sleep time of more than 2000ms, precisely after the highest multiple of 2000ms, and then sleeps again for the remaining time. This intermediate wakeup won't happen for durations less than 2000ms or for exact multiples of 2000, e.g. 10000ms.
I thought that this may be caused by the LoRa Radio but adding Radio.Sleep( );
in the setup doesn't change this behavior. Unfortunately, I could not find the internal code responsible for managing the Timer / low Power functionality, yet... 🤓
Sleep duration of 3250ms
An intermediate wakeup occurs after 2000ms of sleep. The board continues to sleep for another 1250ms after that.
Intermediate wakeup after 2000ms
Final wakeup after 3250ms
Sleep duration of 9500ms
An intermediate wakeup occurs after 8000ms of sleep. The board continues to sleep for another 1500ms after that.
Intermediate wakeup afte
r 8000ms
Final wakeup after 9500ms
Please don't take the measured currents in the upper right corner of the screenshots as accurate, because I didn't put the measuring intervals exactly in the deep sleep interval. My CubeCell Board Plus that I used here has an average current consumption of 3.12uA at 3.30V.
I don't like the current behavior, since if I say "sleep for 9500ms" I expect that to be the case. But I can see if other timers than just one are started, it is prudent to wake up sooner, so those timers can be triggered. IMHO the "right" way to deal with that is to calculate the soonest next event and wakeup appropriately, not "round to the closest 2000 ms".