Skip to main content
Graduate
July 11, 2025
Question

STM32H747I-DISCO: SAI DMA Returns Transfer Error

  • July 11, 2025
  • 4 replies
  • 675 views

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:

miloa_0-1752192585335.png

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:

miloa_1-1752192658707.png

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();
    This topic has been closed for replies.

    4 replies

    miloaAuthor
    Graduate
    July 11, 2025

    Update: also configured the DMA module in CubeMX so that is included in the initialization as well. Did not really fix anything.

    Super User
    July 11, 2025

    Where exactly is Error_Handler being called and why? Stack trace is there, should be easy to find out.

     

    miloaAuthor
    Graduate
    July 11, 2025

    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;
    ...

     

    Super User
    July 11, 2025

    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.

    Super User
    July 11, 2025

    It could be that your buffer is located in a place that DMA cannot access.

    miloaAuthor
    Graduate
    July 11, 2025

    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.

    miloaAuthor
    Graduate
    July 11, 2025

    Okay! So the issue in this case was that DMA uses SAI4 and not SAI1. After fixing the issue with CubeMX I'm still reaching the error handler but at least it's a different error now: an SAI ErrorCode 2 (underrun)

    miloaAuthor
    Graduate
    July 17, 2025

    I've been running in circles for a few days now... I tried loading in the BSP SAI audio playback example and the buffer was still just getting filled with zeroes. I'm convinced my microphones are somehow broken.