cancel
Showing results for 
Search instead for 
Did you mean: 

HAL_SPI_TransmitReceive_DMA() transmit interrupt always triggered after receive interrupt

Ross Yeager
Associate III

I have a HAL_SPI_TransmitReceive_DMA() transaction that I am performing. The data can be seen on the line to properly get clocked out over SPI.

The problem is that in the receive interrupt, we kick off the next transaction (a DMA SPI write). This write fails because the HAL erroneously still has a lock on the DMA tx handler. The transmit eventually comes through, but we fail to write a transaction due to the lock.

I cannot figure out why the transmit interrupt does not fire before the rx interrupt. I did see that the SW priority of the DMA streams was the same, and the natural priority in that case is to prefer the lower stream number (which in my case was the rx stream); however, when I bumped up the priority of the sw dma stream priority to be higher than the rx stream, that did nothing to change the outcome.

14 REPLIES 14

HAL 1.9, Cube 4.27.0

The HAL in today's implementation will enable all interrupts in case user overrides any of the weak declared callbacks. So to get the peripheral state machine not lock up, just let it handle. When optimisation is required, LL or direct register manipulation maybe necessary. Since I transfer kbytes, the loss of performance is minor.

correct, but if triggering another transfer from the receive handler, if the transmit isr isn’t run then the HAL lock will prevent the next transaction from going through... we use the HAL for portability reasons across many mcus so just directly accessing the registers is not a preferred way. It seems that the HAL doesn’t offer much else in terms of this solution.

@Ross Yeager​  How Please, i found dma locked and return hal_busy when i increase the spi master frequency ?

LVan .31
Associate III

I see the same problem, only not when using HAL_SPI_TransmitReceive_DMA. Using this function, the callback that is executed is HAL_SPI_TX_RX_COMPLETE_CB_ID and not HAL_SPI_RX_COMPLETE_CB_ID. Using this callback I am able to restart the next SPI transfer from the callback without any issues. Where I do see the problem is when using HAL_SPI_Transmit_DMA. Then, when restarting the next transfer from the HAL_SPI_TX_COMPLETE_CB_ID the lockup described in this thread occurs for me too. 

Based on the info in this thread I understand now where the problem comes from. Actually I would expect that starting a new transfer from any SPI callback would be possible but unfortunatelly it is not. I consider this an error in the HAL layer which should be fixed by ST.

I see three possible solutions:

1: Only use HAL_SPI_TransmitReceive_DMA. When sending data, the DMA receive stream can be changed from the memory pointer being incremented on each byte transfer to no-increment. The DMA receive stream can then be set to a single byte (dummy) buffer. Likewise when receiving data do the same for the transmit DMA channel. The downside is that this breaks compatibility over different STM32 types since they have different DMA architectures. The proposed change would have to be made for different DMA architectures.

2: Like solution 1 but use a dummy array instead of a single byte. Again when sending, set the DMA receive stream to this dummy buffer and vice versa for receiving. The downside of this is that the data length would be limited to the size of this dummy buffer. Of course this can be fixed by splitting a transfer in multiple transfers when the size of the dummy buffer is exceeded.

3: Use the suggestion proposed in this thread to schedule the restart to a deferred interrupt based on using PendSV. The downside of this is that such a mechanism (Deferred Interrupt Handling) would always have to run at the lowest interrupt priority, being the priority of PendSV. I have some situations where SPI is running at the highest priority for performance reasons and when using a Deferred Interrupt Handler, the SPI priority would no longer be leading and hurt performance.

In the end I chose for solution 2 with a buffer of a few hundred bytes. But again, I consider this a bug in the HAL layer which should be fixed by ST.