8000 Merge pull request #7169 from blues/pdmin · domdfcoding/circuitpython@e6936de · GitHub
[go: up one dir, main page]

Skip to content

Commit e6936de

Browse files
authored
Merge pull request adafruit#7169 from blues/pdmin
STM32L4 PDMIn support
2 parents 0870e0f + 97f693d commit e6936de

File tree

17 files changed

+1648
-47
lines changed

17 files changed

+1648
-47
lines changed

locale/circuitpython.pot

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3698,10 +3698,20 @@ msgid "offset out of bounds"
36983698
msgstr ""
36993699

37003700
#: ports/nrf/common-hal/audiobusio/PDMIn.c
3701+
#: ports/stm/common-hal/audiobusio/PDMIn.c
37013702
msgid "only bit_depth=16 is supported"
37023703
msgstr ""
37033704

3705+
#: ports/stm/common-hal/audiobusio/PDMIn.c
3706+
msgid "only mono is supported"
3707+
msgstr ""
3708+
3709+
#: ports/stm/common-hal/audiobusio/PDMIn.c
3710+
msgid "only oversample=64 is supported"
3711+
msgstr ""
3712+
37043713
#: ports/nrf/common-hal/audiobusio/PDMIn.c
3714+
#: ports/stm/common-hal/audiobusio/PDMIn.c
37053715
msgid "only sample_rate=16000 is supported"
37063716
msgstr ""
37073717

ports/stm/Makefile

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,17 @@ SRC_C += \
234234
peripherals/stm32$(MCU_SERIES_LOWER)/$(MCU_VARIANT_LOWER)/periph.c \
235235
packages/$(MCU_PACKAGE).c
236236

237+
ifneq ($(CIRCUITPY_AUDIOBUSIO_PDMIN),0)
238+
SRC_C += \
239+
common-hal/audiobusio/MEMS_Audio.c \
240+
common-hal/audiobusio/MEMS_Audio_ll_stm32l4.c \
241+
common-hal/audiobusio/OpenPDMFilter.c
242+
243+
SRC_STM32 += \
244+
$(HAL_DIR)/Src/stm32$(MCU_SERIES_LOWER)xx_hal_sai.c
245+
246+
endif
247+
237248
ifneq ($(CIRCUITPY_USB),0)
238249
SRC_C += lib/tinyusb/src/portable/st/synopsys/dcd_synopsys.c
239250
endif

ports/stm/boards/swan_r5/mpconfigboard.mk

Lines changed: 28 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -15,61 +15,42 @@ LD_DEFAULT = boards/STM32L4R5_default.ld
1515
LD_BOOT = boards/STM32L4R5_boot.ld
1616
UF2_OFFSET = 0x8010000
1717
UF2_BOOTLOADER ?= 1
18+
CIRCUITPY_BUILD_EXTENSIONS = bin,uf2
1819

19-
# Turn all of the below off while trying to get the thing to run
20-
# These modules are implemented in ports/<port>/common-hal:
21-
22-
# Typically the first module to create
23-
CIRCUITPY_MICROCONTROLLER = 1
2420
CIRCUITPY_ALARM = 1
25-
26-
# Typically the second module to create
27-
CIRCUITPY_DIGITALIO = 1
28-
# Other modules:
29-
30-
CIRCUITPY_OS = 1
31-
CIRCUITPY_STORAGE = 1
32-
CIRCUITPY_USB_MSC = 1
33-
CIRCUITPY_UDB_CDC = 1
34-
CIRCUITPY_USB_VENDOR = 1
35-
CIRCUITPY_NVM = 0
36-
3721
CIRCUITPY_ANALOGIO = 1
38-
CIRCUITPY_BUSIO = 1
39-
CIRCUITPY_NEOPIXEL_WRITE = 0
40-
CIRCUITPY_PULSEIO = 1
41-
CIRCUITPY_PWMIO = 1
22+
CIRCUITPY_AUDIOBUSIO = 1
23+
CIRCUITPY_AUDIOBUSIO_I2SOUT = 0
24+
CIRCUITPY_AUDIOBUSIO_PDMIN = 1
4225
CIRCUITPY_AUDIOPWMIO = 1
26+
CIRCUITPY_BITBANGIO = 1
27+
CIRCUITPY_BLEIO = 0
28+
CIRCUITPY_BLEIO_HCI = 0
29+
CIRCUITPY_BUSDEVICE = 0
30+
CIRCUITPY_BUSIO = 1
4331
CIRCUITPY_CANIO = 0
44-
CIRCUITPY_AUDIOBUSIO = 0
32+
CIRCUITPY_DIGITALIO = 1
33+
CIRCUITPY_DISPLAYIO = 1
34+
CIRCUITPY_ENABLE_MPY_NATIVE = 1
4535
CIRCUITPY_I2CTARGET = 0
46-
# Requires SPI, PulseIO (stub ok):
47-
CIRCUITPY_DISPLAYIO = 0
48-
49-
# These modules are implemented in shared-module/ - they can be included in
50-
# any port once their prerequisites in common-hal are complete.
51-
# Requires DigitalIO:
52-
CIRCUITPY_BITBANGIO = 1
53-
# Requires neopixel_write or SPI (dotstar)
36+
CIRCUITPY_KEYPAD = 1
37+
CIRCUITPY_MICROCONTROLLER = 1
38+
CIRCUITPY_NEOPIXEL_WRITE = 0
39+
CIRCUITPY_NVM = 0
40+
CIRCUITPY_OS = 1
5441
CIRCUITPY_PIXELBUF = 0
55-
# Requires OS
42+
CIRCUITPY_PULSEIO = 1
43+
CIRCUITPY_PWMIO = 1
5644
CIRCUITPY_RANDOM = 1
57-
# Requires Microcontroller
58-
CIRCUITPY_TOUCHIO = 1
59-
# Requires USB
60-
CIRCUITPY_USB_HID = 0
61-
CIRCUITPY_USB_MIDI = 0
62-
# Does nothing without I2C
6345
CIRCUITPY_REQUIRE_I2C_PULLUPS = 0
64-
# No requirements, but takes extra flash
65-
CIRCUITPY_ULAB = 1
66-
# requires SPI
67-
CIRCUITPY_SDCARDIO = 0
68-
CIRCUITPY_BLEIO_HCI = 0
69-
CIRCUITPY_BLEIO = 0
70-
CIRCUITPY_BUSDEVICE = 0
71-
CIRCUITPY_KEYPAD = 1
7246
CIRCUITPY_RGBMATRIX = 0
7347
CIRCUITPY_RTC = 1
74-
75-
CIRCUITPY_BUILD_EXTENSIONS = bin,uf2
48+
CIRCUITPY_SDCARDIO = 0
49+
CIRCUITPY_STORAGE = 1
50+
CIRCUITPY_TOUCHIO = 1
51+
CIRCUITPY_UDB_CDC = 1
52+
CIRCUITPY_ULAB = 1
53+
CIRCUITPY_USB_HID = 0
54+
CIRCUITPY_USB_MIDI = 0
55+
CIRCUITPY_USB_MSC = 1
56+
CIRCUITPY_USB_VENDOR = 1

ports/stm/boards/swan_r5/pins.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,5 +129,8 @@ STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
129129
{ MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) },
130130
{ MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) },
131131
{ MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) },
132+
133+
{ MP_ROM_QSTR(MP_QSTR_MICROPHONE_CLOCK), MP_ROM_PTR(&pin_PA03) },
134+
{ MP_ROM_QSTR(MP_QSTR_MICROPHONE_DATA), MP_ROM_PTR(&pin_PC03) },
132135
};
133136
MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table);
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
// Although IS2Out is not enabled on the STM32L4 family, this file is still required for the build to pass
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
// Although IS2Out is not enabled on the STM32L4 family, this file is still required for the build to pass
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/*
2+
* The MIT License (MIT)
3+
*
4+
* Copyright (c) 2022 Matthew McGowan for Blues Inc.
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in
14+
* all copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+
* THE SOFTWARE.
23+
*/
24+
25+
#include <assert.h>
26+
#include <stm32l4xx_hal.h>
27+
28+
#include "MEMS_Audio.h"
29+
#include "MEMS_Audio_ll.h"
30+
31+
static void default_pcm_data_available(MemsAudio *audio, pcm_sample_t *pcmSamples, size_t pcmLength) {
32+
}
33+
34+
35+
36+
/**
37+
* @brief Initializes the MemsAudio instance. Only one instance can be initialized and used at a given time.
38+
*
39+
* @param audio
40+
* @return mems_audio_err_t
41+
*/
42+
mems_audio_err_t mems_audio_init(MemsAudio *audio) {
43+
if (!audio->pcm_data_available) {
44+
audio->pcm_data_available = default_pcm_data_available;
45+
}
46+
return mems_audio_ll_init(audio);
47+
}
48+
49+
/**
50+
* @brief Uninitializes the MemsAudio instance.
51+
*
52+
* @param audio
53+
* @return mems_audio_err_t
54+
*/
55+
mems_audio_err_t mems_audio_uninit(MemsAudio *audio) {
56+
return mems_audio_ll_uninit(audio);
57+
}
58+
59+
/**
60+
* @brief Asynchronously records audio.
61+
*
62+
* @param audio
63+
* @param pdmBuffer
64+
* @param pdmBufferLength
65+
* @return mems_audio_err_t
66+
*/
67+
mems_audio_err_t mems_audio_record(MemsAudio *audio) {
68+
return mems_audio_ll_record(audio);
69+
}
70+
71+
/**
72+
* @brief Pause recording audio.
73+
*/
74+
mems_audio_err_t mems_audio_pause(MemsAudio *audio) {
75+
return mems_audio_ll_pause(audio);
76+
}
77+
78+
/**
79+
* @brief Resume recording audio.
80+
*
81+
* @param audio
82+
* @return mems_audio_err_t
83+
*/
84+
mems_audio_err_t mems_audio_resume(MemsAudio *audio) {
85+
return mems_audio_ll_resume(audio);
86+
}
87+
88+
/**
89+
* @brief Stop recording audio and
90+
*
91+
* @param audio
92+
* @return mems_audio_err_t
93+
*/
94+
mems_audio_err_t mems_audio_stop(MemsAudio *audio) {
95+
return mems_audio_ll_stop(audio);
96+
}
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
/*
2+
* The MIT License (MIT)
3+
*
4+
* Copyright (c) 2022 Matthew McGowan for Blues Inc.
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in
14+
* all copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+
* THE SOFTWARE.
23+
*/
24+
25+
#ifndef _MEMS_AUDIO_H_
26+
#define _MEMS_AUDIO_H_
27+
28+
#include <stdint.h>
29+
#include <stddef.h>
30+
31+
#ifdef __cplusplus
32+
extern "C" {
33+
#endif
34+
35+
36+
/**
37+
* @brief How many milliseconds of audio can fit in the audio buffer(s).
38+
* Interrupts for recieved data fire at half this duration / twice the frequency.
39+
*/
40+
#ifndef MEMS_AUDIO_MS_BUFFER
41+
#define MEMS_AUDIO_MS_BUFFER (1)
42+
#endif
43+
44+
45+
/**
46+
* @brief The number of bits per sample of the PCM output
47+
*/
48+
#define PCM_OUT_RESOLUTION 16
49+
50+
/**
51+
* @brief The output frequency of PCM samples in Hz.
52+
*/
53+
#define PCM_OUT_SAMPLING_FREQUENCY 16000
54+
55+
/**
56+
* @brief type for describing error conditions.
57+
*/
58+
typedef int32_t mems_audio_err_t;
59+
60+
/**
61+
* @brief The datatype that holds an output PCM sample.
62+
*/
63+
typedef int16_t pcm_sample_t;
64+
_Static_assert(PCM_OUT_RESOLUTION==16, "Output PCM resolution must be 16-bits");
65+
66+
67+
typedef enum {
68+
MEMS_AUDIO_OK = 0,
69+
MEMS_AUDIO_ERROR_ALREADY_INITIALIZED = -1,
70+
MEMS_AUDIO_ERROR_NOT_INITIALIZED = -2
71+
} mems_audio_err_enum_t;
72+
73+
#define IS_MEMS_AUDIO_ERROR(e) (e)
74+
#define CHECK_MEMS_AUDIO_ERROR(e) { if (IS_MEMS_AUDIO_ERROR(e)) return e; }
75+
#define CHECK_MEMS_AUDIO_INITIALIZED(x) { if (!x) return MEMS_AUDIO_ERROR_NOT_INITIALIZED; }
76+
77+
typedef struct MemsAudio_t MemsAudio;
78+
79+
/**
80+
* @brief Callback informing that PCM samples are available for processing.
81+
*/
82+
typedef void (*pcm_data_available_t)(MemsAudio* audio, pcm_sample_t* pcmSamples, size_t pcmLength);
83+
84+
/**
85+
* @brief MemsAudio manages the filter, buffers and callbacks used to capture PDM audio samples and convert to PCM.
86+
*
87+
*/
88+
typedef struct MemsAudio_t {
89+
90+
/**
91+
* @brief The buffer to store PCM audio samples
92+
*/
93+
volatile pcm_sample_t* volatile pcmOutputBuffer;
94+
95+
/**
96+
* @brief The length of the PCM buffer. SHould be at least MEMS_AUDIO_PCM_BUFFER_LENGTH
97+
*/
98+
volatile size_t pcmOutputBufferLength;
99+
100+
/**
101+
* @brief Optional callback for when PCM data is available.
102+
*/
103+
pcm_data_available_t pcm_data_available;
104+
105+
void* audioImpl;
106+
void* userData;
107+
} MemsAudio;
108+
109+
110+
mems_audio_err_t mems_audio_init(MemsAudio* audio);
111+
112+
/**
113+
* @brief Uninitializes the MemsAudio instance.
114+
*
115+
* @param audio
116+
* @return mems_audio_err_t
117+
*/
118+
mems_audio_err_t mems_audio_uninit(MemsAudio* audio);
119+
120+
/**
121+
* @brief Asynchronously records audio.
122+
*
123+
* @param audio
124+
* @param pdmBuffer
125+
* @param pdmBufferLength
126+
* @return mems_audio_err_t
127+
*/
128+
mems_audio_err_t mems_audio_record(MemsAudio* audio);
129+
130+
/**
131+
* @brief Pause recording audio.
132+
*/
133+
mems_audio_err_t mems_audio_pause(MemsAudio* audio);
134+
135+
/**
136+
* @brief Resume recording audio.
137+
*
138+
* @param audio
139+
* @return mems_audio_err_t
140+
*/
141+
mems_audio_err_t mems_audio_resume(MemsAudio* audio);
142+
143+
/**
144+
* @brief Stop recording audio and
145+
*
146+
* @param audio
147+
* @return mems_audio_err_t
148+
*/
149+
mems_audio_err_t mems_audio_stop(MemsAudio* audio);
150+
151+
#ifdef __cplusplus
152+
}
153+
#endif
154+
155+
156+
#endif // _MEMS_AUDIO_H_

0 commit comments

Comments
 (0)
0