Skip to content

Commit cfd4117

Browse files
authored
Merge pull request #9828 from JetForMe/main
Added basic Espressif PDM microphone support #7454
2 parents 617915e + 66c3ee8 commit cfd4117

File tree

5 files changed

+152
-2
lines changed

5 files changed

+152
-2
lines changed

locale/circuitpython.pot

+5-1
Original file line numberDiff line numberDiff line change
@@ -2498,6 +2498,10 @@ msgstr ""
24982498
msgid "binary op %q not implemented"
24992499
msgstr ""
25002500

2501+
#: ports/espressif/common-hal/audiobusio/PDMIn.c
2502+
msgid "bit_depth must be 8, 16, 24, or 32."
2503+
msgstr ""
2504+
25012505
#: shared-module/bitmapfilter/__init__.c
25022506
msgid "bitmap size and depth must match"
25032507
msgstr ""
@@ -2592,7 +2596,7 @@ msgstr ""
25922596
msgid "can't cancel self"
25932597
msgstr ""
25942598

2595-
#: shared-module/adafruit_pixelbuf/PixelBuf.c
2599+
#: py/obj.c shared-module/adafruit_pixelbuf/PixelBuf.c
25962600
msgid "can't convert %q to %q"
25972601
msgstr ""
25982602

ports/espressif/common-hal/audiobusio/PDMIn.c

+126
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,129 @@
33
// SPDX-FileCopyrightText: Copyright (c) 2024 Adafruit Industries LLC
44
//
55
// SPDX-License-Identifier: MIT
6+
7+
8+
#include "bindings/espidf/__init__.h"
9+
10+
#include "common-hal/audiobusio/PDMIn.h"
11+
#include "py/mpprint.h"
12+
#include "py/runtime.h"
13+
#include "shared-bindings/audiobusio/PDMIn.h"
14+
15+
16+
#include "driver/i2s_pdm.h"
17+
18+
19+
20+
#if CIRCUITPY_AUDIOBUSIO_PDMIN
21+
22+
23+
24+
/**
25+
Note: I think this function needs an additional parameter for the word select
26+
pin. It takes `mono`, a boolean indicating if it should be mono or
27+
stereo, but without a word select pin, I don't think one can get
28+
the other channel.
29+
*/
30+
31+
void common_hal_audiobusio_pdmin_construct(audiobusio_pdmin_obj_t *self,
32+
const mcu_pin_obj_t *clock_pin,
33+
const mcu_pin_obj_t *data_pin,
34+
uint32_t sample_rate,
35+
uint8_t bit_depth,
36+
bool mono,
37+
uint8_t oversample) {
38+
39+
if (bit_depth != I2S_DATA_BIT_WIDTH_8BIT
40+
&& bit_depth != I2S_DATA_BIT_WIDTH_16BIT
41+
&& bit_depth != I2S_DATA_BIT_WIDTH_24BIT
42+
&& bit_depth != I2S_DATA_BIT_WIDTH_32BIT) {
43+
mp_raise_ValueError(MP_ERROR_TEXT("bit_depth must be 8, 16, 24, or 32."));
44+
}
45+
46+
i2s_chan_config_t chanConfig = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_0, I2S_ROLE_MASTER);
47+
esp_err_t err = i2s_new_channel(&chanConfig, NULL, &self->rx_chan);
48+
CHECK_ESP_RESULT(err);
49+
50+
i2s_pdm_rx_config_t pdm_rx_cfg = {
51+
.clk_cfg = I2S_PDM_RX_CLK_DEFAULT_CONFIG(sample_rate),
52+
.slot_cfg = I2S_PDM_RX_SLOT_DEFAULT_CONFIG(bit_depth, mono ? I2S_SLOT_MODE_MONO : I2S_SLOT_MODE_STEREO),
53+
.gpio_cfg =
54+
{
55+
.clk = clock_pin->number,
56+
.din = data_pin->number,
57+
.invert_flags =
58+
{
59+
.clk_inv = false,
60+
},
61+
},
62+
};
63+
err = i2s_channel_init_pdm_rx_mode(self->rx_chan, &pdm_rx_cfg);
64+
CHECK_ESP_RESULT(err);
65+
66+
err = i2s_channel_enable(self->rx_chan);
67+
CHECK_ESP_RESULT(err);
68+
69+
self->clock_pin = clock_pin;
70+
self->data_pin = data_pin;
71+
claim_pin(clock_pin);
72+
claim_pin(data_pin);
73+
74+
self->sample_rate = sample_rate;
75+
self->bit_depth = bit_depth;
76+
}
77+
78+
bool common_hal_audiobusio_pdmin_deinited(audiobusio_pdmin_obj_t *self) {
79+
return self->clock_pin == NULL;
80+
}
81+
82+
void common_hal_audiobusio_pdmin_deinit(audiobusio_pdmin_obj_t *self) {
83+
mp_printf(MP_PYTHON_PRINTER, "Deinit\n");
84+
if (common_hal_audiobusio_pdmin_deinited(self)) {
85+
mp_printf(MP_PYTHON_PRINTER, "Already deinitted, bailing\n");
86+
return;
87+
}
88+
89+
esp_err_t err = i2s_channel_disable(self->rx_chan);
90+
CHECK_ESP_RESULT(err);
91+
err = i2s_del_channel(self->rx_chan);
92+
CHECK_ESP_RESULT(err);
93+
94+
// common_hal_audiobusio_i2sout_stop(self);
95+
96+
if (self->clock_pin) {
97+
reset_pin_number(self->clock_pin->number);
98+
}
99+
self->clock_pin = NULL;
100+
101+
if (self->data_pin) {
102+
reset_pin_number(self->data_pin->number);
103+
}
104+
self->data_pin = NULL;
105+
}
106+
107+
/**
108+
`length` is the buffer element count, not the byte count.
109+
*/
110+
111+
uint32_t common_hal_audiobusio_pdmin_record_to_buffer(audiobusio_pdmin_obj_t *self,
112+
uint16_t *buffer,
113+
uint32_t length) {
114+
// mp_printf(MP_PYTHON_PRINTER, "Copying bytes to buffer\n");
115+
116+
size_t result = 0;
117+
size_t elementSize = common_hal_audiobusio_pdmin_get_bit_depth(self) / 8;
118+
esp_err_t err = i2s_channel_read(self->rx_chan, buffer, length * elementSize, &result, 100);
119+
CHECK_ESP_RESULT(err);
120+
return result;
121+
}
122+
123+
uint8_t common_hal_audiobusio_pdmin_get_bit_depth(audiobusio_pdmin_obj_t *self) {
124+
return self->bit_depth;
125+
}
126+
127+
uint32_t common_hal_audiobusio_pdmin_get_sample_rate(audiobusio_pdmin_obj_t *self) {
128+
return self->sample_rate;
129+
}
130+
131+
#endif

ports/espressif/common-hal/audiobusio/PDMIn.h

+18
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,21 @@
55
// SPDX-License-Identifier: MIT
66

77
#pragma once
8+
9+
#include "py/obj.h"
10+
11+
#include "common-hal/audiobusio/__init__.h"
12+
#include "common-hal/microcontroller/Pin.h"
13+
14+
#if CIRCUITPY_AUDIOBUSIO_PDMIN
15+
16+
typedef struct {
17+
i2s_t i2s;
18+
i2s_chan_handle_t rx_chan;
19+
const mcu_pin_obj_t *clock_pin;
20+
const mcu_pin_obj_t *data_pin;
21+
uint32_t sample_rate;
22+
uint8_t bit_depth;
23+
} audiobusio_pdmin_obj_t;
24+
25+
#endif

ports/espressif/mpconfigport.mk

+1
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@ CIRCUITPY_ESP_USB_SERIAL_JTAG ?= 0
230230
else ifeq ($(IDF_TARGET),esp32s3)
231231
# Modules
232232
CIRCUITPY_ALARM_TOUCH = 1
233+
CIRCUITPY_AUDIOBUSIO_PDMIN = 1
233234
CIRCUITPY_ESP_USB_SERIAL_JTAG ?= 0
234235

235236
# No room for _bleio on boards with 4MB flash

shared-bindings/audiobusio/PDMIn.c

+2-1
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ static mp_obj_t audiobusio_pdmin_make_new(const mp_obj_type_t *type, size_t n_ar
9595
const mcu_pin_obj_t *data_pin = validate_obj_is_free_pin(args[ARG_data_pin].u_obj, MP_QSTR_data_pin);
9696

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

100100
uint32_t sample_rate = args[ARG_sample_rate].u_int;
101101
uint8_t bit_depth = args[ARG_bit_depth].u_int;
@@ -210,6 +210,7 @@ MP_PROPERTY_GETTER(audiobusio_pdmin_sample_rate_obj,
210210

211211
static const mp_rom_map_elem_t audiobusio_pdmin_locals_dict_table[] = {
212212
// Methods
213+
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&audiobusio_pdmin_deinit_obj) },
213214
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&audiobusio_pdmin_deinit_obj) },
214215
{ MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
215216
{ MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&audiobusio_pdmin___exit___obj) },

0 commit comments

Comments
 (0)