Add DFSDM support to audio module. (#1459)

* Add DFSDM support to audio module.
This commit is contained in:
Ibrahim Abd Elkader 2021-10-15 16:05:12 +02:00 committed by GitHub
parent b32aa4597e
commit d412e9e017
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 358 additions and 112 deletions

View File

@ -304,33 +304,56 @@ void SystemClock_Config(void)
#endif #endif
#if defined(MCU_SERIES_H7) #if defined(MCU_SERIES_H7)
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_RTC|RCC_PERIPHCLK_FDCAN PeriphClkInitStruct.PeriphClockSelection |= RCC_PERIPHCLK_RTC;
|RCC_PERIPHCLK_SPI3|RCC_PERIPHCLK_SPI2 PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSI;
|RCC_PERIPHCLK_SDMMC|RCC_PERIPHCLK_I2C2
|RCC_PERIPHCLK_ADC|RCC_PERIPHCLK_USB PeriphClkInitStruct.PeriphClockSelection |= RCC_PERIPHCLK_RNG;
|RCC_PERIPHCLK_QSPI|RCC_PERIPHCLK_FMC PeriphClkInitStruct.RngClockSelection = OMV_OSC_RNG_CLKSOURCE;
|RCC_PERIPHCLK_RNG|RCC_PERIPHCLK_SAI4A;
PeriphClkInitStruct.PeriphClockSelection |= RCC_PERIPHCLK_USB;
PeriphClkInitStruct.UsbClockSelection = OMV_OSC_USB_CLKSOURCE; PeriphClkInitStruct.UsbClockSelection = OMV_OSC_USB_CLKSOURCE;
PeriphClkInitStruct.SdmmcClockSelection = RCC_SDMMCCLKSOURCE_PLL;
PeriphClkInitStruct.FdcanClockSelection = RCC_FDCANCLKSOURCE_PLL; PeriphClkInitStruct.PeriphClockSelection |= RCC_PERIPHCLK_FMC;
PeriphClkInitStruct.FmcClockSelection = RCC_FMCCLKSOURCE_PLL2; PeriphClkInitStruct.FmcClockSelection = RCC_FMCCLKSOURCE_PLL2;
PeriphClkInitStruct.QspiClockSelection = RCC_QSPICLKSOURCE_PLL2;
PeriphClkInitStruct.PeriphClockSelection |= RCC_PERIPHCLK_ADC;
PeriphClkInitStruct.AdcClockSelection = OMV_OSC_ADC_CLKSOURCE; PeriphClkInitStruct.AdcClockSelection = OMV_OSC_ADC_CLKSOURCE;
PeriphClkInitStruct.PeriphClockSelection |= RCC_PERIPHCLK_SDMMC;
PeriphClkInitStruct.SdmmcClockSelection = RCC_SDMMCCLKSOURCE_PLL;
PeriphClkInitStruct.PeriphClockSelection |= RCC_PERIPHCLK_FDCAN;
PeriphClkInitStruct.FdcanClockSelection = RCC_FDCANCLKSOURCE_PLL;
PeriphClkInitStruct.PeriphClockSelection |= RCC_PERIPHCLK_QSPI;
PeriphClkInitStruct.QspiClockSelection = RCC_QSPICLKSOURCE_PLL2;
PeriphClkInitStruct.PeriphClockSelection |= RCC_PERIPHCLK_SPI123;
PeriphClkInitStruct.Spi123ClockSelection = OMV_OSC_SPI123_CLKSOURCE; PeriphClkInitStruct.Spi123ClockSelection = OMV_OSC_SPI123_CLKSOURCE;
PeriphClkInitStruct.PeriphClockSelection |= RCC_PERIPHCLK_I2C123;
PeriphClkInitStruct.I2c123ClockSelection = RCC_I2C123CLKSOURCE_D2PCLK1;
PeriphClkInitStruct.PeriphClockSelection |= RCC_PERIPHCLK_SAI4A;
PeriphClkInitStruct.Sai4AClockSelection = RCC_SAI4ACLKSOURCE_PLL;
#if defined(OMV_OSC_DFSDM1_CLKSOURCE)
PeriphClkInitStruct.PeriphClockSelection |= RCC_PERIPHCLK_DFSDM1;
PeriphClkInitStruct.Dfsdm1ClockSelection = OMV_OSC_DFSDM1_CLKSOURCE;
#endif
PeriphClkInitStruct.PeriphClockSelection |= RCC_PERIPHCLK_SPI45;
#if defined(OMV_OSC_SPI45_CLKSOURCE) #if defined(OMV_OSC_SPI45_CLKSOURCE)
PeriphClkInitStruct.Spi45ClockSelection = OMV_OSC_SPI45_CLKSOURCE; PeriphClkInitStruct.Spi45ClockSelection = OMV_OSC_SPI45_CLKSOURCE;
#endif #else
PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSI;
PeriphClkInitStruct.I2c123ClockSelection = RCC_I2C123CLKSOURCE_D2PCLK1;
PeriphClkInitStruct.Spi45ClockSelection = RCC_SPI45CLKSOURCE_PLL2; PeriphClkInitStruct.Spi45ClockSelection = RCC_SPI45CLKSOURCE_PLL2;
PeriphClkInitStruct.RngClockSelection = OMV_OSC_RNG_CLKSOURCE; #endif
PeriphClkInitStruct.Sai4AClockSelection = RCC_SAI4ACLKSOURCE_PLL;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK) { if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK) {
// Initialization Error // Initialization Error
__fatal_error("HAL_RCCEx_PeriphCLKConfig"); __fatal_error("HAL_RCCEx_PeriphCLKConfig");
} }
#endif #endif // defined(MCU_SERIES_H7)
#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
if (HAL_PWREx_EnableOverDrive() != HAL_OK) { if (HAL_PWREx_EnableOverDrive() != HAL_OK) {

View File

@ -16,6 +16,8 @@ stm32h7xx_hal_cortex.c\
stm32h7xx_hal_crc.c\ stm32h7xx_hal_crc.c\
stm32h7xx_hal_crc_ex.c\ stm32h7xx_hal_crc_ex.c\
stm32h7xx_hal_dcmi.c\ stm32h7xx_hal_dcmi.c\
stm32h7xx_hal_dfsdm.c\
stm32h7xx_hal_dfsdm_ex.c\
stm32h7xx_hal_dma.c\ stm32h7xx_hal_dma.c\
stm32h7xx_hal_dma_ex.c\ stm32h7xx_hal_dma_ex.c\
stm32h7xx_hal_dma2d.c\ stm32h7xx_hal_dma2d.c\

@ -1 +1 @@
Subproject commit 6f1022cbc15df7fcb05572a28992069096caea08 Subproject commit d44b3ba367d04d05212062ce536bd23c8a7a402b

View File

@ -126,7 +126,8 @@
#define OMV_OSC_RNG_CLKSOURCE RCC_RNGCLKSOURCE_HSI48 #define OMV_OSC_RNG_CLKSOURCE RCC_RNGCLKSOURCE_HSI48
#define OMV_OSC_ADC_CLKSOURCE RCC_ADCCLKSOURCE_PLL3 #define OMV_OSC_ADC_CLKSOURCE RCC_ADCCLKSOURCE_PLL3
#define OMV_OSC_SPI45_CLKSOURCE RCC_SPI45CLKSOURCE_PLL3 #define OMV_OSC_SPI45_CLKSOURCE RCC_SPI45CLKSOURCE_PLL3
#define OMV_OSC_SPI123_CLKSOURCE RCC_SPI123CLKSOURCE_PLL3 #define OMV_OSC_SPI123_CLKSOURCE RCC_SPI123CLKSOURCE_PLL2
#define OMV_OSC_DFSDM1_CLKSOURCE RCC_DFSDM1CLKSOURCE_D2PCLK1
// HSE/HSI/CSI State // HSE/HSI/CSI State
#define OMV_OSC_HSE_STATE (RCC_HSE_BYPASS) #define OMV_OSC_HSE_STATE (RCC_HSE_BYPASS)
@ -153,7 +154,7 @@
#define OMV_FB_SIZE (400K) // FB memory: header + VGA/GS image #define OMV_FB_SIZE (400K) // FB memory: header + VGA/GS image
#define OMV_FB_ALLOC_SIZE (100K) // minimum fb alloc size #define OMV_FB_ALLOC_SIZE (100K) // minimum fb alloc size
#define OMV_STACK_SIZE (64K) #define OMV_STACK_SIZE (64K)
#define OMV_HEAP_SIZE (200K) #define OMV_HEAP_SIZE (192K)
#define OMV_LINE_BUF_SIZE (3 * 1024) // Image line buffer round(640 * 2BPP * 2 buffers). #define OMV_LINE_BUF_SIZE (3 * 1024) // Image line buffer round(640 * 2BPP * 2 buffers).
#define OMV_MSC_BUF_SIZE (2K) // USB MSC bot data #define OMV_MSC_BUF_SIZE (2K) // USB MSC bot data
@ -170,9 +171,9 @@
#define OMV_ITCM_ORIGIN 0x00000000 #define OMV_ITCM_ORIGIN 0x00000000
#define OMV_ITCM_LENGTH 64K #define OMV_ITCM_LENGTH 64K
#define OMV_SRAM1_ORIGIN 0x30000000 #define OMV_SRAM1_ORIGIN 0x30000000
#define OMV_SRAM1_LENGTH 248K #define OMV_SRAM1_LENGTH 240K
#define OMV_SRAM2_ORIGIN 0x3003E000 // 8KB of SRAM1 #define OMV_SRAM2_ORIGIN 0x3003C000 // 16KB of SRAM1
#define OMV_SRAM2_LENGTH 8K #define OMV_SRAM2_LENGTH 16K
#define OMV_SRAM3_ORIGIN 0x30040000 #define OMV_SRAM3_ORIGIN 0x30040000
#define OMV_SRAM3_LENGTH 32K #define OMV_SRAM3_LENGTH 32K
#define OMV_SRAM4_ORIGIN 0x38000000 #define OMV_SRAM4_ORIGIN 0x38000000
@ -190,9 +191,9 @@
// Domain 2 DMA buffers region. // Domain 2 DMA buffers region.
#define OMV_DMA_MEMORY_D2 SRAM2 #define OMV_DMA_MEMORY_D2 SRAM2
#define OMV_DMA_MEMORY_D2_SIZE (1*1024) // Reserved memory for DMA buffers #define OMV_DMA_MEMORY_D2_SIZE (6*1024) // Reserved memory for DMA buffers
#define OMV_DMA_REGION_D2_BASE (OMV_SRAM2_ORIGIN+(0*1024)) #define OMV_DMA_REGION_D2_BASE (OMV_SRAM2_ORIGIN+(0*1024))
#define OMV_DMA_REGION_D2_SIZE MPU_REGION_SIZE_8KB #define OMV_DMA_REGION_D2_SIZE MPU_REGION_SIZE_16KB
// Domain 3 DMA buffers region. // Domain 3 DMA buffers region.
//#define OMV_DMA_MEMORY_D3 SRAM4 //#define OMV_DMA_MEMORY_D3 SRAM4
@ -317,6 +318,34 @@
#define SOFT_I2C_SPIN_DELAY 64 #define SOFT_I2C_SPIN_DELAY 64
// DFSDM1
#define AUDIO_DFSDM (DFSDM1_Channel2)
#define AUDIO_DFSDM_CHANNEL (DFSDM_CHANNEL_2)
// DFSDM output clock is derived from the Aclk (set in SAI1SEL[2:0])
// for SAI1 and DFSDM1, which is clocked from PLL1Q by default (50MHz).
#define AUDIO_DFSDM_FREQMHZ (50)
#define AUDIO_MAX_CHANNELS (1) // Maximum number of channels.
#define AUDIO_DFSDM_CK_PORT (GPIOD)
#define AUDIO_DFSDM_CK_PIN (GPIO_PIN_10)
#define AUDIO_DFSDM_CK_AF (GPIO_AF3_DFSDM1)
#define AUDIO_DFSDM_D1_PORT (GPIOE)
#define AUDIO_DFSDM_D1_PIN (GPIO_PIN_7)
#define AUDIO_DFSDM_D1_AF (GPIO_AF3_DFSDM1)
#define AUDIO_DFSDM_FLT0 DFSDM1_Filter0
#define AUDIO_DFSDM_FLT0_IRQ DFSDM1_FLT0_IRQn
#define AUDIO_DFSDM_FLT0_IRQHandler DFSDM1_FLT0_IRQHandler
#define AUDIO_DFSDM_FLT0_DMA_STREAM DMA1_Stream1
#define AUDIO_DFSDM_FLT0_DMA_REQUEST DMA_REQUEST_DFSDM1_FLT0
#define AUDIO_DFSDM_FLT0_DMA_IRQ DMA1_Stream1_IRQn
#define AUDIO_DFSDM_FLT0_DMA_IRQHandler DMA1_Stream1_IRQHandler
#define AUDIO_DFSDM_CLK_ENABLE() __HAL_RCC_DFSDM1_CLK_ENABLE()
#define AUDIO_DFSDM_CLK_DISABLE() __HAL_RCC_DFSDM1_CLK_DISABLE()
#define AUDIO_DFSDM_DMA_CLK_ENABLE() __HAL_RCC_DMA1_CLK_ENABLE()
#define IMU_CHIP_LSM6DSOX (1) #define IMU_CHIP_LSM6DSOX (1)
#define IMU_SPI (SPI5) #define IMU_SPI (SPI5)
#define IMU_SPI_AF (GPIO_AF5_SPI5) #define IMU_SPI_AF (GPIO_AF5_SPI5)

View File

@ -19,7 +19,7 @@ MICROPY_PY_WINC1500 = 0
MICROPY_PY_IMU = 1 MICROPY_PY_IMU = 1
MICROPY_PY_LWIP = 1 MICROPY_PY_LWIP = 1
MICROPY_PY_NETWORK_CYW43 = 1 MICROPY_PY_NETWORK_CYW43 = 1
MICROPY_PY_AUDIO = 0 MICROPY_PY_AUDIO = 1
MICROPY_PY_MICRO_SPEECH = 0 MICROPY_PY_MICRO_SPEECH = 0
MICROPY_PY_LCD = 1 MICROPY_PY_LCD = 1
MICROPY_PY_TV = 1 MICROPY_PY_TV = 1

View File

@ -363,7 +363,7 @@
// SCKx frequency = SAI_KER_CK / MCKDIV / 2 // SCKx frequency = SAI_KER_CK / MCKDIV / 2
#define AUDIO_SAI_MCKDIV (12) #define AUDIO_SAI_MCKDIV (12)
#define AUDIO_SAI_FREQKHZ (2048U) // 2048KHz #define AUDIO_SAI_FREQKHZ (2048U) // 2048KHz
#define AUDIO_SAI_NBR_CHANNELS (2) // Default number of channels. #define AUDIO_MAX_CHANNELS (2) // Maximum number of channels.
#define AUDIO_SAI_CK_PORT (GPIOE) #define AUDIO_SAI_CK_PORT (GPIOE)
#define AUDIO_SAI_CK_PIN (GPIO_PIN_2) #define AUDIO_SAI_CK_PIN (GPIO_PIN_2)
@ -387,7 +387,7 @@
// #define AUDIO_SAI (SAI1_Block_A) // #define AUDIO_SAI (SAI1_Block_A)
// #define AUDIO_SAI_MCKDIV (12) // #define AUDIO_SAI_MCKDIV (12)
// #define AUDIO_SAI_FREQKHZ (2048U) // 2048KHz // #define AUDIO_SAI_FREQKHZ (2048U) // 2048KHz
// #define AUDIO_SAI_NBR_CHANNELS (2) // Default number of channels. // #define AUDIO_MAX_CHANNELS (2) // Maximum number of channels.
// //
// #define AUDIO_SAI_CK_PORT (GPIOE) // #define AUDIO_SAI_CK_PORT (GPIOE)
// #define AUDIO_SAI_CK_PIN (GPIO_PIN_2) // #define AUDIO_SAI_CK_PIN (GPIO_PIN_2)

View File

@ -28,54 +28,85 @@
#if MICROPY_PY_AUDIO #if MICROPY_PY_AUDIO
#define RAISE_OS_EXCEPTION(msg) mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT(msg)) #if defined(AUDIO_SAI)
static CRC_HandleTypeDef hcrc; static CRC_HandleTypeDef hcrc;
static SAI_HandleTypeDef hsai; static SAI_HandleTypeDef hsai;
static DMA_HandleTypeDef hdma_sai_rx; static DMA_HandleTypeDef hdma_sai_rx;
static PDM_Filter_Config_t PDM_FilterConfig[AUDIO_MAX_CHANNELS];
static PDM_Filter_Handler_t PDM_FilterHandler[AUDIO_MAX_CHANNELS];
// NOTE: BDMA can only access D3 SRAM4 memory.
#define PDM_BUFFER_SIZE (16384)
uint8_t OMV_ATTR_SECTION(OMV_ATTR_ALIGNED(PDM_BUFFER[PDM_BUFFER_SIZE], 32), ".d3_dma_buffer");
#elif defined(AUDIO_DFSDM)
static DFSDM_Channel_HandleTypeDef hdfsdm;
// NOTE: Only 1 filter is supported right now.
static DFSDM_Filter_HandleTypeDef hdfsdm_filter[AUDIO_MAX_CHANNELS];
static DMA_HandleTypeDef hdma_filter[AUDIO_MAX_CHANNELS];
// NOTE: placed in D2 memory.
#define PDM_BUFFER_SIZE (512)
int32_t OMV_ATTR_SECTION(OMV_ATTR_ALIGNED(PDM_BUFFER[PDM_BUFFER_SIZE], 32), ".d2_dma_buffer");
#define SaturaLH(N, L, H) (((N)<(L))?(L):(((N)>(H))?(H):(N)))
#else
#error "No audio driver defined for this board"
#endif
static volatile uint32_t xfer_status = 0;
static mp_obj_array_t *g_pcmbuf = NULL; static mp_obj_array_t *g_pcmbuf = NULL;
static mp_obj_t g_audio_callback = mp_const_none; static mp_obj_t g_audio_callback = mp_const_none;
static int g_channels = AUDIO_MAX_CHANNELS;
static int g_channels = AUDIO_SAI_NBR_CHANNELS;
static PDM_Filter_Handler_t PDM_FilterHandler[2];
static PDM_Filter_Config_t PDM_FilterConfig[2];
#define DMA_XFER_NONE (0x00U) #define DMA_XFER_NONE (0x00U)
#define DMA_XFER_HALF (0x01U) #define DMA_XFER_HALF (0x01U)
#define DMA_XFER_FULL (0x04U) #define DMA_XFER_FULL (0x04U)
static volatile uint32_t xfer_status = 0; #define RAISE_OS_EXCEPTION(msg) mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT(msg))
#define PDM_BUFFER_SIZE (16384)
// BDMA can only access D3 SRAM4 memory.
uint8_t OMV_ATTR_SECTION(OMV_ATTR_ALIGNED(PDM_BUFFER[PDM_BUFFER_SIZE], 32), ".d3_dma_buffer");
// Pendsv dispatch callback. // Pendsv dispatch callback.
static void audio_pendsv_callback(void); static void audio_pendsv_callback(void);
#if defined(AUDIO_SAI)
void AUDIO_SAI_DMA_IRQHandler(void) void AUDIO_SAI_DMA_IRQHandler(void)
{ {
HAL_DMA_IRQHandler(hsai.hdmarx); HAL_DMA_IRQHandler(hsai.hdmarx);
} }
#elif defined(AUDIO_DFSDM)
void AUDIO_DFSDM_FLT0_IRQHandler()
{
HAL_DFSDM_IRQHandler(&hdfsdm_filter[0]);
}
void AUDIO_DFSDM_FLT0_DMA_IRQHandler()
{
HAL_DMA_IRQHandler(&hdma_filter[0]);
}
#endif // defined(AUDIO_SAI)
#if defined(AUDIO_SAI)
void HAL_SAI_RxHalfCpltCallback(SAI_HandleTypeDef *hsai) void HAL_SAI_RxHalfCpltCallback(SAI_HandleTypeDef *hsai)
#elif defined(AUDIO_DFSDM)
void HAL_DFSDM_FilterRegConvHalfCpltCallback(DFSDM_Filter_HandleTypeDef *hdfsdm_filter)
#endif
{ {
xfer_status |= DMA_XFER_HALF; xfer_status |= DMA_XFER_HALF;
SCB_InvalidateDCache_by_Addr((uint32_t *)(&PDM_BUFFER[0]), PDM_BUFFER_SIZE / 2); SCB_InvalidateDCache_by_Addr((uint32_t *)(&PDM_BUFFER[0]), sizeof(PDM_BUFFER) / 2);
if (g_audio_callback != mp_const_none) { if (g_audio_callback != mp_const_none) {
pendsv_schedule_dispatch(PENDSV_DISPATCH_AUDIO, audio_pendsv_callback); pendsv_schedule_dispatch(PENDSV_DISPATCH_AUDIO, audio_pendsv_callback);
} }
} }
#if defined(AUDIO_SAI)
void HAL_SAI_RxCpltCallback(SAI_HandleTypeDef *hsai) void HAL_SAI_RxCpltCallback(SAI_HandleTypeDef *hsai)
#elif defined(AUDIO_DFSDM)
void HAL_DFSDM_FilterRegConvCpltCallback(DFSDM_Filter_HandleTypeDef *hdfsdm_filter)
#endif
{ {
xfer_status |= DMA_XFER_FULL; xfer_status |= DMA_XFER_FULL;
SCB_InvalidateDCache_by_Addr((uint32_t *)(&PDM_BUFFER[PDM_BUFFER_SIZE / 2]), PDM_BUFFER_SIZE / 2); SCB_InvalidateDCache_by_Addr((uint32_t *)(&PDM_BUFFER[PDM_BUFFER_SIZE / 2]), sizeof(PDM_BUFFER) / 2);
if (g_audio_callback != mp_const_none) { if (g_audio_callback != mp_const_none) {
pendsv_schedule_dispatch(PENDSV_DISPATCH_AUDIO, audio_pendsv_callback); pendsv_schedule_dispatch(PENDSV_DISPATCH_AUDIO, audio_pendsv_callback);
} }
} }
#if defined(AUDIO_SAI)
static uint32_t get_decimation_factor(uint32_t decimation) static uint32_t get_decimation_factor(uint32_t decimation)
{ {
switch (decimation) { switch (decimation) {
@ -89,24 +120,28 @@ static uint32_t get_decimation_factor(uint32_t decimation)
default: return 0; default: return 0;
} }
} }
#endif
static mp_obj_t py_audio_init(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) static mp_obj_t py_audio_init(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{ {
// Read Args. // Read Args.
g_channels = py_helper_keyword_int(n_args, args, 0, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_channels), 2); g_channels = py_helper_keyword_int(n_args, args, 0, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_channels), AUDIO_MAX_CHANNELS);
uint32_t frequency = py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_frequency), 16000); uint32_t frequency = py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_frequency), 16000);
#if defined(AUDIO_SAI)
int gain_db = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_gain_db), 24); int gain_db = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_gain_db), 24);
float highpass = py_helper_keyword_float(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_highpass), 0.9883f); float highpass = py_helper_keyword_float(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_highpass), 0.9883f);
#endif
// Sanity checks // Sanity checks
if (frequency < 16000 || frequency > 128000) { if (frequency < 16000 || frequency > 128000) {
RAISE_OS_EXCEPTION("Invalid frequency!"); RAISE_OS_EXCEPTION("Invalid frequency!");
} }
if (g_channels != 1 && g_channels != 2) { if (g_channels != 1 && g_channels > AUDIO_MAX_CHANNELS) {
RAISE_OS_EXCEPTION("Invalid number of channels! Expected 1 or 2."); RAISE_OS_EXCEPTION("Invalid number of channels!");
} }
#if defined(AUDIO_SAI)
uint32_t decimation_factor = AUDIO_SAI_FREQKHZ / (frequency / 1000); uint32_t decimation_factor = AUDIO_SAI_FREQKHZ / (frequency / 1000);
uint32_t decimation_factor_const = get_decimation_factor(decimation_factor); uint32_t decimation_factor_const = get_decimation_factor(decimation_factor);
if (decimation_factor_const == 0) { if (decimation_factor_const == 0) {
@ -213,6 +248,79 @@ static mp_obj_t py_audio_init(uint n_args, const mp_obj_t *args, mp_map_t *kw_ar
PDM_FilterConfig[i].decimation_factor = decimation_factor_const; PDM_FilterConfig[i].decimation_factor = decimation_factor_const;
PDM_Filter_setConfig(&PDM_FilterHandler[i], &PDM_FilterConfig[i]); PDM_Filter_setConfig(&PDM_FilterHandler[i], &PDM_FilterConfig[i]);
} }
#elif defined(AUDIO_DFSDM)
hdfsdm.Instance = AUDIO_DFSDM;
hdfsdm.Init.OutputClock.Activation = ENABLE;
hdfsdm.Init.OutputClock.Selection = DFSDM_CHANNEL_OUTPUT_CLOCK_AUDIO;
hdfsdm.Init.OutputClock.Divider = AUDIO_DFSDM_FREQMHZ / 2; /* Divider = Aclk / 2MHz*/
hdfsdm.Init.Input.Multiplexer = DFSDM_CHANNEL_EXTERNAL_INPUTS;
hdfsdm.Init.Input.DataPacking = DFSDM_CHANNEL_STANDARD_MODE;
hdfsdm.Init.Input.Pins = DFSDM_CHANNEL_SAME_CHANNEL_PINS;
hdfsdm.Init.SerialInterface.Type = DFSDM_CHANNEL_SPI_RISING;
hdfsdm.Init.SerialInterface.SpiClock = DFSDM_CHANNEL_SPI_CLOCK_INTERNAL;
hdfsdm.Init.Awd.FilterOrder = DFSDM_CHANNEL_FASTSINC_ORDER;
hdfsdm.Init.Awd.Oversampling = 125; /* 2MHz/125 = 16kHz */
hdfsdm.Init.Offset = 0;
hdfsdm.Init.RightBitShift = 0x02;
__HAL_DFSDM_CHANNEL_RESET_HANDLE_STATE(&hdfsdm);
if (HAL_DFSDM_ChannelInit(&hdfsdm) != HAL_OK) {
RAISE_OS_EXCEPTION("Failed to init DFSDM");
}
hdfsdm_filter[0].Instance = AUDIO_DFSDM_FLT0;
hdfsdm_filter[0].Init.RegularParam.Trigger = DFSDM_FILTER_SW_TRIGGER;
hdfsdm_filter[0].Init.RegularParam.FastMode = ENABLE;
hdfsdm_filter[0].Init.RegularParam.DmaMode = ENABLE;
hdfsdm_filter[0].Init.InjectedParam.Trigger = DFSDM_FILTER_SINC3_ORDER;
hdfsdm_filter[0].Init.InjectedParam.ScanMode = ENABLE;
hdfsdm_filter[0].Init.InjectedParam.DmaMode = ENABLE;
hdfsdm_filter[0].Init.InjectedParam.ExtTrigger = DFSDM_FILTER_EXT_TRIG_TIM1_TRGO;
hdfsdm_filter[0].Init.InjectedParam.ExtTriggerEdge = DFSDM_FILTER_EXT_TRIG_RISING_EDGE;
hdfsdm_filter[0].Init.FilterParam.SincOrder = DFSDM_FILTER_FASTSINC_ORDER;
hdfsdm_filter[0].Init.FilterParam.Oversampling = 125; /* 2MHz/125 = 16kHz */
hdfsdm_filter[0].Init.FilterParam.IntOversampling = 1;
__HAL_DFSDM_FILTER_RESET_HANDLE_STATE(&hdfsdm_filter[0]);
if (HAL_DFSDM_FilterInit(&hdfsdm_filter[0]) != HAL_OK ||
HAL_DFSDM_FilterConfigRegChannel(&hdfsdm_filter[0],
AUDIO_DFSDM_CHANNEL, DFSDM_CONTINUOUS_CONV_ON) != HAL_OK) {
RAISE_OS_EXCEPTION("Failed to init DFSDM filter");
return 0;
}
// Enable the DMA clock
AUDIO_DFSDM_DMA_CLK_ENABLE();
// Configure the DFSDM Filter 0 DMA/IRQ
hdma_filter[0].Instance = AUDIO_DFSDM_FLT0_DMA_STREAM;
hdma_filter[0].Init.Request = AUDIO_DFSDM_FLT0_DMA_REQUEST;
hdma_filter[0].Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_filter[0].Init.PeriphInc = DMA_PINC_DISABLE;
hdma_filter[0].Init.MemInc = DMA_MINC_ENABLE;
hdma_filter[0].Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
hdma_filter[0].Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
hdma_filter[0].Init.Mode = DMA_CIRCULAR;
hdma_filter[0].Init.Priority = DMA_PRIORITY_HIGH;
__HAL_LINKDMA(&hdfsdm_filter[0], hdmaInj, hdma_filter[0]);
__HAL_LINKDMA(&hdfsdm_filter[0], hdmaReg, hdma_filter[0]);
// Initialize the DMA stream
HAL_DMA_DeInit(&hdma_filter[0]);
if (HAL_DMA_Init(&hdma_filter[0]) != HAL_OK) {
RAISE_OS_EXCEPTION("SAI DFSDM init failed!");
}
// Configure and enable DFSDM Filter 0 DMA IRQ.
NVIC_SetPriority(AUDIO_DFSDM_FLT0_DMA_IRQ, IRQ_PRI_DMA21);
HAL_NVIC_EnableIRQ(AUDIO_DFSDM_FLT0_DMA_IRQ);
NVIC_SetPriority(AUDIO_DFSDM_FLT0_IRQ, IRQ_PRI_DMA21);
HAL_NVIC_EnableIRQ(AUDIO_DFSDM_FLT0_IRQ);
uint32_t samples_per_channel = PDM_BUFFER_SIZE / 2; // Half a transfer
#endif // defined(AUDIO_SAI)
// Allocate global PCM buffer. // Allocate global PCM buffer.
g_pcmbuf = mp_obj_new_bytearray_by_ref( g_pcmbuf = mp_obj_new_bytearray_by_ref(
@ -221,9 +329,11 @@ static mp_obj_t py_audio_init(uint n_args, const mp_obj_t *args, mp_map_t *kw_ar
return mp_const_none; return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_audio_init_obj, 0, py_audio_init);
void py_audio_deinit() void py_audio_deinit()
{ {
#if defined(AUDIO_SAI)
// Stop SAI DMA. // Stop SAI DMA.
if (hdma_sai_rx.Instance != NULL) { if (hdma_sai_rx.Instance != NULL) {
HAL_SAI_DMAStop(&hsai); HAL_SAI_DMAStop(&hsai);
@ -241,12 +351,116 @@ void py_audio_deinit()
HAL_DMA_DeInit(&hdma_sai_rx); HAL_DMA_DeInit(&hdma_sai_rx);
hdma_sai_rx.Instance = NULL; hdma_sai_rx.Instance = NULL;
} }
#elif defined(AUDIO_DFSDM)
if (hdma_filter[0].Instance != NULL) {
HAL_DFSDM_FilterRegularStop_DMA(&hdfsdm_filter[0]);
}
// Disable IRQs
HAL_NVIC_DisableIRQ(AUDIO_DFSDM_FLT0_DMA_IRQ);
HAL_NVIC_DisableIRQ(AUDIO_DFSDM_FLT0_IRQ);
if (hdfsdm.Instance != NULL) {
HAL_DFSDM_ChannelDeInit(&hdfsdm);
hdfsdm.Instance = NULL;
}
if (hdma_filter[0].Instance != NULL) {
HAL_DMA_DeInit(&hdma_filter[0]);
hdma_filter[0].Instance = NULL;
}
#endif
g_channels = 0; g_channels = 0;
g_pcmbuf = NULL; g_pcmbuf = NULL;
g_audio_callback = mp_const_none; g_audio_callback = mp_const_none;
} }
static void audio_pendsv_callback(void)
{
// Check for half transfer complete.
if ((xfer_status & DMA_XFER_HALF)) {
// Clear buffer state.
xfer_status &= ~(DMA_XFER_HALF);
#if defined(AUDIO_SAI)
// Convert PDM samples to PCM.
for (int i=0; i<g_channels; i++) {
PDM_Filter(&((uint8_t*)PDM_BUFFER)[i], &((int16_t*)g_pcmbuf->items)[i], &PDM_FilterHandler[i]);
}
#elif defined(AUDIO_DFSDM)
int16_t *pcmbuf = (int16_t*) g_pcmbuf->items;
for (int i=0; i<PDM_BUFFER_SIZE / 2; i++) {
pcmbuf[i] = SaturaLH((PDM_BUFFER[i] >> 8), -32768, 32767);
}
#endif
} else if ((xfer_status & DMA_XFER_FULL)) { // Check for transfer complete.
// Clear buffer state.
xfer_status &= ~(DMA_XFER_FULL);
#if defined(AUDIO_SAI)
// Convert PDM samples to PCM.
for (int i=0; i<g_channels; i++) {
PDM_Filter(&((uint8_t*)PDM_BUFFER)[PDM_BUFFER_SIZE / 2 + i], &((int16_t*)g_pcmbuf->items)[i], &PDM_FilterHandler[i]);
}
#elif defined(AUDIO_DFSDM)
int16_t *pcmbuf = (int16_t*) g_pcmbuf->items;
for(int i = 0; i < PDM_BUFFER_SIZE / 2; i++) {
pcmbuf[i] = SaturaLH((PDM_BUFFER[PDM_BUFFER_SIZE / 2 + i] >> 8), -32768, 32767);
}
#endif
}
// Call user callback
mp_call_function_1(g_audio_callback, MP_OBJ_FROM_PTR(g_pcmbuf));
}
static mp_obj_t py_audio_start_streaming(mp_obj_t callback_obj)
{
g_audio_callback = callback_obj;
if (!mp_obj_is_callable(g_audio_callback)) {
g_audio_callback = mp_const_none;
RAISE_OS_EXCEPTION("Invalid callback object!");
}
// Clear DMA buffer status
xfer_status &= DMA_XFER_NONE;
#if defined(AUDIO_SAI)
// Start DMA transfer
if (HAL_SAI_Receive_DMA(&hsai, (uint8_t*) PDM_BUFFER, PDM_BUFFER_SIZE / g_channels) != HAL_OK) {
g_audio_callback = mp_const_none;
RAISE_OS_EXCEPTION("SAI DMA transfer failed!");
}
#elif defined(AUDIO_DFSDM)
// Start DMA transfer
if (HAL_DFSDM_FilterRegularStart_DMA(&hdfsdm_filter[0], PDM_BUFFER, PDM_BUFFER_SIZE) != HAL_OK) {
RAISE_OS_EXCEPTION("DFSDM DMA transfer failed!");
}
#endif
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_audio_start_streaming_obj, py_audio_start_streaming);
static mp_obj_t py_audio_stop_streaming()
{
#if defined(AUDIO_SAI)
// Stop SAI DMA.
if (hdma_sai_rx.Instance != NULL) {
HAL_SAI_DMAStop(&hsai);
}
#elif defined(AUDIO_DFSDM)
if (hdma_filter[0].Instance != NULL) {
HAL_DFSDM_FilterRegularStop_DMA(&hdfsdm_filter[0]);
}
#endif
g_audio_callback = mp_const_none;
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_audio_stop_streaming_obj, py_audio_stop_streaming);
#if defined(AUDIO_SAI)
static mp_obj_t py_audio_read_pdm(mp_obj_t buf_in) static mp_obj_t py_audio_read_pdm(mp_obj_t buf_in)
{ {
mp_buffer_info_t pdmbuf; mp_buffer_info_t pdmbuf;
@ -299,71 +513,17 @@ static mp_obj_t py_audio_read_pdm(mp_obj_t buf_in)
return mp_const_none; return mp_const_none;
} }
static void audio_pendsv_callback(void)
{
// Check for half transfer complete.
if ((xfer_status & DMA_XFER_HALF)) {
// Clear buffer state.
xfer_status &= ~(DMA_XFER_HALF);
// Convert PDM samples to PCM.
for (int i=0; i<g_channels; i++) {
PDM_Filter(&((uint8_t*)PDM_BUFFER)[i], &((int16_t*)g_pcmbuf->items)[i], &PDM_FilterHandler[i]);
}
} else if ((xfer_status & DMA_XFER_FULL)) { // Check for transfer complete.
// Clear buffer state.
xfer_status &= ~(DMA_XFER_FULL);
// Convert PDM samples to PCM.
for (int i=0; i<g_channels; i++) {
PDM_Filter(&((uint8_t*)PDM_BUFFER)[PDM_BUFFER_SIZE / 2 + i], &((int16_t*)g_pcmbuf->items)[i], &PDM_FilterHandler[i]);
}
}
// Call user callback
mp_call_function_1(g_audio_callback, MP_OBJ_FROM_PTR(g_pcmbuf));
}
static mp_obj_t py_audio_start_streaming(mp_obj_t callback_obj)
{
g_audio_callback = callback_obj;
if (!mp_obj_is_callable(g_audio_callback)) {
g_audio_callback = mp_const_none;
RAISE_OS_EXCEPTION("Invalid callback object!");
}
// Clear DMA buffer status
xfer_status &= DMA_XFER_NONE;
// Start DMA transfer
if (HAL_SAI_Receive_DMA(&hsai, (uint8_t*) PDM_BUFFER, PDM_BUFFER_SIZE / g_channels) != HAL_OK) {
g_audio_callback = mp_const_none;
RAISE_OS_EXCEPTION("SAI DMA transfer failed!");
}
return mp_const_none;
}
static mp_obj_t py_audio_stop_streaming()
{
// Stop SAI DMA.
HAL_SAI_DMAStop(&hsai);
g_audio_callback = mp_const_none;
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_audio_init_obj, 0, py_audio_init);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_audio_read_pdm_obj, py_audio_read_pdm); STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_audio_read_pdm_obj, py_audio_read_pdm);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_audio_start_streaming_obj, py_audio_start_streaming); #endif
STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_audio_stop_streaming_obj, py_audio_stop_streaming);
static const mp_rom_map_elem_t globals_dict_table[] = { static const mp_rom_map_elem_t globals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_audio) }, { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_audio) },
{ MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&py_audio_init_obj) }, { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&py_audio_init_obj) },
{ MP_ROM_QSTR(MP_QSTR_read_pdm), MP_ROM_PTR(&py_audio_read_pdm_obj) },
{ MP_ROM_QSTR(MP_QSTR_start_streaming), MP_ROM_PTR(&py_audio_start_streaming_obj)}, { MP_ROM_QSTR(MP_QSTR_start_streaming), MP_ROM_PTR(&py_audio_start_streaming_obj)},
{ MP_ROM_QSTR(MP_QSTR_stop_streaming), MP_ROM_PTR(&py_audio_stop_streaming_obj) }, { MP_ROM_QSTR(MP_QSTR_stop_streaming), MP_ROM_PTR(&py_audio_stop_streaming_obj) },
#if defined(AUDIO_SAI)
{ MP_ROM_QSTR(MP_QSTR_read_pdm), MP_ROM_PTR(&py_audio_read_pdm_obj) },
#endif
}; };
STATIC MP_DEFINE_CONST_DICT(globals_dict, globals_dict_table); STATIC MP_DEFINE_CONST_DICT(globals_dict, globals_dict_table);

View File

@ -512,6 +512,38 @@ void HAL_SAI_MspDeInit(SAI_HandleTypeDef* hsai)
HAL_GPIO_DeInit(AUDIO_SAI_D1_PORT, AUDIO_SAI_D1_PIN); HAL_GPIO_DeInit(AUDIO_SAI_D1_PORT, AUDIO_SAI_D1_PIN);
} }
} }
#elif defined(AUDIO_DFSDM)
void HAL_DFSDM_ChannelMspInit(DFSDM_Channel_HandleTypeDef *hdfsdm)
{
GPIO_InitTypeDef GPIO_InitStruct;
if (hdfsdm->Instance == AUDIO_DFSDM) {
AUDIO_DFSDM_CLK_ENABLE();
GPIO_InitStruct.Pin = AUDIO_DFSDM_CK_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = AUDIO_DFSDM_CK_AF;
HAL_GPIO_Init(AUDIO_DFSDM_CK_PORT, &GPIO_InitStruct);
GPIO_InitStruct.Pin = AUDIO_DFSDM_D1_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = AUDIO_DFSDM_D1_AF;
HAL_GPIO_Init(AUDIO_DFSDM_D1_PORT, &GPIO_InitStruct);
}
}
void HAL_DFSDM_ChannelMspDeInit(DFSDM_Channel_HandleTypeDef *hdfsdm)
{
if (hdfsdm->Instance == AUDIO_DFSDM) {
AUDIO_DFSDM_CLK_DISABLE();
HAL_GPIO_DeInit(AUDIO_DFSDM_CK_PORT, AUDIO_DFSDM_CK_PIN);
HAL_GPIO_DeInit(AUDIO_DFSDM_D1_PORT, AUDIO_DFSDM_D1_PIN);
}
}
#endif #endif
void HAL_CRC_MspInit(CRC_HandleTypeDef* hcrc) void HAL_CRC_MspInit(CRC_HandleTypeDef* hcrc)