Skip to content

STM32L4 PDMIn support #7169

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Nov 9, 2022
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
10 changes: 10 additions & 0 deletions locale/circuitpython.pot
Original file line number Diff line number Diff line change
Expand Up @@ -3714,10 +3714,20 @@ msgid "offset out of bounds"
msgstr ""

#: ports/nrf/common-hal/audiobusio/PDMIn.c
#: ports/stm/common-hal/audiobusio/PDMIn.c
msgid "only bit_depth=16 is supported"
msgstr ""

#: ports/stm/common-hal/audiobusio/PDMIn.c
msgid "only mono is supported"
msgstr ""

#: ports/stm/common-hal/audiobusio/PDMIn.c
msgid "only oversample=64 is supported"
msgstr ""

#: ports/nrf/common-hal/audiobusio/PDMIn.c
#: ports/stm/common-hal/audiobusio/PDMIn.c
msgid "only sample_rate=16000 is supported"
msgstr ""

Expand Down
11 changes: 11 additions & 0 deletions ports/stm/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,17 @@ SRC_C += \
peripherals/stm32$(MCU_SERIES_LOWER)/$(MCU_VARIANT_LOWER)/periph.c \
packages/$(MCU_PACKAGE).c

ifneq ($(CIRCUITPY_AUDIOBUSIO_PDMIN),0)
SRC_C += \
common-hal/audiobusio/MEMS_Audio.c \
common-hal/audiobusio/MEMS_Audio_ll_stm32l4.c \
common-hal/audiobusio/OpenPDMFilter.c

SRC_STM32 += \
$(HAL_DIR)/Src/stm32$(MCU_SERIES_LOWER)xx_hal_sai.c

endif

ifneq ($(CIRCUITPY_USB),0)
SRC_C += lib/tinyusb/src/portable/st/synopsys/dcd_synopsys.c
endif
Expand Down
75 changes: 28 additions & 47 deletions ports/stm/boards/swan_r5/mpconfigboard.mk
Original file line number Diff line number Diff line change
Expand Up @@ -15,61 +15,42 @@ LD_DEFAULT = boards/STM32L4R5_default.ld
LD_BOOT = boards/STM32L4R5_boot.ld
UF2_OFFSET = 0x8010000
UF2_BOOTLOADER ?= 1
CIRCUITPY_BUILD_EXTENSIONS = bin,uf2

# Turn all of the below off while trying to get the thing to run
# These modules are implemented in ports/<port>/common-hal:

# Typically the first module to create
CIRCUITPY_MICROCONTROLLER = 1
CIRCUITPY_ALARM = 1

# Typically the second module to create
CIRCUITPY_DIGITALIO = 1
# Other modules:

CIRCUITPY_OS = 1
CIRCUITPY_STORAGE = 1
CIRCUITPY_USB_MSC = 1
CIRCUITPY_UDB_CDC = 1
CIRCUITPY_USB_VENDOR = 1
CIRCUITPY_NVM = 0

CIRCUITPY_ANALOGIO = 1
CIRCUITPY_BUSIO = 1
CIRCUITPY_NEOPIXEL_WRITE = 0
CIRCUITPY_PULSEIO = 1
CIRCUITPY_PWMIO = 1
CIRCUITPY_AUDIOBUSIO = 1
CIRCUITPY_AUDIOBUSIO_I2SOUT = 0
CIRCUITPY_AUDIOBUSIO_PDMIN = 1
CIRCUITPY_AUDIOPWMIO = 1
CIRCUITPY_BITBANGIO = 1
CIRCUITPY_BLEIO = 0
CIRCUITPY_BLEIO_HCI = 0
CIRCUITPY_BUSDEVICE = 0
CIRCUITPY_BUSIO = 1
CIRCUITPY_CANIO = 0
CIRCUITPY_AUDIOBUSIO = 0
CIRCUITPY_DIGITALIO = 1
CIRCUITPY_DISPLAYIO = 1
CIRCUITPY_ENABLE_MPY_NATIVE = 1
CIRCUITPY_I2CTARGET = 0
# Requires SPI, PulseIO (stub ok):
CIRCUITPY_DISPLAYIO = 0

# These modules are implemented in shared-module/ - they can be included in
# any port once their prerequisites in common-hal are complete.
# Requires DigitalIO:
CIRCUITPY_BITBANGIO = 1
# Requires neopixel_write or SPI (dotstar)
CIRCUITPY_KEYPAD = 1
CIRCUITPY_MICROCONTROLLER = 1
CIRCUITPY_NEOPIXEL_WRITE = 0
CIRCUITPY_NVM = 0
CIRCUITPY_OS = 1
CIRCUITPY_PIXELBUF = 0
# Requires OS
CIRCUITPY_PULSEIO = 1
CIRCUITPY_PWMIO = 1
CIRCUITPY_RANDOM = 1
# Requires Microcontroller
CIRCUITPY_TOUCHIO = 1
# Requires USB
CIRCUITPY_USB_HID = 0
CIRCUITPY_USB_MIDI = 0
# Does nothing without I2C
CIRCUITPY_REQUIRE_I2C_PULLUPS = 0
# No requirements, but takes extra flash
CIRCUITPY_ULAB = 1
# requires SPI
CIRCUITPY_SDCARDIO = 0
CIRCUITPY_BLEIO_HCI = 0
CIRCUITPY_BLEIO = 0
CIRCUITPY_BUSDEVICE = 0
CIRCUITPY_KEYPAD = 1
CIRCUITPY_RGBMATRIX = 0
CIRCUITPY_RTC = 1

CIRCUITPY_BUILD_EXTENSIONS = bin,uf2
CIRCUITPY_SDCARDIO = 0
CIRCUITPY_STORAGE = 1
CIRCUITPY_TOUCHIO = 1
CIRCUITPY_UDB_CDC = 1
CIRCUITPY_ULAB = 1
CIRCUITPY_USB_HID = 0
CIRCUITPY_USB_MIDI = 0
CIRCUITPY_USB_MSC = 1
CIRCUITPY_USB_VENDOR = 1
3 changes: 3 additions & 0 deletions ports/stm/boards/swan_r5/pins.c
Original file line number Diff line number Diff line change
Expand Up @@ -129,5 +129,8 @@ STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) },
{ MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) },
{ MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) },

{ MP_ROM_QSTR(MP_QSTR_MICROPHONE_CLOCK), MP_ROM_PTR(&pin_PA03) },
{ MP_ROM_QSTR(MP_QSTR_MICROPHONE_DATA), MP_ROM_PTR(&pin_PC03) },
};
MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table);
1 change: 1 addition & 0 deletions ports/stm/common-hal/audiobusio/I2SOut.c
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
// Although IS2Out is not enabled on the STM32L4 family, this file is still required for the build to pass
1 change: 1 addition & 0 deletions ports/stm/common-hal/audiobusio/I2SOut.h
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
// Although IS2Out is not enabled on the STM32L4 family, this file is still required for the build to pass
96 changes: 96 additions & 0 deletions ports/stm/common-hal/audiobusio/MEMS_Audio.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2022 Matthew McGowan for Blues Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

#include <assert.h>
#include <stm32l4xx_hal.h>

#include "MEMS_Audio.h"
#include "MEMS_Audio_ll.h"

static void default_pcm_data_available(MemsAudio *audio, pcm_sample_t *pcmSamples, size_t pcmLength) {
}



/**
* @brief Initializes the MemsAudio instance. Only one instance can be initialized and used at a given time.
*
* @param audio
* @return mems_audio_err_t
*/
mems_audio_err_t mems_audio_init(MemsAudio *audio) {
if (!audio->pcm_data_available) {
audio->pcm_data_available = default_pcm_data_available;
}
return mems_audio_ll_init(audio);
}

/**
* @brief Uninitializes the MemsAudio instance.
*
* @param audio
* @return mems_audio_err_t
*/
mems_audio_err_t mems_audio_uninit(MemsAudio *audio) {
return mems_audio_ll_uninit(audio);
}

/**
* @brief Asynchronously records audio.
*
* @param audio
* @param pdmBuffer
* @param pdmBufferLength
* @return mems_audio_err_t
*/
mems_audio_err_t mems_audio_record(MemsAudio *audio) {
return mems_audio_ll_record(audio);
}

/**
* @brief Pause recording audio.
*/
mems_audio_err_t mems_audio_pause(MemsAudio *audio) {
return mems_audio_ll_pause(audio);
}

/**
* @brief Resume recording audio.
*
* @param audio
* @return mems_audio_err_t
*/
mems_audio_err_t mems_audio_resume(MemsAudio *audio) {
return mems_audio_ll_resume(audio);
}

/**
* @brief Stop recording audio and
*
* @param audio
* @return mems_audio_err_t
*/
mems_audio_err_t mems_audio_stop(MemsAudio *audio) {
return mems_audio_ll_stop(audio);
}
156 changes: 156 additions & 0 deletions ports/stm/common-hal/audiobusio/MEMS_Audio.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2022 Matthew McGowan for Blues Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

#ifndef _MEMS_AUDIO_H_
#define _MEMS_AUDIO_H_

#include <stdint.h>
#include <stddef.h>

#ifdef __cplusplus
extern "C" {
#endif


/**
* @brief How many milliseconds of audio can fit in the audio buffer(s).
* Interrupts for recieved data fire at half this duration / twice the frequency.
*/
#ifndef MEMS_AUDIO_MS_BUFFER
#define MEMS_AUDIO_MS_BUFFER (1)
#endif


/**
* @brief The number of bits per sample of the PCM output
*/
#define PCM_OUT_RESOLUTION 16

/**
* @brief The output frequency of PCM samples in Hz.
*/
#define PCM_OUT_SAMPLING_FREQUENCY 16000

/**
* @brief type for describing error conditions.
*/
typedef int32_t mems_audio_err_t;

/**
* @brief The datatype that holds an output PCM sample.
*/
typedef int16_t pcm_sample_t;
_Static_assert(PCM_OUT_RESOLUTION==16, "Output PCM resolution must be 16-bits");


typedef enum {
MEMS_AUDIO_OK = 0,
MEMS_AUDIO_ERROR_ALREADY_INITIALIZED = -1,
MEMS_AUDIO_ERROR_NOT_INITIALIZED = -2
} mems_audio_err_enum_t;

#define IS_MEMS_AUDIO_ERROR(e) (e)
#define CHECK_MEMS_AUDIO_ERROR(e) { if (IS_MEMS_AUDIO_ERROR(e)) return e; }
#define CHECK_MEMS_AUDIO_INITIALIZED(x) { if (!x) return MEMS_AUDIO_ERROR_NOT_INITIALIZED; }

typedef struct MemsAudio_t MemsAudio;

/**
* @brief Callback informing that PCM samples are available for processing.
*/
typedef void (*pcm_data_available_t)(MemsAudio* audio, pcm_sample_t* pcmSamples, size_t pcmLength);

/**
* @brief MemsAudio manages the filter, buffers and callbacks used to capture PDM audio samples and convert to PCM.
*
*/
typedef struct MemsAudio_t {

/**
* @brief The buffer to store PCM audio samples
*/
volatile pcm_sample_t* volatile pcmOutputBuffer;

/**
* @brief The length of the PCM buffer. SHould be at least MEMS_AUDIO_PCM_BUFFER_LENGTH
*/
volatile size_t pcmOutputBufferLength;

/**
* @brief Optional callback for when PCM data is available.
*/
pcm_data_available_t pcm_data_available;

void* audioImpl;
void* userData;
} MemsAudio;


mems_audio_err_t mems_audio_init(MemsAudio* audio);

/**
* @brief Uninitializes the MemsAudio instance.
*
* @param audio
* @return mems_audio_err_t
*/
mems_audio_err_t mems_audio_uninit(MemsAudio* audio);

/**
* @brief Asynchronously records audio.
*
* @param audio
* @param pdmBuffer
* @param pdmBufferLength
* @return mems_audio_err_t
*/
mems_audio_err_t mems_audio_record(MemsAudio* audio);

/**
* @brief Pause recording audio.
*/
mems_audio_err_t mems_audio_pause(MemsAudio* audio);

/**
* @brief Resume recording audio.
*
* @param audio
* @return mems_audio_err_t
*/
mems_audio_err_t mems_audio_resume(MemsAudio* audio);

/**
* @brief Stop recording audio and
*
* @param audio
* @return mems_audio_err_t
*/
mems_audio_err_t mems_audio_stop(MemsAudio* audio);

#ifdef __cplusplus
}
#endif


#endif // _MEMS_AUDIO_H_
Loading