summaryrefslogtreecommitdiff
path: root/ports
diff options
context:
space:
mode:
Diffstat (limited to 'ports')
-rw-r--r--ports/esp32/boards/ESP32_GENERIC_C5/board.json22
-rw-r--r--ports/esp32/boards/ESP32_GENERIC_C5/board.md2
-rw-r--r--ports/esp32/boards/ESP32_GENERIC_C5/mpconfigboard.cmake10
-rw-r--r--ports/esp32/boards/ESP32_GENERIC_C5/mpconfigboard.h7
-rw-r--r--ports/esp32/boards/ESP32_GENERIC_C5/sdkconfig.board2
-rw-r--r--ports/esp32/boards/sdkconfig.base1
-rw-r--r--ports/esp32/esp32_common.cmake8
-rw-r--r--ports/esp32/esp32_rmt.c368
-rw-r--r--ports/esp32/lockfiles/dependencies.lock.esp32c521
-rw-r--r--ports/esp32/machine_adc.c7
-rw-r--r--ports/esp32/machine_bitstream.c141
-rw-r--r--ports/esp32/machine_i2c.c11
-rw-r--r--ports/esp32/machine_pin.c7
-rw-r--r--ports/esp32/machine_pin.h26
-rw-r--r--ports/esp32/modesp32.h6
-rw-r--r--ports/esp32/mpconfigport.h2
16 files changed, 429 insertions, 212 deletions
diff --git a/ports/esp32/boards/ESP32_GENERIC_C5/board.json b/ports/esp32/boards/ESP32_GENERIC_C5/board.json
new file mode 100644
index 000000000..371da3929
--- /dev/null
+++ b/ports/esp32/boards/ESP32_GENERIC_C5/board.json
@@ -0,0 +1,22 @@
+{
+ "deploy": [
+ "../deploy.md"
+ ],
+ "deploy_options": {
+ "flash_offset": "0x2000"
+ },
+ "docs": "",
+ "features": [
+ "BLE",
+ "External Flash",
+ "WiFi"
+ ],
+ "images": [
+ "esp32c5_devkitmini.jpg"
+ ],
+ "mcu": "esp32c5",
+ "product": "ESP32-C5",
+ "thumbnail": "",
+ "url": "https://www.espressif.com/en/products/modules",
+ "vendor": "Espressif"
+}
diff --git a/ports/esp32/boards/ESP32_GENERIC_C5/board.md b/ports/esp32/boards/ESP32_GENERIC_C5/board.md
new file mode 100644
index 000000000..82bac44b9
--- /dev/null
+++ b/ports/esp32/boards/ESP32_GENERIC_C5/board.md
@@ -0,0 +1,2 @@
+The following files are firmware images that should work on most ESP32-C5-based
+boards with at least 4MiB of flash and 40MHz/48MHz crystal frequency.
diff --git a/ports/esp32/boards/ESP32_GENERIC_C5/mpconfigboard.cmake b/ports/esp32/boards/ESP32_GENERIC_C5/mpconfigboard.cmake
new file mode 100644
index 000000000..79aba7d47
--- /dev/null
+++ b/ports/esp32/boards/ESP32_GENERIC_C5/mpconfigboard.cmake
@@ -0,0 +1,10 @@
+set(IDF_TARGET esp32c5)
+
+set(SDKCONFIG_DEFAULTS
+ boards/sdkconfig.base
+ boards/sdkconfig.riscv
+ boards/sdkconfig.ble
+ boards/sdkconfig.240mhz
+ boards/sdkconfig.free_ram
+ boards/ESP32_GENERIC_C5/sdkconfig.board
+)
diff --git a/ports/esp32/boards/ESP32_GENERIC_C5/mpconfigboard.h b/ports/esp32/boards/ESP32_GENERIC_C5/mpconfigboard.h
new file mode 100644
index 000000000..552468497
--- /dev/null
+++ b/ports/esp32/boards/ESP32_GENERIC_C5/mpconfigboard.h
@@ -0,0 +1,7 @@
+// This configuration is for a generic ESP32C5 board with 4MiB (or more) of flash.
+
+#define MICROPY_HW_BOARD_NAME "ESP32C5 module"
+#define MICROPY_HW_MCU_NAME "ESP32C5"
+
+#define MICROPY_PY_MACHINE_I2S (0)
+#define MICROPY_HW_ENABLE_UART_REPL (1)
diff --git a/ports/esp32/boards/ESP32_GENERIC_C5/sdkconfig.board b/ports/esp32/boards/ESP32_GENERIC_C5/sdkconfig.board
new file mode 100644
index 000000000..369330682
--- /dev/null
+++ b/ports/esp32/boards/ESP32_GENERIC_C5/sdkconfig.board
@@ -0,0 +1,2 @@
+CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
+CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
diff --git a/ports/esp32/boards/sdkconfig.base b/ports/esp32/boards/sdkconfig.base
index e1b30b8e5..6c8368ac4 100644
--- a/ports/esp32/boards/sdkconfig.base
+++ b/ports/esp32/boards/sdkconfig.base
@@ -124,7 +124,6 @@ CONFIG_UART_ISR_IN_IRAM=y
# IDF 5 deprecated
CONFIG_PCNT_SUPPRESS_DEPRECATE_WARN=y
-CONFIG_RMT_SUPPRESS_DEPRECATE_WARN=y
CONFIG_TOUCH_SUPPRESS_DEPRECATE_WARN=y
CONFIG_ETH_USE_SPI_ETHERNET=y
diff --git a/ports/esp32/esp32_common.cmake b/ports/esp32/esp32_common.cmake
index 79a60adac..6922ac5fe 100644
--- a/ports/esp32/esp32_common.cmake
+++ b/ports/esp32/esp32_common.cmake
@@ -262,6 +262,14 @@ target_compile_options(${MICROPY_TARGET} PUBLIC
target_include_directories(${MICROPY_TARGET} PUBLIC
${IDF_PATH}/components/bt/host/nimble/nimble
)
+if (IDF_VERSION VERSION_LESS "5.3")
+# Additional include directories needed for private RMT header.
+# IDF 5.x versions before 5.3.1
+ message(STATUS "Using private rmt headers for ${IDF_VERSION}")
+ target_include_directories(${MICROPY_TARGET} PRIVATE
+ ${IDF_PATH}/components/driver/rmt
+ )
+endif()
# Add additional extmod and usermod components.
if (MICROPY_PY_BTREE)
diff --git a/ports/esp32/esp32_rmt.c b/ports/esp32/esp32_rmt.c
index f3bfbecdd..85a98c291 100644
--- a/ports/esp32/esp32_rmt.c
+++ b/ports/esp32/esp32_rmt.c
@@ -4,6 +4,7 @@
* The MIT License (MIT)
*
* Copyright (c) 2019 "Matt Trentini" <matt.trentini@gmail.com>
+ * Copyright (c) 2024 "Elvis Pfützenreuter" <elvis.pfutzenreuter@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -26,13 +27,16 @@
#include "py/mphal.h"
#include "py/runtime.h"
+#include "py/stream.h"
#include "modmachine.h"
#include "modesp32.h"
#include "esp_task.h"
#if SOC_RMT_SUPPORTED
-#include "driver/rmt.h"
+#include "esp_clk_tree.h"
+#include "driver/rmt_tx.h"
+#include "driver/rmt_encoder.h"
// This exposes the ESP32's RMT module to MicroPython. RMT is provided by the Espressif ESP-IDF:
//
@@ -46,105 +50,101 @@
// Originally designed to generate infrared remote control signals, the module is very
// flexible and quite easy-to-use.
//
-// This current MicroPython implementation lacks some major features, notably receive pulses
-// and carrier output.
-
-// Last available RMT channel that can transmit.
-#define RMT_LAST_TX_CHANNEL (SOC_RMT_TX_CANDIDATES_PER_GROUP - 1)
+// This code exposes the RMT TX feature.
// Forward declaration
extern const mp_obj_type_t esp32_rmt_type;
typedef struct _esp32_rmt_obj_t {
mp_obj_base_t base;
- uint8_t channel_id;
+ rmt_channel_handle_t channel;
+ bool enabled;
gpio_num_t pin;
- uint8_t clock_div;
- mp_uint_t num_items;
- rmt_item32_t *items;
- bool loop_en;
+ uint32_t clock_freq;
+ int resolution_hz;
+ mp_uint_t cap_items;
+ rmt_symbol_word_t *items;
+ int loop_count;
+ int tx_ongoing;
+
+ rmt_encoder_handle_t encoder;
+ mp_uint_t idle_level;
} esp32_rmt_obj_t;
-// Current channel used for machine.bitstream, in the machine_bitstream_high_low_rmt
-// implementation. A value of -1 means do not use RMT.
-int8_t esp32_rmt_bitstream_channel_id = RMT_LAST_TX_CHANNEL;
-
-#if MP_TASK_COREID == 0
-
-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;
-}
-
-#else
+// Decide RMT usage in the machine_bitstream_high_low_rmt implementation.
+bool esp32_rmt_bitstream_enabled = true;
-// MicroPython runs on core 1, so we can call the RMT installer directly and its
-// interrupt handler will also run on core 1.
-esp_err_t rmt_driver_install_core1(uint8_t channel_id) {
- return rmt_driver_install(channel_id, 0, 0);
+static bool IRAM_ATTR esp32_rmt_tx_trans_done(rmt_channel_handle_t channel, const rmt_tx_done_event_data_t *edata, void *user_ctx) {
+ esp32_rmt_obj_t *self = user_ctx;
+ self->tx_ongoing -= 1;
+ return false;
}
-#endif // MP_TASK_COREID==0
-
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} },
+ { MP_QSTR_id, MP_ARG_INT, {.u_int = -1} },
{ MP_QSTR_pin, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
- { MP_QSTR_clock_div, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} }, // 100ns resolution
+ { MP_QSTR_resolution_hz, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_clock_div, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
{ MP_QSTR_idle_level, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, // low voltage
{ MP_QSTR_tx_carrier, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, // no carrier
+ { MP_QSTR_num_symbols, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = SOC_RMT_MEM_WORDS_PER_CHANNEL} },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
- mp_uint_t channel_id = args[0].u_int;
+ // RMT channel is an opaque struct in current RMT API and channel_id is a dummy parameter
+ // mp_uint_t channel_id = args[0].u_int;
gpio_num_t pin_id = machine_pin_get_id(args[1].u_obj);
- mp_uint_t clock_div = args[2].u_int;
- mp_uint_t idle_level = args[3].u_bool;
- mp_obj_t tx_carrier_obj = args[4].u_obj;
- if (esp32_rmt_bitstream_channel_id >= 0 && channel_id == esp32_rmt_bitstream_channel_id) {
- mp_raise_ValueError(MP_ERROR_TEXT("channel used by bitstream"));
+ uint32_t clock_freq;
+ check_esp_err(esp_clk_tree_src_get_freq_hz(RMT_CLK_SRC_DEFAULT, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &clock_freq));
+
+ mp_uint_t resolution_hz;
+ if (args[2].u_obj != mp_const_none && args[3].u_obj != mp_const_none) {
+ mp_raise_ValueError(MP_ERROR_TEXT("resolution_hz and clock_div are mutually exclusive"));
+ } else if (args[2].u_obj == mp_const_none && args[3].u_obj == mp_const_none) {
+ // default value
+ resolution_hz = 10000000;
+ } else if (args[2].u_obj != mp_const_none) {
+ resolution_hz = mp_obj_get_int(args[2].u_obj);
+ if (resolution_hz <= 0) {
+ mp_raise_ValueError(MP_ERROR_TEXT("resolution_hz must be positive"));
+ }
+ } else if (args[3].u_obj != mp_const_none) {
+ mp_uint_t clock_div = mp_obj_get_int(args[3].u_obj);
+ if (clock_div < 1 || clock_div > 255) {
+ mp_raise_ValueError(MP_ERROR_TEXT("clock_div must be between 1 and 255"));
+ }
+ resolution_hz = clock_freq / clock_div;
}
- if (clock_div < 1 || clock_div > 255) {
- mp_raise_ValueError(MP_ERROR_TEXT("clock_div must be between 1 and 255"));
+ mp_uint_t idle_level = args[4].u_bool;
+ mp_obj_t tx_carrier_obj = args[5].u_obj;
+ mp_uint_t num_symbols = args[6].u_int;
+
+ if (num_symbols < SOC_RMT_MEM_WORDS_PER_CHANNEL || ((num_symbols % 2) == 1)) {
+ mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("num_symbols must be even and at least %d"), SOC_RMT_MEM_WORDS_PER_CHANNEL);
}
esp32_rmt_obj_t *self = mp_obj_malloc_with_finaliser(esp32_rmt_obj_t, &esp32_rmt_type);
- self->channel_id = channel_id;
+ self->channel = NULL;
self->pin = pin_id;
- self->clock_div = clock_div;
- self->loop_en = false;
+ self->clock_freq = clock_freq;
+ self->resolution_hz = resolution_hz;
+ self->loop_count = 0;
+ self->tx_ongoing = 0;
+ self->idle_level = idle_level;
+ self->enabled = false;
+
+ rmt_tx_channel_config_t tx_chan_config = {
+ .clk_src = RMT_CLK_SRC_DEFAULT,
+ .gpio_num = self->pin,
+ .mem_block_symbols = num_symbols,
+ .resolution_hz = resolution_hz,
+ .trans_queue_depth = 4,
+ };
- rmt_config_t config = {0};
- config.rmt_mode = RMT_MODE_TX;
- config.channel = (rmt_channel_t)self->channel_id;
- config.gpio_num = self->pin;
- config.mem_block_num = 1;
- config.tx_config.loop_en = 0;
+ check_esp_err(rmt_new_tx_channel(&tx_chan_config, &self->channel));
if (tx_carrier_obj != mp_const_none) {
mp_obj_t *tx_carrier_details = NULL;
@@ -160,21 +160,21 @@ static mp_obj_t esp32_rmt_make_new(const mp_obj_type_t *type, size_t n_args, siz
mp_raise_ValueError(MP_ERROR_TEXT("tx_carrier duty must be 0..100"));
}
- config.tx_config.carrier_en = 1;
- config.tx_config.carrier_freq_hz = frequency;
- config.tx_config.carrier_duty_percent = duty;
- config.tx_config.carrier_level = level;
- } else {
- config.tx_config.carrier_en = 0;
+ rmt_carrier_config_t tx_carrier_cfg = {
+ .duty_cycle = ((float)duty) / 100.0,
+ .frequency_hz = frequency,
+ .flags.polarity_active_low = !level,
+ };
+ check_esp_err(rmt_apply_carrier(self->channel, &tx_carrier_cfg));
}
- config.tx_config.idle_output_en = 1;
- config.tx_config.idle_level = idle_level;
-
- config.clk_div = self->clock_div;
+ rmt_copy_encoder_config_t copy_encoder_config = {};
+ check_esp_err(rmt_new_copy_encoder(&copy_encoder_config, &self->encoder));
- check_esp_err(rmt_config(&config));
- check_esp_err(rmt_driver_install_core1(config.channel));
+ rmt_tx_event_callbacks_t callbacks = {
+ .on_trans_done = esp32_rmt_tx_trans_done,
+ };
+ check_esp_err(rmt_tx_register_event_callbacks(self->channel, &callbacks, self));
return MP_OBJ_FROM_PTR(self);
}
@@ -182,33 +182,72 @@ static mp_obj_t esp32_rmt_make_new(const mp_obj_type_t *type, size_t n_args, siz
static void esp32_rmt_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
esp32_rmt_obj_t *self = MP_OBJ_TO_PTR(self_in);
if (self->pin != -1) {
- bool idle_output_en;
- rmt_idle_level_t idle_level;
- check_esp_err(rmt_get_idle_level(self->channel_id, &idle_output_en, &idle_level));
- mp_printf(print, "RMT(channel=%u, pin=%u, source_freq=%u, clock_div=%u, idle_level=%u)",
- self->channel_id, self->pin, APB_CLK_FREQ, self->clock_div, idle_level);
+ mp_printf(print, "RMT(pin=%u, source_freq=%u, resolution_hz=%u, idle_level=%u)",
+ self->pin, self->clock_freq, self->resolution_hz, self->idle_level);
} else {
mp_printf(print, "RMT()");
}
}
+static void esp32_rmt_deactivate(esp32_rmt_obj_t *self) {
+ if (self->enabled) {
+ // FIXME: panics in ESP32 if called while TX is ongoing and TX sequence is long (>300ms)
+ // Does not panic in ESP32-S3, ESP32-C3 and ESP32-C6.
+ // Tested with ESP-IDF up to 5.5
+ // ESP-IDF issue: https://github.com/espressif/esp-idf/issues/17692
+ //
+ // Cause is Interrupt WDT to trigger because ESP-IDF rmt_disable() disables
+ // interrupts and spinlocks until the ongoing TX sequence is finished.
+ //
+ // Workaround is never try to stop RMT sequences longer than 300ms (which are unusual
+ // anyway). Or apply the patch mentioned at the GitHub issue to ESP-IDF.
+ rmt_disable(self->channel);
+ self->enabled = false;
+ }
+}
+
+static mp_obj_t esp32_rmt_active(size_t n_args, const mp_obj_t *args) {
+ esp32_rmt_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+
+ if (n_args == 1) {
+ return mp_obj_new_bool(self->enabled && self->tx_ongoing > 0);
+ } else if (mp_obj_is_true(args[1])) {
+ mp_raise_ValueError(MP_ERROR_TEXT("activate by calling write_pulses()"));
+ }
+
+ esp32_rmt_deactivate(self);
+
+ return mp_const_false;
+}
+static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp32_rmt_active_obj, 1, 2, esp32_rmt_active);
+
static mp_obj_t esp32_rmt_deinit(mp_obj_t self_in) {
- // fixme: check for valid channel. Return exception if error occurs.
esp32_rmt_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
if (self->pin != -1) { // Check if channel has already been deinitialised.
- rmt_driver_uninstall(self->channel_id);
+ esp32_rmt_deactivate(self);
+ rmt_tx_event_callbacks_t callbacks = {
+ .on_trans_done = NULL,
+ };
+ rmt_tx_register_event_callbacks(self->channel, &callbacks, self);
+ rmt_del_encoder(self->encoder);
+ rmt_del_channel(self->channel);
self->pin = -1; // -1 to indicate RMT is unused
+ self->tx_ongoing = 0;
m_free(self->items);
}
+
return mp_const_none;
}
static MP_DEFINE_CONST_FUN_OBJ_1(esp32_rmt_deinit_obj, esp32_rmt_deinit);
// Return the source frequency.
-// Currently only the APB clock (80MHz) can be used but it is possible other
+// Currently only the default clock (80MHz) can be used but it is possible other
// clock sources will added in the future.
static mp_obj_t esp32_rmt_source_freq() {
- return mp_obj_new_int(APB_CLK_FREQ);
+ uint32_t clock_freq;
+ check_esp_err(esp_clk_tree_src_get_freq_hz(RMT_CLK_SRC_DEFAULT, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &clock_freq));
+ return mp_obj_new_int(clock_freq);
}
static MP_DEFINE_CONST_FUN_OBJ_0(esp32_rmt_source_freq_obj, esp32_rmt_source_freq);
static MP_DEFINE_CONST_STATICMETHOD_OBJ(esp32_rmt_source_obj, MP_ROM_PTR(&esp32_rmt_source_freq_obj));
@@ -216,7 +255,11 @@ static MP_DEFINE_CONST_STATICMETHOD_OBJ(esp32_rmt_source_obj, MP_ROM_PTR(&esp32_
// Return the clock divider.
static mp_obj_t esp32_rmt_clock_div(mp_obj_t self_in) {
esp32_rmt_obj_t *self = MP_OBJ_TO_PTR(self_in);
- return mp_obj_new_int(self->clock_div);
+ if (self->pin == -1) {
+ mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("already deinitialized"));
+ }
+
+ return mp_obj_new_int(self->clock_freq / self->resolution_hz);
}
static MP_DEFINE_CONST_FUN_OBJ_1(esp32_rmt_clock_div_obj, esp32_rmt_clock_div);
@@ -233,29 +276,86 @@ static mp_obj_t esp32_rmt_wait_done(size_t n_args, const mp_obj_t *pos_args, mp_
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
esp32_rmt_obj_t *self = MP_OBJ_TO_PTR(args[0].u_obj);
+ if (self->pin == -1) {
+ mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("already deinitialized"));
+ } else if (!self->enabled) {
+ return mp_const_true;
+ } else if (args[1].u_int == 0 && self->tx_ongoing > 0) {
+ // shortcut to avoid console spamming with timeout msgs by rmt_tx_wait_all_done()
+ return mp_const_false;
+ }
- esp_err_t err = rmt_wait_tx_done(self->channel_id, args[1].u_int / portTICK_PERIOD_MS);
+ esp_err_t err = rmt_tx_wait_all_done(self->channel, args[1].u_int);
return err == ESP_OK ? mp_const_true : mp_const_false;
}
static MP_DEFINE_CONST_FUN_OBJ_KW(esp32_rmt_wait_done_obj, 1, esp32_rmt_wait_done);
+static mp_uint_t esp32_rmt_stream_ioctl(
+ mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) {
+ if (request != MP_STREAM_POLL) {
+ *errcode = MP_EINVAL;
+ return MP_STREAM_ERROR;
+ }
+ esp32_rmt_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_uint_t ret = 0;
+ if ((arg & MP_STREAM_POLL_WR) && self->tx_ongoing == 0) {
+ ret |= MP_STREAM_POLL_WR;
+ }
+ return ret;
+}
+
+static const mp_stream_p_t esp32_rmt_stream_p = {
+ .ioctl = esp32_rmt_stream_ioctl,
+};
+
+static void esp32_rmt_loop_in(esp32_rmt_obj_t *self, int new_loop_count) {
+ if (self->enabled && self->tx_ongoing > 0 && self->loop_count != 0 && new_loop_count == 0) {
+ // Break ongoing loop
+ esp32_rmt_deactivate(self);
+ }
+ self->loop_count = new_loop_count;
+}
+
static mp_obj_t esp32_rmt_loop(mp_obj_t self_in, mp_obj_t loop) {
esp32_rmt_obj_t *self = MP_OBJ_TO_PTR(self_in);
- self->loop_en = mp_obj_get_int(loop);
- if (!self->loop_en) {
- bool loop_en;
- check_esp_err(rmt_get_tx_loop_mode(self->channel_id, &loop_en));
- if (loop_en) {
- check_esp_err(rmt_set_tx_loop_mode(self->channel_id, false));
- check_esp_err(rmt_set_tx_intr_en(self->channel_id, true));
- }
+ if (self->pin == -1) {
+ mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("already deinitialized"));
}
+
+ bool loop_en = mp_obj_get_int(loop);
+ esp32_rmt_loop_in(self, loop_en ? -1 : 0);
return mp_const_none;
}
static MP_DEFINE_CONST_FUN_OBJ_2(esp32_rmt_loop_obj, esp32_rmt_loop);
+static mp_obj_t esp32_rmt_loop_count(mp_obj_t self_in, mp_obj_t loop) {
+ esp32_rmt_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ if (self->pin == -1) {
+ mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("already deinitialized"));
+ }
+
+ int loop_count = mp_obj_get_int(loop);
+ if (loop_count < -1) {
+ mp_raise_ValueError(MP_ERROR_TEXT("arg must be -1, 0 or positive"));
+ }
+ esp32_rmt_loop_in(self, loop_count);
+ return mp_const_none;
+}
+static MP_DEFINE_CONST_FUN_OBJ_2(esp32_rmt_loop_count_obj, esp32_rmt_loop_count);
+
static mp_obj_t esp32_rmt_write_pulses(size_t n_args, const mp_obj_t *args) {
esp32_rmt_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+ if (self->pin == -1) {
+ mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("already deinitialized"));
+ }
+
+ if (self->enabled) {
+ rmt_tx_wait_all_done(self->channel, -1);
+ } else {
+ check_esp_err(rmt_enable(self->channel));
+ self->enabled = true;
+ }
+
mp_obj_t duration_obj = args[1];
mp_obj_t data_obj = n_args > 2 ? args[2] : mp_const_true;
@@ -290,14 +390,12 @@ static mp_obj_t esp32_rmt_write_pulses(size_t n_args, const mp_obj_t *args) {
if (num_pulses == 0) {
mp_raise_ValueError(MP_ERROR_TEXT("No pulses"));
}
- if (self->loop_en && num_pulses > 126) {
- mp_raise_ValueError(MP_ERROR_TEXT("Too many pulses for loop"));
- }
mp_uint_t num_items = (num_pulses / 2) + (num_pulses % 2);
- if (num_items > self->num_items) {
- self->items = (rmt_item32_t *)m_realloc(self->items, num_items * sizeof(rmt_item32_t *));
- self->num_items = num_items;
+
+ if (num_items > self->cap_items) {
+ self->items = (rmt_symbol_word_t *)m_realloc(self->items, num_items * sizeof(rmt_symbol_word_t *));
+ self->cap_items = num_items;
}
for (mp_uint_t item_index = 0, pulse_index = 0; item_index < num_items; item_index++) {
@@ -314,63 +412,62 @@ static mp_obj_t esp32_rmt_write_pulses(size_t n_args, const mp_obj_t *args) {
}
}
- if (self->loop_en) {
- bool loop_en;
- check_esp_err(rmt_get_tx_loop_mode(self->channel_id, &loop_en));
- if (loop_en) {
- check_esp_err(rmt_set_tx_intr_en(self->channel_id, true));
- check_esp_err(rmt_set_tx_loop_mode(self->channel_id, false));
- }
- check_esp_err(rmt_wait_tx_done(self->channel_id, portMAX_DELAY));
- }
-
- #if !CONFIG_IDF_TARGET_ESP32S3
- check_esp_err(rmt_write_items(self->channel_id, self->items, num_items, false));
- #endif
-
- if (self->loop_en) {
- check_esp_err(rmt_set_tx_intr_en(self->channel_id, false));
- check_esp_err(rmt_set_tx_loop_mode(self->channel_id, true));
- }
+ rmt_transmit_config_t tx_config = {
+ .loop_count = self->loop_count,
+ .flags.eot_level = self->idle_level ? 1 : 0,
+ };
- #if CONFIG_IDF_TARGET_ESP32S3
- check_esp_err(rmt_write_items(self->channel_id, self->items, num_items, false));
- #endif
+ rmt_encoder_reset(self->encoder);
+ check_esp_err(rmt_transmit(self->channel, self->encoder, self->items, num_items * sizeof(rmt_symbol_word_t), &tx_config));
+ self->tx_ongoing += 1;
return mp_const_none;
}
static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp32_rmt_write_pulses_obj, 2, 3, esp32_rmt_write_pulses);
+static mp_obj_t esp32_rmt_bitstream_rmt(size_t n_args, const mp_obj_t *args) {
+ if (n_args > 0) {
+ esp32_rmt_bitstream_enabled = mp_obj_is_true(args[0]);
+ }
+ return esp32_rmt_bitstream_enabled ? mp_const_true : mp_const_false;
+}
+static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp32_rmt_bitstream_rmt_fun_obj, 0, 1, esp32_rmt_bitstream_rmt);
+static MP_DEFINE_CONST_STATICMETHOD_OBJ(esp32_rmt_bitstream_rmt_obj, MP_ROM_PTR(&esp32_rmt_bitstream_rmt_fun_obj));
+
static mp_obj_t esp32_rmt_bitstream_channel(size_t n_args, const mp_obj_t *args) {
if (n_args > 0) {
if (args[0] == mp_const_none) {
- esp32_rmt_bitstream_channel_id = -1;
+ esp32_rmt_bitstream_enabled = false;
} else {
mp_int_t channel_id = mp_obj_get_int(args[0]);
- if (channel_id < 0 || channel_id > RMT_LAST_TX_CHANNEL) {
+ if (channel_id < 0) {
mp_raise_ValueError(MP_ERROR_TEXT("invalid channel"));
}
- esp32_rmt_bitstream_channel_id = channel_id;
+ esp32_rmt_bitstream_enabled = true;
}
}
- if (esp32_rmt_bitstream_channel_id < 0) {
+ if (!esp32_rmt_bitstream_enabled) {
return mp_const_none;
} else {
- return MP_OBJ_NEW_SMALL_INT(esp32_rmt_bitstream_channel_id);
+ return MP_OBJ_NEW_SMALL_INT(1);
}
}
static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp32_rmt_bitstream_channel_fun_obj, 0, 1, esp32_rmt_bitstream_channel);
static MP_DEFINE_CONST_STATICMETHOD_OBJ(esp32_rmt_bitstream_channel_obj, MP_ROM_PTR(&esp32_rmt_bitstream_channel_fun_obj));
+
static const mp_rom_map_elem_t esp32_rmt_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&esp32_rmt_deinit_obj) },
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&esp32_rmt_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&esp32_rmt_active_obj) },
{ MP_ROM_QSTR(MP_QSTR_clock_div), MP_ROM_PTR(&esp32_rmt_clock_div_obj) },
{ MP_ROM_QSTR(MP_QSTR_wait_done), MP_ROM_PTR(&esp32_rmt_wait_done_obj) },
{ MP_ROM_QSTR(MP_QSTR_loop), MP_ROM_PTR(&esp32_rmt_loop_obj) },
+ { MP_ROM_QSTR(MP_QSTR_loop_count), MP_ROM_PTR(&esp32_rmt_loop_count_obj) },
{ MP_ROM_QSTR(MP_QSTR_write_pulses), MP_ROM_PTR(&esp32_rmt_write_pulses_obj) },
// Static methods
+ { MP_ROM_QSTR(MP_QSTR_bitstream_rmt), MP_ROM_PTR(&esp32_rmt_bitstream_rmt_obj) },
{ MP_ROM_QSTR(MP_QSTR_bitstream_channel), MP_ROM_PTR(&esp32_rmt_bitstream_channel_obj) },
// Class methods
@@ -387,7 +484,8 @@ MP_DEFINE_CONST_OBJ_TYPE(
MP_TYPE_FLAG_NONE,
make_new, esp32_rmt_make_new,
print, esp32_rmt_print,
- locals_dict, &esp32_rmt_locals_dict
+ locals_dict, &esp32_rmt_locals_dict,
+ protocol, &esp32_rmt_stream_p
);
#endif // SOC_RMT_SUPPORTED
diff --git a/ports/esp32/lockfiles/dependencies.lock.esp32c5 b/ports/esp32/lockfiles/dependencies.lock.esp32c5
new file mode 100644
index 000000000..204f64f68
--- /dev/null
+++ b/ports/esp32/lockfiles/dependencies.lock.esp32c5
@@ -0,0 +1,21 @@
+dependencies:
+ espressif/mdns:
+ component_hash: 46ee81d32fbf850462d8af1e83303389602f6a6a9eddd2a55104cb4c063858ed
+ dependencies:
+ - name: idf
+ require: private
+ version: '>=5.0'
+ source:
+ registry_url: https://components.espressif.com/
+ type: service
+ version: 1.1.0
+ idf:
+ source:
+ type: idf
+ version: 5.5.1
+direct_dependencies:
+- espressif/mdns
+- idf
+manifest_hash: 3b18b5bbac91c9fe5098d3759a37c84ed0828546d8cbc92e26e4c1698e689c8a
+target: esp32c5
+version: 2.0.0
diff --git a/ports/esp32/machine_adc.c b/ports/esp32/machine_adc.c
index c5575d45e..432df3d3a 100644
--- a/ports/esp32/machine_adc.c
+++ b/ports/esp32/machine_adc.c
@@ -100,6 +100,13 @@ static const machine_adc_obj_t madc_obj[] = {
{{&machine_adc_type}, ADCBLOCK1, ADC_CHANNEL_3, GPIO_NUM_3},
{{&machine_adc_type}, ADCBLOCK1, ADC_CHANNEL_4, GPIO_NUM_4},
{{&machine_adc_type}, ADCBLOCK2, ADC_CHANNEL_0, GPIO_NUM_5},
+ #elif CONFIG_IDF_TARGET_ESP32C5
+ {{&machine_adc_type}, ADCBLOCK1, ADC_CHANNEL_0, GPIO_NUM_1},
+ {{&machine_adc_type}, ADCBLOCK1, ADC_CHANNEL_1, GPIO_NUM_2},
+ {{&machine_adc_type}, ADCBLOCK1, ADC_CHANNEL_2, GPIO_NUM_3},
+ {{&machine_adc_type}, ADCBLOCK1, ADC_CHANNEL_3, GPIO_NUM_4},
+ {{&machine_adc_type}, ADCBLOCK1, ADC_CHANNEL_4, GPIO_NUM_5},
+ {{&machine_adc_type}, ADCBLOCK1, ADC_CHANNEL_5, GPIO_NUM_6},
#elif CONFIG_IDF_TARGET_ESP32C6
{{&machine_adc_type}, ADCBLOCK1, ADC_CHANNEL_0, GPIO_NUM_0},
{{&machine_adc_type}, ADCBLOCK1, ADC_CHANNEL_1, GPIO_NUM_1},
diff --git a/ports/esp32/machine_bitstream.c b/ports/esp32/machine_bitstream.c
index ed7fcc407..60addcc15 100644
--- a/ports/esp32/machine_bitstream.c
+++ b/ports/esp32/machine_bitstream.c
@@ -91,96 +91,95 @@ static void IRAM_ATTR machine_bitstream_high_low_bitbang(mp_hal_pin_obj_t pin, u
}
#if SOC_RMT_SUPPORTED
+
/******************************************************************************/
// RMT implementation
-#include "driver/rmt.h"
-
-// Logical 0 and 1 values (encoded as a rmt_item32_t).
-// The duration fields will be set later.
-static rmt_item32_t bitstream_high_low_0 = {{{ 0, 1, 0, 0 }}};
-static rmt_item32_t bitstream_high_low_1 = {{{ 0, 1, 0, 0 }}};
-
-// See https://github.com/espressif/esp-idf/blob/master/examples/common_components/led_strip/led_strip_rmt_ws2812.c
-// This is called automatically by the IDF during rmt_write_sample in order to
-// convert the byte stream to rmt_item32_t's.
-static void IRAM_ATTR bitstream_high_low_rmt_adapter(const void *src, rmt_item32_t *dest, size_t src_size, size_t wanted_num, size_t *translated_size, size_t *item_num) {
- if (src == NULL || dest == NULL) {
- *translated_size = 0;
- *item_num = 0;
- return;
- }
-
- size_t size = 0;
- size_t num = 0;
- uint8_t *psrc = (uint8_t *)src;
- rmt_item32_t *pdest = dest;
- while (size < src_size && num < wanted_num) {
- for (int i = 0; i < 8; i++) {
- // MSB first
- if (*psrc & (1 << (7 - i))) {
- pdest->val = bitstream_high_low_1.val;
- } else {
- pdest->val = bitstream_high_low_0.val;
- }
- num++;
- pdest++;
- }
- size++;
- psrc++;
- }
-
- *translated_size = size;
- *item_num = num;
-}
-
-// Use the reserved RMT channel to stream high/low data on the specified pin.
-static void machine_bitstream_high_low_rmt(mp_hal_pin_obj_t pin, uint32_t *timing_ns, const uint8_t *buf, size_t len, uint8_t channel_id) {
- rmt_config_t config = RMT_DEFAULT_CONFIG_TX(pin, channel_id);
+#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 3, 0)
+#include "rmt_private.h"
+#endif
+#include "driver/rmt_tx.h"
+#include "driver/rmt_encoder.h"
+static bool machine_bitstream_high_low_rmt(mp_hal_pin_obj_t pin, uint32_t *timing_ns, const uint8_t *buf, size_t len) {
// Use 40MHz clock (although 2MHz would probably be sufficient).
- config.clk_div = 2;
-
- // Install the driver on this channel & pin.
- check_esp_err(rmt_config(&config));
- check_esp_err(rmt_driver_install_core1(config.channel));
+ uint32_t clock_div = 2;
+ rmt_channel_handle_t channel = NULL;
+ rmt_tx_channel_config_t tx_chan_config = {
+ .clk_src = RMT_CLK_SRC_DEFAULT,
+ .gpio_num = pin,
+ .mem_block_symbols = SOC_RMT_MEM_WORDS_PER_CHANNEL,
+ .resolution_hz = APB_CLK_FREQ / clock_div,
+ .trans_queue_depth = 1,
+ };
+ if (rmt_new_tx_channel(&tx_chan_config, &channel) != ESP_OK) {
+ return false;
+ }
+ check_esp_err(rmt_enable(channel));
// Get the tick rate in kHz (this will likely be 40000).
- uint32_t counter_clk_khz = 0;
- check_esp_err(rmt_get_counter_clock(config.channel, &counter_clk_khz));
-
+ uint32_t counter_clk_khz = APB_CLK_FREQ / clock_div;
counter_clk_khz /= 1000;
// Convert nanoseconds to pulse duration.
- bitstream_high_low_0.duration0 = (counter_clk_khz * timing_ns[0]) / 1e6;
- bitstream_high_low_0.duration1 = (counter_clk_khz * timing_ns[1]) / 1e6;
- bitstream_high_low_1.duration0 = (counter_clk_khz * timing_ns[2]) / 1e6;
- bitstream_high_low_1.duration1 = (counter_clk_khz * timing_ns[3]) / 1e6;
-
- // Install the bits->highlow translator.
- rmt_translator_init(config.channel, bitstream_high_low_rmt_adapter);
-
- // Stream the byte data using the translator.
- check_esp_err(rmt_write_sample(config.channel, buf, len, true));
-
- // Wait 50% longer than we expect (if every bit takes the maximum time).
- uint32_t timeout_ms = (3 * len / 2) * (1 + (8 * MAX(timing_ns[0] + timing_ns[1], timing_ns[2] + timing_ns[3])) / 1000);
- check_esp_err(rmt_wait_tx_done(config.channel, pdMS_TO_TICKS(timeout_ms)));
-
- // Uninstall the driver.
- check_esp_err(rmt_driver_uninstall(config.channel));
+ // Example: 500ns = 40000 * 500 / 1e6 = 20 ticks
+ // 20 ticks / 40MHz = 500e-9
+ rmt_bytes_encoder_config_t bytes_encoder_config = {
+ .bit0 = {
+ .level0 = 1,
+ .duration0 = (counter_clk_khz * timing_ns[0]) / 1e6,
+ .level1 = 0,
+ .duration1 = (counter_clk_khz * timing_ns[1]) / 1e6,
+ },
+ .bit1 = {
+ .level0 = 1,
+ .duration0 = (counter_clk_khz * timing_ns[2]) / 1e6,
+ .level1 = 0,
+ .duration1 = (counter_clk_khz * timing_ns[3]) / 1e6,
+ },
+ .flags.msb_first = 1
+ };
+
+ // Install the bits->highlow encoder.
+ rmt_encoder_handle_t encoder;
+ check_esp_err(rmt_new_bytes_encoder(&bytes_encoder_config, &encoder));
+
+ rmt_transmit_config_t tx_config = {
+ .loop_count = 0,
+ .flags.eot_level = 0,
+ };
+
+ // Stream the byte data using the encoder.
+ rmt_encoder_reset(encoder);
+ check_esp_err(rmt_transmit(channel, encoder, buf, len, &tx_config));
+
+ // Wait until completion.
+ rmt_tx_wait_all_done(channel, -1);
+
+ // Disable and release channel.
+ check_esp_err(rmt_del_encoder(encoder));
+ rmt_disable(channel);
+ #if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 3, 0)
+ channel->del(channel);
+ #else
+ rmt_del_channel(channel);
+ #endif
// Cancel RMT output to GPIO pin.
esp_rom_gpio_connect_out_signal(pin, SIG_GPIO_OUT_IDX, false, false);
+
+ return true;
}
-#endif
+
+#endif // SOC_RMT_SUPPORTED
+
/******************************************************************************/
// Interface to machine.bitstream
void machine_bitstream_high_low(mp_hal_pin_obj_t pin, uint32_t *timing_ns, const uint8_t *buf, size_t len) {
#if SOC_RMT_SUPPORTED
- if (esp32_rmt_bitstream_channel_id >= 0) {
- machine_bitstream_high_low_rmt(pin, timing_ns, buf, len, esp32_rmt_bitstream_channel_id);
+ if (esp32_rmt_bitstream_enabled && machine_bitstream_high_low_rmt(pin, timing_ns, buf, len)) {
+ // Use of RMT was successful.
return;
}
#endif
diff --git a/ports/esp32/machine_i2c.c b/ports/esp32/machine_i2c.c
index 74679d01d..9fb89660f 100644
--- a/ports/esp32/machine_i2c.c
+++ b/ports/esp32/machine_i2c.c
@@ -35,6 +35,7 @@
#include "driver/i2c_master.h"
#else
#include "driver/i2c.h"
+#include "esp_clk_tree.h"
#include "hal/i2c_ll.h"
#endif
@@ -224,6 +225,8 @@ int machine_hw_i2c_transfer(mp_obj_base_t *self_in, uint16_t addr, size_t n, mp_
#if SOC_I2C_SUPPORT_XTAL
#if CONFIG_XTAL_FREQ > 0
#define I2C_SCLK_FREQ (CONFIG_XTAL_FREQ * 1000000)
+#elif CONFIG_XTAL_FREQ == 0 && CONFIG_IDF_TARGET_ESP32C5
+// The crystal is auto-detected, so the I2C sclk frequency will be computed at runtime.
#else
#error "I2C uses XTAL but no configured freq"
#endif // CONFIG_XTAL_FREQ
@@ -257,7 +260,13 @@ static void machine_hw_i2c_init(machine_hw_i2c_obj_t *self, bool first_init) {
.master.clk_speed = self->freq,
};
i2c_param_config(self->port, &conf);
- int timeout = i2c_ll_calculate_timeout_us_to_reg_val(I2C_SCLK_FREQ, self->timeout_us);
+ #if CONFIG_IDF_TARGET_ESP32C5
+ uint32_t i2c_sclk_freq;
+ check_esp_err(esp_clk_tree_src_get_freq_hz(I2C_CLK_SRC_DEFAULT, ESP_CLK_TREE_SRC_FREQ_PRECISION_APPROX, &i2c_sclk_freq));
+ #else
+ uint32_t i2c_sclk_freq = I2C_SCLK_FREQ;
+ #endif
+ int timeout = i2c_ll_calculate_timeout_us_to_reg_val(i2c_sclk_freq, self->timeout_us);
i2c_set_timeout(self->port, (timeout > I2C_LL_MAX_TIMEOUT) ? I2C_LL_MAX_TIMEOUT : timeout);
i2c_driver_install(self->port, I2C_MODE_MASTER, 0, 0, 0);
}
diff --git a/ports/esp32/machine_pin.c b/ports/esp32/machine_pin.c
index 9999223b5..efe673319 100644
--- a/ports/esp32/machine_pin.c
+++ b/ports/esp32/machine_pin.c
@@ -152,7 +152,7 @@ static mp_obj_t machine_pin_obj_init_helper(const machine_pin_obj_t *self, size_
// reset the pin to digital if this is a mode-setting init (grab it back from ADC)
if (args[ARG_mode].u_obj != mp_const_none) {
if (rtc_gpio_is_valid_gpio(index)) {
- #if !(CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6)
+ #if !(CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C5 || CONFIG_IDF_TARGET_ESP32C6)
rtc_gpio_deinit(index);
#endif
}
@@ -163,6 +163,11 @@ static mp_obj_t machine_pin_obj_init_helper(const machine_pin_obj_t *self, size_
CLEAR_PERI_REG_MASK(USB_SERIAL_JTAG_CONF0_REG, USB_SERIAL_JTAG_USB_PAD_ENABLE);
}
#endif
+ #if CONFIG_IDF_TARGET_ESP32C5 && !MICROPY_HW_ESP_USB_SERIAL_JTAG
+ if (index == 13 || index == 14) {
+ CLEAR_PERI_REG_MASK(USB_SERIAL_JTAG_CONF0_REG, USB_SERIAL_JTAG_USB_PAD_ENABLE);
+ }
+ #endif
#if CONFIG_IDF_TARGET_ESP32C6 && !MICROPY_HW_ESP_USB_SERIAL_JTAG
if (index == 12 || index == 13) {
CLEAR_PERI_REG_MASK(USB_SERIAL_JTAG_CONF0_REG, USB_SERIAL_JTAG_USB_PAD_ENABLE);
diff --git a/ports/esp32/machine_pin.h b/ports/esp32/machine_pin.h
index 6fe9ef0e7..9e247a736 100644
--- a/ports/esp32/machine_pin.h
+++ b/ports/esp32/machine_pin.h
@@ -111,6 +111,32 @@
#define MICROPY_HW_ENABLE_GPIO20 (1)
#define MICROPY_HW_ENABLE_GPIO21 (1)
+#elif CONFIG_IDF_TARGET_ESP32C5
+
+#define MICROPY_HW_ENABLE_GPIO0 (1)
+#define MICROPY_HW_ENABLE_GPIO1 (1)
+#define MICROPY_HW_ENABLE_GPIO2 (1)
+#define MICROPY_HW_ENABLE_GPIO3 (1)
+#define MICROPY_HW_ENABLE_GPIO4 (1)
+#define MICROPY_HW_ENABLE_GPIO5 (1)
+#define MICROPY_HW_ENABLE_GPIO6 (1)
+#define MICROPY_HW_ENABLE_GPIO7 (1)
+#define MICROPY_HW_ENABLE_GPIO8 (1)
+#define MICROPY_HW_ENABLE_GPIO9 (1)
+#define MICROPY_HW_ENABLE_GPIO10 (1)
+#define MICROPY_HW_ENABLE_GPIO11 (1)
+#define MICROPY_HW_ENABLE_GPIO12 (1)
+#if !MICROPY_HW_ESP_USB_SERIAL_JTAG
+#define MICROPY_HW_ENABLE_GPIO13 (1)
+#define MICROPY_HW_ENABLE_GPIO14 (1)
+#endif
+#define MICROPY_HW_ENABLE_GPIO23 (1)
+#define MICROPY_HW_ENABLE_GPIO24 (1)
+#define MICROPY_HW_ENABLE_GPIO25 (1)
+#define MICROPY_HW_ENABLE_GPIO26 (1)
+#define MICROPY_HW_ENABLE_GPIO27 (1)
+#define MICROPY_HW_ENABLE_GPIO28 (1)
+
#elif CONFIG_IDF_TARGET_ESP32C6
#define MICROPY_HW_ENABLE_GPIO0 (1)
diff --git a/ports/esp32/modesp32.h b/ports/esp32/modesp32.h
index 81ab94dc6..60c386565 100644
--- a/ports/esp32/modesp32.h
+++ b/ports/esp32/modesp32.h
@@ -1,6 +1,8 @@
#ifndef MICROPY_INCLUDED_ESP32_MODESP32_H
#define MICROPY_INCLUDED_ESP32_MODESP32_H
+#include "driver/rmt_tx.h"
+
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
#define RTC_VALID_EXT_PINS \
@@ -59,7 +61,7 @@
#define RTC_IS_VALID_EXT_PIN(pin_id) ((1ll << (pin_id)) & RTC_VALID_EXT_PINS)
-extern int8_t esp32_rmt_bitstream_channel_id;
+extern bool esp32_rmt_bitstream_enabled;
extern const mp_obj_type_t esp32_nvs_type;
extern const mp_obj_type_t esp32_partition_type;
@@ -72,6 +74,4 @@ extern const mp_obj_type_t esp32_pcnt_type;
void esp32_pcnt_deinit_all(void);
#endif
-esp_err_t rmt_driver_install_core1(uint8_t channel_id);
-
#endif // MICROPY_INCLUDED_ESP32_MODESP32_H
diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h
index 09d75cd1a..fafed3961 100644
--- a/ports/esp32/mpconfigport.h
+++ b/ports/esp32/mpconfigport.h
@@ -172,6 +172,8 @@
#define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "mpy-esp32c2"
#elif CONFIG_IDF_TARGET_ESP32C3
#define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "mpy-esp32c3"
+#elif CONFIG_IDF_TARGET_ESP32C5
+#define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "mpy-esp32c5"
#elif CONFIG_IDF_TARGET_ESP32C6
#define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "mpy-esp32c6"
#endif