STM32H7 - GPDMA Request (data transmit error) when FW tries to update XSPI DR register
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;
}
