cancel
Showing results for 
Search instead for 
Did you mean: 

STM32H747I-DISCO: SAI DMA Returns Transfer Error

miloa
Visitor

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();
9 REPLIES 9
miloa
Visitor

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

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

 

If you feel a post has answered your question, please click "Accept as Solution".

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

 

This is where Error_Handler gets called according to the stack trace.

TDK_0-1752206744878.png

 

If you feel a post has answered your question, please click "Accept as Solution".

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();
}
TDK
Super User

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.

If you feel a post has answered your question, please click "Accept as Solution".
TDK
Super User

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

If you feel a post has answered your question, please click "Accept as Solution".

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

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.