diff --git a/epicardium/api/control.c b/epicardium/api/control.c index f599788426eef36c601925f6929bc91e40a83b76..deff433010bf426c1c8a59bcab5450d7787fe55a 100644 --- a/epicardium/api/control.c +++ b/epicardium/api/control.c @@ -9,7 +9,7 @@ #include "tmr.h" static void __core1_init(void); -extern void interrupt_trigger(api_int_id_t id); +extern void interrupt_trigger_sync(api_int_id_t id); struct core1_info { /* Location of core1's interrupt vector table */ @@ -206,8 +206,13 @@ void core1_boot(void) void core1_trigger_reset(void) { - /* Signal core 1 that we intend to load a new payload. */ - interrupt_trigger(EPIC_INT_RESET); + /* + * Signal core 1 that we intend to load a new payload. + * + * This needs to be synchroneous because otherwise we will deadlock + * (Lifecycle task busy-spins and interrupt can never get dispatched). + */ + interrupt_trigger_sync(EPIC_INT_RESET); } void core1_wait_ready(void) diff --git a/epicardium/main.c b/epicardium/main.c index c5e2768c37177f97f6a2388bdfdd8b71f10cd591..89054e9e199f9ade4236e7e270a0068ddec67ce9 100644 --- a/epicardium/main.c +++ b/epicardium/main.c @@ -133,6 +133,16 @@ int main(void) &dispatcher_task_id) != pdPASS) { panic("Failed to create %s task!", "API Dispatcher"); } + /* Interrupts */ + if (xTaskCreate( + vInterruptsTask, + (const char *)"Interrupt Dispatcher", + configMINIMAL_STACK_SIZE, + NULL, + tskIDLE_PRIORITY + 2, + NULL) != pdPASS) { + panic("Failed to create %s task!", "Interrupt Dispatcher"); + } /* BLE */ if (ble_shall_start()) { diff --git a/epicardium/modules/interrupts.c b/epicardium/modules/interrupts.c index e33e35769d887fbcc6eafdf79186e7015f88106c..0ead54fc58b1d6341071cd377a8ab239bbbff8e7 100644 --- a/epicardium/modules/interrupts.c +++ b/epicardium/modules/interrupts.c @@ -1,4 +1,5 @@ #include "modules/mutex.h" +#include "modules/log.h" #include "epicardium.h" #include "api/interrupt-sender.h" #include <assert.h> @@ -14,11 +15,28 @@ struct interrupt_priv { static struct interrupt_priv interrupt_data; static struct mutex interrupt_mutex; +static TaskHandle_t interrupts_task; void interrupt_trigger(api_int_id_t id) { assert(id < EPIC_INT_NUM); + mutex_lock(&interrupt_mutex); + + if (interrupt_data.int_enabled[id]) { + interrupt_data.int_pending[id] = true; + interrupt_data.has_pending = true; + mutex_unlock(&interrupt_mutex); + xTaskNotifyGive(interrupts_task); + } else { + mutex_unlock(&interrupt_mutex); + } +} + +void interrupt_trigger_sync(api_int_id_t id) +{ + assert(id < EPIC_INT_NUM); + mutex_lock(&interrupt_mutex); if (!interrupt_data.int_enabled[id]) goto out; @@ -97,3 +115,42 @@ int epic_interrupt_disable(api_int_id_t int_id) return 0; } /* }}} */ + +void vInterruptsTask(void *pvParameters) +{ + interrupts_task = xTaskGetCurrentTaskHandle(); + + while (true) { + mutex_lock(&interrupt_mutex); + + if (!interrupt_data.has_pending) { + /* Wait for a wakeup event from interrupt_trigger() */ + mutex_unlock(&interrupt_mutex); + ulTaskNotifyTake(pdTRUE, portMAX_DELAY); + mutex_lock(&interrupt_mutex); + } + + while (!api_interrupt_is_ready()) { + mutex_unlock(&interrupt_mutex); + vTaskDelay(pdMS_TO_TICKS(5)); + mutex_lock(&interrupt_mutex); + } + + api_int_id_t current_irq = EPIC_INT_NUM; + for (size_t i = 0; i < EPIC_INT_NUM; i++) { + if (interrupt_data.int_pending[i]) { + current_irq = i; + interrupt_data.int_pending[i] = false; + break; + } + } + + if (current_irq == EPIC_INT_NUM) { + interrupt_data.has_pending = false; + } else if (interrupt_data.int_enabled[current_irq]) { + api_interrupt_trigger(current_irq); + } + + mutex_unlock(&interrupt_mutex); + } +} diff --git a/epicardium/modules/modules.h b/epicardium/modules/modules.h index 534901c5ccb6d82a69b7b314e8f3e85da4916616..c26a1ce6cf7a2480eb982d8b80ab1215d4c06278 100644 --- a/epicardium/modules/modules.h +++ b/epicardium/modules/modules.h @@ -31,9 +31,11 @@ void return_to_menu(void); /* ---------- Interrupts --------------------------------------------------- */ void interrupt_init(void); void interrupt_trigger(api_int_id_t id); +void interrupt_trigger_sync(api_int_id_t id); void interrupt_trigger_unsafe(api_int_id_t id) __attribute__((deprecated( "interrupt_trigger_unsafe() is racy and only exists for legacy code." ))); +void vInterruptsTask(void *pvParameters); /* ---------- Serial ------------------------------------------------------- */ #define SERIAL_READ_BUFFER_SIZE 128