cancel
Showing results for 
Search instead for 
Did you mean: 

\0 is added in the front of my message when using HAL_SPI_Receive_DMA()

Dreamer3D
Associate III

Hello,

I'm commucating two STM32 F4 boards  using SPI

The first board is configured as a Master and used to only transmit data 

 

 

#define message_tx_size 4
uint8_t message_tx[message_tx_size] = "ABCD";
....
int main(void){
	while (1){
		HAL_SPI_Transmit(&hspi1, message_tx, message_tx_size, HAL_MAX_DELAY);
	}
}

 

 

The second board is configured as a Slave and used to only receiver data

 

 

 

//main.c
#define message_rx_size 4
uint8_t message_rx[message_rx_size];

int main(void){
  while (1){
  if ((1 == msgRX)){ //Process the message
			msgRX = 0;
	  } else if (0 == msgRX){
			msgRX = -1;

			memset(&struct_example_data_rx, '\0', size_of_struct_example_data);
			HAL_SPI_Receive_DMA(&hspi1, (uint8_t *)&struct_example_data_rx, size_of_struct_example_data);
	  }

	  HAL_Delay(200);
  }
}

//stm32f4xx_it.c
extern volatile int msgRX;
void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi) {
	if(hspi->Instance == hspi1.Instance && -1 == msgRX) {
		 msgRX = 1;
	}
}

 

 

 

The problem is: for the first iteration, I receive the exact data. But after a few itteration, the data I received becomes "\0ABC".

And if I re-run the receiver, without re-runing the transmiter, then I got the same exact result: OK at the begening, but altered after.

Thank you for help

 

 

1 ACCEPTED SOLUTION

Accepted Solutions
Dreamer3D
Associate III

Hello, 

It's finnaly some experimental work and ChatGPT who resolve the problem

look bellow at this response that ChatGPT gave me.

Apparently, the circular mode is perfect for continous data transfer 

Screenshot_DMA_MODE_STM32.png

View solution in original post

18 REPLIES 18
Bob S
Principal

Is that REALLY your code?  Because your "master" code is in a loop sending those 4 bytes over and over as fast as it can with no (or minimal) delay between each TX call.  Your slave code, on the other hand, has a 200ms delay.  So it will likely start receiving somewhere in the middle of a "packet" from the master, and not even guaranteed to be on a byte boundary.

Are you using a hardware SS signal (slave select)?  You don't show the SPI config code, so I can't tell.  That signal is used to "frame" the data and help ensure the master and slave are synchronized.  If not, you should add that - the slave side can use the hardware SS feature, but (usually) the master needs to use software controlled GPIO as the SS output because the STM32 "master SS" feature usually doesn't do what most people THINK it does (or want it to do).


@Bob S wrote:

 

[...] because the STM32 "master SS" feature usually doesn't do what most people THINK it does (or want it to do).


This is true for older chips (like STM32F103,  STM32G4), but newer chips (Like STM32U5, and others) have introduced new modes for the NSS signal so I'm not sure this fair warning applies to them. One has to check the RM for any specific chip. Some discussion of this is here.

 

Update:

Dupe: Impossible to receive data in loop using SPI with interupt

- 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.

Thank you Bob S for your response,

I'm sorry but I forgot to write that I had a delay of 100 on the master.

My Baude Rate also is set to 656 KBits/s

And I did not use the Hardware NSS Signal.

I found a temporary solution to resolve the problem, I stop the DMA and init the SPI on the slave side.

The solution is not perfect since I close and open the connection every iteration

This is full code I used

///////////////////////////////////////////////
Slave Receiver 
///////////////////////////////////////////////
//main.c
#define message_rx_size 4
uint8_t message_rx[message_rx_size];
...
int main(void){
  while (1){
  if ((1 == msgRX)){ //Process the message
			msgRX = 0;
	  } else if (0 == msgRX){
			msgRX = -1;
			
			//New added code
			HAL_SPI_DMAStop(&hspi1);
			__HAL_RCC_SPI1_FORCE_RESET();
			__HAL_RCC_SPI1_RELEASE_RESET();
			MX_SPI1_Init();
			//End new code

			memset(&struct_example_data_rx, '\0', size_of_struct_example_data);
			HAL_SPI_Receive_DMA(&hspi1, (uint8_t *)&struct_example_data_rx, size_of_struct_example_data);
	  }

	  HAL_Delay(200);
  }
}

//stm32f4xx_it.c
extern volatile int msgRX;
void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi) {
	if(hspi->Instance == hspi1.Instance && -1 == msgRX) {
		 msgRX = 1;
	}
}

///////////////////////////////////////////////
Master Transmiter 
///////////////////////////////////////////////
#define message_tx_size 4
uint8_t message_tx[message_tx_size] = "ABCD";
....
int main(void){
	while (1){
		HAL_SPI_Transmit(&hspi1, message_tx, message_tx_size, HAL_MAX_DELAY);
		HAL_Delay(100);
	}
}

For the solution you proposed, I try to enable the hardware NSS signal only on the client side, but it does not resolve the problem. In case you would recomend me to add also an Hardware NSS signal on the server side, it might be limiting for me, because I'm only allow to use specific PIN numbers. 

 

BarryWhit
Lead II

These kinds of manual delays are often indicators of poor design. Perhaps we could be more helpful if you explain more fully what you're trying to achieve. Whatever that is, synchronizing with hard-coded delays is almost certainly the wrong approach.

- 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.

My only goal is just to use SPI to send data from one board and to receive the exact data on another board. The presence of an '\0' at the begening of the data I received leads to several errors when manipulate the data.  

Fair enough. What was your intention when you introduced the HAL_Delay(200) line into the receiver's main loop?

- 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.

My delay on the transmiter side is set to 100.

So I suppose setting the dalay at 200 on the receiver side would make sinse. And this will make it sure that some data are available.  

What happens if you comment out the 200ms delay? the transmitter is the initiator, so it can wait as much as it wants between sends. But the receiver should, in principle, always be ready to respond to an incoming message. If anything, the TX should have 200ms, and the RX may have 100ms, and by that I mean it might work then. But the RX delay really has absolutely zero benefits. There's no need for it.

 

Also, why are you sending 4 bytes from the transmitter, but asking for `size_of_struct_example_data` bytes on the receiver side? are those quantities equal?

 

Also, isn't HAL_SPI_RxCpltCallback a weak symbol? you can directly reimplement it in main.c to override the one in stm32f4xx_it.c. That way, you can make `msgRX` static instead of extern, which is nicer.

 

Also, it'd be better to use an enum or at least create some #defines to make the states of `msgRX` more readable (IDLE, BUSY, MSG_PENDING).

- 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.

Commenting the 200 ms did not resolve the problem, I still have the '\0' after the second iteration.

The second solution did not also work, when I set the transmiter to 200 ms and the receiver to 100ms.

I tested several types of data, a simple char * and also a structur, both does not work. 

You are rigth, I can implement the HAL_SPI_RxCpltCallback () directely inside the main function. 

Ok for the enum