Skip to content
Merged
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
6 changes: 5 additions & 1 deletion locale/circuitpython.pot
Original file line number Diff line number Diff line change
Expand Up @@ -2498,6 +2498,10 @@ msgstr ""
msgid "binary op %q not implemented"
msgstr ""

#: ports/espressif/common-hal/audiobusio/PDMIn.c
msgid "bit_depth must be 8, 16, 24, or 32."
msgstr ""

#: shared-module/bitmapfilter/__init__.c
msgid "bitmap size and depth must match"
msgstr ""
Expand Down Expand Up @@ -2592,7 +2596,7 @@ msgstr ""
msgid "can't cancel self"
msgstr ""

#: shared-module/adafruit_pixelbuf/PixelBuf.c
#: py/obj.c shared-module/adafruit_pixelbuf/PixelBuf.c
msgid "can't convert %q to %q"
msgstr ""

Expand Down
126 changes: 126 additions & 0 deletions ports/espressif/common-hal/audiobusio/PDMIn.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,129 @@
// SPDX-FileCopyrightText: Copyright (c) 2024 Adafruit Industries LLC
//
// SPDX-License-Identifier: MIT


#include "bindings/espidf/__init__.h"

#include "common-hal/audiobusio/PDMIn.h"
#include "py/mpprint.h"
#include "py/runtime.h"
#include "shared-bindings/audiobusio/PDMIn.h"


#include "driver/i2s_pdm.h"



#if CIRCUITPY_AUDIOBUSIO_PDMIN



/**
Note: I think this function needs an additional parameter for the word select
pin. It takes `mono`, a boolean indicating if it should be mono or
stereo, but without a word select pin, I don't think one can get
the other channel.
*/

void common_hal_audiobusio_pdmin_construct(audiobusio_pdmin_obj_t *self,
const mcu_pin_obj_t *clock_pin,
const mcu_pin_obj_t *data_pin,
uint32_t sample_rate,
uint8_t bit_depth,
bool mono,
uint8_t oversample) {

if (bit_depth != I2S_DATA_BIT_WIDTH_8BIT
&& bit_depth != I2S_DATA_BIT_WIDTH_16BIT
&& bit_depth != I2S_DATA_BIT_WIDTH_24BIT
&& bit_depth != I2S_DATA_BIT_WIDTH_32BIT) {
mp_raise_ValueError(MP_ERROR_TEXT("bit_depth must be 8, 16, 24, or 32."));
}

i2s_chan_config_t chanConfig = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_0, I2S_ROLE_MASTER);
esp_err_t err = i2s_new_channel(&chanConfig, NULL, &self->rx_chan);
CHECK_ESP_RESULT(err);

i2s_pdm_rx_config_t pdm_rx_cfg = {
.clk_cfg = I2S_PDM_RX_CLK_DEFAULT_CONFIG(sample_rate),
.slot_cfg = I2S_PDM_RX_SLOT_DEFAULT_CONFIG(bit_depth, mono ? I2S_SLOT_MODE_MONO : I2S_SLOT_MODE_STEREO),
.gpio_cfg =
{
.clk = clock_pin->number,
.din = data_pin->number,
.invert_flags =
{
.clk_inv = false,
},
},
};
err = i2s_channel_init_pdm_rx_mode(self->rx_chan, &pdm_rx_cfg);
CHECK_ESP_RESULT(err);

err = i2s_channel_enable(self->rx_chan);
CHECK_ESP_RESULT(err);

self->clock_pin = clock_pin;
self->data_pin = data_pin;
claim_pin(clock_pin);
claim_pin(data_pin);

self->sample_rate = sample_rate;
self->bit_depth = bit_depth;
}

bool common_hal_audiobusio_pdmin_deinited(audiobusio_pdmin_obj_t *self) {
return self->clock_pin == NULL;
}

void common_hal_audiobusio_pdmin_deinit(audiobusio_pdmin_obj_t *self) {
mp_printf(MP_PYTHON_PRINTER, "Deinit\n");
if (common_hal_audiobusio_pdmin_deinited(self)) {
mp_printf(MP_PYTHON_PRINTER, "Already deinitted, bailing\n");
return;
}

esp_err_t err = i2s_channel_disable(self->rx_chan);
CHECK_ESP_RESULT(err);
err = i2s_del_channel(self->rx_chan);
CHECK_ESP_RESULT(err);

// common_hal_audiobusio_i2sout_stop(self);

if (self->clock_pin) {
reset_pin_number(self->clock_pin->number);
}
self->clock_pin = NULL;

if (self->data_pin) {
reset_pin_number(self->data_pin->number);
}
self->data_pin = NULL;
}

/**
`length` is the buffer element count, not the byte count.
*/

uint32_t common_hal_audiobusio_pdmin_record_to_buffer(audiobusio_pdmin_obj_t *self,
uint16_t *buffer,
uint32_t length) {
// mp_printf(MP_PYTHON_PRINTER, "Copying bytes to buffer\n");

size_t result = 0;
size_t elementSize = common_hal_audiobusio_pdmin_get_bit_depth(self) / 8;
esp_err_t err = i2s_channel_read(self->rx_chan, buffer, length * elementSize, &result, 100);
CHECK_ESP_RESULT(err);
return result;
}

uint8_t common_hal_audiobusio_pdmin_get_bit_depth(audiobusio_pdmin_obj_t *self) {
return self->bit_depth;
}

uint32_t common_hal_audiobusio_pdmin_get_sample_rate(audiobusio_pdmin_obj_t *self) {
return self->sample_rate;
}

#endif
18 changes: 18 additions & 0 deletions ports/espressif/common-hal/audiobusio/PDMIn.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,21 @@
// SPDX-License-Identifier: MIT

#pragma once

#include "py/obj.h"

#include "common-hal/audiobusio/__init__.h"
#include "common-hal/microcontroller/Pin.h"

#if CIRCUITPY_AUDIOBUSIO_PDMIN

typedef struct {
i2s_t i2s;
i2s_chan_handle_t rx_chan;
const mcu_pin_obj_t *clock_pin;
const mcu_pin_obj_t *data_pin;
uint32_t sample_rate;
uint8_t bit_depth;
} audiobusio_pdmin_obj_t;

#endif
1 change: 1 addition & 0 deletions ports/espressif/mpconfigport.mk
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@ CIRCUITPY_ESP_USB_SERIAL_JTAG ?= 0
else ifeq ($(IDF_TARGET),esp32s3)
# Modules
CIRCUITPY_ALARM_TOUCH = 1
CIRCUITPY_AUDIOBUSIO_PDMIN = 1
CIRCUITPY_ESP_USB_SERIAL_JTAG ?= 0

# No room for _bleio on boards with 4MB flash
Expand Down
3 changes: 2 additions & 1 deletion shared-bindings/audiobusio/PDMIn.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ static mp_obj_t audiobusio_pdmin_make_new(const mp_obj_type_t *type, size_t n_ar
const mcu_pin_obj_t *data_pin = validate_obj_is_free_pin(args[ARG_data_pin].u_obj, MP_QSTR_data_pin);

// create PDMIn object from the given pin
audiobusio_pdmin_obj_t *self = mp_obj_malloc(audiobusio_pdmin_obj_t, &audiobusio_pdmin_type);
audiobusio_pdmin_obj_t *self = mp_obj_malloc_with_finaliser(audiobusio_pdmin_obj_t, &audiobusio_pdmin_type);

uint32_t sample_rate = args[ARG_sample_rate].u_int;
uint8_t bit_depth = args[ARG_bit_depth].u_int;
Expand Down Expand Up @@ -210,6 +210,7 @@ MP_PROPERTY_GETTER(audiobusio_pdmin_sample_rate_obj,

static const mp_rom_map_elem_t audiobusio_pdmin_locals_dict_table[] = {
// Methods
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&audiobusio_pdmin_deinit_obj) },
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&audiobusio_pdmin_deinit_obj) },
{ MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
{ MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&audiobusio_pdmin___exit___obj) },
Expand Down