Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,7 @@ CIRCUITPY_ESP_FLASH_FREQ = 80m
CIRCUITPY_ESP_FLASH_SIZE = 4MB

CIRCUITPY_ESP_USB_SERIAL_JTAG = 0

ESPRESSIF_ESP32C3_LYRA_AUDIOBUSIO_PDMOUT = 1

CFLAGS += -DESPRESSIF_ESP32C3_LYRA_AUDIOBUSIO_PDMOUT=$(ESPRESSIF_ESP32C3_LYRA_AUDIOBUSIO_PDMOUT)
18 changes: 18 additions & 0 deletions ports/espressif/common-hal/audiobusio/I2SOut.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,29 @@

#include "driver/i2s_std.h"

#if ESPRESSIF_ESP32C3_LYRA_AUDIOBUSIO_PDMOUT
#include "driver/i2s_pdm.h"
#endif

// Caller validates that pins are free.
void common_hal_audiobusio_i2sout_construct(audiobusio_i2sout_obj_t *self,
const mcu_pin_obj_t *bit_clock, const mcu_pin_obj_t *word_select,
const mcu_pin_obj_t *data, const mcu_pin_obj_t *main_clock, bool left_justified) {
port_i2s_allocate_init(&self->i2s, left_justified);

#if ESPRESSIF_ESP32C3_LYRA_AUDIOBUSIO_PDMOUT
i2s_pdm_tx_config_t pdm_tx_cfg = {
.clk_cfg = I2S_PDM_TX_CLK_DEFAULT_CONFIG(16000),
.slot_cfg = I2S_PDM_TX_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_MONO),
.gpio_cfg = {
.dout = data->number,
.invert_flags = {
.clk_inv = false,
},
},
};
CHECK_ESP_RESULT(i2s_channel_init_pdm_tx_mode(self->i2s.handle, &pdm_tx_cfg));
#else
i2s_std_config_t i2s_config = {
.clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(48000),
.slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO),
Expand All @@ -43,6 +60,7 @@ void common_hal_audiobusio_i2sout_construct(audiobusio_i2sout_obj_t *self,
}
};
CHECK_ESP_RESULT(i2s_channel_init_std_mode(self->i2s.handle, &i2s_config));
#endif
self->bit_clock = bit_clock;
self->word_select = word_select;
self->mclk = main_clock;
Expand Down
25 changes: 21 additions & 4 deletions ports/espressif/common-hal/audiobusio/__init__.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,18 @@
#define I2S_DMA_BUFFER_MAX_SIZE 4092
// The number of DMA buffers to allocate
#define CIRCUITPY_BUFFER_COUNT (3)

#if ESPRESSIF_ESP32C3_LYRA_AUDIOBUSIO_PDMOUT
// The maximum DMA buffer size in frames (at mono 16-bit)
#define CIRCUITPY_BUFFER_SIZE (I2S_DMA_BUFFER_MAX_SIZE / 8)
// The number of output channels is fixed at 1
#define CIRCUITPY_OUTPUT_SLOTS (1)
#else
// The maximum DMA buffer size in frames (at stereo 16-bit)
#define CIRCUITPY_BUFFER_SIZE (I2S_DMA_BUFFER_MAX_SIZE / 4)
// The number of output channels is fixed at 2
#define CIRCUITPY_OUTPUT_SLOTS (2)
#endif

static void i2s_fill_buffer(i2s_t *self) {
if (self->next_buffer_size == 0) {
Expand All @@ -31,7 +39,7 @@ static void i2s_fill_buffer(i2s_t *self) {
}
int16_t *output_buffer = (int16_t *)self->next_buffer;
size_t output_buffer_size = self->next_buffer_size;
const size_t bytes_per_output_frame = 4;
const size_t bytes_per_output_frame = CIRCUITPY_OUTPUT_SLOTS * 2;
size_t bytes_per_input_frame = self->channel_count * self->bytes_per_sample;
if (!self->playing || self->paused || !self->sample || self->stopping) {
memset(output_buffer, 0, self->next_buffer_size);
Expand Down Expand Up @@ -62,7 +70,8 @@ static void i2s_fill_buffer(i2s_t *self) {
size_t sample_bytecount = self->sample_end - self->sample_data;
// The framecount is the minimum of space left in the output buffer or left in the incoming sample.
size_t framecount = MIN(output_buffer_size / bytes_per_output_frame, sample_bytecount / bytes_per_input_frame);
if (self->samples_signed && self->channel_count == 2) {

if (self->samples_signed && self->channel_count == CIRCUITPY_OUTPUT_SLOTS) {
if (self->bytes_per_sample == 2) {
memcpy(output_buffer, self->sample_data, framecount * bytes_per_output_frame);
} else {
Expand Down Expand Up @@ -165,8 +174,16 @@ void port_i2s_play(i2s_t *self, mp_obj_t sample, bool loop) {
audiosample_reset_buffer(self->sample, false, 0);

uint32_t sample_rate = audiosample_get_sample_rate(sample);

#if ESPRESSIF_ESP32C3_LYRA_AUDIOBUSIO_PDMOUT
i2s_pdm_tx_clk_config_t clk_config = I2S_PDM_TX_CLK_DEFAULT_CONFIG(sample_rate);
CHECK_ESP_RESULT(i2s_channel_reconfig_pdm_tx_clock(self->handle, &clk_config));
size_t frame_size = sizeof(uint16_t);
#else
i2s_std_clk_config_t clk_config = I2S_STD_CLK_DEFAULT_CONFIG(sample_rate);
CHECK_ESP_RESULT(i2s_channel_reconfig_std_clock(self->handle, &clk_config));
size_t frame_size = sizeof(uint32_t);
#endif

// preload the data
self->playing = true;
Expand All @@ -183,12 +200,12 @@ void port_i2s_play(i2s_t *self, mp_obj_t sample, bool loop) {
self->next_buffer = &starting_frame;
self->next_buffer_size = sizeof(starting_frame);
i2s_fill_buffer(self);
i2s_channel_preload_data(self->handle, &starting_frame, sizeof(uint32_t), &bytes_loaded);
i2s_channel_preload_data(self->handle, &starting_frame, frame_size, &bytes_loaded);
preloaded += bytes_loaded;
}

// enable the channel
i2s_channel_enable(self->handle);
CHECK_ESP_RESULT(i2s_channel_enable(self->handle));

// The IDF will call us back when there is a free DMA buffer.
}
Expand Down
4 changes: 4 additions & 0 deletions ports/espressif/common-hal/audiobusio/__init__.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@

#include "driver/i2s_std.h"

#if ESPRESSIF_ESP32C3_LYRA_AUDIOBUSIO_PDMOUT
#include "driver/i2s_pdm.h"
#endif

typedef struct {
mp_obj_t *sample;
bool left_justified;
Expand Down
3 changes: 3 additions & 0 deletions ports/espressif/mpconfigport.mk
Original file line number Diff line number Diff line change
Expand Up @@ -349,3 +349,6 @@ USB_NUM_IN_ENDPOINTS = 5

# Usually lots of flash space available
CIRCUITPY_MESSAGE_COMPRESSION_LEVEL ?= 1

ESPRESSIF_ESP32C3_LYRA_AUDIOBUSIO_PDMOUT ?= 0
CFLAGS += -DESPRESSIF_ESP32C3_LYRA_AUDIOBUSIO_PDMOUT=$(ESPRESSIF_ESP32C3_LYRA_AUDIOBUSIO_PDMOUT)