Skip to main content
Visitor
July 31, 2026
Question

STM32H7 - GPDMA Request (data transmit error) when FW tries to update XSPI DR register

  • July 31, 2026
  • 0 replies
  • 42 views

 

In STM32H7 MCU FW, i am implementing the GPDMA transfer to XSPI in indirect mode, updating DR Register from FW with DMA. I have a custom x8 SPI DDR Slave as target. The issue is i am getting Data transfer error during the HAL_DMA_Transmit_IT function. I have refered the app note for GPDMA - AN5593 where it is mentioned as - 
 


on page 38. 
I am using SW based trigger to dma since there is no GPDMA req signal for xspi for STM32H7. I want to know

  • how to implement software-based trigger if gpdma req signal is not present. I have mentioned the code below.
  • IF there is any workaround to fix the HW DMA req signal issue from xspi?
  • If not then on what other STM device having min of 2 - x8 spi support proper GPDMA transfer with HW DMA req implementation.
  • Code used in my application is mentioned below -







    static void MX_GPDMA1_XSPI2_TX_Init(void)

{

    __HAL_RCC_GPDMA1_CLK_ENABLE();

 

    hdma_xspi2_tx.Instance = GPDMA1_Channel0;   // use typed instance macro

 

    hdma_xspi2_tx.Init.Request               = DMA_REQUEST_SW;          // software-triggered

    hdma_xspi2_tx.Init.BlkHWRequest          = DMA_BREQ_SINGLE_BURST;

    hdma_xspi2_tx.Init.Direction             = DMA_MEMORY_TO_PERIPH;

    hdma_xspi2_tx.Init.SrcInc                = DMA_SINC_INCREMENTED;

    hdma_xspi2_tx.Init.DestInc               = DMA_DINC_FIXED;

    hdma_xspi2_tx.Init.SrcDataWidth          = DMA_SRC_DATAWIDTH_WORD;

    hdma_xspi2_tx.Init.DestDataWidth         = DMA_DEST_DATAWIDTH_WORD;

    hdma_xspi2_tx.Init.Priority              = DMA_HIGH_PRIORITY;

    hdma_xspi2_tx.Init.SrcBurstLength        = 1;

    hdma_xspi2_tx.Init.DestBurstLength       = 1;

    hdma_xspi2_tx.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0 | DMA_DEST_ALLOCATED_PORT0;

    hdma_xspi2_tx.Init.TransferEventMode     = DMA_TCEM_BLOCK_TRANSFER;

    hdma_xspi2_tx.Init.Mode                  = DMA_NORMAL;

 

    if (HAL_DMA_Init(&hdma_xspi2_tx) != HAL_OK)

    {

        Error_Handler();

    }

 

    if (HAL_DMA_RegisterCallback(&hdma_xspi2_tx,

                                 HAL_DMA_XFER_CPLT_CB_ID,

                                 HAL_DMA_XferCpltCallback) != HAL_OK)

    {

        Error_Handler();

    }

 

    if (HAL_DMA_RegisterCallback(&hdma_xspi2_tx,

                                 HAL_DMA_XFER_ERROR_CB_ID,

                                 HAL_DMA_XferErrorCallback) != HAL_OK)

    {

        Error_Handler();

    }

 

    HAL_NVIC_SetPriority(GPDMA1_Channel0_IRQn, 1, 0);

    HAL_NVIC_EnableIRQ(GPDMA1_Channel0_IRQn);

}

 

void GPDMA1_Channel0_IRQHandler(void)

{

    HAL_DMA_IRQHandler(&hdma_xspi2_tx);

}

void HAL_DMA_XferCpltCallback(DMA_HandleTypeDef *hdma)

{

    if (hdma == &hdma_xspi2_tx)

    {

        g_xspi2_dma_busy = 0;

    }

}

 

void HAL_DMA_XferErrorCallback(DMA_HandleTypeDef *hdma)

{

    if (hdma == &hdma_xspi2_tx)

    {

        g_xspi2_dma_error = 1;

        g_xspi2_dma_busy  = 0;

    }

}

static HAL_StatusTypeDef XSPI2_StreamChunk_DMA32(const uint8_t *src, uint32_t timeout_ms)

{

    uint32_t t0 = HAL_GetTick();

 

    if (src == NULL)

        return HAL_ERROR;

 

    /* Require 4-byte alignment for WORD DMA */

    if (((uint32_t)src & 0x3U) != 0U)

        return HAL_ERROR;

 

    g_xspi2_dma_error = 0U;

    g_xspi2_dma_busy  = 1U;

 

    if (HAL_DMA_Start_IT(&hdma_xspi2_tx,

                         (uint32_t)src,

                         (uint32_t)&hxspi2.Instance->DR,

                         32U) != HAL_OK)

    {

        g_xspi2_dma_busy  = 0U;

        g_xspi2_dma_error = 1U;

        return HAL_ERROR;

    }

 

    while (g_xspi2_dma_busy)

    {

        if ((HAL_GetTick() - t0) > timeout_ms)

        {

            (void)HAL_DMA_Abort(&hdma_xspi2_tx);

            g_xspi2_dma_busy  = 0U;

            g_xspi2_dma_error = 1U;

            return HAL_TIMEOUT;

        }

    }

 

    return (g_xspi2_dma_error == 0U) ? HAL_OK : HAL_ERROR;

}

// -------- MAIN CONTROL LOOP ------------- //
 

 #define XSPI_DMA_BURST_BYTES 32U

 

            while ((g_payload_total_len - g_payload_streamed) >= XSPI_DMA_BURST_BYTES)

            {

            /* Wait until FIFO threshold flag indicates enough empty space */

                while (__HAL_XSPI_GET_FLAG(&hxspi2, XSPI_STREAM_FLAG_FT) == RESET)

                {

                    /* optional timeout handling */

                }

 

                /* Pull one full DMA burst chunk */

                uint32_t got = CDC_RxPop_HS(g_usb_stage_buf, XSPI_DMA_BURST_BYTES);

                if (got < XSPI_DMA_BURST_BYTES)

                {

                    /* wait until full 32-byte chunk is available */

                    continue;

                }

 

                st = XSPI2_StreamChunk_DMA32(g_usb_stage_buf, XSPI_STREAM_TIMEOUT_MS);

                if (st != HAL_OK)

                {

                        DBG_Printf("GPDMA burst failed at %lu/%lu\r\n",

                        g_payload_streamed, g_payload_total_len);

                        return st;

                }

 

                g_payload_streamed += XSPI_DMA_BURST_BYTES;

            }