2026-04-30 12:32 PM - last edited on 2026-04-30 12:42 PM by mƎALLEm
I am working on converting projects from STM32F745VET to STM32U575VGT. Part of the startup routine of the projects is checking for flash errors using the CRC peripheral. The STM32F7 projects initialize a DMA channel in the following way:
void MX_DMA_Init(void)
{
/* DMA controller clock enable */
__HAL_RCC_DMA1_CLK_ENABLE();
__HAL_RCC_DMA2_CLK_ENABLE();
/* Configure DMA request hdma_memtomem_dma2_stream1 on DMA2_Stream1 */
hdma_memtomem_dma2_stream1.Instance = DMA2_Stream1;
hdma_memtomem_dma2_stream1.Init.Channel = DMA_CHANNEL_0;
hdma_memtomem_dma2_stream1.Init.Direction = DMA_MEMORY_TO_MEMORY;
hdma_memtomem_dma2_stream1.Init.PeriphInc = DMA_PINC_ENABLE;
hdma_memtomem_dma2_stream1.Init.MemInc = DMA_MINC_DISABLE;
hdma_memtomem_dma2_stream1.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
hdma_memtomem_dma2_stream1.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
hdma_memtomem_dma2_stream1.Init.Mode = DMA_NORMAL;
hdma_memtomem_dma2_stream1.Init.Priority = DMA_PRIORITY_LOW;
hdma_memtomem_dma2_stream1.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
hdma_memtomem_dma2_stream1.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
hdma_memtomem_dma2_stream1.Init.MemBurst = DMA_MBURST_SINGLE;
hdma_memtomem_dma2_stream1.Init.PeriphBurst = DMA_PBURST_SINGLE;
if (HAL_DMA_Init(&hdma_memtomem_dma2_stream1) != HAL_OK)
{
Error_Handler();
}
}
And then in the code:
__HAL_CRC_DR_RESET(&hcrc);
HAL_DMA_Start_IT(&handle_GPDMA1_Channel12, checkstart, CRC_BASE, checkrange);
where checkstart is defined as 0x08000000 and checkrange is 0x0000FFFC
I tried to use a GPDMA channel on the STM32U5 in the same way, but the calculated checksum does not match. Using the HAL_CRC_Calculate function does result in a checksum match, but this uses the CPU instead of offloading it to DMA.
Is there a way to feed the flash into the CRC peripheral through a DMA channel on the STM32U5?
Solved! Go to Solution.
2026-05-15 3:11 AM
Hello all,
On STM32U5, CRC has no dedicated GPDMA request, so the working approach is a software-triggered GPDMA transfer that writes directly to CRC->DR.
The main point to check is the transfer length unit:
HAL_CRC_Calculate() uses a word count when the input format is words, while HAL_DMA_Start_IT() on U5 expects the transfer size in bytes.
So, if your DMA call is:
HAL_DMA_Start_IT(&handle_GPDMA1_Channel12, checkstart, (uint32_t)&CRC->DR, checkrange);and checkrange is a word count, the DMA length is wrong. In that case, try:
__HAL_CRC_DR_RESET(&hcrc);
HAL_DMA_Start_IT(&handle_GPDMA1_Channel12, checkstart,(uint32_t)&CRC->DR, checkrange * 4U);
And the recommended GPDMA settings are:
- Request = DMA_REQUEST_SW
- Direction = DMA_MEMORY_TO_MEMORY
- SrcInc = DMA_SINC_INCREMENTED
- DestInc = DMA_DINC_FIXED
- SrcDataWidth = WORD
- DestDataWidth = WORD
If the byte/word length mismatch was the issue, both results should then match.
Kind regards,
DHIF Khaled
2026-05-15 5:55 AM
Oh, indeed - if a CRC calculator is fed by one byte only (0x80), the result is 0x6800520C as reported.
A nasty gotcha, changing the Cube/HAL's API between families! I see that this matches GPDMA's BNDT behaviour but still - Cube/HAL is supposed to be there to facilitate porting, which it fails here obviously.
Nonetheless, in this case, the DMA has been set to transfer words at both ports, wasn't it. And the RM says this:
so GPDMA shouldn't have transferred even that one single byte, but should've thrown the user setting error, which doesn't appear to have happened.
@Khaled_DHIF, can you please comment?
Thanks,
JW
2026-05-20 10:39 AM
@Khaled_DHIF Thank you for this insight, I was not aware of the change in DMA transfer length calculation. Your solution worked for checking flash memory from 0x08000000 to 0x0800FFFB, where 0x0800FFFB is end of word addressing in terms of bytes in 16 bits. I looked at the reference manual for why this was the limit but did not find anything in the memory map. Stepping through the code with the debugger, I realized that although HAL functions passed the transfer length as a 32bit value, it was in fact limited by the size of BNDT in the GPDMA CxBR1 register. To transfer something larger, I would need to use a linked list. I configured in STM32CubeMX a linked list for transferring blocks of 0xFFFC as follows:
/**
* @brief DMA Linked-list FlashMemory configuration
* @param None
* @retval None
*/
HAL_StatusTypeDef MX_FlashMemory_Config(void)
{
HAL_StatusTypeDef ret = HAL_OK;
/* DMA node configuration declaration */
DMA_NodeConfTypeDef pNodeConfig;
/* Set node configuration ################################################*/
pNodeConfig.NodeType = DMA_GPDMA_LINEAR_NODE;
pNodeConfig.Init.Request = DMA_REQUEST_SW;
pNodeConfig.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;
pNodeConfig.Init.Direction = DMA_MEMORY_TO_MEMORY;
pNodeConfig.Init.SrcInc = DMA_SINC_INCREMENTED;
pNodeConfig.Init.DestInc = DMA_DINC_FIXED;
pNodeConfig.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_WORD;
pNodeConfig.Init.DestDataWidth = DMA_DEST_DATAWIDTH_WORD;
pNodeConfig.Init.SrcBurstLength = 1;
pNodeConfig.Init.DestBurstLength = 1;
pNodeConfig.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT1|DMA_DEST_ALLOCATED_PORT0;
pNodeConfig.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
pNodeConfig.TriggerConfig.TriggerPolarity = DMA_TRIG_POLARITY_MASKED;
pNodeConfig.DataHandlingConfig.DataExchange = DMA_EXCHANGE_NONE;
pNodeConfig.DataHandlingConfig.DataAlignment = DMA_DATA_RIGHTALIGN_ZEROPADDED;
pNodeConfig.SrcAddress = 0x08000000;
pNodeConfig.DstAddress = CRC_BASE;
pNodeConfig.DataSize = 0xFFFC;
/* Build Block1 Node */
ret |= HAL_DMAEx_List_BuildNode(&pNodeConfig, &Block1);
/* Insert Block1 to Queue */
ret |= HAL_DMAEx_List_InsertNode_Tail(&FlashMemory, &Block1);
/* Set node configuration ################################################*/
pNodeConfig.SrcAddress = 0x0800FFFC;
/* Build Block2 Node */
ret |= HAL_DMAEx_List_BuildNode(&pNodeConfig, &Block2);
/* Insert Block2 to Queue */
ret |= HAL_DMAEx_List_InsertNode_Tail(&FlashMemory, &Block2);
return ret;
}And in the code I started the transfer as follows:
MX_FlashMemory_Config();
HAL_DMAEx_List_LinkQ(&handle_GPDMA1_Channel12, &FlashMemory);
__HAL_CRC_DR_RESET(&hcrc);
HAL_DMAEx_List_Start_IT(&handle_GPDMA1_Channel12);This works if the IAR project calculates a checksum from 0x08000000 to 0x0801FFF7. I hope this helps anyone trying to run a checksum on the STM32U5 line.
2026-05-21 2:42 AM
Thanks for coming back with the detailed solution.
This may be helpful not just in 'U5, but also all newer families, which as DMA have the GPDMA (and presumably also LPDMA?) modules.
JW