diff --git a/extmod/machine_i2s.c b/extmod/machine_i2s.c index 7e069c5d76cbf..9c92eb4c926b7 100644 --- a/extmod/machine_i2s.c +++ b/extmod/machine_i2s.c @@ -608,6 +608,7 @@ static mp_uint_t machine_i2s_stream_write(mp_obj_t self_in, const void *buf_in, #else uint32_t num_bytes_written = copy_appbuf_to_dma(self, &appbuf); #endif + return num_bytes_written; } } @@ -632,16 +633,8 @@ static mp_uint_t machine_i2s_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_ ret |= MP_STREAM_POLL_RD; } #else - // check event queue to determine if a DMA buffer has been filled - // (which is an indication that at least one DMA buffer is available to be read) - // note: timeout = 0 so the call is non-blocking - i2s_event_t i2s_event; - if (xQueueReceive(self->i2s_event_queue, &i2s_event, 0)) { - if (i2s_event.type == I2S_EVENT_RX_DONE) { - // getting here means that at least one DMA buffer is now full - // indicating that audio samples can be read from the I2S object - ret |= MP_STREAM_POLL_RD; - } + if (self->dma_buffer_status == DMA_MEMORY_NOT_EMPTY) { + ret |= MP_STREAM_POLL_RD; } #endif } @@ -657,16 +650,8 @@ static mp_uint_t machine_i2s_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_ ret |= MP_STREAM_POLL_WR; } #else - // check event queue to determine if a DMA buffer has been emptied - // (which is an indication that at least one DMA buffer is available to be written) - // note: timeout = 0 so the call is non-blocking - i2s_event_t i2s_event; - if (xQueueReceive(self->i2s_event_queue, &i2s_event, 0)) { - if (i2s_event.type == I2S_EVENT_TX_DONE) { - // getting here means that at least one DMA buffer is now empty - // indicating that audio samples can be written to the I2S object - ret |= MP_STREAM_POLL_WR; - } + if (self->dma_buffer_status == DMA_MEMORY_NOT_FULL) { + ret |= MP_STREAM_POLL_WR; } #endif } diff --git a/ports/esp32/boards/sdkconfig.base b/ports/esp32/boards/sdkconfig.base index 05624f0d7409b..fef25fe3087f5 100644 --- a/ports/esp32/boards/sdkconfig.base +++ b/ports/esp32/boards/sdkconfig.base @@ -112,7 +112,6 @@ CONFIG_UART_ISR_IN_IRAM=y # IDF 5 deprecated CONFIG_ADC_SUPPRESS_DEPRECATE_WARN=y CONFIG_RMT_SUPPRESS_DEPRECATE_WARN=y -CONFIG_I2S_SUPPRESS_DEPRECATE_WARN=y CONFIG_ETH_USE_SPI_ETHERNET=y CONFIG_ETH_SPI_ETHERNET_W5500=y diff --git a/ports/esp32/machine_i2s.c b/ports/esp32/machine_i2s.c index 574125ad6a0d9..6ba2f54c354c6 100644 --- a/ports/esp32/machine_i2s.c +++ b/ports/esp32/machine_i2s.c @@ -28,9 +28,7 @@ // extmod/machine_i2s.c via MICROPY_PY_MACHINE_I2S_INCLUDEFILE. #include "py/mphal.h" - -#include "driver/i2s.h" -#include "soc/i2s_reg.h" +#include "driver/i2s_std.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/queue.h" @@ -62,23 +60,32 @@ typedef struct _non_blocking_descriptor_t { direction_t direction; } non_blocking_descriptor_t; +typedef enum { + DMA_MEMORY_FULL, + DMA_MEMORY_NOT_FULL, + DMA_MEMORY_EMPTY, + DMA_MEMORY_NOT_EMPTY, +} dma_buffer_status_t; + typedef struct _machine_i2s_obj_t { mp_obj_base_t base; i2s_port_t i2s_id; + i2s_chan_handle_t i2s_chan_handle; mp_hal_pin_obj_t sck; mp_hal_pin_obj_t ws; mp_hal_pin_obj_t sd; - int8_t mode; - i2s_bits_per_sample_t bits; + i2s_dir_t mode; + i2s_data_bit_width_t bits; format_t format; int32_t rate; int32_t ibuf; mp_obj_t callback_for_non_blocking; io_mode_t io_mode; + bool is_deinit; uint8_t transform_buffer[SIZEOF_TRANSFORM_BUFFER_IN_BYTES]; - QueueHandle_t i2s_event_queue; QueueHandle_t non_blocking_mode_queue; TaskHandle_t non_blocking_mode_task; + dma_buffer_status_t dma_buffer_status; } machine_i2s_obj_t; static mp_obj_t machine_i2s_deinit(mp_obj_t self_in); @@ -87,10 +94,10 @@ static mp_obj_t machine_i2s_deinit(mp_obj_t self_in); // from DMA memory (32-bit stereo, with the L and R channels reversed) to the format specified // in the I2S constructor. e.g. 16-bit mono static const int8_t i2s_frame_map[NUM_I2S_USER_FORMATS][I2S_RX_FRAME_SIZE_IN_BYTES] = { - { 6, 7, -1, -1, -1, -1, -1, -1 }, // Mono, 16-bits - { 4, 5, 6, 7, -1, -1, -1, -1 }, // Mono, 32-bits - { 6, 7, 2, 3, -1, -1, -1, -1 }, // Stereo, 16-bits - { 4, 5, 6, 7, 0, 1, 2, 3 }, // Stereo, 32-bits + { 2, 3, -1, -1, -1, -1, -1, -1 }, // Mono, 16-bits + { 0, 1, 2, 3, -1, -1, -1, -1 }, // Mono, 32-bits + { 2, 3, 6, 7, -1, -1, -1, -1 }, // Stereo, 16-bits + { 0, 1, 2, 3, 4, 5, 6, 7 }, // Stereo, 32-bits }; void machine_i2s_init0() { @@ -99,49 +106,15 @@ void machine_i2s_init0() { } } -// The following function takes a sample buffer and swaps L/R channels -// -// Background: For 32-bit stereo, the ESP-IDF API has a L/R channel orientation that breaks -// convention with other ESP32 channel formats -// -// appbuf[] = [L_0-7, L_8-15, L_16-23, L_24-31, R_0-7, R_8-15, R_16-23, R_24-31] = [Left channel, Right channel] -// dma[] = [R_0-7, R_8-15, R_16-23, R_24-31, L_0-7, L_8-15, L_16-23, L_24-31] = [Right channel, Left channel] -// -// where: -// L_0-7 is the least significant byte of the 32 bit sample in the Left channel -// L_24-31 is the most significant byte of the 32 bit sample in the Left channel -// -// Example: -// -// appbuf[] = [0x99, 0xBB, 0x11, 0x22, 0x44, 0x55, 0xAB, 0x77] = [Left channel, Right channel] -// dma[] = [0x44, 0x55, 0xAB, 0x77, 0x99, 0xBB, 0x11, 0x22] = [Right channel, Left channel] -// where: -// LEFT Channel = 0x99, 0xBB, 0x11, 0x22 -// RIGHT Channel = 0x44, 0x55, 0xAB, 0x77 -// -// samples in appbuf are in little endian format: -// 0x77 is the most significant byte of the 32-bit sample -// 0x44 is the least significant byte of the 32-bit sample -static void swap_32_bit_stereo_channels(mp_buffer_info_t *bufinfo) { - int32_t swap_sample; - int32_t *sample = bufinfo->buf; - uint32_t num_samples = bufinfo->len / 4; - for (uint32_t i = 0; i < num_samples; i += 2) { - swap_sample = sample[i + 1]; - sample[i + 1] = sample[i]; - sample[i] = swap_sample; - } -} - -static int8_t get_frame_mapping_index(i2s_bits_per_sample_t bits, format_t format) { +static int8_t get_frame_mapping_index(i2s_data_bit_width_t bits, format_t format) { if (format == MONO) { - if (bits == I2S_BITS_PER_SAMPLE_16BIT) { + if (bits == I2S_DATA_BIT_WIDTH_16BIT) { return 0; } else { // 32 bits return 1; } } else { // STEREO - if (bits == I2S_BITS_PER_SAMPLE_16BIT) { + if (bits == I2S_DATA_BIT_WIDTH_16BIT) { return 2; } else { // 32 bits return 3; @@ -149,32 +122,32 @@ static int8_t get_frame_mapping_index(i2s_bits_per_sample_t bits, format_t forma } } -static i2s_bits_per_sample_t get_dma_bits(uint8_t mode, i2s_bits_per_sample_t bits) { - if (mode == (I2S_MODE_MASTER | I2S_MODE_TX)) { +static i2s_data_bit_width_t get_dma_bits(uint8_t mode, i2s_data_bit_width_t bits) { + if (mode == MICROPY_PY_MACHINE_I2S_CONSTANT_TX) { return bits; } else { // Master Rx // read 32 bit samples for I2S hardware. e.g. MEMS microphones - return I2S_BITS_PER_SAMPLE_32BIT; + return I2S_DATA_BIT_WIDTH_32BIT; } } -static i2s_channel_fmt_t get_dma_format(uint8_t mode, format_t format) { - if (mode == (I2S_MODE_MASTER | I2S_MODE_TX)) { +static i2s_slot_mode_t get_dma_format(uint8_t mode, format_t format) { + if (mode == MICROPY_PY_MACHINE_I2S_CONSTANT_TX) { if (format == MONO) { - return I2S_CHANNEL_FMT_ONLY_LEFT; + return I2S_SLOT_MODE_MONO; } else { // STEREO - return I2S_CHANNEL_FMT_RIGHT_LEFT; + return I2S_SLOT_MODE_STEREO; } } else { // Master Rx // read stereo frames for all I2S hardware - return I2S_CHANNEL_FMT_RIGHT_LEFT; + return I2S_SLOT_MODE_STEREO; } } -static uint32_t get_dma_buf_count(uint8_t mode, i2s_bits_per_sample_t bits, format_t format, int32_t ibuf) { +static uint32_t get_dma_buf_count(uint8_t mode, i2s_data_bit_width_t bits, format_t format, int32_t ibuf) { // calculate how many DMA buffers need to be allocated uint32_t dma_frame_size_in_bytes = - (get_dma_bits(mode, bits) / 8) * (get_dma_format(mode, format) == I2S_CHANNEL_FMT_RIGHT_LEFT ? 2: 1); + (get_dma_bits(mode, bits) / 8) * (get_dma_format(mode, format) == I2S_SLOT_MODE_STEREO ? 2: 1); uint32_t dma_buf_count = ibuf / (DMA_BUF_LEN_IN_I2S_FRAMES * dma_frame_size_in_bytes); @@ -204,18 +177,23 @@ static uint32_t fill_appbuf_from_dma(machine_i2s_obj_t *self, mp_buffer_info_t * TickType_t delay; if (self->io_mode == ASYNCIO) { - delay = 0; // stop i2s_read() operation if DMA memory becomes empty + delay = 0; // stop i2s_channel_read() operation if DMA memory becomes empty } else { delay = portMAX_DELAY; // block until supplied buffer is filled } - esp_err_t ret = i2s_read( - self->i2s_id, + esp_err_t ret = i2s_channel_read( + self->i2s_chan_handle, self->transform_buffer, num_bytes_requested_from_dma, &num_bytes_received_from_dma, delay); - check_esp_err(ret); + + // i2s_channel_read returns ESP_ERR_TIMEOUT when buffer cannot be filled by the timeout delay. + if ((self->io_mode != ASYNCIO) || + ((self->io_mode == ASYNCIO) && (ret != ESP_ERR_TIMEOUT))) { + check_esp_err(ret); + } // process the transform buffer one frame at a time. // copy selected bytes from the transform buffer into the user supplied appbuf. @@ -246,9 +224,7 @@ static uint32_t fill_appbuf_from_dma(machine_i2s_obj_t *self, mp_buffer_info_t * if ((self->io_mode == ASYNCIO) && (num_bytes_received_from_dma < num_bytes_requested_from_dma)) { // Unable to fill the entire app buffer from DMA memory. This indicates all DMA RX buffers are empty. - // Clear the I2S event queue so ioctl() indicates that the I2S object cannot currently - // supply more audio samples - xQueueReset(self->i2s_event_queue); + self->dma_buffer_status = DMA_MEMORY_EMPTY; break; } } @@ -257,34 +233,28 @@ static uint32_t fill_appbuf_from_dma(machine_i2s_obj_t *self, mp_buffer_info_t * } static size_t copy_appbuf_to_dma(machine_i2s_obj_t *self, mp_buffer_info_t *appbuf) { - if ((self->bits == I2S_BITS_PER_SAMPLE_32BIT) && (self->format == STEREO)) { - swap_32_bit_stereo_channels(appbuf); - } - size_t num_bytes_written = 0; TickType_t delay; if (self->io_mode == ASYNCIO) { - delay = 0; // stop i2s_write() operation if DMA memory becomes full + delay = 0; // stop i2s_channel_write() operation if DMA memory becomes full } else { delay = portMAX_DELAY; // block until supplied buffer is emptied } - esp_err_t ret = i2s_write(self->i2s_id, appbuf->buf, appbuf->len, &num_bytes_written, delay); - check_esp_err(ret); + esp_err_t ret = i2s_channel_write(self->i2s_chan_handle, appbuf->buf, appbuf->len, &num_bytes_written, delay); + + // i2s_channel_write returns ESP_ERR_TIMEOUT when buffer cannot be emptied by the timeout delay. + if ((self->io_mode != ASYNCIO) || + ((self->io_mode == ASYNCIO) && (ret != ESP_ERR_TIMEOUT))) { + check_esp_err(ret); + } if ((self->io_mode == ASYNCIO) && (num_bytes_written < appbuf->len)) { // Unable to empty the entire app buffer into DMA memory. This indicates all DMA TX buffers are full. - // Clear the I2S event queue so ioctl() indicates that the I2S object cannot currently - // accept more audio samples - xQueueReset(self->i2s_event_queue); - - // Undo the swap transformation as the buffer has not been completely emptied. - // The asyncio stream writer will use the same buffer in a future write call. - if ((self->bits == I2S_BITS_PER_SAMPLE_32BIT) && (self->format == STEREO)) { - swap_32_bit_stereo_channels(appbuf); - } + self->dma_buffer_status = DMA_MEMORY_FULL; } + return num_bytes_written; } @@ -306,6 +276,34 @@ static void task_for_non_blocking_mode(void *self_in) { } } +// callback indicating that a DMA buffer was just filled with samples received from an I2S port +static IRAM_ATTR bool i2s_rx_recv_callback(i2s_chan_handle_t handle, i2s_event_data_t *event, void *self_in) { + machine_i2s_obj_t *self = (machine_i2s_obj_t *)self_in; + self->dma_buffer_status = DMA_MEMORY_NOT_EMPTY; + return false; +} + +// callback indicating that samples in a DMA buffer were just transmitted to an I2S port +static IRAM_ATTR bool i2s_tx_sent_callback(i2s_chan_handle_t handle, i2s_event_data_t *event, void *self_in) { + machine_i2s_obj_t *self = (machine_i2s_obj_t *)self_in; + self->dma_buffer_status = DMA_MEMORY_NOT_FULL; + return false; +} + +i2s_event_callbacks_t i2s_callbacks = { + .on_recv = i2s_rx_recv_callback, + .on_recv_q_ovf = NULL, + .on_sent = i2s_tx_sent_callback, + .on_send_q_ovf = NULL, +}; + +i2s_event_callbacks_t i2s_callbacks_null = { + .on_recv = NULL, + .on_recv_q_ovf = NULL, + .on_sent = NULL, + .on_send_q_ovf = NULL, +}; + static void mp_machine_i2s_init_helper(machine_i2s_obj_t *self, mp_arg_val_t *args) { // are Pins valid? int8_t sck = args[ARG_sck].u_obj == MP_OBJ_NULL ? -1 : machine_pin_get_id(args[ARG_sck].u_obj); @@ -313,16 +311,16 @@ static void mp_machine_i2s_init_helper(machine_i2s_obj_t *self, mp_arg_val_t *ar int8_t sd = args[ARG_sd].u_obj == MP_OBJ_NULL ? -1 : machine_pin_get_id(args[ARG_sd].u_obj); // is Mode valid? - i2s_mode_t mode = args[ARG_mode].u_int; - if ((mode != (I2S_MODE_MASTER | I2S_MODE_RX)) && - (mode != (I2S_MODE_MASTER | I2S_MODE_TX))) { + int8_t mode = args[ARG_mode].u_int; + if ((mode != (MICROPY_PY_MACHINE_I2S_CONSTANT_RX)) && + (mode != (MICROPY_PY_MACHINE_I2S_CONSTANT_TX))) { mp_raise_ValueError(MP_ERROR_TEXT("invalid mode")); } // is Bits valid? - i2s_bits_per_sample_t bits = args[ARG_bits].u_int; - if ((bits != I2S_BITS_PER_SAMPLE_16BIT) && - (bits != I2S_BITS_PER_SAMPLE_32BIT)) { + i2s_data_bit_width_t bits = args[ARG_bits].u_int; + if ((bits != I2S_DATA_BIT_WIDTH_16BIT) && + (bits != I2S_DATA_BIT_WIDTH_32BIT)) { mp_raise_ValueError(MP_ERROR_TEXT("invalid bits")); } @@ -348,54 +346,57 @@ static void mp_machine_i2s_init_helper(machine_i2s_obj_t *self, mp_arg_val_t *ar self->rate = args[ARG_rate].u_int; self->ibuf = args[ARG_ibuf].u_int; self->callback_for_non_blocking = MP_OBJ_NULL; - self->i2s_event_queue = NULL; self->non_blocking_mode_queue = NULL; self->non_blocking_mode_task = NULL; self->io_mode = BLOCKING; + self->is_deinit = false; + + if (mode == MICROPY_PY_MACHINE_I2S_CONSTANT_TX) { + self->dma_buffer_status = DMA_MEMORY_NOT_FULL; + } else { // rx + self->dma_buffer_status = DMA_MEMORY_NOT_EMPTY; + } + + i2s_chan_config_t chan_config = I2S_CHANNEL_DEFAULT_CONFIG(self->i2s_id, I2S_ROLE_MASTER); + chan_config.dma_desc_num = get_dma_buf_count(mode, bits, format, self->ibuf); + chan_config.dma_frame_num = DMA_BUF_LEN_IN_I2S_FRAMES; + chan_config.auto_clear = true; + + if (mode == MICROPY_PY_MACHINE_I2S_CONSTANT_TX) { + ESP_ERROR_CHECK(i2s_new_channel(&chan_config, &self->i2s_chan_handle, NULL)); + } else { // rx + ESP_ERROR_CHECK(i2s_new_channel(&chan_config, NULL, &self->i2s_chan_handle)); + } - i2s_config_t i2s_config; - i2s_config.communication_format = I2S_COMM_FORMAT_STAND_I2S; - i2s_config.mode = mode; - i2s_config.bits_per_sample = get_dma_bits(mode, bits); - i2s_config.channel_format = get_dma_format(mode, format); - i2s_config.sample_rate = self->rate; - i2s_config.intr_alloc_flags = ESP_INTR_FLAG_LOWMED; - i2s_config.dma_desc_num = get_dma_buf_count(mode, bits, format, self->ibuf); - i2s_config.dma_frame_num = DMA_BUF_LEN_IN_I2S_FRAMES; - i2s_config.use_apll = false; - i2s_config.tx_desc_auto_clear = true; - i2s_config.fixed_mclk = 0; - i2s_config.mclk_multiple = I2S_MCLK_MULTIPLE_256; - i2s_config.bits_per_chan = 0; - - // I2S queue size equals the number of DMA buffers - check_esp_err(i2s_driver_install(self->i2s_id, &i2s_config, i2s_config.dma_desc_num, &self->i2s_event_queue)); - - // apply low-level workaround for bug in some ESP-IDF versions that swap - // the left and right channels - // https://github.com/espressif/esp-idf/issues/6625 - #if CONFIG_IDF_TARGET_ESP32S3 - REG_SET_BIT(I2S_TX_CONF_REG(self->i2s_id), I2S_TX_MSB_SHIFT); - REG_SET_BIT(I2S_TX_CONF_REG(self->i2s_id), I2S_RX_MSB_SHIFT); - #else - REG_SET_BIT(I2S_CONF_REG(self->i2s_id), I2S_TX_MSB_RIGHT); - REG_SET_BIT(I2S_CONF_REG(self->i2s_id), I2S_RX_MSB_RIGHT); - #endif - - i2s_pin_config_t pin_config; - pin_config.mck_io_num = I2S_PIN_NO_CHANGE; - pin_config.bck_io_num = self->sck; - pin_config.ws_io_num = self->ws; - - if (mode == (I2S_MODE_MASTER | I2S_MODE_RX)) { - pin_config.data_in_num = self->sd; - pin_config.data_out_num = I2S_PIN_NO_CHANGE; - } else { // TX - pin_config.data_in_num = I2S_PIN_NO_CHANGE; - pin_config.data_out_num = self->sd; + i2s_std_slot_config_t slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(get_dma_bits(mode, bits), get_dma_format(mode, format)); + slot_cfg.slot_mask = I2S_STD_SLOT_BOTH; + + i2s_std_config_t std_cfg = { + .clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(self->rate), + .slot_cfg = slot_cfg, + .gpio_cfg = { + .mclk = I2S_GPIO_UNUSED, + .bclk = self->sck, + .ws = self->ws, + .invert_flags = { + .mclk_inv = false, + .bclk_inv = false, + .ws_inv = false, + }, + }, + }; + + if (mode == MICROPY_PY_MACHINE_I2S_CONSTANT_TX) { + std_cfg.gpio_cfg.dout = self->sd; + std_cfg.gpio_cfg.din = I2S_GPIO_UNUSED; + } else { // rx + std_cfg.gpio_cfg.dout = I2S_GPIO_UNUSED; + std_cfg.gpio_cfg.din = self->sd; } - check_esp_err(i2s_set_pin(self->i2s_id, &pin_config)); + ESP_ERROR_CHECK(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)); + ESP_ERROR_CHECK(i2s_channel_enable(self->i2s_chan_handle)); } static machine_i2s_obj_t *mp_machine_i2s_make_new_instance(mp_int_t i2s_id) { @@ -417,19 +418,22 @@ 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) { - i2s_driver_uninstall(self->i2s_id); + if (!self->is_deinit) { + ESP_ERROR_CHECK(i2s_channel_disable(self->i2s_chan_handle)); + ESP_ERROR_CHECK(i2s_channel_register_event_callback(self->i2s_chan_handle, &i2s_callbacks_null, self)); + ESP_ERROR_CHECK(i2s_del_channel(self->i2s_chan_handle)); - if (self->non_blocking_mode_task != NULL) { - vTaskDelete(self->non_blocking_mode_task); - self->non_blocking_mode_task = NULL; - } + if (self->non_blocking_mode_task != NULL) { + vTaskDelete(self->non_blocking_mode_task); + self->non_blocking_mode_task = NULL; + } - if (self->non_blocking_mode_queue != NULL) { - vQueueDelete(self->non_blocking_mode_queue); - self->non_blocking_mode_queue = NULL; + if (self->non_blocking_mode_queue != NULL) { + vQueueDelete(self->non_blocking_mode_queue); + self->non_blocking_mode_queue = NULL; + } + self->is_deinit = true; } - - self->i2s_event_queue = NULL; } static void mp_machine_i2s_irq_update(machine_i2s_obj_t *self) { diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index acf065384b7da..be02d45883bcd 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -9,7 +9,7 @@ #include "esp_random.h" #include "esp_system.h" #include "freertos/FreeRTOS.h" -#include "driver/i2s.h" +#include "driver/i2s_std.h" #include "esp_wifi_types.h" #ifndef MICROPY_CONFIG_ROM_LEVEL @@ -147,8 +147,8 @@ #endif #define MICROPY_PY_MACHINE_I2S_INCLUDEFILE "ports/esp32/machine_i2s.c" #define MICROPY_PY_MACHINE_I2S_FINALISER (1) -#define MICROPY_PY_MACHINE_I2S_CONSTANT_RX (I2S_MODE_MASTER | I2S_MODE_RX) -#define MICROPY_PY_MACHINE_I2S_CONSTANT_TX (I2S_MODE_MASTER | I2S_MODE_TX) +#define MICROPY_PY_MACHINE_I2S_CONSTANT_RX (I2S_DIR_RX) +#define MICROPY_PY_MACHINE_I2S_CONSTANT_TX (I2S_DIR_TX) #define MICROPY_PY_MACHINE_UART (1) #define MICROPY_PY_MACHINE_UART_INCLUDEFILE "ports/esp32/machine_uart.c" #define MICROPY_PY_MACHINE_UART_SENDBREAK (1)
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: