Slave serial printing 255 instead of given input

Hello. I am trying to implement a slave/master relationship (Arduino Uno as master and Arduino Pro Mini as slave) where the master sends a mode command to the slave and receives data in return once the mode command is accepted by the slave. My problem is that the serial monitor of the master only prints the number 255, no matter what data it is fed by the slave. Any help would be much appreciated. Master and Slave code attached below.

// SPI Example of Sending a Byte or 2 Bytes from an Arduino Uno Board to a Pro Micro Arduino Board using the SPI interface (Slave)
// 
// 10th December 2021
//

#include <SPI.h>

// GPIO pin that determines the state of the RS458 defining it as either High (transmission state) or Low (receiver state)
// setting up of the data pins for transmission and receiving of data from the master on Pro Micro Arduino Board
int dataEnablePin = 8;
int dataReceiverPin = 12; // MOSI (Master Out Slave In for SPI interface)
int dataTransmitterPin = 11; // MISO (Master In Slave Out for SPI interfacte)
int ssPin = 10;

// setting up of the clock pins for only the receiving of the clock from the master
int clockEnablePin = 9;
int clockReceiverPin = 13; // The SCLK of the SPI interface on the Pro Micro

volatile byte command = 0;

void setup (void)
{
  // defining the states of the data pins
  pinMode(dataEnablePin, OUTPUT);
  pinMode(dataReceiverPin, INPUT);
  pinMode(dataTransmitterPin, OUTPUT);
  pinMode(ssPin, INPUT);

  // defining the states of the clock pins
  pinMode(clockEnablePin, OUTPUT);
  pinMode(clockReceiverPin, INPUT);

  digitalWrite(dataEnablePin, LOW); // pin 8 always LOW to receive value from Master
  digitalWrite(clockEnablePin, LOW); // pin 9 is the Clock Line and it will always be LOW to receive

  SPI.begin();
  // turn on SPI in slave mode
  SPCR |= _BV(SPE);
  SPCR |= !(_BV(MSTR)); //Arduino is Slave

  // turn on interrupts
  SPCR |= _BV(SPIE);

}  // end of setup


// SPI interrupt routine
ISR (SPI_STC_vect)
{
  byte slaveReceived = SPDR;
  // byte slaveSend = 00010101; // decimal 15
  int slaveSend = 15;

  switch (command)
  {
    // no command? then this is the command
    case 0:
      command = slaveReceived;
      SPDR = 0;
      break;

    // add to incoming byte, return result
    case 'a':
      digitalWrite(dataEnablePin, HIGH);
      SPDR = slaveSend; 
      digitalWrite(dataEnablePin, LOW);
      break;

  } // end of switch
  
}  // end of interrupt service routine (ISR) SPI_STC_vect

void loop (void)
{
  // if SPI not active, clear current command
  if (digitalRead(ssPin) == HIGH)
    command = 0;
}  // end of loop
//  SPI Example of Sending a Byte or 2 Bytes from an Arduino Uno Board to a Pro Micro Arduino Board using the SPI interface (Master)
// 
// December 2021


#include <SPI.h>
int dataOut = 11;   // MOSI
int dataIn = 12;    // MISO
int dataEnablePin = 8;

int clockPin = 13;  // SCLK
int clockEnablePin = 9;

void setup (void)
{
  Serial.begin(9600);
  pinMode(dataOut, OUTPUT);
  pinMode(dataEnablePin, OUTPUT);
  pinMode(dataIn, INPUT);

  pinMode(clockPin, OUTPUT);
  pinMode(clockEnablePin, OUTPUT);

  digitalWrite(dataOut, HIGH);
  digitalWrite(dataEnablePin, HIGH);  // for transmission using the RS485
  digitalWrite(clockEnablePin, HIGH); // for the transmission using the RS485

  SPI.beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE2)); // Slow down the master a bit
  SPI.begin();
  Serial.begin (115200);
  Serial.println ();

  digitalWrite(SS, HIGH);  // ensure SS stays high for now

  // Put SCK, MOSI, SS pins into output mode
  // also put SCK, MOSI into LOW state, and SS into HIGH state.
  // Then put SPI hardware into Master mode and turn SPI on




}  // end of setup

byte transferAndWait (const byte trans)
{
  byte a = SPI.transfer (trans);
  digitalWrite(dataEnablePin, LOW);
  delayMicroseconds (20);
  return a;
} // end of transferAndWait

void loop (void)
{

  byte a, b, c, d;

  // enable Slave Select
  digitalWrite(SS, LOW);

  a = transferAndWait ('a');  // add command
  digitalWrite(dataEnablePin, HIGH);
  //  transferAndWait (10);
  // a = SPDR;
  b = transferAndWait (0);
  //digitalWrite(dataEnablePin, HIGH);
  //  b = transferAndWait (33);
  //  c = transferAndWait (42);
  //  d = transferAndWait (0);

  // disable Slave Select
  digitalWrite(SS, HIGH);

  Serial.println ("Adding results:");
  Serial.println (a, DEC);
  Serial.println (b, DEC);
  //  Serial.println (c, DEC);
  //  Serial.println (d, DEC);

  delay (1000);  // 1 second delay
}  // end of loop

(In minimum) in the Slave code the following line seems to be missing:

 SPI.attachInterrupt(); // turn on interrupt

See reference SPI Tutorial

That's a least worth a try ...

I'm thinking it may be a hardware issue, since when I remove the power to the slave somehow the slave LEDs are still on so power must be going from the slave to the master somehow. Maybe through the SS line or something?

Which slave LEDs are still on?

You could always try the SPI master & slave examples on Nicks website. Scroll down to the section titled "How to make an SPI slave".

That might help is identifying if it is a hardware issue.

The code above is very heavily derived from Nick's website already, it's almost the exact same except of course for pin configurations. An important note that I didn't include in my original post is that I'm using 2 RS485 modules for the slave side and 2 for the master side to use in serial communication. I will attach a circuit diagram to help with visualizing how the circuit fits together.

All of them

Interesting picture!

It was also posted by user @papatonop around 20 minutes earlier in another thread called "Setting up an SPI interface between an Arduino UNO and Arduino Pro Mini while implementing RS485 Modules".

Yes it's exactly the same circuit, we're working together on the project. My PC is running the master side and he is running the slave side.

Just a short hint before I leave you for the time being (I am sure that @markd833 is already a reasonable support for you,and too many cooks ... :innocent: ):

I suggest to put both controllers on a separate breadboard and just wire the SPIs. This will probably remove any hardware/wiring issues you may have at the moment. Get it to work there and then back to this arrangement (and its specific problems :wink: ) ... But that's clearly up to you!

1 Like

Yes it is a called parasite powering, never turn the power off from one element of a system with other elements still powered up. It can damage things.

@unomeister @papatonop

I think it would be a good idea to merge the topics. I know that you are each working on different aspects of the project but where there is a master/slave system there is, by definition, interaction between the two

Once merged you can maybe change the topic title to something encompassing the whole project

@UKHeliBob Thanks for that suggestion. I was not aware that that could be done but we will definitely do that!

That's the best way to isolate the problem. Thanks for the suggestion! Will only be able to do this on Monday so will get back to you then with updates! :grinning_face_with_smiling_eyes:

Hi, I'm a little new to this so forgive me for any mistakes or wrongdoings. I am currently working on a project where I am using an Arduino Uno (master) and Arduino Pro Mini (Slave) to communicate to each other using the SPI protocol. I am also using RS485 Modules to create 2 distinct communication lines namely Data and Clock (the end goal is to implement the EnDat 2.2 communication protocol). I have been following Nick Gammons forum on SPI communication found at: Gammon Forum : Electronics : Microprocessors : SPI - Serial Peripheral Interface - for Arduino. I am trying to send a mode command to the slave, which will then send back a a number (in my case 15). The Master should then display the number in the serial monitor, however, when it does it alwauys prints the number 255. I'm not sure whether this has got to do with 2^8 -1 as SPI sends bytes or what exactly but if anyone can provide some guidance or clarity it would be much appreciated! I'll send my master and slave code shortly as well as attach a circuit diagram.


Note that I added pull up resistors to the slave side as well.

The code is as follows:

// Master Code for Uno
// 
// December 2021

#include <SPI.h>
int dataOut = 11;   // MOSI
int dataIn = 12;    // MISO
int dataEnablePin = 8;

int clockPin = 13;  // SCLK
int clockEnablePin = 9;

void setup (void)
{
  Serial.begin(9600);
  pinMode(dataOut, OUTPUT);
  pinMode(dataEnablePin, OUTPUT);
  pinMode(dataIn, INPUT);

  pinMode(clockPin, OUTPUT);
  pinMode(clockEnablePin, OUTPUT);

  digitalWrite(dataOut, HIGH);
  digitalWrite(dataEnablePin, HIGH);  // for transmission using the RS485
  digitalWrite(clockEnablePin, HIGH); // for the transmission using the RS485

  SPI.beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE2)); // Slow down the master a bit
  SPI.begin();
  Serial.begin (115200);
  Serial.println ();

  digitalWrite(SS, HIGH);  // ensure SS stays high for now

}  // end of setup

byte transferAndWait (const byte trans)
{
  byte a = SPI.transfer (trans);
  digitalWrite(dataEnablePin, LOW);
  delayMicroseconds (20);
  return a;
} // end of transferAndWait

void loop (void)
{

  byte a, b, c, d;

  // enable Slave Select
  digitalWrite(SS, LOW);

  a = transferAndWait ('a');  // add command
  digitalWrite(dataEnablePin, HIGH);
  //  transferAndWait (10);
  // a = SPDR;
  b = transferAndWait (0);
  //digitalWrite(dataEnablePin, HIGH);
  //  b = transferAndWait (33);
  //  c = transferAndWait (42);
  //  d = transferAndWait (0);

  // disable Slave Select
  digitalWrite(SS, HIGH);

  Serial.println ("Adding results:");
  Serial.println (a, DEC);
  Serial.println (b, DEC);
  //  Serial.println (c, DEC);
  //  Serial.println (d, DEC);

  delay (1000);  // 1 second delay
}  // end of loop

Slave code:

// Master Code for Uno
// 
// December 2021

#include <SPI.h>

// GPIO pin that determines the state of the RS458 defining it as either High (transmission state) or Low (receiver state)
// setting up of the data pins for transmission and receiving of data from the master on Pro Micro Arduino Board
int dataEnablePin = 8;
int dataReceiverPin = 12; // MISO (Master In Slave Out for SPI interface)
int dataTransmitterPin = 11; // MOSI (Master Out Slave In for SPI interface)
int ssPin = 10;

// setting up of the clock pins for only the receiving of the clock from the master
int clockEnablePin = 9;
int clockReceiverPin = 13; // The SCLK of the SPI interface on the Pro Micro

volatile byte command = 0;

void setup (void)
{
  
  Serial.begin(9600);
  // defining the states of the data pins
  pinMode(dataEnablePin, OUTPUT);
  pinMode(dataReceiverPin, INPUT);
  pinMode(dataTransmitterPin, OUTPUT);
  pinMode(ssPin, INPUT);

  // defining the states of the clock pins
  pinMode(clockEnablePin, OUTPUT);
  pinMode(clockReceiverPin, INPUT);

  digitalWrite(dataEnablePin, LOW); // pin 8 always LOW to receive value from Master
  digitalWrite(clockEnablePin, LOW); // pin 9 is the Clock Line and it will always be LOW to receive

  SPI.begin();
  // turn on SPI in slave mode
  SPCR |= _BV(SPE);
  // SPCR |= !(_BV(MSTR)); //Arduino is Slave

  // turn on interrupts
  // SPCR |= _BV(SPIE);
  SPI.attachInterrupt(); // turn on interrupt

}  // end of setup


// SPI interrupt routine
ISR (SPI_STC_vect)
{
  int slaveReceived = SPDR;
  Serial.println(1);
  // byte slaveSend = 00010101; // decimal 15
  int slaveSend = 15;

  switch (command)
  {
    // no command? then this is the command
    case 0:
      command = slaveReceived;
      SPDR = 0;
      break;

    // add to incoming byte, return result
    case 'a':
      digitalWrite(dataEnablePin, HIGH);
      SPDR = slaveSend; 
      digitalWrite(dataEnablePin, LOW);
      break;

  } // end of switch
  
}  // end of interrupt service routine (ISR) SPI_STC_vect

void loop (void)
{
  // if SPI not active, clear current command
  
  if (digitalRead(ssPin) == HIGH)
    command = 0;
}  // end of loop

I think I understand what you are trying to do!

You have a pair of RS485 modules, one in permanent Tx and the other in permanent Rx to transfer the SPI SCK signal from the master to the slave.

You have another pair of RS485 modules that switch between Tx and Rx and either transfer the master SPI MOSI signal to the slave (when the master is in Tx and the slave in Rx), or transfer the slave MISO signal to the master (when the master is in Rx and the slave is in Tx).

I had a quick look at the EnDat protocol and it looks like it's a differential clock signal and a differential data signal.

I wonder if the simpler ShiftIn and ShiftOut functions would be a better fit rather than the hardware SPI interface?

EDIT: The above won't work in this scenario as ShiftIn on the slave device means that the slave would generate the clock rather than the master.

1 Like

Yes exactly that!

Will definitely look at using the Shift functions now, however, I tried using the SPI functions as they are said to be significantly faster.

After initial research, it says that the clockPins of the functions should be defined as OUTPUT in both cases (see below):

Note that the dataPin has to be defined as OUTPUT for shiftOut() and INPUT for shiftIn() . The clockPin has to be defined as OUTPUT in both cases.

This may not work with the SCLK pin on the Pro Mini being a permanent INPUT in my original setup.

Nonetheless will still give a try. Thanks for the quick response!

It may be easier for others to visualise your project if you were to do as suggested in your colleagues post and have 2 breadboards rather than the 1 big one.

On reflection, I don't think ShiftIn will work for you as the receiving device doing the "shifting in" is generating the clock, which is not what your scenario does.

You may be able to stick with an SPI based solution like you have. Looking briefly at the EnDat spec, it's differential clock & data. There isn't the Slave Select signal that SPI has. Normally the SS signal going low on the slave sets the receiving hardware to a known state ready to receive the first bit from the master.

Your setup of routing MOSI & MISO to the DI & RO on the master and the RO & DI on the slave might work.

I know less than nothing about the EnDat protocol so what follows may be complete garbage :laughing:

If EnDat is a command/response protocol, then you may be able to get your slave to control its own SS pin.

I guess that the clock RS485 on the master is always in transmit mode and clock on the slave RS485 is always in receive mode?

I wonder if you used a spare digital output pin on your slave device and connected it to the slave SS pin. That way, whenever the slave puts its data RS485 line driver into receive mode, it also drives its own SS pin low - i.e. it self selects and then waits for a byte to be clocked in from the master. The slave then gathers the bytes, works out what they mean, and if a response is required, it deselects its own SS pin, loads up the response byte, and puts its data RS485 line driver into transmit mode, and waits for the master to clock the byte out.

@papatonop @unomeister

The 2 topics have been merged

1 Like

@markd833 Thanks for the quick response again! Apologies for the late response. I've didn't have access to the equipment over the weekend.

"if you were to do as suggested in your colleagues post and have 2 breadboards rather than the 1 big one."

Could you clarify what you mean by 2 breadboards? At the moment we are using 2 as per the circuit diagram. Are you perhaps referring to separating the master and slave side onto to different boards?

"I guess that the clock RS485 on the master is always in transmit mode and clock on the slave RS485 is always in receive mode?"

Yes that is correct about the clock RS485!

"I wonder if you used a spare digital output pin on your slave device and connected it to the slave SS pin."

I have connected the SS pin to interruptible digital pin 2 so I will try configure that to the suggestion you made. Someone on the other forum did suggest removing the RS485's for now and directly connecting the slave and master to ensure our code is working correctly. I will most probably test this first and from there work my way back up.

Will keep you posted. Thanks for all the help!