cancel
Showing results for 
Search instead for 
Did you mean: 

Advice on SPI and DMA for 24bit data on STM32H723

tec683
Associate III

I want to solicit the advice of those more experienced with the STM32 processors. I'm experienced in general with embedded software and peripherals such as SPI but only about 6 months in on the STM32 processors and only in the last few weeks have I been delving into the SPI and DMA. My first dives were into timers and USB.  In specific, I'm using a STM32H723.

I'm using a 4 channel SPI based ADC.  The TI ADS131M04 in specific.  SPI communication is 6 words with a default word size of 24 bits.  The word size can be changed to 16 or 32 bits but initial size after reset is 24 bits.  It has a data ready line to indicate samples are available.

I realize 24 bits is an awkward size but so many ADC's support it.  I would assume there are efficient ways for the STM32 to handle this size of SPI data.  While it isn't absolutely mandatory in this application for data to be handled the most efficient way, I have future projects that will need the efficiency.  So this is a good time to learn.

What I would like to implement is a totally DMA based data transfer. The DRDY signal would initiate the transfer of the 6 word frame.  In that frame are the 4 samples of the specified word size plus 2 words of overhead information.  The RX DMA would go into a double buffer with multiple frames per buffer to reduce interrupt frequency.  The TX DMA just needs to output 6 words of 0's to create the SPI clocking. I've seen references to a timer capture input being used to trigger a DMA.  So I currently have DRDY going into a timer capture input. I haven't figured out the details of this yet. Is this a workable direction? I'm ok with an interrupt to deinterleave the data periodically probably scaling it in the process. I'm using a GPIO for the chip select.

I have basic SPI with DMA working (that was a learning experience). What I ran into the ADC expects the SPI data most significant byte first while the STM32 appears to be little endian.  With 24 bit data, I am manually ordering the bytes I put into the transmit buffer so the order is correct.  When I tried 32 bit data directly from an int, I realized the byte order was wrong. I know I can manually order the bytes but that seems very inefficient.  I made a brief attempt to define a 24bit SPI word size but that messed with the DMA so I had to turn off the FIFO.  I got to where 6 words of 24 bits shifted out correctly but the completion interrupt didn't happen and no change to the byte order.  I gave up and went back to what works and wrote this message.  Since the byte order didn't change, this direction didn't seem useful.

So far I'm using the HAL interface. I expect I will have to get to the register level to realize some of these ambitions but I'm trying to walk before I run.

After setting the context, here are some specific questions.

1) Are their any optimizations for handling 24 bit data words in the SPI and/or DMA controller setup?

2) Any examples of using a timer input to trigger an DMA SPI transfers?

3) Any way other than coding to deal with the byte ordering of SPI data?

4) Would the serial audio interface be better than the SPI for this? This is an SPI based ADC.

I am using a Nucleo board with a prototype IO board I've developed.  I can modify this board or do something different for the production board if needed.

Any suggestions and advice will be appreciated.

1 ACCEPTED SOLUTION

Accepted Solutions

>I'm not sure the DMA understand 24 bit word lengths.

No. Only 32b are transferred. (24b in a 32b frame )

Did you set the dma to word (=32b) ? Do it.

And have your 24b data in an int32 array , it makes everything more clear and easy.

btw

I have (for audio) to deal with 16, 24 or 32 bit data ; first : i convert all to 32b , then only 32b is to handle.

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

View solution in original post

7 REPLIES 7
AScha.3
Chief II

1) Are their any optimizations for handling 24 bit data

Just set the SPI to 24 bit data , the DMA anyway transfers it as word 32b .

2) Any examples of using a timer input to trigger an DMA SPI ...

many. But should be no problem to set it in Cube.

3) Any way other than coding to deal with the byte ordering of SPI data?

Try it - with correct setting data should be ok without gambling.

4) Would the serial audio interface be better than the SPI for this? This is an SPI based ADC.

Is about same - but SPI is more flexible, in I2S you have to keep to standard.

 

>but I'm trying to walk before I run.

Good idea - i do same.

>I realized the byte order was wrong

Pffft - the "endianess problem" - maybe. Let me look at the ds first.

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

Ok, ADC msb first - you can set this in SPI parameters , like this:

AScha3_0-1706041581646.png

ADC:

AScha3_1-1706041753804.png

Should work.

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

I do have MSB set in the SPI but that is the bit order.  When I tried setting the SPI word length to 24, I got an error with the DMA using the FIFO.  I disabled the FIFO and got the configuration errors to go away.  Data was shifted out on the SPI but no change to the byte order.  Something to be aware of, I'm using a byte array and manually packing the 24 bit values into ie 3 bytes into the array.  I'm using HAL_SPI_TransmitReceive_DMA to transmit and receive the response. I'm not sure the DMA understand 24 bit word lengths. 

I tried the CPU based blocking HAL SPI call to see if acts differently with 24 bits SPI length set.  Using a logic analyzer and looping the transmit into the receive, the bytes receives seem to be trying to be written as 4 byte integers (I speculate).  I'm sending out 0, 1, 2, 3, 4, 5, and so on. I see that as expected. I'm getting back 0, 0, 1, 2, 0, 4, 5, 6 and so on. With DMA, I'm seeing the output echoed back exactly.

>I'm not sure the DMA understand 24 bit word lengths.

No. Only 32b are transferred. (24b in a 32b frame )

Did you set the dma to word (=32b) ? Do it.

And have your 24b data in an int32 array , it makes everything more clear and easy.

btw

I have (for audio) to deal with 16, 24 or 32 bit data ; first : i convert all to 32b , then only 32b is to handle.

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

Thanks. I think I see the direction to head. Looking at HAL_SPI_TransmitReceive, SPI word sizes >16 are expected to be in be uint32_t. Lengths 9 through 16 through in uint16_t and 8 bits or lower are uint8_t. This makes sense. I expect DMA will need similar size configuration.

I was planning on doing any processing with 32 bit integers as well. It looks like 24bit SPI words will be handled as 32 bit integers which is what I want.

tec683
Associate III

To summarize, the variable size depends on the SPI word length.  For 4 thru 8, a byte is expected.  For 9 thru 16, a short (16b int) is expected, and for 17 thru 32, a 32b integer is expected.  The SPI peripheral will use the defined number of bits when transmitting.  The receive will accept the defined number of serial bits and present them as a byte, short, or integer as appropriate.  The DMA data alignment should be configured as the previous sizes. 

This also handles the bit and byte ordering.

Another thing of note, the HAL_SPI transfer functions size argument really seems more appropriate to be count. It defines the number of SPI data length transactions to transfer from the buffer. For example, if you are transferring 6 SPI words of 24 bits each, the buffer is 6 integers while the size would seem to be 24 bytes.  These routines expect 6 in this case.

There does not seem to be the option to sign extend the 24 bit SPI word that is written to the 32 bit integer. I could not find anything in the reference manual. So it seems signed values would require some additional processing.

Now you understand the SPI , at least partly . 🙂

About sign extend the 24 bit SPI word that is written to the 32 bit integer : you dont need this, if (what you can choose) it is msb /left in the 32bits, the msb is the sign then; the rightmost 8 bits are filled with zero.

If you use it in audio mode, the I2S mode, even more is possible (depends on cpu series and the more or less complex "spi-thing" , thats implemented), it can 16bits extend or have msb first, but right aligned and then also msb sign extended. This was the (now old) PCM Sony-mode, used in their CD players etc.

You just can try the SAI module (no problem in Cube, just try different settings and see, what Cube shows as options to set), this is the most flexible thing , can even multi-channel protocols (2 "slots" = stereo, 6 -> 6 channels ...) and frames up to 256 bit length ( if you de-select I2S/PCM standard mode).

On top : the DMA (if fifo is enabled) can put together 8 or 16 bit to 32 bit words and on some (the new H563 or similar) can ever reorder 8 or 16bit wise. But the downside is : the more complex , the more you have to read and do the try and error game - no free lunch here. So the DMA in H563 manual (called GPDMA) has 80 pages to read .... 😳

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