Browse Source

Reduce MillisTimer interrupt disable time

teensy4-core
PaulStoffregen 7 years ago
parent
commit
8ee4381890
2 changed files with 65 additions and 31 deletions
  1. +55
    -28
      teensy3/EventResponder.cpp
  2. +10
    -3
      teensy3/EventResponder.h

+ 55
- 28
teensy3/EventResponder.cpp View File

//------------------------------------------------------------- //-------------------------------------------------------------




MillisTimer * MillisTimer::list = nullptr;
MillisTimer * MillisTimer::listWaiting = nullptr;
MillisTimer * MillisTimer::listActive = nullptr;


void MillisTimer::begin(unsigned long milliseconds, EventResponderRef event) void MillisTimer::begin(unsigned long milliseconds, EventResponderRef event)
{ {
end();
if (_state != TimerOff) end();
if (!milliseconds) return; if (!milliseconds) return;
_event = &event; _event = &event;
_ms = milliseconds; _ms = milliseconds;
_reload = 0; _reload = 0;
addToList();
addToWaitingList();
} }


void MillisTimer::beginRepeating(unsigned long milliseconds, EventResponderRef event) void MillisTimer::beginRepeating(unsigned long milliseconds, EventResponderRef event)
{ {
end();
if (_state != TimerOff) end();
if (!milliseconds) return; if (!milliseconds) return;
_event = &event; _event = &event;
_ms = milliseconds; _ms = milliseconds;
_reload = milliseconds; _reload = milliseconds;
addToList();
addToWaitingList();
} }


void MillisTimer::addToList()
void MillisTimer::addToWaitingList()
{ {
_prev = nullptr;
bool irq = disableTimerInterrupt(); bool irq = disableTimerInterrupt();
if (list == nullptr) {
_next = listWaiting;
listWaiting = this; // TODO: use STREX to avoid interrupt disable
enableTimerInterrupt(irq);
}

void MillisTimer::addToActiveList() // only called by runFromTimer()
{
if (listActive == nullptr) {
// list is empty, easy case // list is empty, easy case
_next = nullptr; _next = nullptr;
_prev = nullptr; _prev = nullptr;
list = this;
} else if (_ms < list->_ms) {
listActive = this;
} else if (_ms < listActive->_ms) {
// this timer triggers before any on the list // this timer triggers before any on the list
_next = list;
_next = listActive;
_prev = nullptr; _prev = nullptr;
list->_prev = this;
list = this;
listActive->_prev = this;
listActive = this;
} else { } else {
// add this timer somewhere after the first already on the list // add this timer somewhere after the first already on the list
MillisTimer *timer = list;
MillisTimer *timer = listActive;
while (timer->_next) { while (timer->_next) {
_ms -= timer->_ms; _ms -= timer->_ms;
timer = timer->_next; timer = timer->_next;
_prev = timer->_prev; _prev = timer->_prev;
timer->_prev = this; timer->_prev = this;
_prev->_next = this; _prev->_next = this;
isQueued = true;
enableTimerInterrupt(irq);
_state = TimerActive;
return; return;
} }
} }
_prev = timer; _prev = timer;
timer->_next = this; timer->_next = this;
} }
isQueued = true;
enableTimerInterrupt(irq);
_state = TimerActive;
} }


void MillisTimer::end() void MillisTimer::end()
{ {
bool irq = disableTimerInterrupt(); bool irq = disableTimerInterrupt();
if (isQueued) {
TimerStateType s = _state;
if (s == TimerActive) {
if (_next) { if (_next) {
_next->_prev = _prev; _next->_prev = _prev;
} }
if (_prev) { if (_prev) {
_prev->_next = _next; _prev->_next = _next;
} else { } else {
list = _next;
listActive = _next;
} }
isQueued = false;
_state = TimerOff;
} else if (s == TimerWaiting) {
if (listWaiting == this) {
listWaiting = _next;
} else {
MillisTimer *timer = listWaiting;
while (timer) {
if (timer->_next == this) {
timer->_next = _next;
break;
}
timer = timer->_next;
}
}
_state = TimerOff;
} }
enableTimerInterrupt(irq); enableTimerInterrupt(irq);
} }


void MillisTimer::runFromTimer() void MillisTimer::runFromTimer()
{ {
bool irq = disableTimerInterrupt();
MillisTimer *timer = list;
MillisTimer *timer = listActive;
while (timer) { while (timer) {
if (timer->_ms > 0) { if (timer->_ms > 0) {
timer->_ms--; timer->_ms--;
} else { } else {
MillisTimer *next = timer->_next; MillisTimer *next = timer->_next;
if (next) next->_prev = nullptr; if (next) next->_prev = nullptr;
list = next;
enableTimerInterrupt(irq);
timer->isQueued = false;
listActive = next;
timer->_state = TimerOff;
EventResponderRef event = *(timer->_event); EventResponderRef event = *(timer->_event);
event.triggerEvent(0, timer); event.triggerEvent(0, timer);
if (timer->_reload) { if (timer->_reload) {
timer->_ms = timer->_reload; timer->_ms = timer->_reload;
timer->addToList();
timer->addToActiveList();
} }
irq = disableTimerInterrupt();
timer = list;
timer = listActive;
} }
} }
bool irq = disableTimerInterrupt();
MillisTimer *waiting = listWaiting;
listWaiting = nullptr; // TODO: use STREX to avoid interrupt disable
enableTimerInterrupt(irq); enableTimerInterrupt(irq);
while (waiting) {
MillisTimer *next = waiting->_next;
waiting->addToActiveList();
waiting = next;
}
} }


extern "C" volatile uint32_t systick_millis_count; extern "C" volatile uint32_t systick_millis_count;

+ 10
- 3
teensy3/EventResponder.h View File

void end(); void end();
static void runFromTimer(); static void runFromTimer();
private: private:
void addToList();
void addToWaitingList();
void addToActiveList();
unsigned long _ms = 0; unsigned long _ms = 0;
unsigned long _reload = 0; unsigned long _reload = 0;
MillisTimer *_next = nullptr; MillisTimer *_next = nullptr;
MillisTimer *_prev = nullptr; MillisTimer *_prev = nullptr;
EventResponder *_event = nullptr; EventResponder *_event = nullptr;
bool isQueued = false;
static MillisTimer *list;
enum TimerStateType {
TimerOff = 0,
TimerWaiting,
TimerActive
};
volatile TimerStateType _state = TimerOff;
static MillisTimer *listWaiting; // single linked list of waiting to start timers
static MillisTimer *listActive; // double linked list of running timers
static bool disableTimerInterrupt() { static bool disableTimerInterrupt() {
uint32_t primask; uint32_t primask;
__asm__ volatile("mrs %0, primask\n" : "=r" (primask)::); __asm__ volatile("mrs %0, primask\n" : "=r" (primask)::);

Loading…
Cancel
Save