diff options
author | Damien George <damien.p.george@gmail.com> | 2019-02-08 01:11:21 +1100 |
---|---|---|
committer | Damien George <damien.p.george@gmail.com> | 2019-02-08 01:20:13 +1100 |
commit | 18cfa156d628873dfe0e12bcaad19bd802f32994 (patch) | |
tree | b86a22b92601ea3509c8dd2e9f6fdfef54cc8ada | |
parent | b178958c0799f16847a70c7a5c717a39528407ec (diff) |
stm32/pendsv: Add ability to schedule callbacks at pendsv IRQ level.
-rw-r--r-- | ports/stm32/pendsv.c | 40 | ||||
-rw-r--r-- | ports/stm32/pendsv.h | 5 |
2 files changed, 45 insertions, 0 deletions
diff --git a/ports/stm32/pendsv.c b/ports/stm32/pendsv.c index a6a9afc14..6c6b3c7bf 100644 --- a/ports/stm32/pendsv.c +++ b/ports/stm32/pendsv.c @@ -38,7 +38,15 @@ // mp_kbd_exception which is in the root-pointer set. void *pendsv_object; +#if PENDSV_DISPATCH_NUM_SLOTS > 0 +uint32_t pendsv_dispatch_active; +pendsv_dispatch_t pendsv_dispatch_table[PENDSV_DISPATCH_NUM_SLOTS]; +#endif + void pendsv_init(void) { + #if PENDSV_DISPATCH_NUM_SLOTS > 0 + pendsv_dispatch_active = false; + #endif // set PendSV interrupt at lowest priority NVIC_SetPriority(PendSV_IRQn, IRQ_PRI_PENDSV); } @@ -61,6 +69,23 @@ void pendsv_kbd_intr(void) { } } +#if PENDSV_DISPATCH_NUM_SLOTS > 0 +void pendsv_schedule_dispatch(size_t slot, pendsv_dispatch_t f) { + pendsv_dispatch_table[slot] = f; + pendsv_dispatch_active = true; + SCB->ICSR = SCB_ICSR_PENDSVSET_Msk; +} + +void pendsv_dispatch_handler(void) { + for (size_t i = 0; i < PENDSV_DISPATCH_NUM_SLOTS; ++i) { + if (pendsv_dispatch_table[i] != NULL) { + pendsv_dispatch_table[i] = NULL; + pendsv_dispatch_table[i](); + } + } +} +#endif + __attribute__((naked)) void PendSV_Handler(void) { // Handle a PendSV interrupt // @@ -94,6 +119,18 @@ __attribute__((naked)) void PendSV_Handler(void) { // sp[0]: ? __asm volatile ( + #if PENDSV_DISPATCH_NUM_SLOTS > 0 + // Check if there are any pending calls to dispatch to + "ldr r1, pendsv_dispatch_active_ptr\n" + "ldr r0, [r1]\n" + "cmp r0, 0\n" + "beq .no_dispatch\n" + "mov r2, #0\n" + "str r2, [r1]\n" // clear pendsv_dispatch_active + "b pendsv_dispatch_handler\n" // jump to the handler + ".no_dispatch:\n" + #endif + // Check if there is an active object to throw via nlr_jump "ldr r1, pendsv_object_ptr\n" "ldr r0, [r1]\n" @@ -137,6 +174,9 @@ __attribute__((naked)) void PendSV_Handler(void) { // Data ".align 2\n" + #if PENDSV_DISPATCH_NUM_SLOTS > 0 + "pendsv_dispatch_active_ptr: .word pendsv_dispatch_active\n" + #endif "pendsv_object_ptr: .word pendsv_object\n" "nlr_jump_ptr: .word nlr_jump\n" ); diff --git a/ports/stm32/pendsv.h b/ports/stm32/pendsv.h index 52ce80536..c8cc64d76 100644 --- a/ports/stm32/pendsv.h +++ b/ports/stm32/pendsv.h @@ -26,7 +26,12 @@ #ifndef MICROPY_INCLUDED_STM32_PENDSV_H #define MICROPY_INCLUDED_STM32_PENDSV_H +#define PENDSV_DISPATCH_NUM_SLOTS (0) + +typedef void (*pendsv_dispatch_t)(void); + void pendsv_init(void); void pendsv_kbd_intr(void); +void pendsv_schedule_dispatch(size_t slot, pendsv_dispatch_t f); #endif // MICROPY_INCLUDED_STM32_PENDSV_H |