Skip to content

Commit

Permalink
PDM RX support
Browse files Browse the repository at this point in the history
  • Loading branch information
pschatzmann committed Nov 7, 2024
1 parent 177fbd5 commit 5214dec
Showing 1 changed file with 171 additions and 124 deletions.
295 changes: 171 additions & 124 deletions src/AudioTools/CoreAudio/AudioI2S/I2SESP32V1.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@
#include "driver/i2s_tdm.h"
#include "esp_system.h"

#define IS_I2S_IMPLEMENTED

#define IS_I2S_IMPLEMENTED

namespace audio_tools {

Expand Down Expand Up @@ -106,7 +105,7 @@ class I2SDriverESP32V1 {
size_t writeBytes(const void *src, size_t size_bytes) {
TRACED();
size_t result;
assert(tx_chan !=nullptr);
assert(tx_chan != nullptr);
if (i2s_channel_write(tx_chan, src, size_bytes, &result,
ticks_to_wait_write) != ESP_OK) {
TRACEE();
Expand Down Expand Up @@ -140,11 +139,12 @@ class I2SDriverESP32V1 {
TickType_t ticks_to_wait_write = portMAX_DELAY;

struct DriverCommon {
virtual i2s_chan_config_t getChannelConfig(I2SConfigESP32V1 &cfg) = 0;
virtual bool startChannels(I2SConfigESP32V1 &cfg,
i2s_chan_handle_t &tx_chan,
i2s_chan_handle_t &rx_chan, int txPin,
int rxPin) = 0;

virtual i2s_chan_config_t getChannelConfig(I2SConfigESP32V1 &cfg) = 0;
// changes the sample rate
virtual bool changeSampleRate(I2SConfigESP32V1 &cfg,
i2s_chan_handle_t &tx_chan,
Expand All @@ -154,6 +154,56 @@ class I2SDriverESP32V1 {
};

struct DriverI2S : public DriverCommon {
bool startChannels(I2SConfigESP32V1 &cfg, i2s_chan_handle_t &tx_chan,
i2s_chan_handle_t &rx_chan, int txPin, int rxPin) {
TRACED();
LOGI("tx: %d, rx: %d", txPin, rxPin);
i2s_std_config_t std_cfg = {
.clk_cfg = getClockConfig(cfg),
.slot_cfg = getSlotConfig(cfg),
.gpio_cfg =
{
.mclk = (gpio_num_t)cfg.pin_mck,
.bclk = (gpio_num_t)cfg.pin_bck,
.ws = (gpio_num_t)cfg.pin_ws,
.dout = (gpio_num_t)txPin,
.din = (gpio_num_t)rxPin,
.invert_flags =
{
.mclk_inv = false,
.bclk_inv = false,
.ws_inv = false,
},
},
};

if (cfg.rx_tx_mode == RXTX_MODE || cfg.rx_tx_mode == TX_MODE) {
if (i2s_channel_init_std_mode(tx_chan, &std_cfg) != ESP_OK) {
LOGE("i2s_channel_init_std_mode %s", "tx");
return false;
}
if (i2s_channel_enable(tx_chan) != ESP_OK) {
LOGE("i2s_channel_enable %s", "tx");
return false;
}
}

if (cfg.rx_tx_mode == RXTX_MODE || cfg.rx_tx_mode == RX_MODE) {
if (i2s_channel_init_std_mode(rx_chan, &std_cfg) != ESP_OK) {
LOGE("i2s_channel_init_std_mode %s", "rx");
return false;
}
if (i2s_channel_enable(rx_chan) != ESP_OK) {
LOGE("i2s_channel_enable %s", "rx");
return false;
}
}

LOGD("%s - %s", __func__, "started");
return true;
}

protected:
i2s_std_slot_config_t getSlotConfig(I2SConfigESP32V1 &cfg) {
TRACED();
i2s_std_slot_config_t result;
Expand Down Expand Up @@ -212,10 +262,10 @@ class I2SDriverESP32V1 {
TRACED();
i2s_std_clk_config_t clk_cfg =
I2S_STD_CLK_DEFAULT_CONFIG((uint32_t)cfg.sample_rate);
if (cfg.mclk_multiple > 0){
clk_cfg.mclk_multiple = (i2s_mclk_multiple_t) cfg.mclk_multiple;
if (cfg.mclk_multiple > 0) {
clk_cfg.mclk_multiple = (i2s_mclk_multiple_t)cfg.mclk_multiple;
} else {
if (cfg.pin_mck !=-1 && cfg.bits_per_sample == 24) {
if (cfg.pin_mck != -1 && cfg.bits_per_sample == 24) {
// mclk_multiple' should be the multiple of 3 while using 24-bit
clk_cfg.mclk_multiple = I2S_MCLK_MULTIPLE_384;
LOGI("mclk_multiple=384");
Expand All @@ -224,55 +274,6 @@ class I2SDriverESP32V1 {
return clk_cfg;
}

bool startChannels(I2SConfigESP32V1 &cfg, i2s_chan_handle_t &tx_chan,
i2s_chan_handle_t &rx_chan, int txPin, int rxPin) {
TRACED();
LOGI("tx: %d, rx: %d", txPin, rxPin);
i2s_std_config_t std_cfg = {
.clk_cfg = getClockConfig(cfg),
.slot_cfg = getSlotConfig(cfg),
.gpio_cfg =
{
.mclk = (gpio_num_t)cfg.pin_mck,
.bclk = (gpio_num_t)cfg.pin_bck,
.ws = (gpio_num_t)cfg.pin_ws,
.dout = (gpio_num_t)txPin,
.din = (gpio_num_t)rxPin,
.invert_flags =
{
.mclk_inv = false,
.bclk_inv = false,
.ws_inv = false,
},
},
};

if (cfg.rx_tx_mode == RXTX_MODE || cfg.rx_tx_mode == TX_MODE) {
if (i2s_channel_init_std_mode(tx_chan, &std_cfg) != ESP_OK) {
LOGE("i2s_channel_init_std_mode %s", "tx");
return false;
}
if (i2s_channel_enable(tx_chan) != ESP_OK) {
LOGE("i2s_channel_enable %s", "tx");
return false;
}
}

if (cfg.rx_tx_mode == RXTX_MODE || cfg.rx_tx_mode == RX_MODE) {
if (i2s_channel_init_std_mode(rx_chan, &std_cfg) != ESP_OK) {
LOGE("i2s_channel_init_std_mode %s", "rx");
return false;
}
if (i2s_channel_enable(rx_chan) != ESP_OK) {
LOGE("i2s_channel_enable %s", "rx");
return false;
}
}

LOGD("%s - %s", __func__, "started");
return true;
}

bool changeSampleRate(I2SConfigESP32V1 &cfg, i2s_chan_handle_t &tx_chan,
i2s_chan_handle_t &rx_chan) override {
bool rc = false;
Expand All @@ -295,12 +296,30 @@ class I2SDriverESP32V1 {
#ifdef USE_PDM

struct DriverPDM : public DriverCommon {
bool startChannels(I2SConfigESP32V1 &cfg, i2s_chan_handle_t &tx_chan,
i2s_chan_handle_t &rx_chan, int txPin, int rxPin) {
if (cfg.rx_tx_mode == TX_MODE) {
return startTX(cfg, tx_chan, txPin);
} else if (cfg.rx_tx_mode == RX_MODE) {
return startRX(cfg, tx_chan, txPin);
}
LOGE("Only RX and TX is supported for PDM")
return false;
}

protected:
i2s_pdm_tx_slot_config_t getTxSlotConfig(I2SConfigESP32V1 &cfg) {
return I2S_PDM_TX_SLOT_DEFAULT_CONFIG(
(i2s_data_bit_width_t)cfg.bits_per_sample,
(i2s_slot_mode_t)cfg.channels);
}

i2s_pdm_rx_slot_config_t getRxSlotConfig(I2SConfigESP32V1 &cfg) {
return I2S_PDM_RX_SLOT_DEFAULT_CONFIG(
(i2s_data_bit_width_t)cfg.bits_per_sample,
(i2s_slot_mode_t)cfg.channels);
}

i2s_chan_config_t getChannelConfig(I2SConfigESP32V1 &cfg) {
return I2S_CHANNEL_DEFAULT_CONFIG(
(i2s_port_t)cfg.port_no,
Expand All @@ -311,37 +330,62 @@ class I2SDriverESP32V1 {
return I2S_PDM_TX_CLK_DEFAULT_CONFIG((uint32_t)cfg.sample_rate);
}

bool startChannels(I2SConfigESP32V1 &cfg, i2s_chan_handle_t &tx_chan,
i2s_chan_handle_t &rx_chan, int txPin, int rxPin) {
if (cfg.rx_tx_mode == TX_MODE) {
i2s_pdm_tx_config_t pdm_tx_cfg = {
.clk_cfg = getTxClockConfig(cfg),
.slot_cfg = getTxSlotConfig(cfg),
.gpio_cfg =
{
.clk = (gpio_num_t)cfg.pin_bck,
.dout = (gpio_num_t)txPin,
.invert_flags =
{
.clk_inv = false,
},
},
};

if (i2s_channel_init_pdm_tx_mode(tx_chan, &pdm_tx_cfg) != ESP_OK) {
LOGE("i2s_channel_init_pdm_tx_mode %s", "tx");
return false;
}
if (i2s_channel_enable(tx_chan) != ESP_OK) {
LOGE("i2s_channel_enable %s", "tx");
return false;
}
} else {
LOGE("Only TX supported for PDM");
i2s_pdm_rx_clk_config_t getRxClockConfig(I2SConfigESP32V1 &cfg) {
return I2S_PDM_RX_CLK_DEFAULT_CONFIG((uint32_t)cfg.sample_rate);
}

bool startTX(I2SConfigESP32V1 &cfg, i2s_chan_handle_t &tx_chan, int txPin) {
i2s_pdm_tx_config_t pdm_tx_cfg = {
.clk_cfg = getTxClockConfig(cfg),
.slot_cfg = getTxSlotConfig(cfg),
.gpio_cfg =
{
.clk = (gpio_num_t)cfg.pin_bck,
.dout = (gpio_num_t)txPin,
.invert_flags =
{
.clk_inv = false,
},
},
};

if (i2s_channel_init_pdm_tx_mode(tx_chan, &pdm_tx_cfg) != ESP_OK) {
LOGE("i2s_channel_init_pdm_tx_mode %s", "tx");
return false;
}
if (i2s_channel_enable(tx_chan) != ESP_OK) {
LOGE("i2s_channel_enable %s", "tx");
return false;
}
return true;
}

bool startRX(I2SConfigESP32V1 &cfg, i2s_chan_handle_t &rx_chan, int rxPin) {
i2s_pdm_rx_config_t pdm_rx_cfg = {
.clk_cfg = getRxClockConfig(cfg),
.slot_cfg = getRxSlotConfig(cfg),
.gpio_cfg =
{
.clk = (gpio_num_t)cfg.pin_bck,
.din = (gpio_num_t)rxPin,
.invert_flags =
{
.clk_inv = false,
},
},
};

if (i2s_channel_init_pdm_rx_mode(rx_chan, &pdm_rx_cfg) != ESP_OK) {
LOGE("i2s_channel_init_pdm_rx_mode %s", "rx");
return false;
}
if (i2s_channel_enable(rx_chan) != ESP_OK) {
LOGE("i2s_channel_enable %s", "tx");
return false;
}
return true;
}

} pdm;

#endif
Expand All @@ -350,26 +394,65 @@ class I2SDriverESP32V1 {
// example at
// https://github.com/espressif/esp-idf/blob/v5.3-dev/examples/peripherals/i2s/i2s_basic/i2s_tdm/main/i2s_tdm_example_main.c
struct DriverTDM : public DriverCommon {
bool startChannels(I2SConfigESP32V1 &cfg, i2s_chan_handle_t &tx_chan,
i2s_chan_handle_t &rx_chan, int txPin, int rxPin) {
i2s_tdm_config_t tdm_cfg = {
.clk_cfg = getClockConfig(cfg),
.slot_cfg = getSlotConfig(cfg),
.gpio_cfg =
{
.mclk = (gpio_num_t)cfg.pin_mck,
.bclk = (gpio_num_t)cfg.pin_bck,
.ws = (gpio_num_t)cfg.pin_ws,
.dout = (gpio_num_t)txPin,
.din = (gpio_num_t)rxPin,
.invert_flags =
{
.mclk_inv = false,
.bclk_inv = false,
.ws_inv = false,
},
},
};

if (cfg.rx_tx_mode == TX_MODE) {
if (i2s_channel_init_tdm_mode(tx_chan, &tdm_cfg) != ESP_OK) {
LOGE("i2s_channel_init_tdm_tx_mode %s", "tx");
return false;
}
}
if (cfg.rx_tx_mode == RX_MODE) {
if (i2s_channel_init_tdm_mode(rx_chan, &tdm_cfg) != ESP_OK) {
LOGE("i2s_channel_init_tdm_tx_mode %s", "rx");
return false;
}
return true;
}
LOGE("Only RX and TX is supported for TDM")
return false;
}

protected:
i2s_tdm_slot_config_t getSlotConfig(I2SConfigESP32V1 &cfg) {
int slots = 0;
for (int j = 0; j < cfg.channels; j++) {
slots |= 1 << j;
}
// setup default format
i2s_tdm_slot_config_t slot_cfg = I2S_TDM_PHILIPS_SLOT_DEFAULT_CONFIG(
(i2s_data_bit_width_t)cfg.bits_per_sample, I2S_SLOT_MODE_STEREO,
(i2s_tdm_slot_mask_t)slots);
(i2s_data_bit_width_t)cfg.bits_per_sample, I2S_SLOT_MODE_STEREO,
(i2s_tdm_slot_mask_t)slots);

switch(cfg.i2s_format){
case I2S_RIGHT_JUSTIFIED_FORMAT:
switch (cfg.i2s_format) {
case I2S_RIGHT_JUSTIFIED_FORMAT:
case I2S_LSB_FORMAT:
case I2S_PHILIPS_FORMAT:
case I2S_STD_FORMAT:
slot_cfg = I2S_TDM_PHILIPS_SLOT_DEFAULT_CONFIG(
(i2s_data_bit_width_t)cfg.bits_per_sample, I2S_SLOT_MODE_STEREO,
(i2s_tdm_slot_mask_t)slots);
break;
case I2S_LEFT_JUSTIFIED_FORMAT:
case I2S_LEFT_JUSTIFIED_FORMAT:
case I2S_MSB_FORMAT:
slot_cfg = I2S_TDM_MSB_SLOT_DEFAULT_CONFIG(
(i2s_data_bit_width_t)cfg.bits_per_sample, I2S_SLOT_MODE_STEREO,
Expand Down Expand Up @@ -397,42 +480,6 @@ class I2SDriverESP32V1 {
return I2S_TDM_CLK_DEFAULT_CONFIG((uint32_t)cfg.sample_rate);
}

bool startChannels(I2SConfigESP32V1 &cfg, i2s_chan_handle_t &tx_chan,
i2s_chan_handle_t &rx_chan, int txPin, int rxPin) {
i2s_tdm_config_t tdm_cfg = {
.clk_cfg = getClockConfig(cfg),
.slot_cfg = getSlotConfig(cfg),
.gpio_cfg =
{
.mclk = (gpio_num_t)cfg.pin_mck,
.bclk = (gpio_num_t)cfg.pin_bck,
.ws = (gpio_num_t)cfg.pin_ws,
.dout = (gpio_num_t)txPin,
.din = (gpio_num_t)rxPin,
.invert_flags =
{
.mclk_inv = false,
.bclk_inv = false,
.ws_inv = false,
},
},
};

if (cfg.rx_tx_mode == TX_MODE) {
if (i2s_channel_init_tdm_mode(tx_chan, &tdm_cfg) != ESP_OK) {
LOGE("i2s_channel_init_tdm_tx_mode %s", "tx");
return false;
}
}
if (cfg.rx_tx_mode == RX_MODE) {
if (i2s_channel_init_tdm_mode(rx_chan, &tdm_cfg) != ESP_OK) {
LOGE("i2s_channel_init_tdm_tx_mode %s", "rx");
return false;
}
return true;
}
return false;
}
} tdm;

#endif
Expand Down

0 comments on commit 5214dec

Please sign in to comment.