cancel
Showing results for 
Search instead for 
Did you mean: 

SPI with DMA incorrect NSS behavior

Leon1
Associate II

HI.

My MCU is STM32L071CZ, CubeMX latest version on this period of time.

I try to communicate with an external SPI-Flash IC. The SPI uses software NSS. The communication is good but only if I'm not using DMA. 

When I try to communicate with flash using HAL_SPI_TransmitReceive_DMA() function and try to transmit or receive more than 2 bytes, the communication fails. Because of on second transmitted byte NSS goes into High (unactive) mode.

I also try to use TxRx transmit complete callback, but the behavior is the same.

What I do wrong? How to force NSS pin rise up when the transaction is complete?0690X00000AAOHyQAP.png

6 REPLIES 6

I read in a book that NSS is an open collector output so that you can connect multiple CPUs together in a multi-master configuration, and to get NSS to work as you'd expect you need a pull-up resistor.

Hi Andrei.

Yes, but in my case I use a software NSS. It's a simple configured GPIO in to out. It initialized with high level and when I need to start SPI transaction I put it manualy into low stater, which indicate for external flash that transaction is started, prepare to listen a comands...

On the same spi bus I plan to use one more SPI device, thets whay I'm not use hardware NSS

The DMA system doesn't know anything about your software control of NSS. It will not call your code.

If you were to assert NSS, then start the DMA, then deassert NSS, assume that the DMA start takes no time. At that point it is all in the hands of the hardware.

You can see in your plot that SCK starts before NSS gets deasserted. This is the start of the DMA hardware doing the transfers, but control is given back to your code and you deassert NSS.

Assume that HAL_SPI_TransmitReceive_DMA is asynchronous. You shouldn't deassert until you get the DMA complete interrupt.

"Assume that HAL_SPI_TransmitReceive_DMA is asynchronous. You shouldn't deassert until you get the DMA complete interrupt."

Yes, I try to do that with registered "HAL_SPI_TxRxCpltCallback" callback, but it fires before the transaction was compleat.

I register it by using this function "HAL_SPI_RegisterCallback(&hspi1, HAL_SPI_TX_RX_COMPLETE_CB_ID, HAL_SPI_TxRxCpltCallback);"

Also I found two another callbacks

" HAL_SPI_RegisterCallback(&hspi1, HAL_SPI_TX_COMPLETE_CB_ID, HAL_SPIDMA_TxCpltCallback);

 HAL_SPI_RegisterCallback(&hspi1, HAL_SPI_RX_COMPLETE_CB_ID, HAL_SPIDMA_RxCpltCallback);"

But thous two dosn't work at all.

In this callback, I check the Transmit Compleat flag for each channel and that behaves as I describe above

void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
{  
    if (SPI1 == hspi->Instance)
    {
			if (__HAL_DMA_GET_FLAG(&hdma_spi1_tx, DMA_FLAG_TC3))
			{
				__HAL_DMA_ENABLE_IT(&hdma_spi1_tx, DMA_IT_TC);
				  flashspi1.isSpiTransmite = false;
			}
			
			if (__HAL_DMA_GET_FLAG(&hdma_spi1_rx, DMA_FLAG_TC2))
			{
				__HAL_DMA_ENABLE_IT(&hdma_spi1_rx, DMA_IT_TC);
				  flashspi1.isSpiReceive = false;
			}
    }
}

Wouldn't those give you a callback when a SPI transaction (1 byte or so) go out? I think you need the DMA complete interrupt.

It seems that I use the wrong register callback function. I found this "HAL_DMA_RegisterCallback()" I will try it tomorrow. Thanks!