ports/stm32: Support setting audio module samples at runtime.

This commit is contained in:
iabdalkader 2024-06-27 22:19:46 +02:00
parent 54104039b4
commit 40710a3573

View File

@ -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];
}