cancel
Showing results for 
Search instead for 
Did you mean: 

STM Nucleo Boards SPI Master/Slave Communication Problem. I set up a Nucleo-F446R as Slave Full Duplex and a Nucleo-G431R as Master Full Duplex. Master Sends -- Slave gets garbage.

DIngr.1
Associate II
The Slave Code
 
  while (1)
  {
     
      //Slave Section
      // Check If Data is about to be received
      Spi3_CE_State = HAL_GPIO_ReadPin(SPI3_CE_GPIO_Port, SPI3_CE_Pin);
      Spi3_CS_State = HAL_GPIO_ReadPin(SPI3_CS_GPIO_Port, SPI3_CS_Pin);
      if((Spi3_CE_State == true) && (Spi3_CS_State == false) &&(Done == false))
      {
         // prepare the buffers
         memset(Spi3RxData, 0, sizeof(Spi3RxData));
         memset(Spi3TxData, 0, sizeof(Spi3TxData));
         sprintf(Spi3TxData, "R3: 0X%x: %s",Kntr3++, Spi3RxData);
          
         Rslt = HAL_SPI_Receive(&hspi3, pSpi3RxData, 16, 300);           
         if(Rslt == HAL_OK)
         {
            // Prepare Reply
            sprintf(Spi3TxData, "R3: 0X%x: %s",Kntr3++, Spi3RxData); 
            //Trnamitter expecting 16 bytes so....         
            Rslt = HAL_SPI_Transmit(&hspi3, pSpi3TxData, 16, 300); 
         }
         Done = true;
         HAL_Delay(1);
         
      }
The Master Code
 
  while (1)
  {
     // Added internal pullups on CLK MISO MOSI == No change
 
      // Master Section
      if(Tmr_02 >= 3)  //Ever 3 Seconds send a message
      {
         Tmr_02 = 0;
         HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);
         
         // Set Signal lines
         HAL_GPIO_WritePin(SPI2_CE_GPIO_Port, SPI2_CE_Pin, GPIO_PIN_SET);
         HAL_GPIO_WritePin(SPI2_CS_GPIO_Port, SPI2_CS_Pin,  GPIO_PIN_RESET);
         
         // Prepare message
         memset(Spi2TxData, 0, sizeof(Spi2TxData));
         sprintf(Spi2TxData, "TX1: 0X%x", Kntr1++);   
         
         //HAL_Delay(2); // Tried 0, 1, 2 ms delays -- no joy
         
         Rslt = HAL_SPI_Transmit(&hspi2, pSpi2TxData, strlen(Spi2TxData), 200); 
         if(Rslt == HAL_OK)
         {
            // Receive Reply
            memset(Spi2RxData, 0, sizeof(Spi2RxData));
            
             // HAL_Delay(2); // Tried 0, 1, 2 ms delays -- no joy
            Rslt = HAL_SPI_Receive(&hspi2, pSpi2RxData, 16, 200);
            if(Rslt == HAL_OK)
            {
                 // Print Reply
               memset(TxtBuff2, 0, sizeof(TxtBuff2));
               sprintf(TxtBuff2, "R1: %s \r\n", Spi2RxData);
              // HAL_UART_Transmit(&hlpuart1, pTxtBuff2, strlen(TxtBuff2),10);        
            }
         }
         // Reset Sidnal lines
         HAL_GPIO_WritePin(SPI2_CS_GPIO_Port, SPI2_CS_Pin, GPIO_PIN_SET);
         HAL_GPIO_WritePin(SPI2_CE_GPIO_Port, SPI2_CE_Pin, GPIO_PIN_RESET);
         //Tmr_02 = 0;
     }

0693W00000AOVMVQA5.pngI am attempting to work my way through SPI interfacing and am using two Nucleo boards to increase my understanding. At this point I am trying to do a simple polling SPI transfer from one Nucleo board to another Nucleo board. The plan is to move on to interrupt transfer and then to DMA Transfer.

I set up the clock for both boards to run at 64MHz and the SPI master clock to run at 1MHz. I am using CPOL as low and CPHA as 1 edge on both boards. i use an output pin on the master to signal the Slave to receive data. When the slave signal pin goes low, then it attempts to receive a message, modify the message and send it back. I use a logic analyzer to monitor the transfer. I have been over the wiring several time an it is correct. I am trying to

I have obviously overlooked something simple for it to be this difficult.

Any Suggestons

9 REPLIES 9
TDK
Guru

Your master sends:

Rslt = HAL_SPI_Transmit(&hspi2, pSpi2TxData, strlen(Spi2TxData), 200);

while the slave receives:

Rslt = HAL_SPI_Receive(&hspi3, pSpi3RxData, 16, 300);

From your scope, it looks like strlen(Spi2TxData) = 8 (and not 16), which makes master/slave out of sync.

You'll also need delays to ensure the slave is ready to send before the master starts clocking data. 2ms delay is probably enough, but use 10ms to be safe until you get things working. In addition to the delay you have commented you, you will also need a delay between the two parts of the transaction on the master side.

Also look at the return values from the HAL functions. You would have caught that the slave transmit is timing out.

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

Too high or too low GPIO_OSPEEDR setting, long interconnects, inadequate ground/signal return.

JW

DIngr.1
Associate II

I have tried Low speed, medium speed, and very high speed. No luck.

There is a good ground connection between boards. Interconnects are about 5" long.

I use a counter in the transmit message so the length changes occasionally, While expecting 16 bytes, it should timeout and give me what it has received. Plus I have tried specifying the number of bytes (16) to send and receive. The only difference is the master size pads out with zero(0) and the slave still receives garbage.

I have also tried using TransmitReceive(..) and still get the same results.

Some posts suggest there is a problem with the HAL Slave routines.

I'm looking for any suggestions. I'm going bald here.

I have also tried several strategic delays but didn't change anything.

> I have tried Low speed, medium speed, and very high speed. No luck.

Tried high speed on MISO on slave, too?

> Interconnects are about 5" long.

So about 12cm in international units. Plus a couple of cm on the board itself. That may be too long for SPI, depending on circumstances.

> There is a good ground connection between boards.

You need signal return rather than "good ground". It means, each signal has to have its own dedicated ground, best in form of twisted with the signal wire, or in case of flat cable, grounds interspersed between signals.

> slave still receives garbage.

How do you know? IMO, slave may receive OK, just what it transmits looks as garbage. Try to verify using debugger or transmitting received data onto an independent channel (UART perhaps).

Try to look at MISO using an oscilloscope.

Check if any of the signals doesn't collide with some on-board resource on the Nucleos (e.g. VCP connection to STLink).

Try to bit-bang the protocol on slave (probably would require slowing down the master's baudrate); start just by echoing MOSI into MISO.

Try to use a different SPI.

JW

Greatly appreciate the advice. Thank you!!

I am using a logic analyzer to look at the signals (see screenshot) but I'll try looking at MISO on a scope.

I am using the default setup for the Nucleo boards and only setting up the SPI channels on both.

I have tried multiple speeds on both master and slave.

The clock speed is only settable on the master and I have limited that to 1Mhz. It should be low enough to be used for testing purposes on these boards. I've reduced the clock speed on the master to 500KHz without any change. At this speed, line length shouldn't be a factor, I would expect an occasional byte glitch but nothing like what I am seeing on the analyzer.

Right now I'm trying to get familiar with SPI with the HAL code with just polling. If that works I'll move on to interrupts and DMA. Once I understand those, I'll try the lower level bit-bang for increased efficiency,

I'll try a different Nucleo board. If that doesn't work, I'll assume it is a HAL problem and move on.

Still using the same boards and setup.

Some Progress but not a lot.

I noticed that the changing HAL_delays caused shifts in the received data. After modifying delays I had things working for a short time: Then I changed settings to increase speed of transmission had to change a HAL_delays; basic code structure remains unchanged. Then things stopped working again. Timing seems to be extremely sensitive.

Now Back to original settings BUT still have problems.

Significant notes:

  1. The very first message received by the Slave after a reset is Correct.
  2. All Subsequent messages received by the Slave as the first character set to NULL (Zero).
  3. Reloading the Master with code, without resetting the slave, requires the Slave to be reset before it receives correct data as noted in 1 &2. A synchronization problem?? How to re-sync without resetting slave??
  4. The slave response message received by the master is a buffer of the same character. It changes with each reset. The character received is the same as the character decoded by the logic analyzer. Looks like the slave buffer is preloaded and doesn't get changed by the software. Stick bits in the register??

Next I'll try a different SPI Slave and change the wiring and see shat happens.

Any suggestions would be greatly appreciated.

In the meantime I'll continue stumble through this simple SPI master/slave polling test. Lots to learn yet.

It's only sensitive in the sense that the slave needs to be ready to send or receive BEFORE the master starts clocking that data, as explained in the first reply. One method to debug would be to add a GPIO output to indicate when the slave is ready so that you can see this on your scope plots.

One way to resync is to interrupt on the falling CS edge and restart the transfer to realign data. Note that you'll need a delay on the master between the edge and the first clock to wait for the slave to be ready. A better method would be to ensure nothing gets out of sync in the first place.

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

I really appreciate the response from everyone. This has been a real hair-puller for me. I just needed to get something to work before moving to the next step.

Anyway. I replaced the Nucleo-F446R board with a Nucelo-G031K which i set up in the same configuration as the F446 board. The slave receive worked with only a couple of changes to the HAL_Delay. The slave transmit worked on with only a slight adjustment to a HAL- delay. Right Now every thing is working well.