cancel
Showing results for 
Search instead for 
Did you mean: 

What is the recommended approach for aborting a SPI transaction via DMA or IT?

MFolk.1
Senior

I have been using HAL_SPI_DMAStop to abort my SPI transactions and usually it works, but every once in a while I notice my SPI bus gets all jammed up or whatever and stops working. I noticed that the HAL_SPI_DMAStop function is not returning HAL_OK.

Should I be using a different approach when using DMA?

Also, How would I do this same thing if using IT (interrupts) instead of DMA? I tried using HAL_SPI_Abort_IT without any luck.

To add a bit more context, I need to be able to use the SPI receive command to always be listening to another device and this device is a slave to it. As data becomes available to transmit back to the master, I need to abort the receive transaction and start a TransmitReceive transaction. Also note that this is being performed within a callback function (ISR) because my timing requirements are extremely tight.

Thanks!

1 ACCEPTED SOLUTION

Accepted Solutions
MFolk.1
Senior

I can't make any modifications to the master due to the fact that I need to maintain backwards compatibility with another slave device that I'm replacing with this MCU. So the master will not allow any dummy bytes. By the time the master comes back to collect rent the money needs to be there without IOUs. So perhaps I could insert the first bytes directly onto the SPI Transmit Data register?

This conversation feels like very bad practice. I was hoping to be able to take advantage of the SPI stop/abort APIs, but since they don't work perhaps I will just rewrite my code so that I don't ever start a transaction unless I know with certainty that that transaction will not need to be aborted.

By the way, to shed more light on the issue I'm seeing on the HAL_SPI_DMAStop error that seems to occasionally break SPI communication. Within this API, the status of both Tx & Rx are checked. What is interesting though is that in my case I am trying to abort an Rx only transaction, but it is the Tx check that is flagging the HAL error. Perhaps the API could be updated to only check the streams that are active or separate APIs could be created to deal with all three Rx, Tx, and Rx & Tx possible situations. I'm not sure why the HAL_SPI_Abort_IT call wasn't working, but I don't think I'm going to debug that one at this time.

View solution in original post

6 REPLIES 6

Perhaps the solution is to splice into the feed, ie rather than hard starting everything, you determine where in the circular buffer to start inserting the data you want to leave next. Although there is still possibly a race condition if you try to determine the where in the bit cycle you are, as that's not exposed.

Most I think would use the TransmitReceive, and just stuff the channel with slack/dummy data.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

"Most I think would use the TransmitReceive, and just stuff the channel with slack/dummy data."

I had that idea as well, but for me its not that simple because what is driving this is that when the master requests data from the slave (this MCU) It expects that data to be ready by the time the next SPI command gets there because the next SPI command from master is always just a dummy command in order to grab the data.

Because of this, I like your first idea. How would you do that without having a race condition?

Count clock cycles?

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

To expand perhaps on that thought, you could monitor the master clock, perhaps frequency, phase, duty, with respect to the slave. Shift count on the SPI side, relate those to RXNE, and TXE. Perhaps also related to the edge of the -CS, and in the time line of the MCU, so you've got some time to prepare to have a response.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
TDK
Guru

Set up a circular DMA TransmitReceive call with dummy outgoing data that is never interrupted. When you need to transmit, look at where the DMA pointer is (by reading the NDTR register), and update the data at that location. If you can ensure the master either waits to clock, or if you can ensure your code is fast enough to always populate the first byte of this data within a byte of data being clocked out, this will work. The amount of dummy bytes will depend on the pipeline/chip you're using. For the STM32F4, I use 2 dummy bytes in this scheme and it is bulletproof. The master needs to read the dummy bytes before it can read the real response.

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

I can't make any modifications to the master due to the fact that I need to maintain backwards compatibility with another slave device that I'm replacing with this MCU. So the master will not allow any dummy bytes. By the time the master comes back to collect rent the money needs to be there without IOUs. So perhaps I could insert the first bytes directly onto the SPI Transmit Data register?

This conversation feels like very bad practice. I was hoping to be able to take advantage of the SPI stop/abort APIs, but since they don't work perhaps I will just rewrite my code so that I don't ever start a transaction unless I know with certainty that that transaction will not need to be aborted.

By the way, to shed more light on the issue I'm seeing on the HAL_SPI_DMAStop error that seems to occasionally break SPI communication. Within this API, the status of both Tx & Rx are checked. What is interesting though is that in my case I am trying to abort an Rx only transaction, but it is the Tx check that is flagging the HAL error. Perhaps the API could be updated to only check the streams that are active or separate APIs could be created to deal with all three Rx, Tx, and Rx & Tx possible situations. I'm not sure why the HAL_SPI_Abort_IT call wasn't working, but I don't think I'm going to debug that one at this time.