diff --git a/ports/esp32/esp32_rmt.c b/ports/esp32/esp32_rmt.c index 1a7e77b9d2..941f20818e 100644 --- a/ports/esp32/esp32_rmt.c +++ b/ports/esp32/esp32_rmt.c @@ -27,10 +27,11 @@ #include "py/runtime.h" #include "modmachine.h" #include "mphalport.h" -#include "driver/rmt.h" - #include "modesp32.h" +#include "esp_task.h" +#include "driver/rmt.h" + // This exposes the ESP32's RMT module to MicroPython. RMT is provided by the Espressif ESP-IDF: // // https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/peripherals/rmt.html @@ -59,6 +60,34 @@ typedef struct _esp32_rmt_obj_t { bool loop_en; } esp32_rmt_obj_t; +typedef struct _rmt_install_state_t { + SemaphoreHandle_t handle; + uint8_t channel_id; + esp_err_t ret; +} rmt_install_state_t; + +STATIC void rmt_install_task(void *pvParameter) { + rmt_install_state_t *state = pvParameter; + state->ret = rmt_driver_install(state->channel_id, 0, 0); + xSemaphoreGive(state->handle); + vTaskDelete(NULL); + for (;;) { + } +} + +// Call rmt_driver_install on core 1. This ensures that the RMT interrupt handler is +// serviced on core 1, so that WiFi (if active) does not interrupt it and cause glitches. +esp_err_t rmt_driver_install_core1(uint8_t channel_id) { + TaskHandle_t th; + rmt_install_state_t state; + state.handle = xSemaphoreCreateBinary(); + state.channel_id = channel_id; + xTaskCreatePinnedToCore(rmt_install_task, "rmt_install_task", 2048 / sizeof(StackType_t), &state, ESP_TASK_PRIO_MIN + 1, &th, 1); + xSemaphoreTake(state.handle, portMAX_DELAY); + vSemaphoreDelete(state.handle); + return state.ret; +} + STATIC mp_obj_t esp32_rmt_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { static const mp_arg_t allowed_args[] = { { MP_QSTR_id, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = -1} }, @@ -125,7 +154,7 @@ STATIC mp_obj_t esp32_rmt_make_new(const mp_obj_type_t *type, size_t n_args, siz config.clk_div = self->clock_div; check_esp_err(rmt_config(&config)); - check_esp_err(rmt_driver_install(config.channel, 0, 0)); + check_esp_err(rmt_driver_install_core1(config.channel)); return MP_OBJ_FROM_PTR(self); } diff --git a/ports/esp32/machine_bitstream.c b/ports/esp32/machine_bitstream.c index 4ba05e8895..5f9eb32c3f 100644 --- a/ports/esp32/machine_bitstream.c +++ b/ports/esp32/machine_bitstream.c @@ -101,7 +101,7 @@ void machine_bitstream_high_low(mp_hal_pin_obj_t pin, uint32_t *timing_ns, const // Install the driver on this channel & pin. check_esp_err(rmt_config(&config)); - check_esp_err(rmt_driver_install(config.channel, 0, 0)); + check_esp_err(rmt_driver_install_core1(config.channel)); // Get the tick rate in kHz (this will likely be 40000). uint32_t counter_clk_khz = 0; diff --git a/ports/esp32/modesp32.h b/ports/esp32/modesp32.h index 86979f0b3e..368b40db04 100644 --- a/ports/esp32/modesp32.h +++ b/ports/esp32/modesp32.h @@ -34,4 +34,6 @@ extern const mp_obj_type_t esp32_ulp_type; // Reserve the last channel for machine.bitstream. #define MICROPY_HW_ESP32_RMT_CHANNEL_BITSTREAM (RMT_CHANNEL_MAX - 1) +esp_err_t rmt_driver_install_core1(uint8_t channel_id); + #endif // MICROPY_INCLUDED_ESP32_MODESP32_H