esp32/machine_i2s: Ensure 2 DMA buffers and improve I2S error handling.

ESP-IDF driver always requires at least two DMA buffers, so ensure that's
the case.

Failures during initialisation were being lost because ESP_ERROR_CHECK is
configured as a no-op, so the failure was deferred until read() or write()
was called on the port.  Raise an error from init, instead.

This work was funded through GitHub Sponsors.

Signed-off-by: Angus Gratton <angus@redyak.com.au>
This commit is contained in:
Angus Gratton
2024-07-25 12:19:11 +10:00
committed by Damien George
parent 9ba04cc756
commit 0d00d72b76

View File

@@ -151,7 +151,7 @@ static uint32_t get_dma_buf_count(uint8_t mode, i2s_data_bit_width_t bits, forma
uint32_t dma_buf_count = ibuf / (DMA_BUF_LEN_IN_I2S_FRAMES * dma_frame_size_in_bytes); uint32_t dma_buf_count = ibuf / (DMA_BUF_LEN_IN_I2S_FRAMES * dma_frame_size_in_bytes);
return dma_buf_count; return MAX(dma_buf_count, 2); // ESP-IDF requires at least two DMA buffers
} }
static uint32_t fill_appbuf_from_dma(machine_i2s_obj_t *self, mp_buffer_info_t *appbuf) { static uint32_t fill_appbuf_from_dma(machine_i2s_obj_t *self, mp_buffer_info_t *appbuf) {
@@ -363,9 +363,9 @@ static void mp_machine_i2s_init_helper(machine_i2s_obj_t *self, mp_arg_val_t *ar
chan_config.auto_clear = true; chan_config.auto_clear = true;
if (mode == MICROPY_PY_MACHINE_I2S_CONSTANT_TX) { if (mode == MICROPY_PY_MACHINE_I2S_CONSTANT_TX) {
ESP_ERROR_CHECK(i2s_new_channel(&chan_config, &self->i2s_chan_handle, NULL)); check_esp_err(i2s_new_channel(&chan_config, &self->i2s_chan_handle, NULL));
} else { // rx } else { // rx
ESP_ERROR_CHECK(i2s_new_channel(&chan_config, NULL, &self->i2s_chan_handle)); check_esp_err(i2s_new_channel(&chan_config, NULL, &self->i2s_chan_handle));
} }
i2s_std_slot_config_t slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(get_dma_bits(mode, bits), get_dma_format(mode, format)); i2s_std_slot_config_t slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(get_dma_bits(mode, bits), get_dma_format(mode, format));
@@ -394,9 +394,9 @@ static void mp_machine_i2s_init_helper(machine_i2s_obj_t *self, mp_arg_val_t *ar
std_cfg.gpio_cfg.din = self->sd; std_cfg.gpio_cfg.din = self->sd;
} }
ESP_ERROR_CHECK(i2s_channel_init_std_mode(self->i2s_chan_handle, &std_cfg)); check_esp_err(i2s_channel_init_std_mode(self->i2s_chan_handle, &std_cfg));
ESP_ERROR_CHECK(i2s_channel_register_event_callback(self->i2s_chan_handle, &i2s_callbacks, self)); check_esp_err(i2s_channel_register_event_callback(self->i2s_chan_handle, &i2s_callbacks, self));
ESP_ERROR_CHECK(i2s_channel_enable(self->i2s_chan_handle)); check_esp_err(i2s_channel_enable(self->i2s_chan_handle));
} }
static machine_i2s_obj_t *mp_machine_i2s_make_new_instance(mp_int_t i2s_id) { static machine_i2s_obj_t *mp_machine_i2s_make_new_instance(mp_int_t i2s_id) {
@@ -419,9 +419,12 @@ static machine_i2s_obj_t *mp_machine_i2s_make_new_instance(mp_int_t i2s_id) {
static void mp_machine_i2s_deinit(machine_i2s_obj_t *self) { static void mp_machine_i2s_deinit(machine_i2s_obj_t *self) {
if (!self->is_deinit) { if (!self->is_deinit) {
ESP_ERROR_CHECK(i2s_channel_disable(self->i2s_chan_handle)); if (self->i2s_chan_handle) {
ESP_ERROR_CHECK(i2s_channel_register_event_callback(self->i2s_chan_handle, &i2s_callbacks_null, self)); i2s_channel_disable(self->i2s_chan_handle);
ESP_ERROR_CHECK(i2s_del_channel(self->i2s_chan_handle)); i2s_channel_register_event_callback(self->i2s_chan_handle, &i2s_callbacks_null, self);
i2s_del_channel(self->i2s_chan_handle);
self->i2s_chan_handle = NULL;
}
if (self->non_blocking_mode_task != NULL) { if (self->non_blocking_mode_task != NULL) {
vTaskDelete(self->non_blocking_mode_task); vTaskDelete(self->non_blocking_mode_task);