2024-09-04 06:45 AM
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
Solved! Go to Solution.
2024-09-25 02:24 AM
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
2024-09-04 02:34 PM
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).
2024-09-04 03:21 PM - edited 2024-09-05 06:05 AM
@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
2024-09-05 12:05 AM
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.
2024-09-05 03:46 AM - edited 2024-09-05 03:46 AM
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.
2024-09-05 05:10 AM
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.
2024-09-05 05:13 AM - edited 2024-09-05 05:33 AM
Fair enough. What was your intention when you introduced the HAL_Delay(200) line into the receiver's main loop?
2024-09-05 05:19 AM
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.
2024-09-05 05:21 AM - edited 2024-09-05 05:33 AM
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).
2024-09-05 05:46 AM
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