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-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-01 8:36 AM
And does DMA and "manual" checksum match, if you use e.g. checkrange=1?
If not, what are the content of CRC registers for the two cases?
JW
2026-05-05 6:18 AM
I set the end address to 0x08000003 in the IAR EWARM linker dialog. If I set checkrange to 1, the HAL_CRC_Calculate method comes up with a match. The DMA version does not match.
Expected value calculated by EWARM: 0x29C17239
Calculated value from CRC with DMA input: 0x6800520C
2026-05-05 7:23 AM
I meant, comparing all CRC registers' content, and perhaps looking at DMA's registers, too.
What value is at 0x0800'0000?
JW
2026-05-05 12:59 PM
The DR register is reset to 0xFFFFFFFF before the DMA transfer or HAL_CRC_Calculate command. Changing between the two does not change the value at 0x0800000, which in the memory map of EWARM is listed as 08 53 01 20.
2026-05-07 1:44 AM
Hello @Roth.Ian
Could you please provide your DMA configuration?
2026-05-07 11:48 AM
HI @Saket_Om
Please see the STM32F7 code from above. Here is the STM32U5 configuration where I try to replicate it:
/* GPDMA1 init function */
void MX_GPDMA1_Init(void)
{
/* USER CODE BEGIN GPDMA1_Init 0 */
/* USER CODE END GPDMA1_Init 0 */
/* Peripheral clock enable */
__HAL_RCC_GPDMA1_CLK_ENABLE();
/* GPDMA1 interrupt Init */
HAL_NVIC_SetPriority(GPDMA1_Channel1_IRQn, 8, 0);
HAL_NVIC_EnableIRQ(GPDMA1_Channel1_IRQn);
HAL_NVIC_SetPriority(GPDMA1_Channel2_IRQn, 7, 0);
HAL_NVIC_EnableIRQ(GPDMA1_Channel2_IRQn);
HAL_NVIC_SetPriority(GPDMA1_Channel3_IRQn, 7, 0);
HAL_NVIC_EnableIRQ(GPDMA1_Channel3_IRQn);
HAL_NVIC_SetPriority(GPDMA1_Channel4_IRQn, 7, 0);
HAL_NVIC_EnableIRQ(GPDMA1_Channel4_IRQn);
HAL_NVIC_SetPriority(GPDMA1_Channel5_IRQn, 7, 0);
HAL_NVIC_EnableIRQ(GPDMA1_Channel5_IRQn);
HAL_NVIC_SetPriority(GPDMA1_Channel7_IRQn, 7, 0);
HAL_NVIC_EnableIRQ(GPDMA1_Channel7_IRQn);
HAL_NVIC_SetPriority(GPDMA1_Channel8_IRQn, 8, 0);
HAL_NVIC_EnableIRQ(GPDMA1_Channel8_IRQn);
HAL_NVIC_SetPriority(GPDMA1_Channel12_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(GPDMA1_Channel12_IRQn);
/* USER CODE BEGIN GPDMA1_Init 1 */
/* USER CODE END GPDMA1_Init 1 */
handle_GPDMA1_Channel12.Instance = GPDMA1_Channel12;
handle_GPDMA1_Channel12.Init.Request = DMA_REQUEST_SW;
handle_GPDMA1_Channel12.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;
handle_GPDMA1_Channel12.Init.Direction = DMA_MEMORY_TO_MEMORY;
handle_GPDMA1_Channel12.Init.SrcInc = DMA_SINC_INCREMENTED;
handle_GPDMA1_Channel12.Init.DestInc = DMA_DINC_FIXED;
handle_GPDMA1_Channel12.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_WORD;
handle_GPDMA1_Channel12.Init.DestDataWidth = DMA_DEST_DATAWIDTH_WORD;
handle_GPDMA1_Channel12.Init.Priority = DMA_LOW_PRIORITY_LOW_WEIGHT;
handle_GPDMA1_Channel12.Init.SrcBurstLength = 1;
handle_GPDMA1_Channel12.Init.DestBurstLength = 1;
handle_GPDMA1_Channel12.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT1|DMA_DEST_ALLOCATED_PORT0;
handle_GPDMA1_Channel12.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
handle_GPDMA1_Channel12.Init.Mode = DMA_NORMAL;
if (HAL_DMA_Init(&handle_GPDMA1_Channel12) != HAL_OK)
{
Error_Handler();
}
if (HAL_DMA_ConfigChannelAttributes(&handle_GPDMA1_Channel12, DMA_CHANNEL_NPRIV) != HAL_OK)
{
Error_Handler();
}
handle_GPDMA1_Channel7.Instance = GPDMA1_Channel7;
handle_GPDMA1_Channel7.Init.Request = DMA_REQUEST_SW;
handle_GPDMA1_Channel7.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;
handle_GPDMA1_Channel7.Init.Direction = DMA_MEMORY_TO_MEMORY;
handle_GPDMA1_Channel7.Init.SrcInc = DMA_SINC_INCREMENTED;
handle_GPDMA1_Channel7.Init.DestInc = DMA_DINC_FIXED;
handle_GPDMA1_Channel7.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_WORD;
handle_GPDMA1_Channel7.Init.DestDataWidth = DMA_DEST_DATAWIDTH_WORD;
handle_GPDMA1_Channel7.Init.Priority = DMA_LOW_PRIORITY_LOW_WEIGHT;
handle_GPDMA1_Channel7.Init.SrcBurstLength = 1;
handle_GPDMA1_Channel7.Init.DestBurstLength = 1;
handle_GPDMA1_Channel7.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT1|DMA_DEST_ALLOCATED_PORT0;
handle_GPDMA1_Channel7.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
handle_GPDMA1_Channel7.Init.Mode = DMA_NORMAL;
if (HAL_DMA_Init(&handle_GPDMA1_Channel7) != HAL_OK)
{
Error_Handler();
}
if (HAL_DMA_ConfigChannelAttributes(&handle_GPDMA1_Channel7, DMA_CHANNEL_NPRIV) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN GPDMA1_Init 2 */
/* USER CODE END GPDMA1_Init 2 */
}I have tried both Channel 7 and 12 to see if there was a difference with a larger FIFO. I have changed the ports around based on my understand of Figure 2 in AN5593. Circular mode for the source did not seem to lead to good results.
2026-05-12 6:42 AM
Hello @Roth.Ian
Are the DMA HTC and TC interrupt flags triggered correctly?
2026-05-12 7:03 AM
Also, what happens if you define an array in memory and in the DMA command change the destination address to that array? Is the first word from FLASH stored there?
JW
2026-05-14 8:27 AM
Hello @Saket_Om ,
They are triggered correctly.