ports/esp32: Implement PDM RX mode for I2S.

Signed-off-by: maple "mavica" syrup <maple@maple.pet>
pull/14176/head
maple "mavica" syrup 2024-03-25 18:50:06 -03:00
rodzic ec24a150e0
commit 843085b7cf
2 zmienionych plików z 73 dodań i 26 usunięć

Wyświetl plik

@ -29,6 +29,9 @@
#include "py/mphal.h"
#include "driver/i2s_std.h"
#if MICROPY_PY_MACHINE_PDM
#include "driver/i2s_pdm.h"
#endif
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
@ -125,6 +128,9 @@ static int8_t get_frame_mapping_index(i2s_data_bit_width_t bits, format_t format
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 if (mode == MICROPY_PY_MACHINE_I2S_PDM_RX) { // PDM Rx
// fixed to 16-bit per ESP-IDF documentation
return I2S_DATA_BIT_WIDTH_16BIT;
} else { // Master Rx
// read 32 bit samples for I2S hardware. e.g. MEMS microphones
return I2S_DATA_BIT_WIDTH_32BIT;
@ -132,7 +138,8 @@ static i2s_data_bit_width_t get_dma_bits(uint8_t mode, i2s_data_bit_width_t bits
}
static i2s_slot_mode_t get_dma_format(uint8_t mode, format_t format) {
if (mode == MICROPY_PY_MACHINE_I2S_CONSTANT_TX) {
if ((mode == MICROPY_PY_MACHINE_I2S_CONSTANT_TX) ||
(mode == MICROPY_PY_MACHINE_I2S_PDM_RX)) {
if (format == MONO) {
return I2S_SLOT_MODE_MONO;
} else { // STEREO
@ -305,15 +312,20 @@ i2s_event_callbacks_t i2s_callbacks_null = {
};
static void mp_machine_i2s_init_helper(machine_i2s_obj_t *self, mp_arg_val_t *args) {
int8_t mode = args[ARG_mode].u_int;
int8_t ws = -1;
// are Pins valid?
int8_t sck = args[ARG_sck].u_obj == MP_OBJ_NULL ? -1 : machine_pin_get_id(args[ARG_sck].u_obj);
int8_t ws = args[ARG_ws].u_obj == MP_OBJ_NULL ? -1 : machine_pin_get_id(args[ARG_ws].u_obj);
if (mode != (MICROPY_PY_MACHINE_I2S_PDM_RX)) {
ws = args[ARG_ws].u_obj == MP_OBJ_NULL ? -1 : machine_pin_get_id(args[ARG_ws].u_obj);
}
int8_t sd = args[ARG_sd].u_obj == MP_OBJ_NULL ? -1 : machine_pin_get_id(args[ARG_sd].u_obj);
// is Mode valid?
int8_t mode = args[ARG_mode].u_int;
if ((mode != (MICROPY_PY_MACHINE_I2S_CONSTANT_RX)) &&
(mode != (MICROPY_PY_MACHINE_I2S_CONSTANT_TX))) {
(mode != (MICROPY_PY_MACHINE_I2S_CONSTANT_TX)) &&
(mode != (MICROPY_PY_MACHINE_I2S_PDM_RX))) {
mp_raise_ValueError(MP_ERROR_TEXT("invalid mode"));
}
@ -368,33 +380,64 @@ static void mp_machine_i2s_init_helper(machine_i2s_obj_t *self, mp_arg_val_t *ar
ESP_ERROR_CHECK(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));
slot_cfg.slot_mask = I2S_STD_SLOT_BOTH;
if (mode != MICROPY_PY_MACHINE_I2S_PDM_RX) {
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,
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;
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;
}
ESP_ERROR_CHECK(i2s_channel_init_std_mode(self->i2s_chan_handle, &std_cfg));
} else { // PDM mode
#if MICROPY_PY_MACHINE_PDM
// PDM can only be in id 0
if (self->i2s_id != 0) {
mp_raise_ValueError(MP_ERROR_TEXT("invalid i2s id for PDM mode"));
}
i2s_pdm_rx_slot_config_t slot_cfg = I2S_PDM_RX_SLOT_DEFAULT_CONFIG(get_dma_bits(mode, bits), get_dma_format(mode, format));
slot_cfg.slot_mask = I2S_PDM_SLOT_BOTH;
i2s_pdm_rx_config_t pdm_cfg = {
.clk_cfg = I2S_PDM_RX_CLK_DEFAULT_CONFIG(self->rate),
.slot_cfg = slot_cfg,
.gpio_cfg = {
.clk = self->sck,
.din = self->sd,
.invert_flags = {
.clk_inv = false,
},
},
};
pdm_cfg.clk_cfg.dn_sample_mode = I2S_PDM_DSR_MAX;
ESP_ERROR_CHECK(i2s_channel_init_pdm_rx_mode(self->i2s_chan_handle, &pdm_cfg));
#else
mp_raise_ValueError(MP_ERROR_TEXT("invalid mode"));
#endif
}
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));
}

Wyświetl plik

@ -149,6 +149,10 @@
#define MICROPY_PY_MACHINE_I2S_FINALISER (1)
#define MICROPY_PY_MACHINE_I2S_CONSTANT_RX (I2S_DIR_RX)
#define MICROPY_PY_MACHINE_I2S_CONSTANT_TX (I2S_DIR_TX)
#ifndef MICROPY_PY_MACHINE_PDM
#define MICROPY_PY_MACHINE_PDM (SOC_I2S_SUPPORTS_PDM_RX)
#endif
#define MICROPY_PY_MACHINE_I2S_PDM_RX ((I2S_DIR_RX) | (BIT(2)))
#define MICROPY_PY_MACHINE_UART (1)
#define MICROPY_PY_MACHINE_UART_INCLUDEFILE "ports/esp32/machine_uart.c"
#define MICROPY_PY_MACHINE_UART_SENDBREAK (1)