Skip to content

Commit fbdb6c7

Browse files
committed
Util Timer no longer uses RTC - works based on estimated time from the hardware timer itself (fix espruino#1749, ref espruino#1444)
1 parent 5c21237 commit fbdb6c7

3 files changed

Lines changed: 51 additions & 23 deletions

File tree

ChangeLog

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
nRF52: Ensure SPI 1 byte DMA errata workaround isn't applied to non-52832 parts
99
nRF52: When outputting assertions, if we have an terminal device (eg LCD) use that
1010
When load(filename) is used, set global variable __FILE__ to the filename
11+
Util Timer no longer uses RTC - works based on estimated time from the hardware timer itself (fix #1749, ref #1444)
1112

1213
2v08 : nRF52: Added option to build in I2C slave support
1314
Fix Tensorflow aiGesture regression from 2v07 (re-add opcodes) (fix #1936)

src/jstimer.c

Lines changed: 49 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,24 @@
1515
#include "jsparse.h"
1616
#include "jsinteractive.h"
1717

18+
/// Data for our tasks (eg when, what they are, etc)
1819
UtilTimerTask utilTimerTasks[UTILTIMERTASK_TASKS];
20+
/// queue beginning (push tasks on here)
1921
volatile unsigned char utilTimerTasksHead = 0;
22+
/// queue end (tasks pop off here as they are complete)
2023
volatile unsigned char utilTimerTasksTail = 0;
2124

22-
25+
/// Is the utility timer actually running?
2326
volatile bool utilTimerOn = false;
27+
2428
unsigned int utilTimerBit;
2529
bool utilTimerInIRQ = false;
2630
unsigned int utilTimerData;
2731
uint16_t utilTimerReload0H, utilTimerReload0L, utilTimerReload1H, utilTimerReload1L;
32+
/// When did the timer last run? This is used for timekeeping. Should be jshGetSystemTime() cropped to 32 bits
33+
volatile int utilTimerTime;
34+
/// When we rescheduled the timer, how far in the future were we meant to get called?
35+
int utilTimerPeriod;
2836

2937

3038
#ifndef SAVE_ON_FLASH
@@ -77,11 +85,19 @@ static inline unsigned char *jstUtilTimerInterruptHandlerByte(UtilTimerTask *tas
7785
#endif
7886

7987
void jstUtilTimerInterruptHandler() {
88+
/* Note: we're using 32 bit times here, even though the real time counter is 64 bit.
89+
* It means when we do compares, we do them by first subtracting 'utilTimerTime'
90+
* which means that even if the numbers overflow, they will still be correct relative
91+
* to each other.
92+
*/
93+
jshPinOutput(31,1);
8094
if (utilTimerOn) {
8195
utilTimerInIRQ = true;
82-
JsSysTime time = jshGetSystemTime();
96+
// Increment estimated timer time
97+
// TODO: use SysTick to estimate time in this fn and update utilTimerTime accordingly
98+
utilTimerTime += utilTimerPeriod;
8399
// execute any timers that are due
84-
while (utilTimerTasksTail!=utilTimerTasksHead && utilTimerTasks[utilTimerTasksTail].time <= time) {
100+
while (utilTimerTasksTail!=utilTimerTasksHead && (utilTimerTasks[utilTimerTasksTail].time - utilTimerTime)<=0) {
85101
UtilTimerTask *task = &utilTimerTasks[utilTimerTasksTail];
86102
void (*executeFn)(JsSysTime time, void* userdata) = 0;
87103
void *executeData = 0;
@@ -150,15 +166,14 @@ void jstUtilTimerInterruptHandler() {
150166
}
151167
// If we need to repeat
152168
if (task->repeatInterval) {
153-
// update time (we know time > task->time) - what if we're being asked to do too fast? skip one (or 500 :)
154-
unsigned int t = ((unsigned int)(time+task->repeatInterval - task->time)) / task->repeatInterval;
155-
if (t<1) t=1;
156-
task->time = task->time + (JsSysTime)task->repeatInterval*t;
169+
// update time (we know time > task->time)
170+
task->time += task->repeatInterval;
171+
157172
// do an in-place bubble sort to ensure that times are still in the right order
158173
unsigned char ta = utilTimerTasksTail;
159174
unsigned char tb = (ta+1) & (UTILTIMERTASK_TASKS-1);
160175
while (tb != utilTimerTasksHead) {
161-
if (utilTimerTasks[ta].time > utilTimerTasks[tb].time) {
176+
if ((utilTimerTasks[ta].time-utilTimerTime) > (utilTimerTasks[tb].time-utilTimerTime)) {
162177
UtilTimerTask task = utilTimerTasks[ta];
163178
utilTimerTasks[ta] = utilTimerTasks[tb];
164179
utilTimerTasks[tb] = task;
@@ -172,12 +187,14 @@ void jstUtilTimerInterruptHandler() {
172187
}
173188

174189
// execute the function if we had one (we do this now, because if we did it earlier we'd have to cope with everything changing)
175-
if (executeFn) executeFn(time, executeData);
190+
if (executeFn) executeFn(jshGetSystemTime(), executeData);
176191
}
177192

178193
// re-schedule the timer if there is something left to do
179194
if (utilTimerTasksTail != utilTimerTasksHead) {
180-
jshUtilTimerReschedule(utilTimerTasks[utilTimerTasksTail].time - time);
195+
utilTimerPeriod = utilTimerTasks[utilTimerTasksTail].time - utilTimerTime;
196+
if (utilTimerPeriod<0) utilTimerPeriod=0;
197+
jshUtilTimerReschedule(utilTimerPeriod);
181198
} else {
182199
utilTimerOn = false;
183200
jshUtilTimerDisable();
@@ -187,6 +204,7 @@ void jstUtilTimerInterruptHandler() {
187204
// Nothing left to do - disable the timer
188205
jshUtilTimerDisable();
189206
}
207+
jshPinOutput(31,0);
190208
}
191209

192210
/// Return true if the utility timer is running
@@ -207,7 +225,10 @@ static bool utilTimerIsFull() {
207225
/* Restart the utility timer with the right period. This should not normally
208226
need to be called by anything outside jstimer.c */
209227
void jstRestartUtilTimer() {
210-
jshUtilTimerStart(utilTimerTasks[utilTimerTasksTail].time - jshGetSystemTime());
228+
utilTimerTime = (int)jshGetSystemTime();
229+
utilTimerPeriod = utilTimerTasks[utilTimerTasksTail].time - utilTimerTime;
230+
if (utilTimerPeriod<0) utilTimerPeriod=0;
231+
jshUtilTimerStart(utilTimerPeriod);
211232
}
212233

213234
// Queue a task up to be executed when a timer fires... return false on failure
@@ -347,7 +368,7 @@ bool jstGetLastBufferTimerTask(JsVar *var, UtilTimerTask *task) {
347368
bool jstPinOutputAtTime(JsSysTime time, Pin *pins, int pinCount, uint8_t value) {
348369
assert(pinCount<=UTILTIMERTASK_PIN_COUNT);
349370
UtilTimerTask task;
350-
task.time = time;
371+
task.time = (int)time;
351372
task.repeatInterval = 0;
352373
task.type = UET_SET;
353374
int i;
@@ -415,12 +436,11 @@ bool jstPinPWM(JsVarFloat freq, JsVarFloat dutyCycle, Pin pin) {
415436
while (utilTimerRemoveTask(jstPinTaskChecker, (void*)&pin));
416437
}
417438
JsSysTime time = jshGetSystemTime();
418-
419439
UtilTimerTask taskon, taskoff;
420440
taskon.data.set.value = 1;
421441
taskoff.data.set.value = 0;
422-
taskon.time = time;
423-
taskoff.time = time + pulseLength;
442+
taskon.time = (int)time;
443+
taskoff.time = (int)(time + pulseLength);
424444
taskon.repeatInterval = (unsigned int)period;
425445
taskoff.repeatInterval = (unsigned int)period;
426446
taskon.type = UET_SET;
@@ -442,7 +462,7 @@ bool jstPinPWM(JsVarFloat freq, JsVarFloat dutyCycle, Pin pin) {
442462
/// Execute the given function repeatedly after the given time period
443463
bool jstExecuteFn(UtilTimerTaskExecFn fn, void *userdata, JsSysTime startTime, uint32_t period) {
444464
UtilTimerTask task;
445-
task.time = startTime;
465+
task.time = (int)startTime;
446466
task.repeatInterval = period;
447467
task.type = UET_EXECUTE;
448468
task.data.execute.fn = fn;
@@ -463,12 +483,12 @@ bool jstStopExecuteFn(UtilTimerTaskExecFn fn, void *userdata) {
463483
/// Set the utility timer so we're woken up in whatever time period
464484
bool jstSetWakeUp(JsSysTime period) {
465485
UtilTimerTask task;
466-
task.time = jshGetSystemTime() + period;
486+
task.time = (int)(jshGetSystemTime() + period);
467487
task.repeatInterval = 0;
468488
task.type = UET_WAKEUP;
469489

470490
bool hasTimer = false;
471-
JsSysTime nextTime;
491+
int nextTime;
472492

473493
// work out if we're waiting for a timer,
474494
// and if so, when it's going to be
@@ -479,7 +499,7 @@ bool jstSetWakeUp(JsSysTime period) {
479499
}
480500
jshInterruptOn();
481501

482-
if (hasTimer && task.time >= nextTime) {
502+
if (hasTimer && (task.time-utilTimerTime) >= (nextTime-utilTimerTime)) {
483503
// we already had a timer, and it's going to wake us up sooner.
484504
// don't create a WAKEUP timer task
485505
return true;
@@ -516,7 +536,7 @@ bool jstStartSignal(JsSysTime startTime, JsSysTime period, Pin pin, JsVar *curre
516536
if (!jshIsPinValid(pin)) return false;
517537
UtilTimerTask task;
518538
task.repeatInterval = (unsigned int)period;
519-
task.time = startTime + period;
539+
task.time = (int)(startTime + period);
520540
task.type = type;
521541
if (UET_IS_BUFFER_WRITE_EVENT(type)) {
522542
task.data.buffer.pinFunction = jshGetCurrentPinFunction(pin);
@@ -556,6 +576,8 @@ bool jstStopBufferTimerTask(JsVar *var) {
556576
void jstReset() {
557577
jshUtilTimerDisable();
558578
utilTimerTasksTail = utilTimerTasksHead = 0;
579+
utilTimerTime = (int)jshGetSystemTime();
580+
utilTimerPeriod = 0;
559581
}
560582

561583
/** when system time is changed, also change the time in the timers.
@@ -566,6 +588,7 @@ void jstSystemTimeChanged(JsSysTime diff) {
566588
utilTimerTasks[t].time += diff;
567589
t = (t+1) & (UTILTIMERTASK_TASKS-1);
568590
}
591+
utilTimerTime += diff;
569592
}
570593

571594
void jstDumpUtilityTimers() {
@@ -576,23 +599,26 @@ void jstDumpUtilityTimers() {
576599
uTimerTasks[i] = utilTimerTasks[i];
577600
unsigned char uTimerTasksHead = utilTimerTasksHead;
578601
unsigned char uTimerTasksTail = utilTimerTasksTail;
602+
int uTimerTime = utilTimerTime;
579603
jshInterruptOn();
580604

605+
jsiConsolePrintf("Current timer difference %d us", (int)(1000*jshGetMillisecondsFromTime(jshGetSystemTime()-uTimerTime)));
581606
unsigned char t = uTimerTasksTail;
582607
bool hadTimers = false;
583608
while (t!=uTimerTasksHead) {
584609
hadTimers = true;
585610

586611
UtilTimerTask task = uTimerTasks[t];
587-
jsiConsolePrintf("%08d us", (int)(1000*jshGetMillisecondsFromTime(task.time-jsiLastIdleTime)));
612+
jsiConsolePrintf("%08d us", (int)(1000*jshGetMillisecondsFromTime(task.time-uTimerTime)));
588613
jsiConsolePrintf(", repeat %08d us", (int)(1000*jshGetMillisecondsFromTime(task.repeatInterval)));
589614
jsiConsolePrintf(" : ");
590615

591616
switch (task.type) {
592617
case UET_WAKEUP : jsiConsolePrintf("WAKEUP\n"); break;
593618
case UET_SET : jsiConsolePrintf("SET ");
594619
for (i=0;i<UTILTIMERTASK_PIN_COUNT;i++)
595-
jsiConsolePrintf("%p=%d,", task.data.set.pins[i], (task.data.set.value>>i)&1);
620+
if (task.data.set.pins[i] != PIN_UNDEFINED)
621+
jsiConsolePrintf("%p=%d,", task.data.set.pins[i], (task.data.set.value>>i)&1);
596622
jsiConsolePrintf("\n");
597623
break;
598624
#ifndef SAVE_ON_FLASH
@@ -609,4 +635,5 @@ void jstDumpUtilityTimers() {
609635
}
610636
if (!hadTimers)
611637
jsiConsolePrintf("No Timers found.\n");
638+
612639
}

src/jstimer.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ typedef union UtilTimerTaskData {
8989
} UtilTimerTaskData;
9090

9191
typedef struct UtilTimerTask {
92-
JsSysTime time; // time at which to set pins
92+
int time; // time at which to set pins (JshSysTime, cropped to 32 bits)
9393
unsigned int repeatInterval; // if nonzero, repeat the timer
9494
UtilTimerTaskData data; // data used when timer is hit
9595
UtilTimerEventType type; // the type of this task - do we set pin(s) or read/write data

0 commit comments

Comments
 (0)