0
\$\begingroup\$

I'm reading samples at a fairly high bitrate (820kbps) from an external ADC over SPI. I need to add a CRC byte and then forward each sample to USART.

As a consequence of my inexperience, within the DMA (SPI) transfer complete ISR where I have a frame of received samples in a memory buffer I attempted to (in a loop over each sample) add CRC and send each byte to USART. This was too slow and delayed setting up the next SPI transfer such that samples were getting dropped.

I believe I need to move the CRC and USART transfer code out of the ISR and into the main loop however I don't think then I can then read from the same memory buffer that SPI is writing to since I can't control when it might change (due to SPI DMA being autonomous and continuous).

One solution I imagined is to have the DMA (SPI) target alternating memory buffers (A and B). SPI would write to buffer A while USART reads from B, then swap. I'd need to ensure

  1. the main loop only reads from the buffer that's currently not targeted.
  2. The main loop sets a lock flag on the buffer it's reading from and the DMA ISR is prevented from setting up a new transfer to that buffer while the lock is set

What is common practice for this type of situation?

Latency isn't a concern.

Extra Background:

The ADC is 24bit but an extra 8 bits is appended (for a total of 32bit) which is static and represents the configured downsampling factor. I am overwriting the final 8 bits received in each sample with an 8bit CRC of the 24bits representing the sample.

The USART is set to a baud of 1.7Mbps. I've done an echo test and confirmed no data corruption is happening.

The STM32 model is STM32U5.

The USART output is purely for diagnostics during development. It will be disabled under normal operation.

\$\endgroup\$
3
  • 1
    \$\begingroup\$ Yes, you should not be doing CRC in the ISR. You can use read and write indexes for keeping track of the buffer which are updated by DMA start/stop interrupts. I think the DMA also has a register to keep track of how many transfers left which you can combine with indexes to know where it is in real time. You can ping pong buffers though. Safer and easier but doesn't use memory as efficiently but has less overhead. It's what I did first before a circular buffer with R/W indexes. Takes a lot less work and can be built up into a circular buffer. \$\endgroup\$
    – DKNguyen
    Commented Feb 11, 2022 at 15:30
  • 1
    \$\begingroup\$ Can you satisfy my curiosity about your USART baud rate? Seems like adding CRC to each sample will stretch its capabilities to its limits. Can you checksum blocks of samples, instead? \$\endgroup\$
    – akwky
    Commented Feb 11, 2022 at 15:36
  • 1
    \$\begingroup\$ @akwky added baud info. CRC on sample blocks is a good option thanks. \$\endgroup\$
    – davegravy
    Commented Feb 11, 2022 at 21:21

2 Answers 2

2
\$\begingroup\$

Depends on your exact STM32 model but usually you would use two buffers, which can be one buffer used as two halves of a larger buffer or two separate buffers, exact implementation does not matter. DMA can automatically support two buffers or two half-buffers.

\$\endgroup\$
2
  • \$\begingroup\$ The more advanced STMs can, anyways. But it's still simple to do it with DMA interrupts. Just gotta be careful you don't jump buffers at the wrong time due to reading flags in between when an interrupt updates the flag and the action the flag represents starts or stops. \$\endgroup\$
    – DKNguyen
    Commented Feb 11, 2022 at 15:27
  • \$\begingroup\$ Added model info to question. \$\endgroup\$
    – davegravy
    Commented Feb 11, 2022 at 21:22
0
\$\begingroup\$

If DMA is flow controller of the SPI-DMA transfer, then you could use use either two buffers or Half-Transfer interrupt and Transfer Complete interrupt.

What's the size of SPI data? 8-bit? 16-bit? What's the size of CRC?
I just thought, what if you do SPI receive with memory increment of 32 bits (fixed memory increment), then you will be able to have free space in 32-bit word for CRC bits. You won't have to shuffle around the data. Literally out of every 32 bits of buffer there will be 16 bits empty (for CRC to be written later) and 16 bits of data (for example).

So you can DMA data from SPI into buffer and CRC it, then DMA the entire thing out of USART without much data manipulation. You can CRC on SPI-DMA half-transfer interrupt until the middle, and the second half on Transfer Complete interrupt. Also, you can probably DMA them out to USART meanwhile.

Maaybe you could consider using FIFO for transfers. Or even two DMAs (for SPI and for USART, alternating buffers, with CRC operation squeezed in between). The question is, how much speed do you want to squeeze from it. Remember, that the goal is not "the best possible". The goal is "good enough for my application".

\$\endgroup\$
1
  • \$\begingroup\$ Added background on SPI data to the question. \$\endgroup\$
    – davegravy
    Commented Feb 11, 2022 at 21:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.