Stop the utility timer queue filling with WAKEUP tasks if Espruino gets woken up early

This commit is contained in:
Gordon Williams 2014-07-05 14:45:16 +01:00
parent 814f29c547
commit 5e1b2118cd
7 changed files with 104 additions and 4 deletions

View File

@ -3,6 +3,7 @@
Fixed exception catching
Fix Serial1 initialisation after 'reset()'
Fix parsing of try..catch when a serious error (not an exception) occurred
Stop the utility timer queue filling with WAKEUP tasks if Espruino gets woken up early
1v66 : Ensure that analogWrite(pin,1) works on negated outputs
Allow multiple Waveform playback on one pin (+ wave fixes)

View File

@ -234,6 +234,10 @@ else:
bufferSizeIO = 64 if board.chip["ram"]<20 else 128
bufferSizeTX = 32 if board.chip["ram"]<20 else 128
bufferSizeTimer = 4 if board.chip["ram"]<20 else 16
if 'util_timer_tasks' in board.info:
bufferSizeTimer = board.info['util_timer_tasks']
codeOut("#define IOBUFFERMASK "+str(bufferSizeIO-1)+" // (max 255) amount of items in event buffer - events take ~9 bytes each")
codeOut("#define TXBUFFERMASK "+str(bufferSizeTX-1)+" // (max 255)")
codeOut("#define UTILTIMERTASK_TASKS ("+str(bufferSizeTimer)+") // Must be power of 2 - and max 256")

View File

@ -13,6 +13,7 @@
*/
#include "jstimer.h"
#include "jsparse.h"
#include "jsinteractive.h"
UtilTimerTask utilTimerTasks[UTILTIMERTASK_TASKS];
volatile unsigned char utilTimerTasksHead = 0;
@ -279,14 +280,51 @@ bool jstPinOutputAtTime(JsSysTime time, Pin *pins, int pinCount, uint8_t value)
/// Set the utility timer so we're woken up in whatever time period
bool jstSetWakeUp(JsSysTime period) {
UtilTimerTask task;
task.repeatInterval = 0;
task.time = jshGetSystemTime() + period;
task.repeatInterval = 0;
task.type = UET_WAKEUP;
bool hasTimer = false;
JsSysTime nextTime;
// work out if we're waiting for a timer,
// and if so, when it's going to be
jshInterruptOff();
if (utilTimerTasksTail!=utilTimerTasksHead) {
hasTimer = true;
nextTime = utilTimerTasks[utilTimerTasksTail].time;
}
jshInterruptOn();
if (hasTimer && task.time >= nextTime) {
// we already had a timer, and it's going to wake us up sooner.
// don't create a WAKEUP timer task
return true;
}
bool ok = utilTimerInsertTask(&task);
// We wait until the timer is out of the reload event, because the reload event itself would wake us up
return ok;
}
/** If the first timer task is a wakeup task, remove it. This stops
* us filling the timer full of wakeup events if we wake up from sleep
* before the wakeup event */
void jstClearWakeUp() {
bool removedTimer = false;
jshInterruptOff();
// while the first item is a wakeup, remove it
while (utilTimerTasksTail!=utilTimerTasksHead &&
utilTimerTasks[utilTimerTasksTail].type == UET_WAKEUP) {
utilTimerTasksTail = (utilTimerTasksTail+1) & (UTILTIMERTASK_TASKS-1);
removedTimer = true;
}
// if the queue is now empty, and we stop the timer
if (utilTimerTasksTail==utilTimerTasksHead && removedTimer)
jshUtilTimerDisable();
jshInterruptOn();
}
#ifndef SAVE_ON_FLASH
bool jstStartSignal(JsSysTime startTime, JsSysTime period, Pin pin, JsVar *currentData, JsVar *nextData, UtilTimerEventType type) {
if (!jshIsPinValid(pin)) return false;
@ -332,7 +370,7 @@ bool jstStopBufferTimerTask(JsVar *var) {
if (UET_IS_BUFFER_EVENT(utilTimerTasks[ptr].type)) {
if (utilTimerTasks[ptr].data.buffer.currentBuffer==ref || utilTimerTasks[ptr].data.buffer.nextBuffer==ref) {
// shift tail back along
int next = (ptr+UTILTIMERTASK_TASKS-1) & (UTILTIMERTASK_TASKS-1);
unsigned char next = (ptr+UTILTIMERTASK_TASKS-1) & (UTILTIMERTASK_TASKS-1);
while (next!=endPtr) {
utilTimerTasks[ptr] = utilTimerTasks[next];
ptr = next;
@ -356,3 +394,37 @@ void jstReset() {
jshUtilTimerDisable();
utilTimerTasksTail = utilTimerTasksHead = 0;
}
void jstDumpUtilityTimers() {
int i;
UtilTimerTask uTimerTasks[UTILTIMERTASK_TASKS];
jshInterruptOff();
for (i=0;i<UTILTIMERTASK_TASKS;i++)
uTimerTasks[i] = utilTimerTasks[i];
unsigned char uTimerTasksHead = utilTimerTasksHead;
unsigned char uTimerTasksTail = utilTimerTasksTail;
jshInterruptOn();
unsigned char t = uTimerTasksTail;
while (t!=uTimerTasksHead) {
UtilTimerTask task = uTimerTasks[t];
jsiConsolePrintf("%08d us : ", (int)(1000*jshGetMillisecondsFromTime(task.time-jsiLastIdleTime)));
switch (task.type) {
case UET_WAKEUP : jsiConsolePrintf("WAKEUP\n"); break;
case UET_SET : jsiConsolePrintf("SET ");
for (i=0;i<UTILTIMERTASK_PIN_COUNT;i++)
jsiConsolePrintf("%p=%d,", task.data.set.pins[i], (task.data.set.value>>i)&i);
jsiConsolePrintf("\n");
break;
case UET_WRITE_BYTE : jsiConsolePrintf("WRITE_BYTE\n"); break;
case UET_READ_BYTE : jsiConsolePrintf("READ_BYTE\n"); break;
case UET_WRITE_SHORT : jsiConsolePrintf("WRITE_SHORT\n"); break;
case UET_READ_SHORT : jsiConsolePrintf("READ_SHORT\n"); break;
default : jsiConsolePrintf("Unknown type %d\n", task.type); break;
}
t = (t+1) & (UTILTIMERTASK_TASKS-1);
}
}

View File

@ -105,6 +105,11 @@ bool jstPinOutputAtTime(JsSysTime time, Pin *pins, int pinCount, uint8_t value);
/// Set the utility timer so we're woken up in whatever time period
bool jstSetWakeUp(JsSysTime period);
/** If the first timer task is a wakeup task, remove it. This stops
* us filling the timer full of wakeup events if we wake up from sleep
* before the wakeup event */
void jstClearWakeUp();
/// Start writing a string out at the given period between samples
bool jstStartSignal(JsSysTime startTime, JsSysTime period, Pin pin, JsVar *currentData, JsVar *nextData, UtilTimerEventType type);
@ -114,5 +119,8 @@ bool jstStopBufferTimerTask(JsVar *var);
/// Stop ALL timer tasks (including digitalPulse - use this when resetting the VM)
void jstReset();
/// Dump the current list of timers
void jstDumpUtilityTimers();
#endif /* JSTIMER_H_ */

View File

@ -17,6 +17,7 @@
#include "jswrap_math.h"
#include "jswrapper.h"
#include "jsinteractive.h"
#include "jstimer.h"
/*JSON{ "type":"class",
"class" : "E",
@ -497,3 +498,13 @@ int jswrap_espruino_reverseByte(int v) {
return (((b * 0x0802LU & 0x22110LU) | (b * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16) & 0xFF;
}
/*JSON{ "type":"staticmethod",
"class" : "E", "name" : "dumpTimers", "ifndef":"RELEASE",
"description" : ["Output the current list of Utility Timer Tasks - for debugging only"],
"generate" : "jswrap_espruino_dumpTimers"
}*/
void jswrap_espruino_dumpTimers() {
jstDumpUtilityTimers();
}

View File

@ -28,3 +28,4 @@ JsVarFloat jswrap_espruino_interpolate2d(JsVar *array, int width, JsVarFloat x,
void jswrap_espruino_enableWatchdog(JsVarFloat time);
JsVar *jswrap_espruino_toArrayBuffer(JsVar *str);
int jswrap_espruino_reverseByte(int v);
void jswrap_espruino_dumpTimers();

View File

@ -2459,10 +2459,13 @@ bool jshSleep(JsSysTime timeUntilWake) {
// we're going to wake on a System Tick timer anyway, so don't bother
}
// TODO: we can do better than this. look at lastSysTickTime
jsiSetSleep(JSI_SLEEP_ASLEEP);
__WFI(); // Wait for Interrupt
jsiSetSleep(JSI_SLEEP_AWAKE);
/* We may have woken up before the wakeup event. If so
then make sure we clear the event */
jstClearWakeUp();
return true;
}
@ -2600,7 +2603,7 @@ void jshSetOutputValue(JshPinFunction func, int value) {
} else if (JSH_PINFUNCTION_IS_TIMER(func)) {
TIM_TypeDef* TIMx = getTimerFromPinFunction(func);
if (TIMx) {
unsigned int period = (int)TIMx->ARR; // No getter available
unsigned int period = (unsigned int)TIMx->ARR; // No getter available
uint16_t timerVal = (uint16_t)(((unsigned int)value * period) >> 16);
switch (func & JSH_MASK_TIMER_CH) {
case JSH_TIMER_CH1: TIM_SetCompare1(TIMx, timerVal); break;