cancel
Showing results for 
Search instead for 
Did you mean: 

STM32G473CETx: SPI Full Duplex Slave able to receive correct data but not respond

STM-aspirant
Associate

Hello everyone,

I have setup my stm32 to use interrupts and have enabled them to work on spi1 and all 4 i2c ports. The relevance of the i2c ports is that they run continuously and may call the interrupt service routine while the spi one is being called. To isolate this possibility I have disabled interrupts for the spi callback.

 

At the start of the main of the stm32 slave I call

 

 

 

HAL_SPI_TransmitReceive_IT(&hspi1, tx_buff, rx_buff, size);

 

 

 

From a Raspberry Pi I am sending from 0 to 95 in a single transaction while simultaneously reading the bus. The stm32 receives the data as expected (which I have checked in debug mode) but sends nothing in response. I have checked the miso port with a logic analyzer and you can see in the photos.

 

This is the SPI callback

 

 

 

#define BYTES_PER_BUS 	(8*3)
#define BYTES_I2C4		((6-2)*(3))
#define RPI_PACKET_LEN 	((8*3)+((2)*3))

uint8_t spi_rx_buffer[RPI_PACKET_LEN] = {};
uint8_t spi_tx_buffer[RPI_PACKET_LEN] = {};

void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
{
  /* Prevent unused argument(s) compilation warning */
    __disable_irq();  
	UNUSED(hspi);
	flag_spi_transfered = true;
	__HAL_RCC_SPI1_FORCE_RESET();
	__HAL_RCC_SPI1_RELEASE_RESET();
	MX_SPI1_Init();

	int nb_arrays = sizeof(sensor_arrays)/sizeof(sensor_arrays[0]);
	for(int i=0; i<nb_arrays;i++){
		uint8_t buff_size = (i == 3) ? BYTES_I2C4 : BYTES_PER_BUS; // account for less sensors on i2c4
		memmove((tx_buff+(PREAMBLE_LEN)+(i)*(BYTES_PER_BUS)), sensor_arrays[i]->getResultBuffer(), buff_size);
	}
	HAL_SPI_TransmitReceive_IT(&hspi1, tx_buff, rx_buff, RPI_PACKET_LEN); // send all data to RPi
	__enable_irq();   // Disable all interrupts globally
}

 

 

 

I reset the port every time because I have seen that problems may be linked to desynchronization between master and slave.

 

I'm quite unsure of what I am doing wrong, does anyone have any idea? Could it just be a damaged chip or am I missing something? Is static discharge a feasible culprit?

 

Thanks

 

P.S. I checked the SPI_FLAG_TXE at the start of the callback and literally the next line after calling HAL_SPI_TransmitReceive_IT and both times it was 1. Is this normal? The raspberry pi is sending every 2s only so there is no way it could complete a new transaction immediately after.


Screenshot 2024-11-22 165243.pngScreenshot 2024-11-22 171046.pngScreenshot 2024-11-22 171108.pngScreenshot 2024-11-22 171031.pngScreenshot 2024-11-22 172124.png

1 ACCEPTED SOLUTION

Accepted Solutions

Ok thank you, I will shorten the interconnects and twist them together. To be clear are you saying having a separate line for each signal line to ground? I'm not sure how to implement this because the signals go directly to the MCU so I only have one ground.

 

The screenshots of the registers were when a frame was received (in the interrupt service handler) but before HAL_SPI_TransmitReceive_IT() was called again. I thought this would be more relevant as this is a result the previous HAL_SPI_TransmitReceive_IT() call and the buffers used no?

 

It turns that after running for a while I was getting the spi1 BSY flag was being raised and staying high. I then reset the port and it corrected itself. So I'm guessing it was combination of hardware issues (as JW suggests) and poor error handling on my behalf.

This is the fix I made:

void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi){

	__HAL_RCC_SPI1_FORCE_RESET();
	__HAL_RCC_SPI1_RELEASE_RESET();
	MX_SPI1_Init();
	HAL_SPI_TransmitReceive_IT(hspi1, tx_buff, rx_buff, size); // needed to make stm32 wait for next message again
	flag_spi_error = true;
}

 Thanks again JW, much appreciated

View solution in original post

7 REPLIES 7

Write a simple program with polled implementation of Tx only.

This can be pulled out very simply by direct register accesses - initialize the SPI-related pins in GPIO, set up SPI for slave, and then in a loop check the TXE status bit and if set, write some (nonzero) byte into the (transmit) data register.

JW

With this code as the whole main I still got no response. It prints "Writing" twice before the master even sends anything but I don't see anything on the logic analyzer. alt_main() is called just before the while(1) in the normal main()

 

uint8_t spi_tx_buffer[RPI_PACKET_LEN] = {0x44};

void alt_main(){	

	while (1)
	{
		if (__HAL_SPI_GET_FLAG(&hspi1, SPI_FLAG_TXE)) {
		    
			uart_printf("Writing\n");
		    hspi1.Instance->DR = spi_tx_buffer[tx_index];  

		    tx_index++;  
			if(tx_index >= RPI_PACKET_LEN)
				tx_index = 0;
		}

	}
}

 

 

Read out and check the SPI registers content and relevant GPIO registers content, especially for MISO.

Check, that MISO is properly connected to your LA probe by setting it as GPIO Out and toggling.

JW

Thanks for your suggestions. As a GPIO output the MISO pin works perfectly. I did 3 tests, the first two were at 50kHz and gave wrong results but indicate a bit offset which accumulates and destroys the whole miso packet. In bold are the preamble to help check for offsets: 0x60=96 is the packet length, then 0xFF and 0x00 are there to make it obvious. I am not completely sure but the registers look good to me.

 

1st test:

  • Master is trying to send {0x00, 0x01, 0x02, ..., 0x5D, 0x5E, 0x5F} (96 B) : no preamble
  • Slave is trying to send {0x60, 0xFF, 0x00, 0x8, 0x8, 0x8 .... 0x8, 0x8, 0x8, 0x00, 0xFF, 0x60} (96 B)

STMaspirant_0-1732532618490.png

STMaspirant_1-1732532625489.png

STMaspirant_2-1732532632551.png

STMaspirant_3-1732532637271.png

STMaspirant_4-1732532643465.png

 

 

2nd test: Works until 5th byte, then appears to be shifted right by one bit (kind of) based on what the stm32 received which is not the same as seen on the logic analyzer

  • Master is trying to send {0x60, 0x00, 0xFF, 0x03, 0x04, ..., 0x5D, 0x5E, 0x5F} (96 B)
  • Slave is trying to send {0x60, 0xFF, 0x00, 0x8, 0x8, 0x8 .... 0x8, 0x8, 0x8, 0x00, 0xFF, 0x60} (96 B)

STMaspirant_5-1732532707241.png

 

 

3rd test: CLK is 500kHz and it works perfectly except when it doesn't. There are a few packets that give random data but the consequent packets are fine. Slave and master receive data as expected too.

  • Master is trying to send {0x60, 0xFF, 0x00, 0x03, 0x04, ..., 0x5B, 0x5C, 0x60, 0xFF, 0x00} (96 B)
  • Slave is trying to send {0x60, 0xFF, 0x00, 0x8, 0x8, 0x8 .... 0x8, 0x8, 0x8, 0x00, 0xFF, 0x60} (96 B)

STMaspirant_7-1732533185599.png

STMaspirant_6-1732533173969.png

 

 

 

 

 

 

STMaspirant_8-1732533228641.png

STMaspirant_9-1732533247833.png

STMaspirant_10-1732533261418.png

 

So all I was doing wrong was having the CLK frequency too low? I still don't understand why it wasn't responding at all last week and today responded (albeit incorrectly initially). I have a few questions:

  • What may cause such an offset in the data?
  • Where can I find information on slave clock frequencies? I can't find it in the datasheet, nor the application note
  • What would cause it to stop responding then after a few days start again? I didn't touch the wiring at all.

Thanks

 

This is quite likely a hardware problem, the slave "sees" multiple SCLK edges where master generated one.

Use very short interconnections. Avoid "flying leads", crappy connectors. Use dedicated ground=return to each signal plus ground to power supply. Keep the SCLK return together with the signal (preferrably twisted). Reduce SCLK's slew rate on master, if possible.

JW

PS. Btw. you've shown registers content before enabling the SPI (as witnessed by SPE=0), that's not very useful. My intention with asking people to read and check/post registers is, that they actually investigate what's in the registers and why and how does that relate to the problem they are observing, and only if they've done all this and have no further ideas, to come here and explain what did they do and what were the observations.

Ok thank you, I will shorten the interconnects and twist them together. To be clear are you saying having a separate line for each signal line to ground? I'm not sure how to implement this because the signals go directly to the MCU so I only have one ground.

 

The screenshots of the registers were when a frame was received (in the interrupt service handler) but before HAL_SPI_TransmitReceive_IT() was called again. I thought this would be more relevant as this is a result the previous HAL_SPI_TransmitReceive_IT() call and the buffers used no?

 

It turns that after running for a while I was getting the spi1 BSY flag was being raised and staying high. I then reset the port and it corrected itself. So I'm guessing it was combination of hardware issues (as JW suggests) and poor error handling on my behalf.

This is the fix I made:

void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi){

	__HAL_RCC_SPI1_FORCE_RESET();
	__HAL_RCC_SPI1_RELEASE_RESET();
	MX_SPI1_Init();
	HAL_SPI_TransmitReceive_IT(hspi1, tx_buff, rx_buff, size); // needed to make stm32 wait for next message again
	flag_spi_error = true;
}

 Thanks again JW, much appreciated

> To be clear are you saying having a separate line for each signal line to ground? I'm not sure how to implement this because the signals go directly to the MCU so I only have one ground.

"Ground" is a first-order concept which falls apart as soon as second- and higher order concepts start to be non-negligible - here, real-world non-zero-length non-zero-resistance conductors are used together with high frequencies (and here the edges represent frequencies going easily to gigahertz range). You want to avoid shared ground/return as pulses at its impedance give rise to pulses at other signals, too; and you want to minimize loops which are prone to EMI.

(Btw. one more thing to do is to try to terminate the signals.)

JW