cancel
Showing results for 
Search instead for 
Did you mean: 

SPI MISO shifted

Nikolaj_TL
Associate III

Hello ST Community, 

I have setup a SPI master and a SPI slave, both use DMA in Normal mode. The word size is 8-bits and the data size is 8-bytes. The problem is that the slave transmits messages which contains old data. 

When it should send:
MISO: { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }
it sends:
MISO: { 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01 }

When it should send:
MISO: { 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 }
it sends:
MISO: { 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02 }

Nikolaj_TL_0-1718698066796.png

OBS: The debug gpio is toggled when the ISR finishes and when theTxBuffer is edited in main.



This pattern continues for every transfer it contains 3 old bytes.

Implementation (slave):
The slave updates the response in the main function.

 

int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_SPI1_Init();

  HAL_SPI_TransmitReceive_DMA(&hspi1, TxBuffer, RxBuffer, 8);

  while (1)
  {
	if(msgReceived == 1) {
		memset(TxBuffer, SPI_Counter, BUFFERSIZE);
		HAL_SPI_TransmitReceive_DMA(&hspi1, TxBuffer, RxBuffer, BUFFERSIZE); // update SPI transfer
		
		msgReceived = 0;
		HAL_GPIO_TogglePin(GPIOF, GPIO_PIN_1);		// DEBUG
	}
  }
}

 

 

void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
{
	msgReceived = 1;
	SPI_Counter++;
	HAL_SPI_TransmitReceive_DMA(&hspi1, TxBuffer, RxBuffer, 8); // setup a new transfer
	HAL_GPIO_TogglePin(GPIOF, GPIO_PIN_1);		// DEBUG
}

 


Setup:
SetupSetup

How can it be that the MISO transfer contains old data?
 

24 REPLIES 24
Nikolaj_TL
Associate III

Thank you for your replies. 

@BarryWhit I do want to understand why the current setup isn't working. I am well aware that if I only call the HAL_SPI_TransmitReceive_DMA in the main loop (or in the ISR) it would work as expected.
I have setup this code example to simplify my problem as much as possible. Really I am working on a motor control project with two chips a dedicated motor controller and a main chip that handles bluetooth and so on. The main chip should always be able to ping the motor controller, even if it has requested it to carry out a command. Secondly the motor controller should respons the main controller when it has executed a command and is ready for a new. If the main chip cannot ping the motor controller it should kill the motor controller (turn off the power).

The diagram depicts the current functionality and the desired functionality. 

Nikolaj_TL_5-1718865825829.png


Currently the transfer is handled using synchronization flags, this introduces a delay. Although the slave has finished its task and has a result ready it transfers 'Busy_State', because a transfer only can be setup in the ISR. 
Double Buffering has the same problem it still has a response delay. 

Nikolaj_TL
Associate III

The only purpose of the DEBUG pin is to show that there is plenty of time between the TxBuffer is updated in main until a new transfer starts. 

Nikolaj_TL_1-1718864795497.png


I know that I should monitor whether a SPI transfer is ongoing before I update the TxBuffer. I will handle this after I have resolved my main problem, which is that I cannot update the TxBuffer after I have initiated a SPI transfer. 

I see the same behaviour as in the Screenshot if I only update the TxBuffer in the main loop and omits calling HAL_SPI_TransmitReceive_DMA

int main() {
    ...

    if (HAL_SPI_TransmitReceive_DMA(&hspi1, currentTxBuffer, RxBuffer, BUFFERSIZE) != HAL_OK) {
        Error_Handler(); // Handle error
    }

  while (1)
  {
	if(msgReceived == 1) {
		memset(TxBuffer, SPI_Counter, BUFFERSIZE);
		msgReceived = 0;
		HAL_GPIO_TogglePin(GPIOF, GPIO_PIN_1);		// DEBUG
	}
}

void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
{
	msgReceived = 1;
	SPI_Counter++;
	HAL_SPI_TransmitReceive_DMA(&hspi1, TxBuffer, RxBuffer, BUFFERSIZE); // setup a new transfer
	HAL_GPIO_TogglePin(GPIOF, GPIO_PIN_1);		// DEBUG
}
BarryWhit
Lead II

> @BarryWhit I do want to understand why the current setup isn't working. I am well aware that if I only call

> the HAL_SPI_TransmitReceive_DMA in the main loop (or in the ISR) it would work as expected.

 

So, you do understand you can't start a DMA while one is ongoing, but you don't understand why your code, which does just that, is corrupting data? I don't follow.

 

>> I know that I should monitor whether a SPI transfer is ongoing before I update the TxBuffer. I will

>> handle this after I have resolved my main problem, which is that I cannot update the TxBuffer

>> after I have initiated a SPI transfer. 

 

Your original post asked why you're seeing data corruption, and you got an answer.

You also cannot touch the buffer while a transfer is ongoing (not in code, not by restarting DMA). You're not going to "resolve" that.

 

> Currently the transfer is handled using synchronization flags, this introduces a delay.

 

are you trying to say that you need a way to interrupt an ongoing transfer? because that's completely unrelated to the issue we've been trying to help you with. If you've resolved the data corruption issue, I suggest you accept the solution  @PPopo.1 provided and start a new thread.

 

- If someone's post helped resolve your issue, please thank them by clicking "Accept as Solution".
- Please post an update with details once you've solved your issue. Your experience may help others.
Nikolaj_TL
Associate III

Sorry for the unclear communication and the inconvenience it has caused. I tried communicated the desired functionality through the sequence diagrams. 
I will accept @PPopo.1 s soultion and start a new thread. 

BarryWhit
Lead II

So the data corruption issue has been resolved. That's progress!

- If someone's post helped resolve your issue, please thank them by clicking "Accept as Solution".
- Please post an update with details once you've solved your issue. Your experience may help others.