cancel
Showing results for 
Search instead for 
Did you mean: 

Re-enabling TX DMA of SPI cause wrong transmit unit (STM32F407ZET6)

thisdp
Associate II

I am working on STM32F407ZET6 with DMA+SPI in slave mode. Trying to reset DMA Counter when NSS is high to avoid shifted data transmit.

TX and RX DMA are working on Circular mode.

This is my tx data

 

typedef struct {
  uint8_t InputState[4];
  uint8_t reserved1[4];
  uint8_t reserved2[4];
  uint8_t reserved3[4];
} SyncDataTX;

 

 Inside init function, i did

 

*((uint32_t*)(txData.InputState)) = 0x11121314;
*((uint32_t*)(txData.reserved1)) = 0x15161718;
*((uint32_t*)(txData.reserved2)) = 0x19202122;
*((uint32_t*)(txData.reserved3)) = 0x23242526;
HAL_SPI_TransmitReceive_DMA(&hspi1, (uint8_t *)&txData, (uint8_t *)&rxData, sizeof(txData));

 

Inside interrupt function, i did

 

__HAL_DMA_DISABLE(&hdma_spi1_rx);
__HAL_DMA_DISABLE(&hdma_spi1_tx);
__HAL_DMA_SET_COUNTER(&hdma_spi1_rx,sizeof(SyncDataTX));
__HAL_DMA_SET_COUNTER(&hdma_spi1_tx,sizeof(SyncDataTX));
__HAL_DMA_ENABLE(&hdma_spi1_rx);
__HAL_DMA_ENABLE(&hdma_spi1_tx);

 

In the first transaction, I get this, which is correct data:

 

11121314
15161718
19202122
23242526

 

In the second transaction, I get this:

 

12131414
16171811
20212215
24252619

 

From the third transaction, I start to getting this:

 

12131423
16171811
20212215
24252619

 

 

This happens even only:

__HAL_DMA_DISABLE(&hdma_spi1_tx);
__HAL_DMA_ENABLE(&hdma_spi1_tx);

 

:thinking_face:I didn't encounter such problem in STM32H750

1 ACCEPTED SOLUTION

Accepted Solutions
TDK
Guru

> Trying to reset DMA Counter when NSS is high to avoid shifted data transmit.

This is flawed. Data is already in the shift register. Changing NDTR register in DMA will affect bytes 1-2+ in the future, but not the next byte that is sent out.

You can re-sync by disabling SPI entirely and restarting with HAL_SPI_TransmitReceive_DMA from the beginning.

 

Or, better, look into why it's getting de-synced in the first place and address that.

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

View solution in original post

11 REPLIES 11
AScha.3
Chief III

Hi,

To understand, what you do - or try to do - some questions :

- who (this F407 ? ) is sender and who is slave receiver ?

- i see only ...  send + receive as master ?

HAL_SPI_TransmitReceive_DMA

 - on circular setup -- why this dis-/enable dma ? (should be never needed)

- why double same commands ?

__HAL_DMA_DISABLE(&hdma_spi1_rx);
__HAL_DMA_DISABLE(&hdma_spi1_tx);
If you feel a post has answered your question, please click "Accept as Solution".

1.  F407 as SPI Slave.

2.  disable/enable dma is used to clear dma counter :

In order to make sure the last SPI communication failure won't affect the next SPI communication.

For example, I have a 2 bytes data that need to be transfer, but the last SPI communication just send 1 byte clock and then stopped. And at this time, if i starts the next SPI communication, the whole data will be 1 byte shifted.

3.  These are not the same commands, one is rx, and another one is tx

__HAL_DMA_DISABLE(&hdma_spi1_rx);
__HAL_DMA_DISABLE(&hdma_spi1_tx);

>3.  These are not the same commands, one is rx, and another one is tx

OK, my bad eyes ... :)

But - ( i use some 3 circular dma rx +tx same time ) you control, whats tx + rx doing ? 

So keeping to the way of circular dma is working, wouldnt it be much easier and save to send constant block/packet size (and just fill unused bytes with 00 or AA ) and never need some dis- /enable ?

I have it this way, the cpu has nothing to do with it anyway, even when its running "idle" , with zero data.

+

About the SPI lines , data etc. , maybe you should switch on pullups/pulldowns on all lines, to keep the "idle" state between transfers; if you switch it off and on, it might get an extra transition , when line is "open" (tri-state).

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

TX transfers some data to SPI Master

RX receices some data from SPI Master

I tried to reset DMA counter, because the SPI Master is ESP32.

For example, when flashing ESP32, SPI may stopped in the middle of transfer. And cause continuous data byte shifts of STM32 SPI Transfer.

 

Haha - funny : i have an ESP8266 as master on my audio-player-project . :)

+ with circular dma rx at 32Mbit ; 

To keep spi + dma working, if a error occurred , i have added to callbacks for receiving this :

void  HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi4)
{
	fresult = HAL_SPI_Abort(hspi4);
	printf("SPI: restart \n");
	drawText(118, 92, "SPIerror" , RED ,  0, 1);
	fresult = HAL_SPI_Receive_DMA(hspi4, ESPinbuf , (sizeof(ESPinbuf)));	// ESP input-loop start again
}
If you feel a post has answered your question, please click "Accept as Solution".

That's weird. I've tried your solution. Turn on interrupt of SPI and DMA, add 

void  HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi)
{
	HAL_SPI_Abort(hspi);
	HAL_SPI_TransmitReceive_DMA(&hspi1, (uint8_t *)&txData, (uint8_t *)&rxData, sizeof(txData));
	SPITransferErrorTimes++;
}

SPITransferErrorTimes remains 0. And after hit SCK to GND multiple times, the data starts to shifting.:thinking_face:

Still you didnt tell me: 

>I am working on STM32F407ZET6 with DMA+SPI in slave mode.

BUT:

- i see only ...  send + receive as master ?

HAL_SPI_TransmitReceive_DMA

--> so F407 is master , ESP slave ??

I have ESP master , H743 is slave receiver;

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

> Trying to reset DMA Counter when NSS is high to avoid shifted data transmit.

This is flawed. Data is already in the shift register. Changing NDTR register in DMA will affect bytes 1-2+ in the future, but not the next byte that is sent out.

You can re-sync by disabling SPI entirely and restarting with HAL_SPI_TransmitReceive_DMA from the beginning.

 

Or, better, look into why it's getting de-synced in the first place and address that.

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

can be also used in slave mode.

thisdp_0-1705210594272.png