MCP23S17 using SS on pin 18?

Hi All,
I'm working on a project which uses Arduino Nano 3.0 connected to a MCP23S17 ( http://www.microchip.com/wwwproducts/en/MCP23S17 ). This is used for output only, and controls relays driven with ULN2803A chips. I have been able to make the MCP23S17 chip work using this method - Arduino DUE and MCP23S17 - software SPI and hardware SPI - Arduino Due - Arduino Forum , so I know it is wired correctly. But, I can't seem to get any output pins above 4 to behave correctly, so trying to use a library to make this work. My Chip Select is pin 18 (A4), and the MISO, MOSI, SCK are standard 11, 12 ,13. I want to be able to digitalWrite all pins 1-16 on the MCP23S17 as HIGH or LOW as it will ease my logic programming later - just trying to get the basic hardware control working for now. I'm using the library from Cort Buffington - Arduino Playground - MCP23S17 Class for Arduino. I have the latest V.2 which "Changed direct manipulation of pin 10 on ATMega168/328 via "PORTB" to use digitalWrite on an arbitrary SlaveSelect pin passed to the object through the constructor." Also using IDE 1.6.8.
Things I have tried;
Read through Gammon Forum : Electronics : Microprocessors : SPI - Serial Peripheral Interface - for Arduino - gained a little from this (only because my brain is not a programming type!) Mainly learned to watch for bring the SS Low to write to the MCP, then High to stop writing. From reading the MCP23S17.cpp file, I think that handles bringing the ss pin Low, writes the info to the specified pin, then returns the ss pin High.
Also have tried to change the SS pin in the pins_arduino.h file, even though this was not recommended. This did not work for me.
A simplified version of my sketch is below. Can anybody point out what I have missed or done wrong? I have been trying to get this working for a long time, and finally decided to ask for some help from those who are much more experienced at this!

#include <SPI.h>

#include <MCP23S17.h>
//const int MOSI = 12;
//const int MISO = 11;
//const int SCK = 13;
const int ss = 18;    
const int address = 0;

MCP iochip(0, 18);             // Instantiate an object called "iochip" on an MCP23S17 device at address 0
                   // and slave-select on Arduino pin 18
void setup() {
      analogReference(EXTERNAL);
      pinMode(8, OUTPUT);
      digitalWrite(8, HIGH);  //turn on main power relay
      delay(2000);  // wait for chip to stabilize
      pinMode(10, OUTPUT);  // keep this as output

   iochip.begin();
   
      digitalWrite(10, HIGH);
      pinMode(ss, OUTPUT);  //ss
      //digitalWrite(_ss, HIGH);
      pinMode(11, INPUT); //MISO
      pinMode(12, OUTPUT);  //MOSI
      pinMode(13, OUTPUT);  //SCK

  iochip.pinMode(1, LOW);       // Use bit-write mode to set the current pin to be an output
  iochip.pinMode(3, LOW);       // Use bit-write mode to set the current pin to be an output
  //iochip.pinMode(0B0000000000000000);  // set all MCP23S17 pins as output
  
iochip.byteWrite(IODIRB, 0x00); //Use byte-write to set all 8 bits of IO Direction register for portB to outputs
iochip.byteWrite(IODIRA, 0x00); //Use byte-write to set all 8 bits of IO Direction register for portA to outputs
}

void loop() {
  digitalWrite(ss, HIGH);
  //digitalWrite(ss, LOW);
  iochip.digitalWrite(1, HIGH);
  delay(500);
  iochip.digitalWrite(3, HIGH);
  delay(1000);
  iochip.digitalWrite(1, LOW);
  delay(500);
  iochip.digitalWrite(3, LOW);
  
  digitalWrite(ss, HIGH);

}

Thanks in advance for any pointers for me to look at!

BigAl1:
Hi All,
I'm working on a project which uses Arduino Nano 3.0 connected to a MCP23S17 ( http://www.microchip.com/wwwproducts/en/MCP23S17 ). This is used for output only, and controls relays driven with ULN2803A chips. I have been able to make the MCP23S17 chip work using this method - Arduino DUE and MCP23S17 - software SPI and hardware SPI - Arduino Due - Arduino Forum , so I know it is wired correctly. But, I can't seem to get any output pins above 4 to behave correctly, so trying to use a library to make this work. My Chip Select is pin 18 (A4), and the MISO, MOSI, SCK are standard 11, 12 ,13. I want to be able to digitalWrite all pins 1-16 on the MCP23S17 as HIGH or LOW as it will ease my logic programming later - just trying to get the basic hardware control working for now. I'm using the library from Cort Buffington - Arduino Playground - HomePage. I have the latest V.2 which "Changed direct manipulation of pin 10 on ATMega168/328 via "PORTB" to use digitalWrite on an arbitrary SlaveSelect pin passed to the object through the constructor." Also using IDE 1.6.8.
Things I have tried;
Read through Gammon Forum : Electronics : Microprocessors : SPI - Serial Peripheral Interface - for Arduino - gained a little from this (only because my brain is not a programming type!) Mainly learned to watch for bring the SS Low to write to the MCP, then High to stop writing. From reading the MCP23S17.cpp file, I think that handles bringing the ss pin Low, writes the info to the specified pin, then returns the ss pin High.
Also have tried to change the SS pin in the pins_arduino.h file, even though this was not recommended. This did not work for me.
A simplified version of my sketch is below. Can anybody point out what I have missed or done wrong? I have been trying to get this working for a long time, and finally decided to ask for some help from those who are much more experienced at this!

I have never used that library.
I skimmed through it and, your code has unnecessary stuff:

#include <SPI.h>

#include <MCP23S17.h>
//const int MOSI = 12;
//const int MISO = 11;
//const int SCK = 13;
const int ss = 18;    
const int address = 0;

// I would use your defined value of 'ss'
MCP iochip(0, ss);             // Instantiate an object called "iochip" on an MCP23S17 device at address 0
                   // and slave-select on Arduino pin 18

// And your hardware must have the three address lines grounded (address 0)

void setup() {
      analogReference(EXTERNAL);
      pinMode(8, OUTPUT);
      digitalWrite(8, HIGH);  //turn on main power relay
      delay(2000);  // wait for chip to stabilize
      pinMode(10, OUTPUT);  // keep this as output

   iochip.begin();
   
/* the following code is unnessary, the iochip.begin() does it for you
 
     digitalWrite(10, HIGH);      //SPI.begin() 
      pinMode(ss, OUTPUT);      //iochip.begin()
      //digitalWrite(_ss, HIGH);
      pinMode(11, INPUT); //MISO     //SPI.begin() enables the SPI hardware which takes over these pins
      pinMode(12, OUTPUT);  //MOSI //SPI.begin() enables the SPI hardware which takes over these pins
      pinMode(13, OUTPUT);  //SCK   //SPI.begin() enables the SPI hardware which takes over these pins
*/

  iochip.pinMode(1, LOW);       // Use bit-write mode to set the current pin to be an output
  iochip.pinMode(3, LOW);       // Use bit-write mode to set the current pin to be an output
  //iochip.pinMode(0B0000000000000000);  // set all MCP23S17 pins as output
  
iochip.byteWrite(IODIRB, 0x00); //Use byte-write to set all 8 bits of IO Direction register for portB to outputs
iochip.byteWrite(IODIRA, 0x00); //Use byte-write to set all 8 bits of IO Direction register for portA to outputs
}

void loop() {
//  digitalWrite(ss, HIGH); Handled by iochip()
  //digitalWrite(ss, LOW);
  iochip.digitalWrite(1, HIGH);
  delay(500);
  iochip.digitalWrite(3, HIGH);
  delay(1000);
  iochip.digitalWrite(1, LOW);
  delay(500);
  iochip.digitalWrite(3, LOW);
  
//  digitalWrite(ss, HIGH); Handled by iochip()

}

Verify that you have the MCP23S17 wired with A,B,C address bits tied to GND.

try this simple code:

#include <SPI.h>

#define mySS A4   // you do realize the A4 is also used by the I2C hardware? You Cannot use A4..A5 if you use I2C
#define S17WRITE 0x40 // hardware address is 0
#define S17READ 0x41 // hardware address is 0
#define S17IODIRA 0     // Direction control reg 0=outoup
#define S17IOCON 0x0A // configuration register 
#define S17IOCON_VALUE 0x80 // turn on Hardware addressing

#define S17GPIOA 0x12 // GPI port A

void setup(){
  Serial.begin(9600); // debug output to Serial Monitor

  SPI.begin();
  pinMode(mySS,OUTPUT);
  digitalWrite(mySS,HIGH);
  delay(1);// make sure MCP23S17 is not selected

  SPI.beginTransaction(SPISettings(14000000, MSBFIRST, SPI_MODE0)); // SPI settings for this device

// configure ALL MC23S17 that use mySS to address themselves using their hardware A..C pins
  digitalWrite(mySS,LOW); select device
  SPI.transfer(S17WRITE);
  SPI.transfer(S17IOCON);
  SPI.transfer(S17IOCON_VALUE);
  digitalWrite(mySS,HIGH);

// now I can address my specific S17 at address 0 
  digitalWrite(mySS,LOW)
  SPI.transfer(S17WRITE);
  SPI.transfer(S17IODIRA)
  SPI.transfer(0);  // all of port A is output
  SPI.transfer(0);  // all of port B is output
  digitalWrite(mySS,HIGH);

// now I will set the output values to 0;

  digitalWrite(mySS,LOW)
  SPI.transfer(S17WRITE);
  SPI.transfer(S17GPIOA)
  SPI.transfer(0);  // all of port A is LOW
  SPI.transfer(0);  // all of port B is LOW
  digitalWrite(mySS,HIGH);

  SPI.endTransmission();  // let other's (interrupt routines use the SPI interface)

  }

static unsigned long tick = millis(); // init tick 
static bool aValue = false;

void loop(){
// flash output A LOW B HIGH, A HIGH B LOW every Second

if(millis()-tick>1000){ // one second since last activation
  tick=millis(); // new activation time
  aValue = !aValue; // alternate values

  SPI.beginTransaction(SPISettings(14000000, MSBFIRST, SPI_MODE0)); // SPI settings for this device
  digitalWrite(mySS,LOW)
  SPI.transfer(S17WRITE);
  SPI.transfer(S17GPIOA); // address of port A

  if(aValue){ // set A port HIGH, B port LOW
 
    SPI.transfer(0xFF);  // all of port A is HIGH
    SPI.transfer(0);  // all of port B is LOW
    }
   else{
    SPI.transfer(0); // all of port A is LOW
    SPI.transfer(0xff); // all of port B is HIGH
    }
  digitalWrite(mySS,HIGH);
  SPI.endTransmission();  // let other's (interrupt routines use the SPI interface)
  If(aValue){
     Serial.println("Port A is HIGH!");
    }
  else Serial.println("Port B is HIGH!");
  }

}

Chuck.

Thanks Chuck. I went through your comments in my code, removed those items that are unnecessary, and changed the MCP iochip(0, 18); to "ss" instead of 18. Still no joy using my code. I do have A0, A1, A2 on the MCP23S17 chip tied to GND. I believe the problem is something about the ss being on pin 18 instead of standard pin 10, when using this library.
I did try your suggested code - no joy from that either.
I have been able to get the MCP23S17 chip to operate Port A and B pins 0,1,2 all work consecutively, but no relay click on pins 3-7 for either port. As a test, I shifted all the port pins up by 3 in the order, just to test my hardware and see if I was overloading the chip for output current - no change to the output problem - only pins 0,1,2 are working. I must credit the code below to Arduino DUE and MCP23S17 - software SPI and hardware SPI - Arduino Due - Arduino Forum - I borrowed heavily from this.
If I could get this code to control all 8 pins on each port, then I would happily use this method for my program! My other problem with this method is I don't know how to shut off each pin individually - a must for my project. Can you point me where to look?

// MCP23S17 registers setup
const int MCPWRT = 0x40;    //Command to write in MCP23S17 Address $00
const int IOCON  = 0x0A;    //Register address to MCP23S17 Config
const int IODIRA = 0x00;    //Register address to MCP23S17 PortA(1)
const int IODIRB = 0x01;    //Register address to MCP23S17 PortB(2)
const int GPIOA  = 0x12;    //Register address to MCP23S17 GPIOA(1)
const int GPIOB  = 0x13;    //Register address to MCP23S17 GPIOB(2)
const int OLATA  = 0x14;    //Register address to MCP23S17 LATCH-A(1)
const int OLATB  = 0x15;    //Register address to MCP23S17 LATCH-B(2)
//const int MCPREG = 

// SPI software variables
// Warning - the software SPI pins must be defined
// init with zeros so the internal memory is alocated at startup
int  DataPin = 0, DataInPin=0, ClockPin = 0;
byte DataOut=0, MCPReg=0;
int SS1=0, SS2=0;

const int mainPWRrelay = 8; // Main power relay digital out

// ACrelay(R5-10A) = A0   = Port A, MCP pin 0
// Relay1 = A1    
// Relay2 = A2   
// Relay3 = A4   
// Relay4 = A3    
// Relay15 = A5   
// Relay13 = A6   
// Relay14 = A7   
// Relay12 = B0  = Port B, MCP pin 0
// Relay11 = B1   
// Relay10 = B2   
// Relay5 = B3    
// Relay6 = B4    
// Relay7 = B5  
// Relay8 = B6    

// send data to MCP23S17 (software SPI)

void soft_send (int MCPREG, int DATAOUT, int SS2) {   // 
    digitalWrite(SS2, LOW);   // select the chip
    shiftOut(DataPin, ClockPin, MSBFIRST, MCPWRT);  // tell it I wish to send
    shiftOut(DataPin, ClockPin, MSBFIRST, MCPREG); // tell it where I wish to send
    shiftOut(DataPin, ClockPin, MSBFIRST, DATAOUT); // and what I wish to send
    digitalWrite(SS2, HIGH);                                                  
}

void init_soft_bus() {

     DataPin = 12;  // MOSI
     ClockPin = 13; // SCK
     DataInPin = 11; // MISO
     SS2=18;   // Select MCP23S17 Port EXpander
   //SS1=10;   // MCP4241 digital pot
 
     pinMode(DataPin, OUTPUT);            // data output pin - output
     pinMode(DataInPin, INPUT);        // data input pin - this is an input for incoming data
     pinMode(ClockPin, OUTPUT);     // again output - I have to pulse the MCPs in order to get them working
     pinMode(SS2, OUTPUT);   // select pins also outputs
     pinMode(SS1, OUTPUT);

     digitalWrite(SS2, LOW);
     digitalWrite(SS2, HIGH);
     delay(100);
             
     soft_send(IOCON, 0x20, SS2);   // init CS2 MCP23S17 port expander
     soft_send(IODIRA, 0x00, SS2);  // SS2 PORTA = output
     soft_send(IODIRB, 0x00, SS2);  // SS2 PORTB = output         
}

void setup() {
      analogReference(EXTERNAL);
      pinMode(mainPWRrelay, OUTPUT);
      digitalWrite(mainPWRrelay, HIGH);
      delay(2000);
     init_soft_bus();   // configure the MCP23S17 for the GPIOA = output and GPIOB = output
    //Serial.begin(9600);
}

void loop() {
  
   digitalWrite(mainPWRrelay, HIGH); // Main power relay
   delay(200);

   //Port A
   soft_send(GPIOA, 0, SS2); 
   delay(200);  
   soft_send(GPIOA, 1, SS2);   
   delay(200);

   soft_send(GPIOA, 2, SS2);
   delay(500);   
   soft_send(GPIOA, 3, SS2);  
   delay(500);

   soft_send(GPIOA, 4, SS2);  
   delay(800);
   soft_send(GPIOA, 5, SS2);  
   delay(800);
  
   soft_send(GPIOA, 6, SS2);
   delay(1300);   
   soft_send(GPIOA, 7, SS2);   
   //delay(1300);

   //Port B 
   delay(4000);
   soft_send(GPIOB, 0, SS2); 
   delay(200);  
   soft_send(GPIOB, 1, SS2);   
   delay(200);
  
   soft_send(GPIOB, 2, SS2);
   delay(500);   
   soft_send(GPIOB, 3, SS2);  
   delay(500);

   soft_send(GPIOB, 4, SS2);  
   delay(800);
   soft_send(GPIOB, 5, SS2);  
   delay(800);
    
   soft_send(GPIOB, 6, SS2);
   delay(1300);   
   soft_send(GPIOB, 7, SS2);   
   delay(4000);
   
 }

BigAl1:
Thanks Chuck. I went through your comments in my code, removed those items that are unnecessary, and changed the MCP iochip(0, 18); to "ss" instead of 18. Still no joy using my code. I do have A0, A1, A2 on the MCP23S17 chip tied to GND. I believe the problem is something about the ss being on pin 18 instead of standard pin 10, when using this library.
I did try your suggested code - no joy from that either.

Did my code compile?

I have used the MCP23S17 in multiple projects, I have had no problems.

Here is a schematic of how I use a MCP23S17 to interface to a 20x4 LCD and drive four status LED's

I would start by verifying your wiring.

Check that the '17 has power on VCC and 0 volts on Gnd, and Reset is at VCC.

What kind of test equipment do you have?

You can make a simple 'logic analyzer' from LED's and Resistors and Transistors. If you have nothing else.

You could use the 'logic analyzer' to watch your CS pin.

Post a schematic of your circuit, and photos of your actual project. Most of the problems found on this forum usually trace back to assumptions.

Until you can verify that the device responds to commands, there is no use writing software.

Chuck.

Thanks for the feedback Chuck. Yeah, I learned early in this project - no assumptions that I designed it "right"! I have a DVM, and have used that several weeks ago to verify the traces on my board are correct, and that the pin 18 (SS2 in the semi-working sketch) is going HIGH/LOW as I command. That pin is correctly connected to the CS on the MCP23S17, as are the SCK, SI, and SO lines - all have been verified with the DVM, probing for the +5V at the MCP chip. All are connected correctly, and the last sketch I showed does work - sort of! So I know the Nano to MCP to ULN2803A connections are working.
Attached are screen shots of the relevant part of the board with the MCP23S17 on it - I don't have a design schematic - just went to board design directly, a case of amateur in electronics design. This is V3 of the board design for this project, and other than a couple small placement issues, it is probably my final major redesign.
I tried to run your sketch, but it didn't compile until I fixed a couple things (missing some ";" and changed "SPI.endTransmission" to "SPI.endTransaction"), and changed the mySS to 18 instead of A4.
My main questions now are "How do I turn off a pin on the MCP once it is turned on?" , and "Why does the last code I posted only control pins 0, 1, 2 on both Ports, and not the rest of the pins?" - Is this something in the registers setup?
Thanks for looking at this - I'm hoping something you mention or point to will give me that "Ah-Ha" moment and I'll understand it better!
Allan

BigAl1:
Thanks for the feedback Chuck. Yeah, I learned early in this project - no assumptions that I designed it "right"! I have a DVM, and have used that several weeks ago to verify the traces on my board are correct, and that the pin 18 (SS2 in the semi-working sketch) is going HIGH/LOW as I command. That pin is correctly connected to the CS on the MCP23S17, as are the SCK, SI, and SO lines - all have been verified with the DVM, probing for the +5V at the MCP chip. All are connected correctly, and the last sketch I showed does work - sort of! So I know the Nano to MCP to ULN2803A connections are working.
Attached are screen shots of the relevant part of the board with the MCP23S17 on it - I don't have a design schematic - just went to board design directly, a case of amateur in electronics design. This is V3 of the board design for this project, and other than a couple small placement issues, it is probably my final major redesign.
I tried to run your sketch, but it didn't compile until I fixed a couple things (missing some ";" and changed "SPI.endTransmission" to "SPI.endTransaction"), and changed the mySS to 18 instead of A4.
My main questions now are "How do I turn off a pin on the MCP once it is turned on?" , and "Why does the last code I posted only control pins 0, 1, 2 on both Ports, and not the rest of the pins?" - Is this something in the registers setup?
Thanks for looking at this - I'm hoping something you mention or point to will give me that "Ah-Ha" moment and I'll understand it better!
Allan

You say "pin 18"? I see you have a 32 pin socket on your second board? Does "pin 18" mean the 18th pin of the socket? or does "pin 18" mean "digital pin 18", Actually Analog pin 4 A4?

To control pins on a MCP23S17:

Step one: set the pin for either Input or Output:

each bit of Port A and Port B have a corresponding bit in register IODIRA(register 0), or IODIRA (register 1).

So to set A0..2 to input, A3..5 to Output, A6,7 to Input you would need to write the value of
B11000111(binary) or 0xC7(hex) to Register 0

digitalWrite(CS,LOW);
SPI.transfer(0x40); // write to '17 at address 0
SPI.transfer(0x00); // select register 0
SPI.transfer(0xC7);
digitalWrite(CS,HIGH);

with this configuration of port A, to set bit 4 High, bits 3,5 LOW:
B00010000. // if the port is configured as input, writing to GPIO does not change the output, so the only bits I need to worry about are b3..b5, now if later you change the input bits to output, They will immediately assume the last value you wrote to the GPIO register.

digitalWrite(CS,LOW); 
SPI.transfer(0x40);
SPI.transfer(0x12); // select GPIOA
SPI.transfer(0x10); // binary B00010000
digitalWrite(CS,HIGH);

to read from port A:

digitalWrite(CS,LOW); 
SPI.transfer(0x41); // read from device
SPI.transfer(0x12); // select GPIOA
uint8_t data = SPI.transfer(0x00); // this output value is ignored, it can be any value
digitalWrite(CS,HIGH);

data will now contain the value read at all of the bits, even the OUTPUT pins.

The following code work with my circuit. The only changes I made was:
I am using a MEGA2560 CPU on a custom board that does not connect Serial back to a PC.
and my CS pin is using pin PG3 (not a Standard Arduino pin) so I defined mySS as 73.
And instead of using Serial.print() I use lcd.print().
And My MCP23S17 is at address 0x26 so S17READ is 0x4D and S17WRITE is 0x4C

#include <SPI.h>
#define mySS A4   // you do realize the A4 is also used by the I2C hardware? You Cannot use A4..A5 if you use I2C
#define S17WRITE 0x40 // hardware address is 0
#define S17READ 0x41 // hardware address is 0
#define S17IODIRA 0     // Direction control reg 0=outoup
#define S17IOCON 0x0A // configuration register
#define S17IOCON_VALUE 0x08 // turn on Hardware addressing

#define S17GPIOA 0x12 // GPI port A

void setup(){
  Serial.begin(9600); // debug output to Serial Monitor

  SPI.begin();
  pinMode(mySS,OUTPUT);
  digitalWrite(mySS,HIGH);
  delay(1);// make sure MCP23S17 is not selected

  SPI.beginTransaction(SPISettings(14000000, MSBFIRST, SPI_MODE0)); // SPI settings for this device

// configure ALL MC23S17 that use mySS to address themselves using their hardware A..C pins
  digitalWrite(mySS,LOW); select device
  SPI.transfer(S17WRITE);
  SPI.transfer(S17IOCON);
  SPI.transfer(S17IOCON_VALUE);
  digitalWrite(mySS,HIGH);

// now I can address my specific S17 at address 0
  digitalWrite(mySS,LOW);
  SPI.transfer(S17WRITE);
  SPI.transfer(S17IODIRA);
  SPI.transfer(0);  // all of port A is output
  SPI.transfer(0);  // all of port B is output
  digitalWrite(mySS,HIGH);

// now I will set the output values to 0;

  digitalWrite(mySS,LOW);
  SPI.transfer(S17WRITE);
  SPI.transfer(S17GPIOA);
  SPI.transfer(0);  // all of port A is LOW
  SPI.transfer(0);  // all of port B is LOW
  digitalWrite(mySS,HIGH);

  SPI.endTransaction();  // let other's (interrupt routines use the SPI interface)

  }



static unsigned long tick = millis(); // init tick
static bool aValue = false;
uint8_t buf[22];

void loop(){
// flash output A LOW B HIGH, A HIGH B LOW every Second

if(millis()-tick>1000){ // one second since last activation
  tick=millis(); // new activation time
  aValue = !aValue; // alternate values

  SPI.beginTransaction(SPISettings(14000000, MSBFIRST, SPI_MODE0)); // SPI settings for this device
  digitalWrite(mySS,LOW);
  SPI.transfer(S17READ);
  SPI.transfer(0);       // start at register 0
  for(uint8_t i=0;i<22;i++){
    buf[i]= SPI.transfer(0xFF);  // the 0xff value is unused, does not matter
  }
  digitalWrite(mySS,HIGH);
  SPI.endTransaction();  // let other's (interrupt routines use the SPI interface)
  Serial.println();
  Serial.print("registers=");
  for(uint8_t i=0;i<22;i++){
    Serial.print(buf[i],HEX);
    Serial.print(' ');
    }
  }

}

My output looks like this

registers=0 0 0 0 0 0 0 0 0 0 8 8 0 0 00 0 0 9F 20 9F 20

The 9F 20 is an artifact of the last instruction to my LCD. The 20 is a space character.

The first two 0 0 show all PORTA and PORTB pins are output.

Try this code and see if your Expander responds.

Chuck.

Hi Chuck,
OK, possible progress here. I ran your code with the mySS = A4, and the Serial Monitor is showing "registers=0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 " . I changed the mySS = 18, and the same result as above. So, for my understanding, does this mean the MCP23S17 is responding? From reading your code, I think the ports have been set to "0", and the loop is reading the pin status 22 times.

I am using the Nano digital pin 18 as my CS pin - my understanding is by specifying it as 18 makes it digital instead of analog (when A4). Probably doesn't matter as long as set to be "OUTPUT" as evidenced by the results above.

The 32 pin socket was much more available than the 30 pin from DigiKey.

My project uses 2 potentiometers and 3 On/OFF buttons to control 14 relays, with as many as 7 relays on at once. From the way SPI works, writing 0B00111000 to Port A would turn on relays A6, A5, A4, and not the A8, A7, A3-A1. My problem with that is when I change a potentiometer, a different group of relays needs to turn on, BUT not affect the relays that are controlled with the buttons. It seems to me the code will quickly become unmanagable trying to use the Byte(?) or Word functions. I believe I need to control each pin the on the MCP individually - where I can specify any pin as ON or OFF without affecting the other pins. This is why I was looking at the MCP23S17 Library from Cort Buffington - the digitalWrite functions would make this level of control easy.

The code I have been able to run (sort of) is just a shift-in/out register method, and I can specify pins A1, A2, A3 and B1, B2, B3 individually as required - that works fine. But, when I try to control any pins higher than 3 on either Port, it only controls pins 1-3 on either Port. I think something in the register setup in my code is not set right. Does this sound like a good theory? Or should I look at something other than registers?

// MCP23S17 registers setup
const int MCPWRT = 0x40;    //Command to write in MCP23S17 Address $00
const int IOCON  = 0x0A;    //Register address to MCP23S17 Config
const int IODIRA = 0x00;    //Register address to MCP23S17 PortA(1)
const int IODIRB = 0x01;    //Register address to MCP23S17 PortB(2)
const int GPIOA  = 0x12;    //Register address to MCP23S17 GPIOA(1)
const int GPIOB  = 0x13;    //Register address to MCP23S17 GPIOB(2)
const int OLATA  = 0x14;    //Register address to MCP23S17 LATCH-A(1)
const int OLATB  = 0x15;    //Register address to MCP23S17 LATCH-B(2)
//const int MCPREG = 

// SPI software variables
// Warning - the software SPI pins must be defined
// init with zeros so the internal memory is alocated at startup
int  DataPin = 0, DataInPin=0, ClockPin = 0;
byte DataOut=0, MCPReg=0;
int SS1=0, SS2=0;

const int mainPWRrelay = 8; // Main power relay digital out

// ACrelay(R5-10A) = A0   = Port A, MCP pin 0
// Relay1 = A1    
// Relay2 = A2   
// Relay3 = A4   
// Relay4 = A3    
// Relay15 = A5   
// Relay13 = A6   
// Relay14 = A7   
// Relay12 = B0  = Port B, MCP pin 0
// Relay11 = B1   
// Relay10 = B2   
// Relay5 = B3    
// Relay6 = B4    
// Relay7 = B5  
// Relay8 = B6    

// send data to MCP23S17 (software SPI)

void soft_send (int MCPREG, int DATAOUT, int SS2) {   // 
    digitalWrite(SS2, LOW);   // select the chip
    shiftOut(DataPin, ClockPin, MSBFIRST, MCPWRT);  // tell it I wish to send
    shiftOut(DataPin, ClockPin, MSBFIRST, MCPREG); // tell it where I wish to send
    shiftOut(DataPin, ClockPin, MSBFIRST, DATAOUT); // and what I wish to send
    digitalWrite(SS2, HIGH);                                                  
}

void init_soft_bus() {

     DataPin = 12;  // MOSI
     ClockPin = 13; // SCK
     DataInPin = 11; // MISO
     SS2=18;   // Select MCP23S17 Port EXpander
   //SS1=10;   // MCP4241 digital pot
 
     pinMode(DataPin, OUTPUT);            // data output pin - output
     pinMode(DataInPin, INPUT);        // data input pin - this is an input for incoming data
     pinMode(ClockPin, OUTPUT);     // again output - I have to pulse the MCPs in order to get them working
     pinMode(SS2, OUTPUT);   // select pins also outputs
     pinMode(SS1, OUTPUT);

     digitalWrite(SS2, LOW);
     digitalWrite(SS2, HIGH);
     delay(100);
             
     soft_send(IOCON, 0x20, SS2);   // init CS2 MCP23S17 port expander
     soft_send(IODIRA, 0x00, SS2);  // SS2 PORTA = output
     soft_send(IODIRB, 0x00, SS2);  // SS2 PORTB = output         
}

void setup() {
      analogReference(EXTERNAL);
      pinMode(mainPWRrelay, OUTPUT);
      digitalWrite(mainPWRrelay, HIGH);
      delay(2000);
     init_soft_bus();   // configure the MCP23S17 for the GPIOA = output and GPIOB = output
    //Serial.begin(9600);
}

void loop() {
  
   digitalWrite(mainPWRrelay, HIGH); // Main power relay
   delay(200);

   //Port A
   soft_send(GPIOA, 0, SS2); 
   delay(200);  
   soft_send(GPIOA, 1, SS2);   
   delay(200);

   soft_send(GPIOA, 2, SS2);
   delay(500);   
   soft_send(GPIOA, 3, SS2);  
   delay(500);

   soft_send(GPIOA, 4, SS2);  
   delay(800);
   soft_send(GPIOA, 5, SS2);  
   delay(800);
  
   soft_send(GPIOA, 6, SS2);
   delay(1300);   
   soft_send(GPIOA, 7, SS2);   
   //delay(1300);

   //Port B 
   delay(4000);
   soft_send(GPIOB, 0, SS2); 
   delay(200);  
   soft_send(GPIOB, 1, SS2);   
   delay(200);
  
   soft_send(GPIOB, 2, SS2);
   delay(500);   
   soft_send(GPIOB, 3, SS2);  
   delay(500);

   soft_send(GPIOB, 4, SS2);  
   delay(800);
   soft_send(GPIOB, 5, SS2);  
   delay(800);
    
   soft_send(GPIOB, 6, SS2);
   delay(1300);   
   soft_send(GPIOB, 7, SS2);   
   delay(4000);
   
 }

BigAl1:
Hi Chuck,
OK, possible progress here. I ran your code with the mySS = A4, and the Serial Monitor is showing "registers=0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 " . I changed the mySS = 18, and the same result as above. So, for my understanding, does this mean the MCP23S17 is responding? From reading your code, I think the ports have been set to "0", and the loop is reading the pin status 22 times.

no, those 22 bytes of data should be the register values from register 0 to register 0x15 in the '17.

Most of the values are zero by default, but you should see an 8 in register 0x0A (IOCON) and a copy in 0x0B.
Since you are only seeing Zero's you have a problem with the SPI buss. Try connecting a 4.7k ohm between VCC and MISO. rerun the code and see if all of the zeros change to FF. If that happens, it would point that the '17 is not answering.

I would step back and write some simple bit twiddleing code for debuging.

First, just code that sets MOSI as output, SS as output, MISO as input and SCK as output.
Use these name, don't convert to pin numbers. Let the Arduino environment do the conversion for you.
(one less possible error :slight_smile: )

Have it just set all the outputs to HIGH, use your DVM to check the MOSI,SCK and CS pins at the '17.
If they are all good(5v) then on to the next stage.

then twiddle SS from LOW to HIGH every 5 seconds. You should be able to see the 5V -> 0V -> 5V on the '17 CS pin with your DVM. If that works then do MOSI, then SCK.

If all of those tests work then we will have to try something else.

If Reset is high then we should be able to send to the '17. It just needs SS,MOSI,SCK + GND,VCC to output data to PORTA and PORTB, MISO is only used for read back.

If your Nano can twiddle MOSI, SCK and SS at the '17 the only possible failure is the '17.

Chuck

Thanks for the idea to name MOSI, MISO, SCK to minimize error sources - good to practice! I did keep the Nano pin 18 as itself, not named SS. I ran the following code with success, and got these results;

SO pin on the MCP23S17 shows 5.00V for a second, floating voltage 183-500mV otherwise
SI pin on the MCP23S17 shows 5.03V for a second, floating voltage 7-22mV otherwise
SCK pin on MCP23S17 shows 4.92V for a second, floating voltage 7-17mV otherwise
CS pin on MCP23S17 shows 4.37V for a second, floating voltage 7-9mV otherwise

I also ran the same code with the pins called specifically by number instead of MISO, MOSI, SCK - same results. All voltages measured by probing the MCP pins on the DIP package, so the traces and sockets from Nano to the MCP are working.

When I changed the pin 18 to SS, no signal at the CS pin on the MCP23S17 - this makes sense as the SPI standard for SS is pin 10 on the Nano. So, probed that, and do see pin 10 on the Nano show 5.03V briefly, so the SPI settings are working correctly.

#include <SPI.h>


void setup() {
  analogReference(EXTERNAL);
  pinMode(8, OUTPUT);
  digitalWrite(8, HIGH);
  delay(1000);
  
  //Serial.begin(9600);
  
  pinMode(10, OUTPUT);  //CS1
  pinMode(MISO, OUTPUT);  //MISO  but testing as output
  pinMode(MOSI, OUTPUT);  //MOSI
  pinMode(SCK, OUTPUT);  //SCK
  pinMode(18, OUTPUT);  //CS2
  

}


void loop() {
 digitalWrite(MISO, HIGH);
 delay(1500);
 digitalWrite(MISO, LOW);
 delay(500);
 digitalWrite(MOSI, HIGH);
 delay(1500);
 digitalWrite(MOSI, LOW);
 delay(500); 
 digitalWrite(SCK, HIGH);
 delay(1500);
 digitalWrite(SCK, LOW);
 delay(500); 
 digitalWrite(18, HIGH);
 delay(1500);
 digitalWrite(18, LOW);
 delay(500);
}

I looked closely at the MCP chip - took it out and reset into the socket. Then reloaded your last test code - same result as before - 22 "0"s in the Serial Monitor screen. Next I replaced the MCP chip with a new one, same result - all "0"s in the Serial Monitor.
I have not tried the 4.7K resistor between MISO and VCC - tomorrow evening. Thanks for the feedback and ideas - I already had the test code above done, just changed the pins from pin numbers to the MISO, MOSI, SCK as suggested. But, good to run it again to know nothing came loose or fried since I last tested it.

BigAl1:
I looked closely at the MCP chip - took it out and reset into the socket. Then reloaded your last test code - same result as before - 22 "0"s in the Serial Monitor screen. Next I replaced the MCP chip with a new one, same result - all "0"s in the Serial Monitor.
I have not tried the 4.7K resistor between MISO and VCC - tomorrow evening. Thanks for the feedback and ideas - I already had the test code above done, just changed the pins from pin numbers to the MISO, MOSI, SCK as suggested. But, good to run it again to know nothing came loose or fried since I last tested it.

another test you can do,

// manual SPI


#define mySS A4
// manual SPI

uint8_t mySPIBit(uint8_t *data){
uint8_t din=0;

digitalWrite(SCK,LOW);
if(*data & 128) digitalWrite(MOSI,HIGH);
else digitalWrite(MOSI,LOW);
delayMicroseconds(10); // really slow SPI, only 50khz, let device output it's bit on MISO 
digitalWrite(SCK,HIGH); // device reads the MOSI bus on the LOW->HIGH SCK translation
if(digitalRead(MISO)) din = 1;
delayMicroseconds(10);
*data = *data << 1;
return din;
} 

uint8_t mySPIByte(uint8_t data, char* ch){
uint8_t din=0;
for(uint8_t i = 0; i<8; i++){
 ch[i]= (data&128) ? '1' : '0'; // reflect high bit value into ch[]
 din = din << 1; // make room for next bit
   din = din | mySPIBit(&data);
 ch[i+9] = (din&1) ? '1' : '0'; // reflect read bit value into ch[]
  }
// 8th bit has transferd, return clock to low (SPI MODE0)
digitalWrite(SCK,LOW);
ch[8]=' ';
ch[17]='\0';
return din;
}

void readit(){
char buf[24][18];

digitalWrite(mySS,LOW);
mySPIByte(0x41,buf[0]); // read command for '17
for(uint8_t i = 0;i<23;i++){ // send 0 .. 22, for a total of 23 bytes
  mySPIByte(i,buf[i+1]);
  }
digitalWrite(mySS,HIGH);

Serial.println("read SPI");
for(uint8_t i=0;i<24;i++){
 Serial.print(i,DEC);
 Serial.print(' ');
 Serial.println(buf[i]);
  }
}

void setup(){
pinMode(mySS,OUTPUT);
digitalWrite(mySS,HIGH);
pinMode(MOSI,OUTPUT);
pinMode(SCK,OUTPUT);
digitalWrite(SCK,LOW);
pinMode(MISO,INPUT_PULLUP);

Serial.begin(9600);

pinMode(2,INPUT_PULLUP); // pin 2 becomes an input , active low
}

static bool sw=false;
void loop(){
if(digitalRead(2)){ // not closed, 'switch' released, ready for next switch closure
  sw=true;
}
else {
 if(sw){ // this is first detection
  readit();
 sw=false; // mark already used
  }
  }
}

to use this code, start out by removing the '17 from the socket.

The code use Digital Pin2 as a switch, If that causes problems either change it to an unused pin or totally remove it. I just used it so that I could move a jumper without resetting my UNO.

With this code you can see what goes out(MOSI) and what comes in (MISO).

It is written to allow you to test MOSI, and MISO, on a UNO, MISO is 12, MOSI is 11. There are three tests possible.
First, just run the code. you should see this.

read SPI
0 01000001 11111111
1 00000000 11111111
2 00000001 11111111
3 00000010 11111111
4 00000011 11111111
5 00000100 11111111
6 00000101 11111111
7 00000110 11111111
8 00000111 11111111
9 00001000 11111111
10 00001001 11111111
11 00001010 11111111
12 00001011 11111111
13 00001100 11111111
14 00001101 11111111
15 00001110 11111111
16 00001111 11111111
17 00010000 11111111
18 00010001 11111111
19 00010010 11111111
20 00010011 11111111
21 00010100 11111111
22 00010101 11111111
23 00010110 11111111

Then connect a jumper from pin 11(MOSI) to 12(MISO)

read SPI
0 01000001 01000001
1 00000000 00000000
2 00000001 00000001
3 00000010 00000010
4 00000011 00000011
5 00000100 00000100
6 00000101 00000101
7 00000110 00000110
8 00000111 00000111
9 00001000 00001000
10 00001001 00001001
11 00001010 00001010
12 00001011 00001011
13 00001100 00001100
14 00001101 00001101
15 00001110 00001110
16 00001111 00001111
17 00010000 00010000
18 00010001 00010001
19 00010010 00010010
20 00010011 00010011
21 00010100 00010100
22 00010101 00010101
23 00010110 00010110

Then Jumper 12(MISO) to Gnd

read SPI
0 01000001 00000000
1 00000000 00000000
2 00000001 00000000
3 00000010 00000000
4 00000011 00000000
5 00000100 00000000
6 00000101 00000000
7 00000110 00000000
8 00000111 00000000
9 00001000 00000000
10 00001001 00000000
11 00001010 00000000
12 00001011 00000000
13 00001100 00000000
14 00001101 00000000
15 00001110 00000000
16 00001111 00000000
17 00010000 00000000
18 00010001 00000000
19 00010010 00000000
20 00010011 00000000
21 00010100 00000000
22 00010101 00000000
23 00010110 00000000

good luck.

Chuck.

Hi Chuck,
I used a 4.7K resistor to jumper MISO to +5V on the Nano, and watching the Serial Monitor the "0"s changed to "FF", when running your test code with pin 18 (A4) as SS. So this is saying the MCP is not communicating with the Nano?
I tried to do your test from last post, but when I load your sketch, nothing happens in the Serial Monitor. I tried removing

 pinMode(2,INPUT_PULLUP); // pin 2 becomes an input , active low
  • no change - nothing in the Serial Monitor. Also tried changing it to pin A5, and changed it to pin 3, and tried MOSI and MISO -no change. It compiles fine, but not working with my hardware for the things I have tried, and I'm not good enough at reading your code to see if there is something to change to get it working with my hardware.

Back to a basic question - the code that has been partially working for me uses shift-in/out to send data to the MSP23S17. By using the shift-in/out method, is my code limited to only the first 3 pins on Ports A and B? And, is this method giving me a false sense of "It's working!" ?

I know you said to prove the connection to the MCP is good before writing any code - that makes perfect sense. My bittwiddler code was showing a +5V signal for all the important pins to feed the MCP, so I'm confident the MCP is connected correctly to the Nano. I have MCP23S17 pins A0,A1,A2 all tied together and going to GND. The MCP Reset pin is tied to +5V. At the Nano I'm using digital pin 18 as SS, and standard MOSI, MISO, SCK pins for the other data connections. I keep coming back to "It partially works!" - that tells me the MCP connection is working correctly, and I need to fix a setting in my sketch to get the rest of the MCP to respond. Unless you have another test suggestion that will help your diagnosis, let me have a few days to work on a simple SPI based sketch to see if I can control individual '17 pins. Again, thank you for your help and time - I learned a few tricks in this thread. I will get back on this thread when I have a SPI test code working.

BigAl1:
Hi Chuck,
I used a 4.7K resistor to jumper MISO to +5V on the Nano, and watching the Serial Monitor the "0"s changed to "FF", when running your test code with pin 18 (A4) as SS. So this is saying the MCP is not communicating with the Nano?
I tried to do your test from last post, but when I load your sketch, nothing happens in the Serial Monitor. I tried removing

 pinMode(2,INPUT_PULLUP); // pin 2 becomes an input , active low
  • no change - nothing in the Serial Monitor. Also tried changing it to pin A5, and changed it to pin 3, and tried MOSI and MISO -no change. It compiles fine, but not working with my hardware for the things I have tried, and I'm not good enough at reading your code to see if there is something to change to get it working with my hardware.

Back to a basic question - the code that has been partially working for me uses shift-in/out to send data to the MSP23S17. By using the shift-in/out method, is my code limited to only the first 3 pins on Ports A and B? And, is this method giving me a false sense of "It's working!" ?

I know you said to prove the connection to the MCP is good before writing any code - that makes perfect sense. My bittwiddler code was showing a +5V signal for all the important pins to feed the MCP, so I'm confident the MCP is connected correctly to the Nano. I have MCP23S17 pins A0,A1,A2 all tied together and going to GND. The MCP Reset pin is tied to +5V. At the Nano I'm using digital pin 18 as SS, and standard MOSI, MISO, SCK pins for the other data connections. I keep coming back to "It partially works!" - that tells me the MCP connection is working correctly, and I need to fix a setting in my sketch to get the rest of the MCP to respond. Unless you have another test suggestion that will help your diagnosis, let me have a few days to work on a simple SPI based sketch to see if I can control individual '17 pins. Again, thank you for your help and time - I learned a few tricks in this thread. I will get back on this thread when I have a SPI test code working.

The pin 2 was used as a simple switch.

use a jumper from pin 2 to ground. When the program sees pin 2 grounded, it starts a sample cycle. I used it so that I can change the test parameters, and control when a test starts.

Test 1:
place a jumper between Pins 11 and 12.
Touch jumper from pin 2 to ground.

Program outputs

second test pattern. This shows that Pin 11 (MOSI) is outputing and Pin 12 (MISO) can read the output.

Test 2:
place a jumper from pin 12 (MISO) to GND.
Touch Jumper from pin 2 to ground

Program outputs

third test pattern. Show Pin 12 can read 0's

Test 3:
No jumper on pin 12.

touch Jumper from pin 2 to ground

Program outputs

First test Patterm. all of the second binary value should be 1's. If any zero show up there is a problem.

Test 4:

At the '17 socket retry test 1 and 2. Instead of MOSI,MISO use SO (pin 14), SI(pin13) This verifies connectivity to the '17.
Pin 14 is (MISO) it is the one you should ground for test 2.

Chuck.

Thanks for the instructions Chuck - great help! I removed my MCP23S17 from the socket, and jumpered the SO/SI socket terminals (which are connected to MISO(11)/MOSI(12) on the Nano). This is your Test 1 above, and something happened! The output matches the second sample in #9 post above - the first group and second group on each line are the same. I can't figure out how to copy/paste from the Serial Monitor screen - be a handy thing to be able to do for diagnostic sessions like this!

The Test 2 above, I jumpered the SO socket terminal to GND, did the Pin D2 touch to GND, and the output looks like your FIRST expected output in #9 post - where the first group of digits per line is "0"s or "1"s in various combinations, and the second group is all "1"s. This is different than what you expected in post #9 for the MISO jumpered to GND - you expected the second group on each line to be all "0"s.

In Test 3 above, I removed the jumper from SO to GND - no jumper installed on the '17 socket, and the MCP23S17 not installed. I touched the pin D2 to GND, and found the following Serial Monitor output.

read SPI
0 01000001 11111111
1 00000000 11111111
2 00000001 11100011 This line has some "0"s - you mentioned that indicates something wrong.
3 00000010 11111111
All the rest of the lines to 23 are the same last group as line 3 above - all "1"s, no matter what the first group is.

As a last test, I reinstalled the '17 in the socket, and ran the Test 3 above - no jumpers. The output matches your first output in post #9 - where no jumpers added - "just run the code". All lines 0-23 have the second group as all "1"s.

As a cross check, I tested continuity between pin GND on the Nano, to GND on the MCP23S17 pin, to my common GND on the board connector - all are connected.

I'm feeling better Chuck - your test code has shown some differences vs what you expected, so if this points to something wrong, that's great! Problems can be fixed! Thanks for your time and patience with me!

BigAl1:
Thanks for the instructions Chuck - great help! I removed my MCP23S17 from the socket, and jumpered the SO/SI socket terminals (which are connected to MISO(11)/MOSI(12) on the Nano). This is your Test 1 above, and something happened! The output matches the second sample in #9 post above - the first group and second group on each line are the same. I can't figure out how to copy/paste from the Serial Monitor screen - be a handy thing to be able to do for diagnostic sessions like this!

The Test 2 above, I jumpered the SO socket terminal to GND, did the Pin D2 touch to GND, and the output looks like your FIRST expected output in #9 post - where the first group of digits per line is "0"s or "1"s in various combinations, and the second group is all "1"s. This is different than what you expected in post #9 for the MISO jumpered to GND - you expected the second group on each line to be all "0"s.

In Test 3 above, I removed the jumper from SO to GND - no jumper installed on the '17 socket, and the MCP23S17 not installed. I touched the pin D2 to GND, and found the following Serial Monitor output.

read SPI
0 01000001 11111111
1 00000000 11111111
2 00000001 11100011 This line has some "0"s - you mentioned that indicates something wrong.
3 00000010 11111111
All the rest of the lines to 23 are the same last group as line 3 above - all "1"s, no matter what the first group is.

As a last test, I reinstalled the '17 in the socket, and ran the Test 3 above - no jumpers. The output matches your first output in post #9 - where no jumpers added - "just run the code". All lines 0-23 have the second group as all "1"s.

As a cross check, I tested continuity between pin GND on the Nano, to GND on the MCP23S17 pin, to my common GND on the board connector - all are connected.

I'm feeling better Chuck - your test code has shown some differences vs what you expected, so if this points to something wrong, that's great! Problems can be fixed! Thanks for your time and patience with me!

The test code enables the INPUT PULLUPS (50k) on the MISO. Those 0's in byte 2 have me worried. Based on what I could see from your Jpegs, The SPI bus should only connect from the '17 to the Nano.

Have you measured resistance with the relayboard pluggin? from the Nano Socket to the '17 Socket? it should be around zero ohms. As low as your meter can read. I though maybe you had MISO connected to SI, the bus reversed. I did that ONCE!

When you have the jumper between SO and SI at the '17 socket do the patterns match?

read SPI
0 01000001 01000001
1 00000000 00000000
2 00000001 00000001
3 00000010 00000010
4 00000011 00000011
5 00000100 00000100
6 00000101 00000101
7 00000110 00000110
8 00000111 00000111
9 00001000 00001000
10 00001001 00001001
11 00001010 00001010
12 00001011 00001011
13 00001100 00001100
14 00001101 00001101
15 00001110 00001110
16 00001111 00001111
17 00010000 00010000
18 00010001 00010001
19 00010010 00010010
20 00010011 00010011
21 00010100 00010100
22 00010101 00010101
23 00010110 00010110

You might write code that just sets up MISO as input and MOSI as output, jumper them at the '17 then measure the voltage on MISO while driving MOSI HIGH then LOW. Those voltage reading should be zero volts and pretty close to 5v. If they are not, you have a short somewhere. The Nano can source and sink about 20mA per pin. The 50k pullup (where you saw the error) are pretty weak. for the Nano to interpret the signal as a LOW, the voltage on the pin has to be below 1.5V. so if we assume there is a short to ground fault. a simple voltage divider with the 50k on top would only need 21.4k to ground to produces this situation. So the short is pretty 'high' resistance.

To test for this 'high' resistance to GND, Just configure MISO as an input with the PULLUP enabled. You should read 5V on the pin. If not you will have to find the 'short'

Another Test:
Remove both the Nano and the '17. Measure resistance from GND to each of the SPI bus pins. you should have infinite resistance. Also try VCC. If you have any resistance, there is your 'fault'.

Chuck.

Hi Chuck,
I removed my '17 from the socket, and jumpered SO to SI, then plugged the second board back into the first, ran your test code again, and see the return pattern you show above - yes, every line has the first and second groups matched.

With the '17 removed, and the SO still jumpered to SI, I wrote a little sketch like you described, and then probed the pins on the Nano. Both pin D11 and D12 show 4.40V on High, and 2.1mV on Low, alternating every 2 seconds. This is using USB power from my PC to run the Nano. These numbers are well within the min/max limits for 5V logic - per Logic Levels - SparkFun Learn .

#define mySS A4


void setup() {
  analogReference(EXTERNAL);
  pinMode(8, OUTPUT);
  digitalWrite(8, HIGH);
  delay(1000);

  pinMode(mySS, OUTPUT);
  pinMode(MOSI, OUTPUT);
  pinMode(MISO, INPUT_PULLUP);
  pinMode(SCK, OUTPUT);
  digitalWrite(SCK, LOW);

  Serial.begin(9600);
  
}

void loop() {
  digitalWrite(MOSI, HIGH);
  delay(2000);
  digitalWrite(MOSI, LOW);
  delay(2000);
}
[code]

Next, I pulled the USB power out, and did some Ohm checking with the DVM set to most sensitive range (000.0 Ohms).  I removed the jumper from SO to SI, and probed the following with these results.

Nano D11 to '17 SO socket terminal = 0.2 - 0.3 Ohm
Nano D12 to '17 SI socket terminal = 0.1 - 0.2 Ohm
Nano D13 to '17 SCK socket terminal = 0.1 Ohm
Nano A4 to '17 CS2 (CS) socket terminal = 0.1 - 0.2 Ohm

Also did continuity check for the '17 socket terminals SO, SI, SCK, CS - cross checking the adjoining pins to check for a solder bridge, no flaws.  Also check each of these to GND - no flaws there either.  I use a 10X loupe to check my solder joints - all look good on these boards.

Checked for A0,A1,A2 all connected to GND - good there.
Checked GND at '17 socket is connected to GND for the system - yep ok there.
The +5V socket terminal for the '17 is connected to +5V from main board with Nano on it.

I tried your last test code again, with SO jumpered to GND at the '17 socket, no '17 installed.  This shows the first group as the "0"s and "1"s, and all 8 digits of each second group are "1"s.  This is opposite what you were expecting - you showed all "0"s for the second group on this test.
And the same code again, no '17 installed, but no jumper at all - the results are below.

read SPI
0  01000001  11111111
1  00000000  11111111
2  00000001  11100111   Note, there are 2 "0"s on this line, but the previous test had 3.
3  00000010  11111111
As before, the rest of the second groups are all "1"s.

Tried a new tact - replaced the Nano I have been using with a brand new one.  Uploaded the same test code as above, and the results are now all "1"s for the second group - all 23 lines!

Something that may be odd - my INTA and INTB on the '17 socket are not tied to anything.

I tried running my original shift in/shift out sketch, it appears to be doing the same as before - no relays higher than Port A #3 or Port B #3 are working.  I'm going to work on a simple SPI sketch to check relay functions for all 14 relays.
If you have any other ideas, let me know!  All this has been great learning for me - you are far more thorough than I have been up until now.  Thanks for your help Chuck!

BigAl1:
Hi Chuck,
I removed my '17 from the socket, and jumpered SO to SI, then plugged the second board back into the first, ran your test code again, and see the return pattern you show above - yes, every line has the first and second groups matched.

With the '17 removed, and the SO still jumpered to SI, I wrote a little sketch like you described, and then probed the pins on the Nano. Both pin D11 and D12 show 4.40V on High, and 2.1mV on Low, alternating every 2 seconds. This is using USB power from my PC to run the Nano. These numbers are well within the min/max limits for 5V logic - per Logic Levels - SparkFun Learn .

I don't have any more guesses. I could look a your schematic, maybe there is something as weird as those board edge connectors shorting, I had a PCB with a tunnel (void) that was filled when the board was plated. It connected 2 not adjacent datalines. Passing UNDER one trace. But, My meter did show the resistance. I ended up doing a binary search with an exacto knife. Too me about 5 cuts to find that little sucker. Of course I had to cutout 10 IC's first!

How about this test:

write code that sets all Arduio pins as input with pullup, loop through each pin, Output, HIGH, LOW while reading MISO. maybe there is a short between pins at the Nano's socket.

Or your code could set one pin as output while reading every other pin as input. Cycle the output pin and read every other pin. Something has to show up.

Those 0's should not be there. Something must be driving them. With just the PULLUPS, there is 0.1mA driving MISO, something is working against it.

The way I wrote the manualSPI, I purposely did not change any other pin while the SPI write/read was taking place. I built up the output string, and only sent it out TX after the SPI twiddling was done.

There has to be some kind of cross connect in the hardware, a capacitance, or inductive. Something!

Do you ever wonder why most IC's and Diodes are made from BLACK epoxy? Light is energy, and many semiconductors are light sensitive. I had a circuit exposed to electric arc's that was misbehaving. It turned out the bright light was upsetting the circuit. I had expected it to be a magnetic induction, but a simple piece of black plastic covering the circuit fixed my problems. So it was definitely the bright lights causing my problems.

So, think outside your 'box', don't limit the possibilities because they seem impossible, check everything and anything.

Chuck.

Chuck.

Thanks Chuck. I re-read my last post and found there was more to it, but I had it inside the
code snippet section. Here is the rest of my post.

Next, I pulled the USB power out, and did some Ohm checking with the DVM set to most sensitive range (000.0 Ohms). I removed the jumper from SO to SI, and probed the following with these results.

Nano D11 to '17 SO socket terminal = 0.2 - 0.3 Ohm
Nano D12 to '17 SI socket terminal = 0.1 - 0.2 Ohm
Nano D13 to '17 SCK socket terminal = 0.1 Ohm
Nano A4 to '17 CS2 (CS) socket terminal = 0.1 - 0.2 Ohm

Also did continuity check for the '17 socket terminals SO, SI, SCK, CS - cross checking the adjoining pins to check for a solder bridge, no flaws. Also check each of these to GND - no flaws there either. I use a 10X loupe to check my solder joints - all look good on these boards.

Checked for A0,A1,A2 all connected to GND - good there.
Checked GND at '17 socket is connected to GND for the system - yep ok there.
The +5V socket terminal for the '17 is connected to +5V from main board with Nano on it.

I tried your last test code again, with SO jumpered to GND at the '17 socket, no '17 installed. This shows the first group as the "0"s and "1"s, and all 8 digits of each second group are "1"s. This is opposite what you were expecting - you showed all "0"s for the second group on this test.
And the same code again, no '17 installed, but no jumper at all - the results are below.

read SPI
0 01000001 11111111
1 00000000 11111111
2 00000001 11100111 Note, there are 2 "0"s on this line, but the previous test had 3.
3 00000010 11111111
As before, the rest of the second groups are all "1"s.

Tried a new tact - replaced the Nano I have been using with a brand new one. Uploaded the same test code as above, and the results are now all "1"s for the second group - all 23 lines!

Something that may be odd - my INTA and INTB on the '17 socket are not tied to anything.

I tried running my original shift in/shift out sketch, it appears to be doing the same as before - no relays higher than Port A #3 or Port B #3 are working. I'm going to work on a simple SPI sketch to check relay functions for all 14 relays.
If you have any other ideas, let me know! All this has been great learning for me - you are far more thorough than I have been up until now. Thanks for your help Chuck!