8000 Added basic Espressif PDM microphone support #7454 · JetForMe/circuitpython@70b310b · GitHub
[go: up one dir, main page]

Skip to content

Commit 70b310b

Browse files
committed
Added basic Espressif PDM microphone support adafruit#7454
1 parent 254f8ef commit 70b310b

File tree

5 files changed

+145
-2
lines changed

5 files changed

+145
-2
lines changed

locale/circuitpython.pot

Lines changed: 5 additions & 1 deletion
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

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

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,18 @@
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+
15+
typedef struct {
16+
i2s_t i2s;
17+
i2s_chan_handle_t rx_chan;
18+
const mcu_pin_obj_t *clock_pin;
19+
const mcu_pin_obj_t *data_pin;
20+
uint32_t sample_rate;
21+
uint8_t bit_depth;
22+
} audiobusio_pdmin_obj_t;

ports/espressif/mpconfigport.mk

Lines changed: 1 addition & 0 deletions
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

Lines changed: 2 additions & 1 deletion
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)
0