2021-09-01 07:07 AM
Hello,
I am working on application that would use microphone array. Together with STM32H735IG board I decided to use STEVAL-MIC001V1 microphone array connected via DFSDM interface. I based my project on example available in CubeMX - DFSDM_AudioRecord project where same interface and microphones are used as an demonstration. While I use this project I don't have any problem, I am receiving echoed audio on headphones.
My problem begin here. While I copy most of this sample solution, my audio input that I read in the buffer on debug mode is totally out of expected results. I receive buffer full of 0x7fff and 0x8000 (after shifting, saturating and casting variable - see in the code).
My initialization code:
[...]
/* MPU Configuration--------------------------------------------------------*/
MPU_Config();
/* Enable I-Cache---------------------------------------------------------*/
SCB_EnableICache();
/* Enable D-Cache---------------------------------------------------------*/
SCB_EnableDCache();
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* Configure the system clock */
SystemClock_Config();
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_DFSDM1_Init();
[...]
As you can see ICache and DCache is enabled, as well as MPU is configured basing on sample project from CubeMX:
void MPU_Config(void)
{
MPU_Region_InitTypeDef MPU_InitStruct = {0};
/* Disables the MPU */
HAL_MPU_Disable();
/** Initializes and configures the Region and the memory to be protected
*/
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.Number = MPU_REGION_NUMBER0;
MPU_InitStruct.BaseAddress = 0x24000000;
MPU_InitStruct.Size = MPU_REGION_SIZE_1MB;
MPU_InitStruct.SubRegionDisable = 0x0;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
MPU_InitStruct.AccessPermission = MPU_REGION_PRIV_RW;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;
HAL_MPU_ConfigRegion(&MPU_InitStruct);
/* Enables the MPU */
HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
}
For memory region configured as RAM_D1 in linker file:
MEMORY
{
ITCMRAM (xrw) : ORIGIN = 0x00000000, LENGTH = 64K
DTCMRAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
RAM_D1 (xrw) : ORIGIN = 0x24000000, LENGTH = 320K
RAM_D2 (xrw) : ORIGIN = 0x30000000, LENGTH = 32K
RAM_D3 (xrw) : ORIGIN = 0x38000000, LENGTH = 16K
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
}
Also I addressed the issue with CubeMX code generator, in which some of section was placed in DTCRAM and that was creating an issue because DMA has no access to that region:
/* used by the startup to initialize data */
_sidata = LOADADDR(.data);
/* Initialized data sections goes into RAM, load LMA copy after code */
.data :
{
. = ALIGN(4);
_sdata = .; /* create a global symbol at data start */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
. = ALIGN(4);
_edata = .; /* define a global symbol at data end */
} >RAM_D1 AT> FLASH /* REPLACED DTCRAM TO RAM_D1 */
/* Uninitialized data section */
. = ALIGN(4);
.bss :
{
/* This is used by the startup in order to initialize the .bss secion */
_sbss = .; /* define a global symbol at bss start */
__bss_start__ = _sbss;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end */
__bss_end__ = _ebss;
} >RAM_D1 /* REPLACED DTCRAM TO RAM_D1 */
/* User_heap_stack section, used to check that there is enough RAM left */
._user_heap_stack :
{
. = ALIGN(8);
PROVIDE ( end = . );
PROVIDE ( _end = . );
. = . + _Min_Heap_Size;
. = . + _Min_Stack_Size;
. = ALIGN(8);
} >RAM_D1 /* REPLACED DTCRAM TO RAM_D1 */
After initialization DFSDM filters are started and without any problem they are interrupting every half and full conversion completions:
void HAL_DFSDM_FilterErrorCallback(DFSDM_Filter_HandleTypeDef *hdfsdm_filter)
{
ItRecError = 1; // not important
}
void HAL_DFSDM_FilterRegConvHalfCpltCallback(DFSDM_Filter_HandleTypeDef *hdfsdm_filter)
{
dfsdm_filter_callback_handler_t *filter;
// acquire filter and sets it as half-ready in it's handler
filter = get_filter_instance(hdfsdm_filter);
filter->half_is_ready = FRAME_READY;
}
void HAL_DFSDM_FilterRegConvCpltCallback(DFSDM_Filter_HandleTypeDef *hdfsdm_filter)
{
dfsdm_filter_callback_handler_t *filter;
// acquire filter and sets it as full-ready in it's handler
filter = get_filter_instance(hdfsdm_filter);
filter->is_ready = FRAME_READY;
}
// in main
[...]
if(HAL_OK != HAL_DFSDM_FilterRegularStart_DMA(filter0_handler.filter, filter0_handler.audio_buffer, AUDIO_BUFFER_HALF)) {
Error_Handler();
}
if(HAL_OK != HAL_DFSDM_FilterRegularStart_DMA(filter1_handler.filter, filter1_handler.audio_buffer, AUDIO_BUFFER_HALF)) {
Error_Handler();
}
[...]
Then data acquiring, while loop looks like this:
while (1) {
if (filter0_handler.half_is_ready || filter1_handler.half_is_ready) {
SCB_InvalidateDCache_by_Addr((uint32_t *)&LeftRecBuff[0], AUDIO_BUFFER_SIZE);
SCB_InvalidateDCache_by_Addr((uint32_t *)&RightRecBuff[0], AUDIO_BUFFER_SIZE);
for (int i = 0; i < AUDIO_BUFFER_SIZE/4; i ++) {
AudioBuffer[i*2] = (uint16_t)(SaturaLH((LeftRecBuff[i] >> 8), -32768, 32767));
AudioBuffer[i*2+1] = (uint16_t)(SaturaLH((RightRecBuff[i] >> 8), -32768, 32767));
}
SCB_CleanDCache_by_Addr((uint32_t*)&AudioBuffer[0], AUDIO_BUFFER_SIZE);
memcpy(temp_array, AudioBuffer, AUDIO_BUFFER_HALF*4);
filter0_handler.half_is_ready = FRAME_NOT_READY;
filter1_handler.half_is_ready = FRAME_NOT_READY;
}
if (filter0_handler.is_ready || filter1_handler.is_ready) {
SCB_InvalidateDCache_by_Addr((uint32_t *)&LeftRecBuff[AUDIO_BUFFER_SIZE/4], AUDIO_BUFFER_SIZE);
SCB_InvalidateDCache_by_Addr((uint32_t *)&RightRecBuff[AUDIO_BUFFER_SIZE/4], AUDIO_BUFFER_SIZE);
for (int i = AUDIO_BUFFER_SIZE/4; i < AUDIO_BUFFER_HALF; i ++) {
AudioBuffer[i*2] = (uint16_t)(SaturaLH((LeftRecBuff[i] >> 8), -32768, 32767));
AudioBuffer[i*2+1] = (uint16_t)(SaturaLH((RightRecBuff[i] >> 8), -32768, 32767));
}
SCB_CleanDCache_by_Addr((uint32_t*)&AudioBuffer[AUDIO_BUFFER_SIZE/2], AUDIO_BUFFER_SIZE/2);
memcpy(temp_array[AUDIO_BUFFER_HALF], AudioBuffer[AUDIO_BUFFER_HALF], AUDIO_BUFFER_HALF*4);
filter0_handler.is_ready = FRAME_NOT_READY;
filter1_handler.is_ready = FRAME_NOT_READY;
}
}
So program logic works without a flaw, interrupts fire correctly, data goes through some processing and everything repeats forever, but the data, as I mentioned on beginning, is just 0x8000 and 0x7fff (~32767) with occasional different values.
My DFSDM configuration should results in 8 kHz sampling frequency (using audio clock with 12 MHz, divided by 4 (results with 3 MHz) and 375 oversampling parameter):
// for both filters
hdfsdm1_filter0.Instance = DFSDM1_Filter0;
hdfsdm1_filter0.Init.RegularParam.Trigger = DFSDM_FILTER_SW_TRIGGER;
hdfsdm1_filter0.Init.RegularParam.FastMode = DISABLE;
hdfsdm1_filter0.Init.RegularParam.DmaMode = ENABLE;
hdfsdm1_filter0.Init.FilterParam.SincOrder = DFSDM_FILTER_SINC3_ORDER;
hdfsdm1_filter0.Init.FilterParam.Oversampling = 375; // 12 MHz / ( 4 * 8 kHz)
hdfsdm1_filter0.Init.FilterParam.IntOversampling = 1;
if (HAL_DFSDM_FilterInit(&hdfsdm1_filter0) != HAL_OK)
{
Error_Handler();
}
// simillar for both channels
hdfsdm1_channel1.Instance = DFSDM1_Channel1;
hdfsdm1_channel1.Init.OutputClock.Activation = ENABLE;
hdfsdm1_channel1.Init.OutputClock.Selection = DFSDM_CHANNEL_OUTPUT_CLOCK_AUDIO;
hdfsdm1_channel1.Init.OutputClock.Divider = 4;
hdfsdm1_channel1.Init.Input.Multiplexer = DFSDM_CHANNEL_EXTERNAL_INPUTS;
hdfsdm1_channel1.Init.Input.DataPacking = DFSDM_CHANNEL_STANDARD_MODE;
hdfsdm1_channel1.Init.Input.Pins = DFSDM_CHANNEL_FOLLOWING_CHANNEL_PINS;
hdfsdm1_channel1.Init.SerialInterface.Type = DFSDM_CHANNEL_SPI_RISING;
hdfsdm1_channel1.Init.SerialInterface.SpiClock = DFSDM_CHANNEL_SPI_CLOCK_INTERNAL;
hdfsdm1_channel1.Init.Awd.FilterOrder = DFSDM_CHANNEL_SINC1_ORDER;
hdfsdm1_channel1.Init.Awd.Oversampling = 1;
hdfsdm1_channel1.Init.Offset = 0;
hdfsdm1_channel1.Init.RightBitShift = 0x00;
if (HAL_DFSDM_ChannelInit(&hdfsdm1_channel1) != HAL_OK)
{
Error_Handler();
}
What is interesting when oversampling is set to 68 (44,1 kHz sampling) values are much different, but still they are unexpected (most of them are based around ~64000 + few of them around 10-300).
PS. I checked clock signals with oscyloscope and they are correct - clocking with 3 MHz, data is changing on data pin.
I hope I gave out all of important information for you, and you will be able to help me in any way, I will be happy to give more information if needed.
Pawel
Solved! Go to Solution.
2021-09-14 12:33 AM
Hello,
after some work with this application and some support from ST employees I managed to get some pretty good outcome, as you can se on Picture 1. On output I can see sinusoidal wave that I am giving on input of microphones, but I get a lot of offset and noise as well.Changes that was applied:
AudioBuffer[i*2] = (int16_t)(SaturaLH((LeftRecBuff[i] >> 8), -32768, 32767)); // changed from (uint16_t)
2021-09-14 12:33 AM
Hello,
after some work with this application and some support from ST employees I managed to get some pretty good outcome, as you can se on Picture 1. On output I can see sinusoidal wave that I am giving on input of microphones, but I get a lot of offset and noise as well.Changes that was applied:
AudioBuffer[i*2] = (int16_t)(SaturaLH((LeftRecBuff[i] >> 8), -32768, 32767)); // changed from (uint16_t)