Skip to content

Commit a85df06

Browse files
committed
I2SIn initial implementation and tests espressif port
1 parent a37aaaf commit a85df06

12 files changed

Lines changed: 602 additions & 6 deletions

File tree

locale/circuitpython.pot

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ msgstr ""
218218
msgid "%q must be array of type 'h'"
219219
msgstr ""
220220

221-
#: shared-bindings/audiobusio/PDMIn.c
221+
#: shared-bindings/audiobusio/I2SIn.c shared-bindings/audiobusio/PDMIn.c
222222
msgid "%q must be multiple of 8."
223223
msgstr ""
224224

@@ -803,7 +803,7 @@ msgstr ""
803803
msgid "Cannot pull on input-only pin."
804804
msgstr ""
805805

806-
#: shared-bindings/audiobusio/PDMIn.c
806+
#: shared-bindings/audiobusio/I2SIn.c shared-bindings/audiobusio/PDMIn.c
807807
msgid "Cannot record to a file"
808808
msgstr ""
809809

@@ -923,7 +923,7 @@ msgstr ""
923923
msgid "Deep sleep pins must use a rising edge with pulldown"
924924
msgstr ""
925925

926-
#: shared-bindings/audiobusio/PDMIn.c
926+
#: shared-bindings/audiobusio/I2SIn.c shared-bindings/audiobusio/PDMIn.c
927927
msgid "Destination capacity is smaller than destination_length."
928928
msgstr ""
929929

@@ -1802,6 +1802,7 @@ msgstr ""
18021802
msgid "Parameter error"
18031803
msgstr ""
18041804

1805+
#: ports/espressif/common-hal/audiobusio/I2SIn.c
18051806
#: ports/espressif/common-hal/audiobusio/__init__.c
18061807
msgid "Peripheral in use"
18071808
msgstr ""
@@ -2692,6 +2693,7 @@ msgstr ""
26922693
msgid "binary op %q not implemented"
26932694
msgstr ""
26942695

2696+
#: ports/espressif/common-hal/audiobusio/I2SIn.c
26952697
#: ports/espressif/common-hal/audiobusio/PDMIn.c
26962698
msgid "bit_depth must be 8, 16, 24, or 32."
26972699
msgstr ""
@@ -3084,15 +3086,20 @@ msgstr ""
30843086
msgid "default is not a function"
30853087
msgstr ""
30863088

3087-
#: shared-bindings/audiobusio/PDMIn.c
3089+
#: shared-bindings/audiobusio/I2SIn.c shared-bindings/audiobusio/PDMIn.c
30883090
msgid ""
30893091
"destination buffer must be a bytearray or array of type 'B' for bit_depth = 8"
30903092
msgstr ""
30913093

3092-
#: shared-bindings/audiobusio/PDMIn.c
3094+
#: shared-bindings/audiobusio/I2SIn.c shared-bindings/audiobusio/PDMIn.c
30933095
msgid "destination buffer must be an array of type 'H' for bit_depth = 16"
30943096
msgstr ""
30953097

3098+
#: shared-bindings/audiobusio/I2SIn.c
3099+
msgid ""
3100+
"destination buffer must be an array of type 'I' for bit_depth = 24 or 32"
3101+
msgstr ""
3102+
30963103
#: py/objdict.c
30973104
msgid "dict update sequence has wrong length"
30983105
msgstr ""
@@ -4049,7 +4056,7 @@ msgstr ""
40494056
msgid "output array must be contiguous"
40504057
msgstr ""
40514058

4052-
#: py/objint_mpz.c
4059+
#: py/objint_longlong.c py/objint_mpz.c
40534060
msgid "overflow converting long int to machine word"
40544061
msgstr ""
40554062

ports/espressif/boards/adafruit_sparkle_motion/pins.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ static const mp_rom_map_elem_t board_module_globals_table[] = {
4646
{ MP_ROM_QSTR(MP_QSTR_SIG4), MP_ROM_PTR(&pin_GPIO23) },
4747
{ MP_ROM_QSTR(MP_QSTR_D23), MP_ROM_PTR(&pin_GPIO23) },
4848

49+
{ MP_ROM_QSTR(MP_QSTR_D25), MP_ROM_PTR(&pin_GPIO25) },
50+
{ MP_ROM_QSTR(MP_QSTR_D26), MP_ROM_PTR(&pin_GPIO26) },
51+
{ MP_ROM_QSTR(MP_QSTR_D33), MP_ROM_PTR(&pin_GPIO33) },
52+
4953
{ MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO9) },
5054
{ MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_GPIO9) },
5155

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
// This file is part of the CircuitPython project: https://circuitpython.org
2+
//
3+
// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries
4+
//
5+
// SPDX-License-Identifier: MIT
6+
7+
#include "bindings/espidf/__init__.h"
8+
9+
#include "common-hal/audiobusio/I2SIn.h"
10+
#include "py/runtime.h"
11+
#include "shared-bindings/audiobusio/I2SIn.h"
12+
#include "shared-bindings/microcontroller/Pin.h"
13+
14+
#include "driver/i2s_std.h"
15+
16+
#if CIRCUITPY_AUDIOBUSIO_I2SIN
17+
18+
void common_hal_audiobusio_i2sin_construct(audiobusio_i2sin_obj_t *self,
19+
const mcu_pin_obj_t *bit_clock, const mcu_pin_obj_t *word_select,
20+
const mcu_pin_obj_t *data, const mcu_pin_obj_t *main_clock,
21+
uint32_t sample_rate, uint8_t bit_depth, bool mono, bool left_justified) {
22+
23+
if (bit_depth != 8 && bit_depth != 16 && bit_depth != 24 && bit_depth != 32) {
24+
mp_raise_ValueError(MP_ERROR_TEXT("bit_depth must be 8, 16, 24, or 32."));
25+
}
26+
27+
i2s_data_bit_width_t bit_width = (i2s_data_bit_width_t)bit_depth;
28+
i2s_slot_mode_t slot_mode = mono ? I2S_SLOT_MODE_MONO : I2S_SLOT_MODE_STEREO;
29+
30+
i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_AUTO, I2S_ROLE_MASTER);
31+
esp_err_t err = i2s_new_channel(&chan_cfg, NULL, &self->rx_chan);
32+
if (err == ESP_ERR_NOT_FOUND) {
33+
mp_raise_RuntimeError(MP_ERROR_TEXT("Peripheral in use"));
34+
}
35+
CHECK_ESP_RESULT(err);
36+
37+
i2s_std_slot_config_t slot_cfg = left_justified
38+
? (i2s_std_slot_config_t)I2S_STD_MSB_SLOT_DEFAULT_CONFIG(bit_width, slot_mode)
39+
: (i2s_std_slot_config_t)I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(bit_width, slot_mode);
40+
41+
i2s_std_config_t std_cfg = {
42+
.clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(sample_rate),
43+
.slot_cfg = slot_cfg,
44+
.gpio_cfg = {
45+
.mclk = main_clock != NULL ? main_clock->number : I2S_GPIO_UNUSED,
46+
.bclk = bit_clock->number,
47+
.ws = word_select->number,
48+
.dout = I2S_GPIO_UNUSED,
49+
.din = data->number,
50+
},
51+
};
52+
CHECK_ESP_RESULT(i2s_channel_init_std_mode(self->rx_chan, &std_cfg));
53+
CHECK_ESP_RESULT(i2s_channel_enable(self->rx_chan));
54+
55+
self->bit_clock = bit_clock;
56+
self->word_select = word_select;
57+
self->data = data;
58+
self->mclk = main_clock;
59+
self->sample_rate = sample_rate;
60+
self->bit_depth = bit_depth;
61+
62+
claim_pin(bit_clock);
63+
claim_pin(word_select);
64+
claim_pin(data);
65+
if (main_clock) {
66+
claim_pin(main_clock);
67+
}
68+
}
69+
70+
bool common_hal_audiobusio_i2sin_deinited(audiobusio_i2sin_obj_t *self) {
71+
return self->data == NULL;
72+
}
73+
74+
void common_hal_audiobusio_i2sin_deinit(audiobusio_i2sin_obj_t *self) {
75+
if (common_hal_audiobusio_i2sin_deinited(self)) {
76+
return;
77+
}
78+
79+
if (self->rx_chan) {
80+
i2s_channel_disable(self->rx_chan);
81+
i2s_del_channel(self->rx_chan);
82+
self->rx_chan = NULL;
83+
}
84+
85+
if (self->bit_clock) {
86+
reset_pin_number(self->bit_clock->number);
87+
}
88+
self->bit_clock = NULL;
89+
90+
if (self->word_select) {
91+
reset_pin_number(self->word_select->number);
92+
}
93+
self->word_select = NULL;
94+
95+
if (self->data) {
96+
reset_pin_number(self->data->number);
97+
}
98+
self->data = NULL;
99+
100+
if (self->mclk) {
101+
reset_pin_number(self->mclk->number);
102+
}
103+
self->mclk = NULL;
104+
}
105+
106+
uint32_t common_hal_audiobusio_i2sin_record_to_buffer(audiobusio_i2sin_obj_t *self,
107+
void *buffer, uint32_t length) {
108+
size_t result = 0;
109+
size_t element_size = self->bit_depth / 8;
110+
// 24-bit samples occupy a 32-bit slot on the I2S bus.
111+
if (self->bit_depth == 24) {
112+
element_size = 4;
113+
}
114+
esp_err_t err = i2s_channel_read(self->rx_chan, buffer, length * element_size, &result, portMAX_DELAY);
115+
CHECK_ESP_RESULT(err);
116+
return result / element_size;
117+
}
118+
119+
uint8_t common_hal_audiobusio_i2sin_get_bit_depth(audiobusio_i2sin_obj_t *self) {
120+
return self->bit_depth;
121+
}
122+
123+
uint32_t common_hal_audiobusio_i2sin_get_sample_rate(audiobusio_i2sin_obj_t *self) {
124+
return self->sample_rate;
125+
}
126+
127+
#endif // CIRCUITPY_AUDIOBUSIO_I2SIN
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// This file is part of the CircuitPython project: https://circuitpython.org
2+
//
3+
// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries
4+
//
5+
// SPDX-License-Identifier: MIT
6+
7+
#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_I2SIN
15+
16+
typedef struct {
17+
mp_obj_base_t base;
18+
i2s_chan_handle_t rx_chan;
19+
const mcu_pin_obj_t *bit_clock;
20+
const mcu_pin_obj_t *word_select;
21+
const mcu_pin_obj_t *data;
22+
const mcu_pin_obj_t *mclk;
23+
uint32_t sample_rate;
24+
uint8_t bit_depth;
25+
} audiobusio_i2sin_obj_t;
26+
27+
#endif

ports/espressif/mpconfigport.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ CIRCUITPY_ALARM_TOUCH ?= 0
6868
CIRCUITPY_ANALOGBUFIO ?= 1
6969
CIRCUITPY_AUDIOBUSIO ?= 1
7070
CIRCUITPY_AUDIOBUSIO_PDMIN ?= 0
71+
CIRCUITPY_AUDIOBUSIO_I2SIN ?= $(CIRCUITPY_AUDIOBUSIO)
7172
CIRCUITPY_AUDIOIO ?= 1
7273
CIRCUITPY_BLEIO_HCI = 0
7374
CIRCUITPY_BLEIO_NATIVE ?= 1

py/circuitpy_defns.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,7 @@ SRC_COMMON_HAL_ALL = \
503503
analogio/AnalogOut.c \
504504
analogio/__init__.c \
505505
audiobusio/I2SOut.c \
506+
audiobusio/I2SIn.c \
506507
audiobusio/PDMIn.c \
507508
audiobusio/__init__.c \
508509
audioio/AudioOut.c \

py/circuitpy_mpconfig.mk

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,10 @@ CFLAGS += -DCIRCUITPY_AUDIOBUSIO_I2SOUT=$(CIRCUITPY_AUDIOBUSIO_I2SOUT)
135135
CIRCUITPY_AUDIOBUSIO_PDMIN ?= $(CIRCUITPY_AUDIOBUSIO)
136136
CFLAGS += -DCIRCUITPY_AUDIOBUSIO_PDMIN=$(CIRCUITPY_AUDIOBUSIO_PDMIN)
137137

138+
# Some boards have I2SOut but do not implement I2SIn.
139+
CIRCUITPY_AUDIOBUSIO_I2SIN ?= 0
140+
CFLAGS += -DCIRCUITPY_AUDIOBUSIO_I2SIN=$(CIRCUITPY_AUDIOBUSIO_I2SIN)
141+
138142
CIRCUITPY_AUDIOIO ?= $(CIRCUITPY_FULL_BUILD)
139143
CFLAGS += -DCIRCUITPY_AUDIOIO=$(CIRCUITPY_AUDIOIO)
140144

0 commit comments

Comments
 (0)