cancel
Showing results for 
Search instead for 
Did you mean: 

Full Duplex SPI: Slave does not trigger callback function

Krautermann
Senior II

I have a SPI Master to slave setup and for some reason whenever the slave receive the full buffer from Master, it does not go inside the callback function.
This is my code from Master:

const uint8_t TX_Buffer1[] = "Hi Slave, wake up!";


uint8_t RX_Buffer[50];
uint8_t RX_Buffer_cpy[50];

volatile int counter = 0;
volatile int TX_complete;
volatile int RX_complete;  

while (1)
  {
    /* USER CODE END WHILE */

  MX_TouchGFX_Process();
    /* USER CODE BEGIN 3 */
  	  while(HAL_SPI_GetState(&hspi2)!= HAL_SPI_STATE_READY){}

  	HAL_GPIO_WritePin(GPIOB, GPIO_PIN_4, GPIO_PIN_RESET);
    TX_complete = 0;
  	HAL_SPI_Transmit_DMA(&hspi2, TX_Buffer1, sizeof(TX_Buffer1));
  	while(TX_complete==0){}

  	RX_complete = 0;
	HAL_SPI_Receive_DMA(&hspi2, RX_Buffer, sizeof(RX_Buffer));
	while(RX_complete==0){}
  	HAL_GPIO_WritePin(GPIOB, GPIO_PIN_4, GPIO_PIN_SET);

  	counter++;
  }
  /* USER CODE END 3 */
}

And then code from slave:

const uint8_t TX_Buffer1[] = "Hi Master, I am finally awake!";  
uint8_t RX_Buffer[50];
uint8_t RX_Buffer_cpy[50];

volatile int counter = 0;
volatile int TX_complete;
volatile int RX_complete;

while (1)
  {
  MX_TouchGFX_Process();

  RX_complete = 0;
  HAL_SPI_Receive_DMA(&hspi2, RX_Buffer, sizeof(RX_Buffer));
  while(RX_complete==0){}

  TX_complete = 0;
  HAL_SPI_Transmit_DMA(&hspi2, TX_Buffer1, sizeof(TX_Buffer1));
  while(TX_complete==0){}

counter++;

  }

 (Pretty much the same as Master except that the Receive function is first and transmit is 2nd.)

When debugging for the slave, after executing HAL_SPI_Receive_DMA, the the callback never gets triggered and hence RX_complete remains at 0 and get stuck there. But when left running, it seems that the callback gets triggered because the green LED gets toggled constantly. Anyway that causes a problem that the Master cannot receive from the slave properly.

void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi)
{
	RX_complete = 1;
	HAL_GPIO_TogglePin(GPIOJ, GPIO_PIN_2);
	strncpy((char*)RX_Buffer_cpy, (char*)RX_Buffer, sizeof(RX_Buffer));
}

Settings for both master and slave are identical and NSS at slave is enabled. For master I manually enabled the GPIO at NSS pin. CPOL, CPHA and 8-bit data format are identical for both STM32H745XIH6 boards.

Master has corrupted received buffer...
Can someone please help??!! 

1 ACCEPTED SOLUTION

Accepted Solutions
Krautermann
Senior II

Thanks for your response.

I finally found a solution to the problem. I made a robust reliable full duplex SPI communication via Master-Slave by calling the HAL functions through callback. For those attempting full SPI communication, hope this helps!

//This is Master:
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_4, GPIO_PIN_RESET);
  HAL_SPI_Transmit_DMA(&hspi2, TX_Buffer1, sizeof(TX_Buffer1));

void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
{
	HAL_GPIO_TogglePin(GPIOI, GPIO_PIN_13);
	HAL_SPI_Receive_DMA(&hspi2, RX_Buffer, sizeof(RX_Buffer));
	HAL_GPIO_WritePin(GPIOB, GPIO_PIN_4, GPIO_PIN_SET);
}

void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi)
{
	HAL_GPIO_TogglePin(GPIOJ, GPIO_PIN_2);
	strncpy((char*)RX_Buffer_cpy, (char*)RX_Buffer, sizeof(RX_Buffer));
	HAL_GPIO_WritePin(GPIOB, GPIO_PIN_4, GPIO_PIN_RESET);
	HAL_SPI_Transmit_DMA(&hspi2, TX_Buffer1, sizeof(TX_Buffer1));
}

// This is slave:
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
{
	HAL_GPIO_TogglePin(GPIOI, GPIO_PIN_13);
	HAL_SPI_Receive_DMA(&hspi2, RX_Buffer, sizeof(RX_Buffer));
}

void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi)
{
	HAL_GPIO_TogglePin(GPIOJ, GPIO_PIN_2);
	strncpy((char*)RX_Buffer_cpy, (char*)RX_Buffer, sizeof(RX_Buffer));
	HAL_SPI_Transmit_DMA(&hspi2, TX_Buffer1, sizeof(TX_Buffer1));
}

Works perfectly and in synchronization!

View solution in original post

6 REPLIES 6
TDK
Guru

The slave is waiting for 50 bytes and the master is only sending around 20 (the string length).

Even after you fix that, you need to ensure the slave is ready (i.e. called HAL_SPI_Receive_DMA) prior to the master sending data.

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

Hi @TDK 

Thank you for your reply.


@TDK wrote:

The slave is waiting for 50 bytes and the master is only sending around 20 (the string length).

Even after you fix that, you need to ensure the slave is ready (i.e. called HAL_SPI_Receive_DMA) prior to the master sending data.


I fixed that by adjusting the size of the RX_buffer of the slave equal to the size of the TX buffer of the master. But still the volatile variable RX_complete does not become 1, so the callback is still not getting triggered somehow even though RX_Buffer (slave) receives the full buffer of the master. Why is that?

I can ensure that the slave is ready before the master sends data by powering on the slave before the master. Alternatively I tried to put the receive function outside the before the while(1) loop and put the function again in the callback, but that didn't work very well. Any suggestion about this?

 

0 Kudos
 



TDK
Guru

Use polling SPI functions instead. If those aren't working, you can debug, pause, see where the state machine is at, and fix the code accordingly. After polling SPI is working, graduate to DMA.

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

I did what you suggested. Went to polling function and it works well and then slowly moved to Interrupt function, that worked too but eventually the slave stopped sending and receiving after a few minutes. Tried DMA next and the same thing happened except that the slave stopped after a few seconds. It seems there is a synchronization problem.The master goes through the while(1) loop faster than the slave and eventually there is a desync problem.

Any way to fix that?

TDK
Guru

> The master goes through the while(1) loop faster than the slave and eventually there is a desync problem.

Speed up the slave or slow down the master. Or have some other signal which the slave sends to the master to indicate it is ready and wait for that.

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

Thanks for your response.

I finally found a solution to the problem. I made a robust reliable full duplex SPI communication via Master-Slave by calling the HAL functions through callback. For those attempting full SPI communication, hope this helps!

//This is Master:
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_4, GPIO_PIN_RESET);
  HAL_SPI_Transmit_DMA(&hspi2, TX_Buffer1, sizeof(TX_Buffer1));

void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
{
	HAL_GPIO_TogglePin(GPIOI, GPIO_PIN_13);
	HAL_SPI_Receive_DMA(&hspi2, RX_Buffer, sizeof(RX_Buffer));
	HAL_GPIO_WritePin(GPIOB, GPIO_PIN_4, GPIO_PIN_SET);
}

void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi)
{
	HAL_GPIO_TogglePin(GPIOJ, GPIO_PIN_2);
	strncpy((char*)RX_Buffer_cpy, (char*)RX_Buffer, sizeof(RX_Buffer));
	HAL_GPIO_WritePin(GPIOB, GPIO_PIN_4, GPIO_PIN_RESET);
	HAL_SPI_Transmit_DMA(&hspi2, TX_Buffer1, sizeof(TX_Buffer1));
}

// This is slave:
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
{
	HAL_GPIO_TogglePin(GPIOI, GPIO_PIN_13);
	HAL_SPI_Receive_DMA(&hspi2, RX_Buffer, sizeof(RX_Buffer));
}

void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi)
{
	HAL_GPIO_TogglePin(GPIOJ, GPIO_PIN_2);
	strncpy((char*)RX_Buffer_cpy, (char*)RX_Buffer, sizeof(RX_Buffer));
	HAL_SPI_Transmit_DMA(&hspi2, TX_Buffer1, sizeof(TX_Buffer1));
}

Works perfectly and in synchronization!