SPI Master - trouble with signal burst

SPI Master on Arduino Nano
I'm having problems to get the SPI commnication to work on an Arduino Nano. The final project shall connect an RaspPi (master at 3.3V) with an Arduino Nano (slave at 5V) via SPI to send test data from the Nano to the RaspPi. I wasn't successful, so I thought to first test the Arduino in master mode with no slave connected (MISO floating). The nano is powered by USB and I'm using the serial monitor.

The Error
a logic analyzer monitors the voltage levels on the 4 pins. When I drive the SS low (pin 10 as Output) i expected the voltage level to go down and up only once when requested by the code, but instead the voltage level jumps between high/low randomly causing the SPI transmission to fail. I cannot figure out what the problem is. I can overcome the unstability at the beginning when SS goes low by adding a delay of 50 microsec, but during the SPI transmission the SS pin is jumping up and down.

Screenshot logic analyzer

The logic analyzer is connected straight to the Arduino pins using the same single ground pin on the POWER connector of the Arduino for all 4 channels.

Master Code

#include <SPI.h>

void setup (void)
{
  Serial.begin (115200);
  
  // pinMode(SS, OUTPUT);
  // digitalWrite(SS, HIGH);   
  
  SPI.begin ();   // setting SS as OUTPUT and set to HIGH
  
  Serial.println ("start...");
}  // end of setup

void loop (void)
{
  byte a;

  delay(5000);  // give time to start analyzer
  
  digitalWrite(SS, LOW);
  delayMicroseconds(5);  // give some time to settle

  byte a = SPI.transfer ('a');  // send ASCII a
  delayMicroseconds(20);  
  
  digitalWrite(SS, HIGH);

while(1){};  // don't loop, wait for reset

}  // end of loop

I have tried all different variations of the delay and also setting the register (PORTB) istead of the function digitalWrite Voltage levels look always similar.

Any ideas what I'm missing out?
Thanks.

If you don't set pin 10 as OUTPUT, then it's in input mode, when you set it HIGH it enable pullup resistor but when you set it LOW it stays at high impedance.
As a result, you get noise and only God knows what happens to communication. :wink:

I recommended you
Gammon Forum : Electronics : Microprocessors : SPI - Serial Peripheral Interface - for Arduino

Thanks for the respond. I thought SPI.begin() does all that. However I added the pinMode

#include <SPI.h>

void setup (void)
{
  Serial.begin (115200);

  pinMode(SS, OUTPUT);      // get GPIO control over pin10 (SS)
  digitalWrite(SS, HIGH);   // set to high for now
  SPI.begin ();

  Serial.println ("start...");

}  // end of setup

void loop (void)
{
  delay(5000);  // give time to start analyzer
  
  digitalWrite(SS, LOW);        // select slave
  delayMicroseconds(5);      // give time to settle

  byte a = SPI.transfer ('a');
  delayMicroseconds (20);   // give time to slave to respond
 
  digitalWrite(SS, HIGH);    // disable Slave Select

  //------------------
  while(1){};   // don't loop, wait for reset

}  // end of loop

and here the screenshot, exactly the same behavior during the SPI transfer:

I will check the links u added. Cheers

another check with all SPI pins cofigured. also send low command to SS twice, with the effect that only the first command shows jumps between high/low. Strange: MOSI is set high by Arduino and I cannot get it low with digitalWrite(MOSI, LOW); It seems that something is taking control in the background. Not sure if the logic analyzer has an influence.

#include <SPI.h>

void setup (void)
{
  pinMode(SS, OUTPUT);      // get GPIO control
  pinMode(MOSI, OUTPUT);    // get GPIO control
  pinMode(MISO, INPUT);     // give GPIO control to slave
  pinMode(SCK, OUTPUT);     // get GPIO control
  
  digitalWrite(SS, HIGH);   // set to high for now
  digitalWrite(MOSI, LOW);   // set to high for now
  digitalWrite(SCK, LOW);   // set to high for now
  
  SPI.begin ();

}  // end of setup


void loop (void)
{
  delay(5000);  // give time to start analyzer

  digitalWrite(MOSI, LOW);        // make sure MOSI is low
  delayMicroseconds(20);         // give time to settle
    
  digitalWrite(SS, LOW);            // select slave
  delayMicroseconds(20);        // give time to settle
  digitalWrite(SS, HIGH);           // de-select slave
  delayMicroseconds(20);        // give time to settle
  digitalWrite(SS, LOW);          
  delayMicroseconds(20);       

  byte a = SPI.transfer ('a');
  delayMicroseconds (20);       // give time to slave to respond
 
  digitalWrite(SS, HIGH);       // disable Slave Select

  //------------------
  while(1){};                           // don't loop, wait for reset

}  // end of loop

analyzer screenshot

zoom-in at SPI transmission

Are you using the classic Nano?
Do you mean the USB connector?
The logic analyser ground should be connected to a Nano GND pin

hi Jim, i'm using the classic Nano. the channels of the analyzer were and still are connected to the Nano ground next to the Reset pin. in the meantime I have connected all available Nano GRD pins together to a rail and then to the analyzer. The result is shown above in the screenshots

You may want to look at those signals with a scope to see if there is any noise present or if they are not making full logic level transitions.

i think you are right. i need to borrow a good scope and check. i will come back when done. thanks so far Jim

i gave it a last try, this time:

  • no USB connected
    this improved the jitter on MOSI, MISO, SCK, but not SS
  • external power source (12V)
  • no SPI enabled,
  • pure GPIO usage (pin10)
  • no use of function digitalWrite(), pure register bit setting
  • no timer interrupt
  • check both: from HIGH to LOW and visa-versa
    the jitter always occurs on the High>Low edge, the L>H edge is fine
void setup (void)
{

  DDRB |= B00000100;        // set pin10 as output
  cli();                    // stop all interrupts
  TIMSK0 &= ~(1 << TOIE0);  // set bit TOIE0 in the TIMSK0 register to zero to disable timer0 interrupt
  sei();                    // allow interrupts
  //PORTB |= B00000100;       // pin 10(SS) to high
  
}  // end of setup

void loop (void)
{

 //digitalWrite(SS, HIGH);   
 PORTB |= B00000100;        // pin 10(SS) to high
 delayMicroseconds (50);    // length of the low signal

 //digitalWrite(10; LOW);
 PORTB &= B11111011;        // pin 10(SS) to low
 delayMicroseconds (50);    // length of the low signal

}  // end of loop

anaylzer

Do you have another Arduino you could try, so you could at least confirm that the logic analyzer is OK.

Please, add another NANO or UNO as a SPI-Slave with your SPI-Master and keep executing the sketch of post #1. I am sure you will see the Serial Monitor of Slave is pronting 'a' at 1-sec interval.

#include <SPI.h>

void setup (void)
{
  Serial.begin (115200);
  SPI.begin ();   // setting SS as OUTPUT and set to HIGH
  digitalWrite(SS, LOW);
  Serial.println ("start...");
}  // end of setup

void loop (void)
{
  byte y = SPI.transfer ('a');  // send ASCII a
  delayMicroseconds(20);  
  digitalWrite(SS, HIGH);
   
  delay(1000);//while(1){};  // don't loop, wait for reset

}  // end of loop

Slave Sketch:

#include<SPI.h>
char ch;

void setup()
{
  Serial.begin(9600);
  pinMode(SS, INPUT_PULLUP);
  pinMode(MISO, OUTPUT);
  bitClear(SPCR, MSTR);  //UNO-2 is Slave
  bitSet(SPCR, SPE);  //SPI Port is created
  SPI.attachInterrupt();  //LIE, GIE are active
}

void loop()
{
    if(flag == true)
   {
       Serial.println(ch);
       flag = false;
   }
}

ISR(SPI_STC_vect)
{
     ch = SPDR;
     flag = true;
}

Hi Golam, i tried (Uno: Master, Nano: slave) but with no success. still burst on the SS pin.

I had some kind of success, but not stable. I will post later. thanks, ralf

Do you have another Arduino you can try?

yes I tried with a brand new Arduino Nano. Same effect. I managed some sort of success where the communication was good and in the next sequence corrupted again. The corruption was casued by the high pulses on SS during SPI.transfer(). I have programmed a delay before and after the transfer (1500ms before and 1000 after). I can see these delays and in between the pulse. Somethimes no pulse and the delay adds up to 2500ms, this is when communication goes through correctly. here the sreenshot:

here is a good sequence, no pulse:

I think, i will give up. that's too frustrating. I have a spare Adafruit FeatherM4 board. Maybe this gives more satisfaction :slight_smile: I will post.
Many thanks so far, ralf

Then either you have a grounding problem or you logic analyzer is faulty.

Yes, I agree. I just reloaded one of the first sketches with "Hello, world!" transfer. And it is received by the slave (UNO) and shown on the serial monitor. I set the lowest speed on the the Nano-Master at 250kHz. Still the analyzer's SPI interpreter shows totally different characters and many faulty transfers. So yes , I agree: the analyzer itself or the driver seems to have issues. So, frustrating, but well some kind of success to get further :slight_smile: Many thanks, really appreciated.

What logic analyzer are you using?

A Saleae 8 channel. I bought couple of years ago. I had to update the driver to the latest version of software. Maybe that is causing a problem. It was a major software change according to Saleae, even the former configuration files won't open in the new version. So, I guess that may be an issue.

Never the less, there was an interessting discussion back in 2012 around pulses on SS pin due to SPI.begin() mentioned in the SPI source files. But that couldn't be the issue in my case ... and actually it wasn't.

https://code.google.com/archive/p/arduino/issues/888

But we have not solved your original problem, which I believe is do to the mixed 3.3V and 5V signals.