cancel
Showing results for 
Search instead for 
Did you mean: 

SPI with circular DMA and CRC not possible?

caco3
Associate II
Posted on October 05, 2015 at 09:46

I need to receive a lot of SPI data on a STM32F4. To handle this, I use a DMA buffer in circular mode. Also, I need to use the CRC feature.

How ever this seems not to be possible with the HAL according to this note in stm32f4xx_hal_spi.c:

The CRC feature is not managed when the DMA circular mode is enabled

Is this only a restriction of the HAL?

Can I use the CRC feature with circular DMA if I implement the receiver myself?

How would I do this?
4 REPLIES 4
Posted on October 05, 2015 at 15:16

Isn't the problem that you provide no termination indication?

You've got to restart the CRC generator, and you've got to check the CRC residual. Figure out how you're going to do that. The DMA is just going to copy the CRC byte into the data stream at the moment, right?

The normal mechanism would be that you get to check the CRC residual is zero after the CRC byte is received.

If the HW doesn't do what you want easily, you can presumably run the data through a table to compute the CRC on the fly quite rapidly.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
caco3
Associate II
Posted on October 05, 2015 at 17:01

The data frames I have to receive are getting transmitted at a high frequency one after the other, without a gap.

I successed now to implement the DMA transfer in manual mode. Do do so, I seem to have to do the following calls in HAL_SPI_RxCpltCallback():

hspi->RxXferCount = frame_length;
/* Reset CRC Calculation */
if
(hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) {
SPI_RESET_CRC(hspi);
}
/* Enable the Rx DMA Stream */
HAL_DMA_Start_IT(hspi->hdmarx, (uint32_t)&hspi->Instance->DR, (uint32_t)hspi->pRxBuffPtr, hspi->RxXferCount);
/* Enable Rx DMA Request */
hspi->Instance->CR2 |= SPI_CR2_RXDMAEN;

Even without the restart of the CRC engine, this takes > 600 ns (>100 cycles on the 196 MHz system clock), which is more than a SPI clock periode. When receiving it in circulare DMA mode, this time would not be required... Note: Since I am using an STM32F4 and CRC8, I can't use the HW CRC Unit afterwards, since it supports only 32 bit and has a hard coded polynomial. I implemented a working CRC generator with a lookup table, but obviously it is too slow. As stated in the first post, the restriction looks like to be in the HAL. At least I can't find anything about such restriction in the STM32F407xx Refenence Manual (RM0090)! I wasn't able to find an example how to use the SPI RX DMA + CRC without the HAL...
Posted on October 05, 2015 at 20:42

Can't really comment on the HAL stuff, but it strikes me as rather improbable that this can be pulled off any more successfully at the SPL or register level. Circular infers continuous, CRC infers discrete, and all of the race/sync issues that come with that.

There often aren't examples for everyone's corner conditions, sometimes you just have to read the manuals and bang out the code.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
caco3
Associate II
Posted on October 06, 2015 at 15:41

Thank you for your explanations!

I hoped that the CRC generator could be automatically restarted. But I understand that it is independant of the DMA and therefore can not get controlled by the DMA.

I switched now to normal DMA transfers and do the initialisation of the DMA transfer and restarting of the CRC generator in the HAL_SPI_RxCpltCallback().

By optimizing the required calls, I could bring it down to approx. 350 ns.

This hopefully will be fast enough for our application.