cancel
Showing results for 
Search instead for 
Did you mean: 

Problem calculating CRC32 with DMA (STM32U585)

GunterH
Associate II

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)

 

 

1 ACCEPTED SOLUTION

Accepted Solutions

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...)

View solution in original post

6 REPLIES 6
TDK
Guru

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.

If you feel a post has answered your question, please click "Accept as Solution".
GunterH
Associate II

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

> 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.

If you feel a post has answered your question, please click "Accept as Solution".

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

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...)

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