From 40710a3573623175bbcdf3958f1ff86f55654f65 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Thu, 27 Jun 2024 22:19:46 +0200 Subject: [PATCH] ports/stm32: Support setting audio module samples at runtime. --- src/omv/ports/stm32/modules/py_audio.c | 55 +++++++++++++++++++------- 1 file changed, 41 insertions(+), 14 deletions(-) diff --git a/src/omv/ports/stm32/modules/py_audio.c b/src/omv/ports/stm32/modules/py_audio.c index e225f2a7a..f410a760c 100644 --- a/src/omv/ports/stm32/modules/py_audio.c +++ b/src/omv/ports/stm32/modules/py_audio.c @@ -52,6 +52,7 @@ int32_t OMV_ATTR_SECTION(OMV_ATTR_ALIGNED(PDM_BUFFER[PDM_BUFFER_SIZE], 32), ".d2 static volatile uint32_t xfer_status = 0; static int g_channels = OMV_AUDIO_MAX_CHANNELS; +static uint32_t g_pdm_buffer_size = 0; static mp_sched_node_t audio_task_sched_node; #define DMA_XFER_NONE (0x00U) @@ -79,7 +80,8 @@ void HAL_DFSDM_FilterRegConvHalfCpltCallback(DFSDM_Filter_HandleTypeDef *hdfsdm_ #endif { xfer_status |= DMA_XFER_HALF; - SCB_InvalidateDCache_by_Addr((uint32_t *) (&PDM_BUFFER[0]), sizeof(PDM_BUFFER) / 2); + uint32_t pdm_buffer_size_bytes = (sizeof(PDM_BUFFER[0]) * g_pdm_buffer_size); + SCB_InvalidateDCache_by_Addr((uint32_t *) (&PDM_BUFFER[0]), pdm_buffer_size_bytes); if (MP_STATE_PORT(audio_callback) != mp_const_none) { mp_sched_schedule_node(&audio_task_sched_node, audio_task_callback); } @@ -92,7 +94,8 @@ void HAL_DFSDM_FilterRegConvCpltCallback(DFSDM_Filter_HandleTypeDef *hdfsdm_filt #endif { xfer_status |= DMA_XFER_FULL; - SCB_InvalidateDCache_by_Addr((uint32_t *) (&PDM_BUFFER[PDM_BUFFER_SIZE / 2]), sizeof(PDM_BUFFER) / 2); + uint32_t pdm_buffer_size_bytes = (sizeof(PDM_BUFFER[0]) * g_pdm_buffer_size); + SCB_InvalidateDCache_by_Addr((uint32_t *) (&PDM_BUFFER[g_pdm_buffer_size]), pdm_buffer_size_bytes / 2); if (MP_STATE_PORT(audio_callback) != mp_const_none) { mp_sched_schedule_node(&audio_task_sched_node, audio_task_callback); } @@ -114,12 +117,13 @@ static uint32_t get_decimation_factor(uint32_t decimation) { #endif static mp_obj_t py_audio_init(uint n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_channels, ARG_frequency, ARG_gain_db, ARG_highpass }; + enum { ARG_channels, ARG_frequency, ARG_gain_db, ARG_highpass, ARG_samples }; static const mp_arg_t allowed_args[] = { { MP_QSTR_channels, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = OMV_AUDIO_MAX_CHANNELS } }, { MP_QSTR_frequency, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 16000 } }, { MP_QSTR_gain_db, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 24 } }, { MP_QSTR_highpass, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_rom_obj = MP_ROM_NONE} }, + { MP_QSTR_samples, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = -1 } }, }; // Parse args. @@ -143,14 +147,39 @@ static mp_obj_t py_audio_init(uint n_args, const mp_obj_t *pos_args, mp_map_t *k RAISE_OS_EXCEPTION("Invalid number of channels!"); } - #if defined(OMV_SAI) + // Default/max PDM buffer size; + g_pdm_buffer_size = PDM_BUFFER_SIZE; + + #if defined(OMV_DFSDM) + uint32_t samples_per_channel = PDM_BUFFER_SIZE / 2; // Half a transfer + #else uint32_t decimation_factor = OMV_SAI_FREQKHZ / (frequency / 1000); uint32_t decimation_factor_const = get_decimation_factor(decimation_factor); if (decimation_factor_const == 0) { RAISE_OS_EXCEPTION("This frequency is not supported!"); } uint32_t samples_per_channel = (PDM_BUFFER_SIZE * 8) / (decimation_factor * g_channels * 2); // Half a transfer + #endif // defined(OMV_DFSDM) + if (args[ARG_samples].u_int > 0) { + if (args[ARG_samples].u_int % 16 != 0 || + args[ARG_samples].u_int > samples_per_channel) { + mp_raise_msg_varg(&mp_type_ValueError, + MP_ERROR_TEXT("Invalid number of samples." \ + "The number of samples must be a multiple of 16," \ + "and a maximum of %d"), + samples_per_channel); + } + samples_per_channel = args[ARG_samples].u_int; + // Recalculate the PDM buffer size for the requested samples. + #if defined(OMV_DFSDM) + g_pdm_buffer_size = samples_per_channel * 2; + #else + g_pdm_buffer_size = (samples_per_channel * decimation_factor * g_channels) / 4; + #endif // defined(OMV_DFSDM) + } + + #if defined(OMV_SAI) hsai.Instance = OMV_SAI; hsai.Init.Protocol = SAI_FREE_PROTOCOL; hsai.Init.AudioMode = SAI_MODEMASTER_RX; @@ -323,8 +352,6 @@ static mp_obj_t py_audio_init(uint n_args, const mp_obj_t *pos_args, mp_map_t *k NVIC_SetPriority(OMV_DFSDM_FLT0_IRQ, IRQ_PRI_DMA21); HAL_NVIC_EnableIRQ(OMV_DFSDM_FLT0_IRQ); - - uint32_t samples_per_channel = PDM_BUFFER_SIZE / 2; // Half a transfer #endif // defined(OMV_SAI) // Allocate global PCM buffer. @@ -395,7 +422,7 @@ static void audio_task_callback(mp_sched_node_t *node) { PDM_Filter(&((uint8_t *) PDM_BUFFER)[i], &pcmbuf[i], &PDM_FilterHandler[i]); } #elif defined(OMV_DFSDM) - for (int i = 0; i < PDM_BUFFER_SIZE / 2; i++) { + for (int i = 0; i < g_pdm_buffer_size / 2; i++) { pcmbuf[i] = SaturaLH((PDM_BUFFER[i] >> 8), -32768, 32767); } #endif @@ -407,11 +434,11 @@ static void audio_task_callback(mp_sched_node_t *node) { #if defined(OMV_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], &pcmbuf[i], &PDM_FilterHandler[i]); + PDM_Filter(&((uint8_t *) PDM_BUFFER)[g_pdm_buffer_size / 2 + i], &pcmbuf[i], &PDM_FilterHandler[i]); } #elif defined(OMV_DFSDM) - for (int i = 0; i < PDM_BUFFER_SIZE / 2; i++) { - pcmbuf[i] = SaturaLH((PDM_BUFFER[PDM_BUFFER_SIZE / 2 + i] >> 8), -32768, 32767); + for (int i = 0; i < g_pdm_buffer_size / 2; i++) { + pcmbuf[i] = SaturaLH((PDM_BUFFER[g_pdm_buffer_size / 2 + i] >> 8), -32768, 32767); } #endif } @@ -432,13 +459,13 @@ static mp_obj_t py_audio_start_streaming(mp_obj_t callback_obj) { #if defined(OMV_SAI) // Start DMA transfer - if (HAL_SAI_Receive_DMA(&hsai, (uint8_t *) PDM_BUFFER, PDM_BUFFER_SIZE / g_channels) != HAL_OK) { + if (HAL_SAI_Receive_DMA(&hsai, (uint8_t *) PDM_BUFFER, g_pdm_buffer_size / g_channels) != HAL_OK) { MP_STATE_PORT(audio_callback) = mp_const_none; RAISE_OS_EXCEPTION("SAI DMA transfer failed!"); } #elif defined(OMV_DFSDM) // Start DMA transfer - if (HAL_DFSDM_FilterRegularStart_DMA(&hdfsdm_filter[0], PDM_BUFFER, PDM_BUFFER_SIZE) != HAL_OK) { + if (HAL_DFSDM_FilterRegularStart_DMA(&hdfsdm_filter[0], PDM_BUFFER, g_pdm_buffer_size) != HAL_OK) { RAISE_OS_EXCEPTION("DFSDM DMA transfer failed!"); } #endif @@ -481,7 +508,7 @@ static mp_obj_t py_audio_read_pdm(mp_obj_t buf_in) { 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) { + if (HAL_SAI_Receive_DMA(&hsai, (uint8_t *) PDM_BUFFER, g_pdm_buffer_size / g_channels) != HAL_OK) { RAISE_OS_EXCEPTION("SAI DMA transfer failed!"); } @@ -500,7 +527,7 @@ static mp_obj_t py_audio_read_pdm(mp_obj_t buf_in) { // Copy samples to pdm output buffer. // Note: samples are copied as bytes for 1 and 2 channels. - uint32_t samples = OMV_MIN(n_samples, PDM_BUFFER_SIZE); + uint32_t samples = OMV_MIN(n_samples, g_pdm_buffer_size); for (int i = 0; i < samples; i++, n_samples--, xfer_samples++) { ((uint8_t *) pdmbuf.buf)[xfer_samples] = ((uint8_t *) PDM_BUFFER)[i]; }