Skip to main content
Explorer
September 26, 2024
Solved

Problem calculating CRC32 with DMA (STM32U585)

  • September 26, 2024
  • 3 replies
  • 1921 views

Hello,

perhaps someone here has an idea what's going wrong:

I wrote a small program with cube ide to calculate a crc32 (standard polynom 0x4c11db7). It took me some time, but now I get the same result when using HAL_CRC_generate and 'manually' feeding the  CRC module.

Then I tried to feed the CRC module via DMA (GPDMA, channel 0), and then it becomes a little bit weird:

if the length of data is 1 to 3 bytes, all three methods calculate the same crc.

But if the length is >= 4, the crc generated via dma differs.

Attached is the main.c, but the interesting code of initializing the crc module and the dma channel is listed below...

Thanks,

Gunter

 

 

 

/*
 * Method 3: CRC module via DMA
 */
 /* init crc module */
 hcrc.Init.DefaultPolynomialUse = DEFAULT_POLYNOMIAL_ENABLE;
 hcrc.Init.DefaultInitValueUse = DEFAULT_INIT_VALUE_ENABLE;
 hcrc.Init.InputDataInversionMode = CRC_INPUTDATA_INVERSION_BYTE;
 hcrc.Init.OutputDataInversionMode = CRC_OUTPUTDATA_INVERSION_ENABLE;
 hcrc.InputDataFormat = CRC_INPUTDATA_FORMAT_BYTES;
 if (HAL_CRC_Init(&hcrc) != HAL_OK)
 {
 Error_Handler();
 }

 /* init gpdma channel 0 */
 __HAL_RCC_GPDMA1_CLK_ENABLE();

 handle_GPDMA1_Channel0.Instance = GPDMA1_Channel0;
 handle_GPDMA1_Channel0.Init.Request = DMA_REQUEST_SW;
 handle_GPDMA1_Channel0.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;
 handle_GPDMA1_Channel0.Init.Direction = DMA_MEMORY_TO_MEMORY;
 handle_GPDMA1_Channel0.Init.SrcInc = DMA_SINC_INCREMENTED;
 handle_GPDMA1_Channel0.Init.DestInc = DMA_DINC_FIXED;
 handle_GPDMA1_Channel0.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_BYTE;
 handle_GPDMA1_Channel0.Init.DestDataWidth = DMA_DEST_DATAWIDTH_BYTE;
 handle_GPDMA1_Channel0.Init.Priority = DMA_LOW_PRIORITY_LOW_WEIGHT;
 handle_GPDMA1_Channel0.Init.SrcBurstLength = 1;
 handle_GPDMA1_Channel0.Init.DestBurstLength = 1;
 handle_GPDMA1_Channel0.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0|DMA_DEST_ALLOCATED_PORT0;
 handle_GPDMA1_Channel0.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
 handle_GPDMA1_Channel0.Init.Mode = DMA_NORMAL;
 if (HAL_DMA_Init(&handle_GPDMA1_Channel0) != HAL_OK)
 {
 Error_Handler();
 }
 if (HAL_DMA_ConfigChannelAttributes(&handle_GPDMA1_Channel0, DMA_CHANNEL_NPRIV) != HAL_OK)
 {
 Error_Handler();
 }

 __HAL_CRC_DR_RESET(&hcrc);

 HAL_DMA_Start(&handle_GPDMA1_Channel0, (uint32_t)&testdata[0], (uint32_t)&CRC->DR, crclen);

 crc_dma = hcrc.Instance->DR ^ 0xFFFFFFFFu;

 if ( (crc_HAL != crc_man) || (crc_HAL != crc_dma) )
 {
	 while (1)

 

 

    This topic has been closed for replies.
    Best answer by GunterH

    Hello TDK,

    that was indeed the problem.

    After introducing a callback for DMA complete

    handle_GPDMA1_Channel0.XferCpltCallback = DmaCompleteCallback;

    where a flag is set

    volatile uint8_t dmaFinished = 0u;
    
    void DmaCompleteCallback(DMA_HandleTypeDef* hdma)
    {
     dmaFinished = 1u;
    }

    and starting the calculation with HAL_DMA_Start_IT(...) (followed by a while loop waiting for flag set...)

     handle_GPDMA1_Channel0.XferCpltCallback = DmaCompleteCallback;
     
     dmaFinished = 0u;
     HAL_DMA_Start_IT(&handle_GPDMA1_Channel0, (uint32_t)&testdata[0], (uint32_t)&CRC->DR, crclen);
    
     while (!dmaFinished)
     {
    	 ;
     }
    
     crc_dma = hcrc.Instance->DR ^ 0xFFFFFFFFu;

     it went smoothly :)

    Thanks,

    Gunter

    (Perhaps this helps others faced the same problem...)

    3 replies

    Super User
    September 26, 2024

    This is probably an endian-ness artifact. If your memory looks like 0x01 0x02 0x03 0x04, and you are treating it as a uint32_t word, then it is read as 0x04030201 and the CRC is calculated with that number.

    If you transfer one byte at a time, it will calculate the crc with 0x01, then 0x02, etc.

    Post exact expected/calculated values you're getting.

    >  hcrc.Init.InputDataInversionMode = CRC_INPUTDATA_INVERSION_BYTE;

    Possibly changing this would fix it.

    ST Employee
    September 26, 2024

    This post has been escalated to the ST Online Support Team for additional assistance. We'll contact you directly.

    GunterHAuthor
    Explorer
    September 26, 2024

    Hello Guru,

    thanks for your answer.

    To be more precise: the test data used is a simple uint8_t array

    static const uint8_t testdata[] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39 };
    
    static uint32_t crclen = 3u;

    When computing the crc32 over the first 3 value, I get

    CubeVar3CubeVar3

    The crc32 over the first 4 values gives the result

    CubeMem4CubeMem4

    The idea with endianness problem...mhh...I doubt.

    All memory access operations are byte wide...

    Thanks,

    Gunter

    Super User
    September 26, 2024

    > HAL_DMA_Start(&handle_GPDMA1_Channel0, (uint32_t)&testdata[0], (uint32_t)&CRC->DR, crclen);

    > crc_dma = hcrc.Instance->DR ^ 0xFFFFFFFFu;

    Are you waiting long enough for the calculation to complete? HAL_DMA_Start only starts the process. Perhaps insert a delay between those statements. Seems unlikely to be it, but it would explain things.

    GunterHAuthorAnswer
    Explorer
    September 27, 2024

    Hello TDK,

    that was indeed the problem.

    After introducing a callback for DMA complete

    handle_GPDMA1_Channel0.XferCpltCallback = DmaCompleteCallback;

    where a flag is set

    volatile uint8_t dmaFinished = 0u;
    
    void DmaCompleteCallback(DMA_HandleTypeDef* hdma)
    {
     dmaFinished = 1u;
    }

    and starting the calculation with HAL_DMA_Start_IT(...) (followed by a while loop waiting for flag set...)

     handle_GPDMA1_Channel0.XferCpltCallback = DmaCompleteCallback;
     
     dmaFinished = 0u;
     HAL_DMA_Start_IT(&handle_GPDMA1_Channel0, (uint32_t)&testdata[0], (uint32_t)&CRC->DR, crclen);
    
     while (!dmaFinished)
     {
    	 ;
     }
    
     crc_dma = hcrc.Instance->DR ^ 0xFFFFFFFFu;

     it went smoothly :)

    Thanks,

    Gunter

    (Perhaps this helps others faced the same problem...)

    Super User
    September 27, 2024

    Thanks for coming back with the solution. Please click on "Accept as solution" in that post so that the thread is marked as solved.

    The interesting thing in this is, that 0x83DCEFB7 is CRC of only 1 byte, 0x31. So how comes that when the same sequence is used on 3 bytes, the result is correct...

    JW