1515#include "jsparse.h"
1616#include "jsinteractive.h"
1717
18+ /// Data for our tasks (eg when, what they are, etc)
1819UtilTimerTask utilTimerTasks [UTILTIMERTASK_TASKS ];
20+ /// queue beginning (push tasks on here)
1921volatile unsigned char utilTimerTasksHead = 0 ;
22+ /// queue end (tasks pop off here as they are complete)
2023volatile unsigned char utilTimerTasksTail = 0 ;
2124
22-
25+ /// Is the utility timer actually running?
2326volatile bool utilTimerOn = false;
27+
2428unsigned int utilTimerBit ;
2529bool utilTimerInIRQ = false;
2630unsigned int utilTimerData ;
2731uint16_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
7987void 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
208226need to be called by anything outside jstimer.c */
209227void 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) {
347368bool 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
443463bool 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
464484bool 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) {
556576void 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
571594void 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}
0 commit comments