2025-07-10 5:15 PM
Hello,
I am trying to fill a buffer from the on-board MEMS microphone using the BSP_AUDIO_IN_RecordPDM() function. However, execution pauses around HAL_SAI_Receive_DMA() and the BSP_AUDIO_IN_IRQHandler() is called. The stack trace is as follows:
Checking the hdma variable on the debugger, I can see the error code is 1, corresponding (I believe) to a transfer error. I tried looking at the relevant registers with breakpoints, but they were at 0x0 at every point:
I've tried almost everything under the sun. I disabled the D-Cache and allocated all the memory to RAM_D1, I tried allocating my buffer (copied below) to each of RAM_D1, D2, and D3
ALIGN_32BYTES (uint16_t recordPDMBuf[AUDIO_IN_PDM_BUFFER_SIZE]) __attribute__((section(".RAM_D1")));
My linker script looks like this:
/* Highest address of the user mode stack */
_estack = ORIGIN(RAM_D1) + LENGTH(RAM_D1); /* end of "RAM_D1" Ram type memory */
_Min_Heap_Size = 0x800 ; /* required amount of heap */
_Min_Stack_Size = 0x800 ; /* required amount of stack */
/* Memories definition */
MEMORY
{
RAM_D1 (xrw) : ORIGIN = 0x24000000, LENGTH = 512K
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K /* Memory is divided. Actual start is 0x08000000 and actual length is 2048K */
DTCMRAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
RAM_D2 (xrw) : ORIGIN = 0x30000000, LENGTH = 288K
RAM_D3 (xrw) : ORIGIN = 0x38000000, LENGTH = 64K
ITCMRAM (xrw) : ORIGIN = 0x00000000, LENGTH = 64K
}
/* ... */
/* Initialized data sections into "RAM" Ram type memory */
.data :
{
. = ALIGN(4);
_sdata = .; /* create a global symbol at data start */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
*(.RamFunc) /* .RamFunc sections */
*(.RamFunc*) /* .RamFunc* sections */
. = ALIGN(4);
_edata = .; /* define a global symbol at data end */
} >RAM_D1 AT> FLASH
/* Uninitialized data section into "RAM" Ram type memory */
. = ALIGN(4);
.bss :
{
/* This is used by the startup in order to initialize the .bss section */
_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
/* User_heap_stack section, used to check that there is enough "RAM" Ram type memory left */
._user_heap_stack :
{
. = ALIGN(8);
PROVIDE ( end = . );
PROVIDE ( _end = . );
. = . + _Min_Heap_Size;
. = . + _Min_Stack_Size;
. = ALIGN(8);
} >RAM_D1
At this point, I'm not entirely sure what to do. Any help is greatly appreciated. Lastly, in case it is useful, here are all the configured peripherals in main.c:
MX_GPIO_Init();
MX_SAI1_Init();
MX_DMA2D_Init();
MX_DSIHOST_DSI_Init();
MX_LTDC_Init();
MX_FMC_Init();
MX_USART1_UART_Init();
MX_SPI2_Init();
MX_X_CUBE_AI_Init();
2025-07-10 5:36 PM
Update: also configured the DMA module in CubeMX so that is included in the initialization as well. Did not really fix anything.
2025-07-10 8:44 PM
Where exactly is Error_Handler being called and why? Stack trace is there, should be easy to find out.
2025-07-10 8:52 PM
Sorry, I'm not entirely sure I understand. I've only been using the IDE for a few weeks so I may be missing something. Is there something I can print out from inside the Error_Handler to help me debug? The function itself takes in no arguments.
Unless you mean following the stack trace, in which case it looks like the HAL_SAI_Receive_DMA() function is erroring in line 9 in the code below (although it sometimes errors in line 16). After that the stack trace has a "signal handler" at 0xffffffe9 which the IDE is unable to show me, and after that it enters the cascade of interrupt handlers.
...
/* Enable the interrupts for error handling */
__HAL_SAI_ENABLE_IT(hsai, SAI_InterruptFlag(hsai, SAI_MODE_DMA));
/* Enable SAI Rx DMA Request */
hsai->Instance->CR1 |= SAI_xCR1_DMAEN;
/* Check if the SAI is already enabled */
if ((hsai->Instance->CR1 & SAI_xCR1_SAIEN) == 0U)
{
/* Enable SAI peripheral */
__HAL_SAI_ENABLE(hsai);
}
/* Process Unlocked */
__HAL_UNLOCK(hsai);
return HAL_OK;
...
2025-07-10 9:06 PM
This is where Error_Handler gets called according to the stack trace.
2025-07-10 9:11 PM
Not a lot going on there...
/**
* @brief Audio IN Error callback function
* @PAram None
* @retval None
*/
void BSP_AUDIO_IN_Error_CallBack(uint32_t Instance)
{
/* Stop the program with an infinite loop */
Error_Handler();
}
2025-07-10 10:11 PM
So keep going down the chain until you see why it was called.
HAL_SAI_Receive_DMA is in the main thread, before the interrupt happened. Error handler was called within the interrupt.
2025-07-10 10:13 PM
It could be that your buffer is located in a place that DMA cannot access.
2025-07-10 10:44 PM
I know, the issue is that signal handler I am unable to read is that critical spot between HAL_SAI_Receive_DMA() and the interrupt
2025-07-10 10:45 PM
That's what I've been thinking, but I don't know what I might be doing wrong in that regard. That's why I posted my linker script and buffer location.