_prev->_next = this; | _prev->_next = this; | ||||
lastYield = this; | lastYield = this; | ||||
} | } | ||||
_pending = true; | |||||
} else if (_type == EventTypeInterrupt) { | } else if (_type == EventTypeInterrupt) { | ||||
// interrupt, called from software interrupt | // interrupt, called from software interrupt | ||||
if (firstInterrupt == nullptr) { | if (firstInterrupt == nullptr) { | ||||
_prev->_next = this; | _prev->_next = this; | ||||
lastInterrupt = this; | lastInterrupt = this; | ||||
} | } | ||||
// TODO set interrupt pending | |||||
_pending = true; | |||||
SCB_ICSR = SCB_ICSR_PENDSVSET; // set PendSV interrupt | |||||
} else { | } else { | ||||
// detached, easy :-) | // detached, easy :-) | ||||
_pending = true; | |||||
} | } | ||||
_pending = true; | |||||
} | } | ||||
void pendablesrvreq_isr(void) | void pendablesrvreq_isr(void) | ||||
void EventResponder::runFromInterrupt() | void EventResponder::runFromInterrupt() | ||||
{ | { | ||||
// FIXME: this will fail if the handler function triggers | |||||
// its own or other EventResponder instances. The list will | |||||
// change while we're holding a pointers to it. | |||||
for (EventResponder *first=firstInterrupt; first; first = first->_next) { | |||||
first->_pending = false; | |||||
(*(first->_function))(*first); | |||||
while (1) { | |||||
EventResponder *first = firstInterrupt; | |||||
if (first) { | |||||
firstInterrupt = first->_next; | |||||
if (firstInterrupt) { | |||||
firstInterrupt->_prev = nullptr; | |||||
} else { | |||||
lastInterrupt = nullptr; | |||||
} | |||||
first->_pending = false; | |||||
(*(first->_function))(*first); | |||||
} else { | |||||
break; | |||||
} | |||||
} | } | ||||
firstInterrupt = nullptr; | |||||
lastInterrupt = nullptr; | |||||
} | } | ||||
bool EventResponder::clearEvent() | bool EventResponder::clearEvent() |
detach(); | detach(); | ||||
_function = function; | _function = function; | ||||
_type = EventTypeInterrupt; | _type = EventTypeInterrupt; | ||||
// TODO: configure PendSV | |||||
SCB_SHPR3 |= 0x00FF0000; // configure PendSV, lowest priority | |||||
} | } | ||||
// Attach a function to be called as its own thread. Boards not running | // Attach a function to be called as its own thread. Boards not running | ||||
static void runFromYield() { | static void runFromYield() { | ||||
EventResponder *first = firstYield; | EventResponder *first = firstYield; | ||||
// FIXME: also check if yield() called from an interrupt | |||||
// never run these functions from any interrupt context | |||||
if (first && !runningFromYield) { | if (first && !runningFromYield) { | ||||
runningFromYield = true; | runningFromYield = true; | ||||
firstYield = first->_next; | firstYield = first->_next; |
// System Control Space (SCS), ARMv7 ref manual, B3.2, page 708 | // System Control Space (SCS), ARMv7 ref manual, B3.2, page 708 | ||||
#define SCB_CPUID (*(const uint32_t *)0xE000ED00) // CPUID Base Register | #define SCB_CPUID (*(const uint32_t *)0xE000ED00) // CPUID Base Register | ||||
#define SCB_ICSR (*(volatile uint32_t *)0xE000ED04) // Interrupt Control and State | #define SCB_ICSR (*(volatile uint32_t *)0xE000ED04) // Interrupt Control and State | ||||
#define SCB_ICSR_NMIPENDSET ((uint32_t)0x80000000) | |||||
#define SCB_ICSR_PENDSVSET ((uint32_t)0x10000000) | |||||
#define SCB_ICSR_PENDSVCLR ((uint32_t)0x08000000) | |||||
#define SCB_ICSR_PENDSTSET ((uint32_t)0x04000000) | #define SCB_ICSR_PENDSTSET ((uint32_t)0x04000000) | ||||
#define SCB_ICSR_PENDSTCLR ((uint32_t)0x02000000) | |||||
#define SCB_ICSR_ISRPREEMPT ((uint32_t)0x00800000) | |||||
#define SCB_ICSR_ISRPENDING ((uint32_t)0x00400000) | |||||
#define SCB_ICSR_RETTOBASE ((uint32_t)0x00000800) | |||||
#define SCB_VTOR (*(volatile uint32_t *)0xE000ED08) // Vector Table Offset | #define SCB_VTOR (*(volatile uint32_t *)0xE000ED08) // Vector Table Offset | ||||
#define SCB_AIRCR (*(volatile uint32_t *)0xE000ED0C) // Application Interrupt and Reset Control | #define SCB_AIRCR (*(volatile uint32_t *)0xE000ED0C) // Application Interrupt and Reset Control | ||||
#define SCB_SCR (*(volatile uint32_t *)0xE000ED10) // System Control Register | #define SCB_SCR (*(volatile uint32_t *)0xE000ED10) // System Control Register |