From 8d5e093994a7193d1a6a3c9a288c9a497dcede1b Mon Sep 17 00:00:00 2001 From: Sola85 Date: Fri, 18 Jul 2025 09:22:43 +0200 Subject: [PATCH 1/2] Rmt dma only when necessary * enable dma in rmt only when necessary * Document limitations of PulseIn --- ports/espressif/common-hal/pulseio/PulseIn.c | 31 ++++++++++++++++---- shared-bindings/pulseio/PulseIn.c | 4 +++ 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/ports/espressif/common-hal/pulseio/PulseIn.c b/ports/espressif/common-hal/pulseio/PulseIn.c index f7e500790562a..cddf6f5dffc6f 100644 --- a/ports/espressif/common-hal/pulseio/PulseIn.c +++ b/ports/espressif/common-hal/pulseio/PulseIn.c @@ -74,14 +74,20 @@ static bool _done_callback(rmt_channel_handle_t rx_chan, void common_hal_pulseio_pulsein_construct(pulseio_pulsein_obj_t *self, const mcu_pin_obj_t *pin, uint16_t maxlen, bool idle_state) { + + // Only use dma when necessary, since dma-rmt might not be available. + // If dma is not available, this will raise an error below. + bool use_dma = maxlen > 128; + self->buffer = (uint16_t *)m_malloc_without_collect(maxlen * sizeof(uint16_t)); if (self->buffer == NULL) { m_malloc_fail(maxlen * sizeof(uint16_t)); } // We add one to the maxlen version to ensure that two symbols at lease are // captured because we may skip the first portion of a symbol. - self->raw_symbols_size = MIN(64, maxlen / 2 + 1) * sizeof(rmt_symbol_word_t); - self->raw_symbols = (rmt_symbol_word_t *)m_malloc_without_collect(self->raw_symbols_size); + self->raw_symbols_size = (maxlen / 2 + 1) * sizeof(rmt_symbol_word_t); + // RMT DMA mode cannot access PSRAM -> ensure raw_symbols is in internal ram + self->raw_symbols = (rmt_symbol_word_t *)port_malloc(self->raw_symbols_size, use_dma); if (self->raw_symbols == NULL) { m_free(self->buffer); m_malloc_fail(self->raw_symbols_size); @@ -109,17 +115,30 @@ void common_hal_pulseio_pulsein_construct(pulseio_pulsein_obj_t *self, const mcu .clk_src = RMT_CLK_SRC_DEFAULT, // 2 us resolution so we can capture 65ms pulses. The RMT period is only 15 bits. .resolution_hz = 1000000 / 2, - .mem_block_symbols = SOC_RMT_MEM_WORDS_PER_CHANNEL, + .mem_block_symbols = use_dma ? self->raw_symbols_size : SOC_RMT_MEM_WORDS_PER_CHANNEL, + .flags.with_dma = use_dma }; - // If we fail here, the buffers allocated above will be garbage collected. - CHECK_ESP_RESULT(rmt_new_rx_channel(&config, &self->channel)); + // If we fail here, the self->buffer will be garbage collected. + esp_err_t result = rmt_new_rx_channel(&config, &self->channel); + if (result != ESP_OK) { + port_free(self->raw_symbols); + if (result == ESP_ERR_NOT_SUPPORTED) { + mp_raise_ValueError_varg(MP_ERROR_TEXT("Invalid %q"), MP_QSTR_maxlen); + } else { + raise_esp_error(result); + } + } rmt_rx_event_callbacks_t rx_callback = { .on_recv_done = _done_callback }; rmt_rx_register_event_callbacks(self->channel, &rx_callback, self); rmt_enable(self->channel); - rmt_receive(self->channel, self->raw_symbols, self->raw_symbols_size, &rx_config); + result = rmt_receive(self->channel, self->raw_symbols, self->raw_symbols_size, &rx_config); + if (result != ESP_OK) { + port_free(self->raw_symbols); + raise_esp_error(result); + } } bool common_hal_pulseio_pulsein_deinited(pulseio_pulsein_obj_t *self) { diff --git a/shared-bindings/pulseio/PulseIn.c b/shared-bindings/pulseio/PulseIn.c index d9e6bfd7aecc3..1df5773114493 100644 --- a/shared-bindings/pulseio/PulseIn.c +++ b/shared-bindings/pulseio/PulseIn.c @@ -33,6 +33,10 @@ //| :param bool idle_state: Idle state of the pin. At start and after `resume` //| the first recorded pulse will the opposite state from idle. //| +//| **Limitations**: The `maxlen` parameter is limited depending on the specific board. +//| On most ESP32 variants the limit is 128. On ESP32-S3 and ESP32-P4 the first `PulseIn` instance +//| can use `maxlen` up to available RAM; all subsequent instances are limited to 128. +//| //| Read a short series of pulses:: //| //| import pulseio From 70da590e3fe75448f6068f9a174547b816d6ef4c Mon Sep 17 00:00:00 2001 From: Sola85 Date: Sat, 19 Jul 2025 11:00:23 +0200 Subject: [PATCH 2/2] catch second type of error --- ports/espressif/common-hal/pulseio/PulseIn.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ports/espressif/common-hal/pulseio/PulseIn.c b/ports/espressif/common-hal/pulseio/PulseIn.c index cddf6f5dffc6f..73ffecd2ed379 100644 --- a/ports/espressif/common-hal/pulseio/PulseIn.c +++ b/ports/espressif/common-hal/pulseio/PulseIn.c @@ -76,7 +76,7 @@ void common_hal_pulseio_pulsein_construct(pulseio_pulsein_obj_t *self, const mcu uint16_t maxlen, bool idle_state) { // Only use dma when necessary, since dma-rmt might not be available. - // If dma is not available, this will raise an error below. + // If dma is necessary but not available, this will raise an error below. bool use_dma = maxlen > 128; self->buffer = (uint16_t *)m_malloc_without_collect(maxlen * sizeof(uint16_t)); @@ -122,7 +122,8 @@ void common_hal_pulseio_pulsein_construct(pulseio_pulsein_obj_t *self, const mcu esp_err_t result = rmt_new_rx_channel(&config, &self->channel); if (result != ESP_OK) { port_free(self->raw_symbols); - if (result == ESP_ERR_NOT_SUPPORTED) { + if (result == ESP_ERR_NOT_SUPPORTED || result == ESP_ERR_NOT_FOUND) { + // DMA not available, cannot record long pulse sequences. mp_raise_ValueError_varg(MP_ERROR_TEXT("Invalid %q"), MP_QSTR_maxlen); } else { raise_esp_error(result); pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy