From 14ab81e87accedfb9ed231b206dd21f3a0143404 Mon Sep 17 00:00:00 2001 From: Nicko van Someren Date: Sun, 1 Jul 2018 20:27:10 -0600 Subject: [PATCH] esp32: Reduce latency for handling of scheduled Python callbacks. Prior to this patch there was a large latency for executing scheduled callbacks when when Python code is sleeping: at the heart of the implementation of sleep_ms() is a call to vTaskDelay(1), which always sleeps for one 100Hz tick, before performing another call to MICROPY_EVENT_POLL_HOOK. This patch fixes this issue by using FreeRTOS Task Notifications to signal the main thread that a new callback is pending. --- ports/esp32/machine_pin.c | 2 ++ ports/esp32/machine_timer.c | 2 ++ ports/esp32/main.c | 4 ++-- ports/esp32/mphalport.c | 16 ++++++++++++++-- ports/esp32/mphalport.h | 8 ++++++++ 5 files changed, 28 insertions(+), 4 deletions(-) diff --git a/ports/esp32/machine_pin.c b/ports/esp32/machine_pin.c index 2a26d6bfb0..0b9150f556 100644 --- a/ports/esp32/machine_pin.c +++ b/ports/esp32/machine_pin.c @@ -33,6 +33,7 @@ #include "py/runtime.h" #include "py/mphal.h" +#include "mphalport.h" #include "modmachine.h" #include "extmod/virtpin.h" #include "machine_rtc.h" @@ -115,6 +116,7 @@ STATIC void IRAM_ATTR machine_pin_isr_handler(void *arg) { machine_pin_obj_t *self = arg; mp_obj_t handler = MP_STATE_PORT(machine_pin_irq_handler)[self->id]; mp_sched_schedule(handler, MP_OBJ_FROM_PTR(self)); + mp_hal_wake_main_task_from_isr(); } gpio_num_t machine_pin_get_id(mp_obj_t pin_in) { diff --git a/ports/esp32/machine_timer.c b/ports/esp32/machine_timer.c index 235a502bd3..eee77e482a 100644 --- a/ports/esp32/machine_timer.c +++ b/ports/esp32/machine_timer.c @@ -34,6 +34,7 @@ #include "py/obj.h" #include "py/runtime.h" #include "modmachine.h" +#include "mphalport.h" #define TIMER_INTR_SEL TIMER_INTR_LEVEL #define TIMER_DIVIDER 40000 @@ -109,6 +110,7 @@ STATIC void machine_timer_isr(void *self_in) { device->hw_timer[self->index].config.alarm_en = self->repeat; mp_sched_schedule(self->callback, self); + mp_hal_wake_main_task_from_isr(); } STATIC void machine_timer_enable(machine_timer_obj_t *self) { diff --git a/ports/esp32/main.c b/ports/esp32/main.c index acbbfdccce..5ef2675de2 100644 --- a/ports/esp32/main.c +++ b/ports/esp32/main.c @@ -131,8 +131,8 @@ soft_reset: void app_main(void) { nvs_flash_init(); - xTaskCreateStaticPinnedToCore(mp_task, "mp_task", MP_TASK_STACK_LEN, NULL, MP_TASK_PRIORITY, - &mp_task_stack[0], &mp_task_tcb, 0); + mp_main_task_handle = xTaskCreateStaticPinnedToCore(mp_task, "mp_task", MP_TASK_STACK_LEN, NULL, MP_TASK_PRIORITY, + &mp_task_stack[0], &mp_task_tcb, 0); } void nlr_jump_fail(void *val) { diff --git a/ports/esp32/mphalport.c b/ports/esp32/mphalport.c index 353e1343b0..aa79c878e5 100644 --- a/ports/esp32/mphalport.c +++ b/ports/esp32/mphalport.c @@ -38,6 +38,9 @@ #include "py/mphal.h" #include "extmod/misc.h" #include "lib/utils/pyexec.h" +#include "mphalport.h" + +TaskHandle_t mp_main_task_handle; STATIC uint8_t stdin_ringbuf_array[256]; ringbuf_t stdin_ringbuf = {stdin_ringbuf_array, sizeof(stdin_ringbuf_array)}; @@ -49,7 +52,7 @@ int mp_hal_stdin_rx_chr(void) { return c; } MICROPY_EVENT_POLL_HOOK - vTaskDelay(1); + ulTaskNotifyTake(pdFALSE, 1); } } @@ -106,7 +109,7 @@ void mp_hal_delay_ms(uint32_t ms) { break; } MICROPY_EVENT_POLL_HOOK - vTaskDelay(1); + ulTaskNotifyTake(pdFALSE, 1); } if (dt < us) { // do the remaining delay accurately @@ -154,3 +157,12 @@ int *__errno() { return &mp_stream_errno; } */ + +// Wake up the main task if it is sleeping +void mp_hal_wake_main_task_from_isr(void) { + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + vTaskNotifyGiveFromISR(mp_main_task_handle, &xHigherPriorityTaskWoken); + if (xHigherPriorityTaskWoken == pdTRUE) { + portYIELD_FROM_ISR(); + } +} diff --git a/ports/esp32/mphalport.h b/ports/esp32/mphalport.h index 3215bc062c..b829627792 100644 --- a/ports/esp32/mphalport.h +++ b/ports/esp32/mphalport.h @@ -32,6 +32,11 @@ #include "py/ringbuf.h" #include "lib/utils/interrupt_char.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +extern TaskHandle_t mp_main_task_handle; + extern ringbuf_t stdin_ringbuf; uint32_t mp_hal_ticks_us(void); @@ -49,6 +54,9 @@ uint32_t mp_hal_get_cpu_freq(void); #define mp_hal_quiet_timing_enter() MICROPY_BEGIN_ATOMIC_SECTION() #define mp_hal_quiet_timing_exit(irq_state) MICROPY_END_ATOMIC_SECTION(irq_state) +// Wake up the main task if it is sleeping +void mp_hal_wake_main_task_from_isr(void); + // C-level pin HAL #include "py/obj.h" #include "driver/gpio.h"