Can 1 Arduino UNO be used as 2 slave devices?

I am doing an Arduino project where I have 1 Arduino UNO acting as a Master device in a SPI protocol, and another Arduino thats supposed to act as 2 slave devices. Yes I know I can use 2 Arduino's each being a slave, but i am hoping to avoid that. The slave Arduino is simulating 2 Hbridges and its basically acting as 2 instances of the same exact device, thats why I was hoping one Arduino can simulate both Hbridges simultaneously.

I tried using an arbitrary digital IO pin as a second Slave Select and using the predefined pin 10 as the first slave device, but SPI does not activate when bringing down the Arbitrary Slave Pin.

My Master and Slave code is below.

/************************************************MASTER TEST FILE******************************/
#include <SPI.h>
#define MSBmessage 0x50
#define MIDmessage 0x00
#define LSBmessage 0x00

#define SS2 9
int del= 0;
byte b[3];
unsigned long message = 0;

/*************************************************    Slave Receive Function     **********************************************/
byte SPI_MasterReceive(void)
{
  /* Wait for reception complete */
  while(!(SPSR & (1<<SPIF)))
  ;
  /* Return Data Register */
  Serial.print("RX: ");
  Serial.print(SPDR,HEX);
  Serial.print('\n');
  return SPDR;
}

/************************************************     Slave Transmit Function     ********************************************/
void SPI_MasterTransmit(byte cData)
{
        Serial.print("TX: ");
        Serial.print(cData, HEX); //debug to monitor master transmit 
        Serial.print('\n');
        SPDR = cData;
        while (!(SPSR & (1 << SPIF)));        
}

void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
SPI.begin();
SPI.setClockDivider(SPI_CLOCK_DIV128);
SPI.setDataMode(SPI_MODE0);
SPI.setBitOrder(MSBFIRST);
pinMode(MISO, INPUT);
pinMode(SS, OUTPUT);
pinMode(SS2, INPUT);
digitalWrite(SS, HIGH);
digitalWrite(SS2, HIGH); 
}
 
void loop() 
{
  digitalWrite(SS2, LOW);  //TURN SPI TRANSFER ON

  //SPI.transfer(0x50);    //0x50 (Command)
/*******************************************************    First byte transmit/recieve   *******************************************************/
  SPI_MasterTransmit(MSBmessage); //0x50 Status Byte
  delay(del);
  b[2] = SPI_MasterReceive();     //First response byte
//  Serial.print("b[2]: ");
//  Serial.print(b[2], HEX);        //debug to monitor master receive
//  Serial.print('\n');
  
/*******************************************************    Second byte transmit/recieve   *******************************************************/
  SPI_MasterTransmit(MIDmessage); //0x00 Status Byte
  delay(del);
  b[1] = SPI_MasterReceive();     //Second response byte
//  Serial.print("b[1]: ");
//  Serial.print(b[1], HEX);        //debug to monitor master receive
//  Serial.print('\n');

/*******************************************************    Third byte transmit/recieve   *******************************************************/
  SPI_MasterTransmit(LSBmessage); //0x00 Status Byte
  delay(del);
  b[0] = SPI_MasterReceive();     //Third response byte
                                   
  digitalWrite(SS2, HIGH); //TURN SPI TRANSFER OFF
}

Slave Code

//#define SERIAL_DEBUG_OFF

#define SS2 9

#define MSBmessage 0x50
#define MIDmessage 0x00
#define LSBmessage 0x00
volatile byte message;
uint8_t message_State = 0;
int messageCounter = 0;

long int myMessages[9] = {0x654321, 0x123456, 0x030000, 0x042000, 0x050100, 0x060080, 0x070040, 0x080008, 0x090004};  //TEST MESSAGES
//long int myMessages[9] = {0x000000, 0x400000, 0x100000, 0x002000, 0x000100, 0x000080, 0x000040, 0x000008, 0x000004};  //REAL MESSAGES

byte TX_buffer_Glass[3];
byte TX_buffer_Shade[3];
volatile byte TX_buffer[3];

/*************************************************     Slave Receive Function     **********************************************/
byte SPI_SlaveReceive(void)
{
  /* Wait for reception complete */
  while(!(SPSR & (1<<SPIF)))
  ;
  /* Return Data Register */
  #ifndef SERIAL_DEBUG_OFF
    Serial.print(SPDR, HEX);
    Serial.print('\n');
  #endif
  
  return SPDR;
}

/************************************************     Slave Transmit Function     ********************************************/
void SPI_SlaveTransmit(byte cData)
{  
  #ifndef SERIAL_DEBUG_OFF
    Serial.print(cData, HEX); //Slave Transmit debug monitor
    Serial.print('\n');
  #endif
  
  SPDR = cData;
  while (!(SPSR & (1 << SPIF)));        
}

/************************************************     SPI_Handler Function     ********************************************/
void SPI_Handler(byte TX_buffer[])
{
    message = SPI_SlaveReceive();
    if      ((message == MSBmessage) && (message_State == 0))
    {
        SPI_SlaveTransmit(TX_buffer[0]); 
        message_State = 1;
    }
    else if ((message == MIDmessage) && (message_State == 1))
    {
        SPI_SlaveTransmit(TX_buffer[1]);  
        message_State = 2;
    }
    else if ((message == LSBmessage) && (message_State == 2))
    {
        SPI_SlaveTransmit(TX_buffer[2]); 
        message_State = 0;
    }
    else
    {
        message_State = 0;
    }   
}

/************************************************     SPI_TXmessageParsing Function     ********************************************/
void SPI_TXmessageParsing(long faultMessage)
{
  
  TX_buffer[0] = (faultMessage >> 16);  //MSB
  TX_buffer[1] = (faultMessage >> 8);
  TX_buffer[2] = (faultMessage);        //LSB
}

void setup() 
{
  #ifndef SERIAL_DEBUG_OFF
    Serial.begin(115200);
  #endif
  
  pinMode(MISO, OUTPUT);
  pinMode(SS, INPUT);
  pinMode(SS2, INPUT);
                                                                  
  SPCR |= _BV(SPE); //turn on SPI in slave mode
}

void loop() 
{ 
  SPI_TXmessageParsing(myMessages[0]);          //654321
  memcpy(TX_buffer_Glass, TX_buffer, sizeof(TX_buffer));
  

  SPI_TXmessageParsing(myMessages[1]);          //123456
  memcpy(TX_buffer_Shade, TX_buffer, sizeof(TX_buffer));
 
  //spi sending happens here
  if (digitalRead (SS) == LOW)
  {       
    SPI_Handler(TX_buffer_Glass);
  }
  else
  {
    // do nothing
  }
  if (digitalRead (SS2) == LOW)
  {       
    SPI_Handler(TX_buffer_Shade);
  }
  else
  {
    // do nothing
  }
}

Blockquote

While you can use an arbitrary pin as SS in master mode to signal a slave Arduino, the same is not true in reverse. The SPI bus can only be signaled by the SS pin in slave mode. Details can be found in the datasheet, pages 169, 170:
^https://4donline.ihs.com/images/VipMasterIC/IC/MCHP/MCHP-S-A0006612857/MCHP-S-A0006612857-1.pdf?hkey=6D3A4C79FDBF58556ACFDE234799DDF0

Combine all the Slave Select signals by an AND gate and pass that signal to the SS pin. Two diodes and a pullup resistor may work as such a gate.

1 Like

What if i do this:

Use an arbitrary SS pin for the Master and Slave, then digitalWrite the actual SS pin of the slave to follow the arbitrary pin(s)?

Maybe...

Interrupt routines for the two external interrupt pins would, on falling edge, simply set a flag to indicate which of SS1 or SS2 was active when the SPI was activated.

#define the second SS to the first one. Then using either name selects the same slave.

Why does there need to be a connection to 5V?

To prevent the slave's SS pin from floating. Either of SS1 or SS2 can pull the slave's SS pin low, but when that is not happening, the pin needs to be pulled high. 10K would be a suitable resistor value.

Depending what @BitSeeker needs to test, that might not be enough. Maybe the slave, which is emulating 2 slaves, needs to know which of the 2 slaves is being communicated to by the master.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.