Skip to main content
Leon1
Associate
August 27, 2019
Question

SPI with DMA incorrect NSS behavior

  • August 27, 2019
  • 6 replies
  • 2237 views

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

This topic has been closed for replies.

6 replies

Andrei Chichak
Lead
August 27, 2019

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.

Leon1
Leon1Author
Associate
August 27, 2019

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

Andrei Chichak
Lead
August 27, 2019

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.

Leon1
Leon1Author
Associate
August 27, 2019

"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;
			}
 }
}

Andrei Chichak
Lead
August 27, 2019

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.

Leon1
Leon1Author
Associate
August 27, 2019

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