3

I found this post and I am having almost the exact same issue. Nick Gammon (the god of arduino) has an excellent answer but I can't for the life of me implement it myself. I am not an advanced user like the initial question asker.

So What I want to do is use 2 MCP23S17's (picture here). I have been messing with one of them all week and have it reading like a charm. I am using the githib library by n0mjs710 to do this. But writing to one will not work.

Along with the zipped library is a few examples. I am trying to read some BCD switches off of one "input MCP" and then display the digits on the "output MCP"

I have used external pullups so I did make one change to the code by commenting out the call for pullups. Here is what Doesn't work:

#include <SPI.h>              // We use this library, so it must be called here.
#include <MCP23S17.h>         // Here is the new class to make using the MCP23S17 easy.

MCP inputchip(1, 10);             // Instantiate an object called "inputchip" on an MCP23S17 device at address 1
                                  // and slave-select on Arduino pin 10
MCP outputchip(2, 10);            // Instantiate an object called "outputchip" on an MCP23S17 device at address 2
                                  // and slave-select on Arduino pin 10

void setup() {
  inputchip.begin();
  outputchip.begin();
  inputchip.pinMode(0xFFFF);     // Use word-write mode to set all of the pins on inputchip to be inputs
  //inputchip.pullupMode(0xFFFF);  // Use word-write mode to Turn on the internal pull-up resistors.
  inputchip.inputInvert(0xFFFF); // Use word-write mode to invert the inputs so that logic 0 is read as HIGH
  outputchip.pinMode(0x0000);    // Use word-write mode to Set all of the pins on outputchip to be outputs
}

void loop() {
  int value;                        // declare an integer to hold the value temporarily.
  value = inputchip.digitalRead();  // read the input chip in word-mode, storing the result in "value"
  outputchip.digitalWrite(value);   // write the output chip in word-mode, using our variable "value" as the argument
  // outputchip.digitalWrite(inputchip.digitalRead()); // this one line replaces the three above, and is more efficient
}

I have tried:

  • slowing the SPI bus by changing the library to SPI_Divide the clock by 2
  • changing the ss line and even splitting the lines so one chip uses pin 10 and the other uses pin 9

So after reading Mr. Gammon's post I have made some changes to the code attempting to rid myself of the old slave select pin low trick he mentioned. Here is my attempt:

MCP inputchip(1, 10);             // Instantiate an object called "inputchip" on an MCP23S17 device at address 1
                                  // and slave-select on Arduino pin 10
MCP outputchip(2, 9);            // Instantiate an object called "outputchip" on an MCP23S17 device at address 2
                                  // and slave-select on Arduino pin 10
int ssPin = 9;

void setup() {
  pinMode(ssPin,OUTPUT);

  inputchip.begin();
  digitalWrite(ssPin, HIGH);
  digitalWrite(ssPin, LOW);
  outputchip.begin();
  inputchip.pinMode(0xFFFF);     // Use word-write mode to set all of the pins on inputchip to be inputs
  //inputchip.pullupMode(0xFFFF);  // Use word-write mode to Turn on the internal pull-up resistors.
  inputchip.inputInvert(0xFFFF); // Use word-write mode to invert the inputs so that logic 0 is read as HIGH
  digitalWrite(ssPin, HIGH);
  digitalWrite(ssPin, LOW);
  outputchip.pinMode(0x0000);    // Use word-write mode to Set all of the pins on outputchip to be outputs
}

void loop() {
  int value;
  // declare an integer to hold the value temporarily.
  value = inputchip.digitalRead();  // read the input chip in word-mode, storing the result in "value"
  digitalWrite(ssPin, HIGH);
  digitalWrite(ssPin, LOW);
  outputchip.digitalWrite(value);   // write the output chip in word-mode, using our variable "value" as the argument
}

So any advice would be great to get this working. Help me Obi wan Gammon your me only hope.

  • Try my library instead. That one looks horrible. github.com/MajenkoLibraries/MCP23S17 – Majenko Aug 18 '16 at 23:23
  • I agree with Majenco...that one looks hard...I am no expert but i used the Adafruit library and found it very friendly... github.com/adafruit/Adafruit-MCP23017-Arduino-Library – Doug Aug 19 '16 at 11:23
  • I will try yours now Mr. Majenko. Doug the library you posted is for the I2C version of the chip. I have worked with it before and found it excellent but must use the SPI for some applications. – enterprisingsoul Aug 19 '16 at 15:32
  • I have one question. Once you set the PinMode of an expander then can you change the mode without giving a reset? I mean, I have to use 3 expanders for controlling an SRAM: on one MCP I have the data lines, on the second one I have the control signals and on the last one I have the address lines. Firstly, I do a SRAM_WRITE, so I need the pins of the first expander to be OUTPUTs,then I do a READ_SRAM so a need the pins of the first expander to be INPUTs. Can I change the mode from output to input? Then I am trying to check the signals with an oscilloscope. When a do a pinMode OUTPUT of the expa – Gabriele Feb 2 '18 at 10:17
2

Majenko's library works. All praise to Majenko https://github.com/MajenkoLibraries/MCP23S17

| improve this answer | |
  • Nick is only a Demi-god :P I am Zeus and Odin rolled into one. Maybe I should change my name to Zein ... or Odus...? ;) – Majenko Aug 19 '16 at 23:58
1

This sketch uses the Majenko Library with two MCP23S17 chips to demonstrate the library functions.

It was tested on an Arduino Uno with IDE 1.6.5.

/*
 * MultiTest_Majenko_02.ino
 * Library Ref: github.com/MajenkoLibraries/MCP23S17
 * 
 * Lowell Bahner
 * 2016-12-11
 *
 * Hardware: Arduino UNO
 * IDE: Arduino 1.6.5
 * 
 * Useful SPI Ref: gammon.com.au/spi
 * 
 * Wire the SPI Interface common lines (Mega2560 SPI pins shown in [ ]):
 * Arduino SPI_MOSI pin 11 [51] <->   SI  MCP23S17 pin 13
 * Arduino SPI_MISO pin 12 [50] <->   SO  MCP23S17 pin 14
 * Arduino SPI_CLOCK pin 13 [52]<->   SCK MCP23S17 pin 12
 * Arduino SPI_CS pin 10 [53]   <->   SS  MCP23S17 pin 11
 * MCP23S17 VDD pin 9 to +5V
 * MCP23S17 VSS pin 10 to Gnd
 * MCP23S17 Reset pin 18 to +5V 
 * MCP23S17 Interrupt pins 19-20
 * MCP23S17 A0,A1,A2 pins connect to Gnd or +5V (000 = Address 0, 100 = Address 1, 010 = Address 2, etc)
 * MCP23S17 Port A pins are chip pins 21-28
 * MCP23S17 Port B pins are chip pins 1-8
 * 
 * This sketch runs a series of functions to demonstrate library capabilities.
 * This sketch does not demonstrate interrupt functionality.
 *  
 * This sketch instantiates 2 MCP23S17 chips.
 * Bank2 (MCP23S17 address 1) pins are set as INPUT or INPUT_PULLUP.
 *    Normally HIGH, use switch to set a pin LOW.
 * Bank1 (MCP23S17 address 0) pins are set as OUTPUT.
 *    MCP23S17 outputs will power LEDs up to 25ma through 1000ohm resistor to ground.
 *
 * Majenko MCP23S17 library functions (see .h,.cpp files for details):
 *
 *  bank.pinMode(uint8_t pin, uint8_t mode)
 *    where modes are:
 *      OUTPUT - sets pin HIGH
 *      INPUT  - sets pin LOW for sensing change to HIGH +V
 *      INPUT_PULLUP - sets pin HIGH for sensing change to LOW 0V
 *
 *  bank.digitalWrite(uint8_t pin, uint8_t value)
 *    if mode=OUTPUT, pin value = LOW (0) or HIGH (1)
 *    if mode=INPUT, value LOW disables pullup on pin, value HIGH enables pullup on pin
 *
 *  uint8_t value = bank.digitalRead(uint8_t pin)
 *    read the state of the pin
 *
 *  uint8_t value = bank.readPort(uint8_t port)
 *    read entire 8-bit port of all INPUT pins on Port A (port=0) or Port B (port>=1)
 *
 *  uint16_t longValue = bank.readPort()
 *    read both ports as 16-bit combined
 *
 *  bank.writePort(uint8_t port, uint8_t val)
 *    write val (0 or 1, hex example 0x55) to all OUTPUT pins on Port A (port=0) or Port B (port>=1)
 *
 *  bank.writePort(uint16_t val)
 *    write val (hex example 0x55AA) to all OUTPUT pins on Port A and Port B
 *
 *  Also, interrupt functions are defined:
 *      enableInterrupt(uint8_t pin, uint8_t type);
 *      void disableInterrupt(uint8_t pin);
 *      void setMirror(boolean m);
 *      uint16_t getInterruptPins();
 *      uint16_t getInterruptValue();
 *      void setInterruptLevel(uint8_t level);
 *      void setInterruptOD(boolean openDrain);
 *
 *
 *
 *
Run Sketch: Serial Monitor Output

 -- RWpins() --

Bank2: Switch i15: 1 (Push button switch not pushed, Bank2 INPUT pin 15 is HIGH +5V)
Bank1: Output j4:  1 (Bank1 OUTPUT pin 4 is HIGH.
                      Arduino pin 7 is set HIGH.
                      LED on pin 4 is ON. LED on pin 7 is ON.)

Bank2: Switch i15: 0 (Push button switch pushed, grounds Bank2 INPUT pin 15)
Bank1: Output j4:  0 (Bank1 OUTPUT pin 4 switches to LOW.
                      Arduino pin 7 is set LOW.
                      LED on pin 4 is OFF. LED on pin 7 is OFF.)

 -- RWport() --

Bank1: Port A BIN: 00000000
Bank1: Port B BIN: 00000000

Bank1: Port A BIN: 11110100  DEC: 244
Bank1: Port B BIN: 00001011  DEC: 11

 -- RWlongPortValue() --

Bank1: Port A & B BIN: 0000101111110100  HEX: 0x0BF4    DEC: 3060

 -- RWlongPort() --

Bank1: Port A & B BIN: 1011100101000010  HEX: 0xB942    DEC: 47426

 -- CyclePins() --

Bank1: Port A & B BIN: 0000000000000000  HEX: 0x0000    DEC: 0
Bank1: Port A & B BIN: 0000000000000001  HEX: 0x0001    DEC: 1
Bank1: Port A & B BIN: 0000000000000011  HEX: 0x0003    DEC: 3
Bank1: Port A & B BIN: 0000000000000111  HEX: 0x0007    DEC: 7
Bank1: Port A & B BIN: 0000000000001111  HEX: 0x000F    DEC: 15
Bank1: Port A & B BIN: 0000000000011111  HEX: 0x001F    DEC: 31
Bank1: Port A & B BIN: 0000000000111111  HEX: 0x003F    DEC: 63
Bank1: Port A & B BIN: 0000000001111111  HEX: 0x007F    DEC: 127
Bank1: Port A & B BIN: 0000000011111111  HEX: 0x00FF    DEC: 255
Bank1: Port A & B BIN: 0000000111111111  HEX: 0x01FF    DEC: 511
Bank1: Port A & B BIN: 0000001111111111  HEX: 0x03FF    DEC: 1023
Bank1: Port A & B BIN: 0000011111111111  HEX: 0x07FF    DEC: 2047
Bank1: Port A & B BIN: 0000111111111111  HEX: 0x0FFF    DEC: 4095
Bank1: Port A & B BIN: 0001111111111111  HEX: 0x1FFF    DEC: 8191
Bank1: Port A & B BIN: 0011111111111111  HEX: 0x3FFF    DEC: 16383
Bank1: Port A & B BIN: 0111111111111111  HEX: 0x7FFF    DEC: 32767
Bank1: Port A & B BIN: 1111111111111111  HEX: 0xFFFF    DEC: 65535

Bank1: Port A & B BIN: 1111111111111111  HEX: 0xFFFF    DEC: 65535
Bank1: Port A & B BIN: 0111111111111111  HEX: 0x7FFF    DEC: 32767
Bank1: Port A & B BIN: 0011111111111111  HEX: 0x3FFF    DEC: 16383
Bank1: Port A & B BIN: 0001111111111111  HEX: 0x1FFF    DEC: 8191
Bank1: Port A & B BIN: 0000111111111111  HEX: 0x0FFF    DEC: 4095
Bank1: Port A & B BIN: 0000011111111111  HEX: 0x07FF    DEC: 2047
Bank1: Port A & B BIN: 0000001111111111  HEX: 0x03FF    DEC: 1023
Bank1: Port A & B BIN: 0000000111111111  HEX: 0x01FF    DEC: 511
Bank1: Port A & B BIN: 0000000011111111  HEX: 0x00FF    DEC: 255
Bank1: Port A & B BIN: 0000000001111111  HEX: 0x007F    DEC: 127
Bank1: Port A & B BIN: 0000000000111111  HEX: 0x003F    DEC: 63
Bank1: Port A & B BIN: 0000000000011111  HEX: 0x001F    DEC: 31
Bank1: Port A & B BIN: 0000000000001111  HEX: 0x000F    DEC: 15
Bank1: Port A & B BIN: 0000000000000111  HEX: 0x0007    DEC: 7
Bank1: Port A & B BIN: 0000000000000011  HEX: 0x0003    DEC: 3
Bank1: Port A & B BIN: 0000000000000001  HEX: 0x0001    DEC: 1
Bank1: Port A & B BIN: 0000000000000000  HEX: 0x0000    DEC: 0
 *
 *
 *
 */

// Majenko MCP23S17 Library
#include <MCP23S17.h>

// Arduino Library SPI.h
#include <SPI.h>

// SPI CS/SS chipselect pin can be changed by user as desired
const uint8_t chipSelect = 10;

// example Arduino board pin
uint8_t pin7 = 7;

// Create an object for each chip
// Bank1 is address 0. Pins A0,A1,A2 grounded.
// Bank2 is address 1. Pin A0=+5V, A1,A2 grounded.

MCP23S17 Bank1(&SPI, chipSelect, 0);
MCP23S17 Bank2(&SPI, chipSelect, 1);

void setup() {

  // Slow down the master a bit if desired
  SPI.setClockDivider(SPI_CLOCK_DIV8);

  Serial.begin(9600);

  Bank1.begin();
  Bank2.begin();

  // LED connected to Arduino pin 7 to test inter-device communication
  pinMode(pin7, OUTPUT);

  //
  // Set MCP23S17 pin modes:
  // example set one pin: chip.pinMode(0, OUTPUT); // sets chip pin 0 (Port A 0) to OUTPUT mode
  //
  // setChipPins(); // use loop to set individual pins
  // or, since this library does not have a setPortPinMode, do 8 pin loops
  setPortPins(); // example: set pins on each Port on each chip to different modes.
  //

}

// Set all Chip pins to desired mode
void setChipPins() {
  // Example usage

  // Set all Bank1 pins to be OUTPUT
  for (uint8_t i = 0; i <= 15; i++)
    Bank1.pinMode(i, OUTPUT);

  // Set all Bank2 pins to be INPUT_PULLUP
  for (uint8_t i = 0; i <= 15; i++)
    //Bank2.pinMode(i, INPUT);  // unswitched pin voltages about +0.1V, switch must pull pin to +5V
    Bank2.pinMode(i, INPUT_PULLUP);  // unswitched pin voltages about +4.9V, switch must ground pin
}

// Set Port pins to desired mode
void setPortPins() {
  // Example usage

  // Set all Bank1 Port A pins to OUTPUT
  for (uint8_t i = 0; i <= 7; i++)
    Bank1.pinMode(i, OUTPUT);

  // Set all Bank1 Port B pins to OUTPUT
  for (uint8_t i = 8; i <= 15; i++)
    Bank1.pinMode(i, OUTPUT);

  // Set all Bank2 Port A pins to be INPUT
  for (uint8_t i = 0; i <= 7; i++)
    Bank2.pinMode(i, INPUT);

  // Set all Bank2 Port B pins to be INPUT_PULLUP
  for (uint8_t i = 8; i <= 15; i++)
    Bank2.pinMode(i, INPUT_PULLUP);
}


//
// Change LED On/Off with button push
// 1) Switch an INPUT_PULLUP pin to ground
// 2) Read the pin value
// 3) Write the value to an OUTPUT pin
// 4) Turn LED On/Off
// Use functions digitalRead(pin) and digitalWrite(pin,value)
//
void RWpins() {

  Serial.print("\n -- RWpins() --"); Serial.println("");

  uint8_t b15 = 0;  // Bank2 input pin value (0 push LOW, 1 normally open HIGH) with push button switch to gnd
  uint8_t i = 15;   // Bank2 pin number
  uint8_t a4 = 0;   // Bank1 output pin value
  uint8_t j = 4;    // Bank1 pin number

  // read the switch value into b15
  b15 = Bank2.digitalRead(i);
  Serial.print("\nBank2: Switch i"); Serial.print(i); Serial.print(": ");  Serial.println(b15);

  // write the switch pin i, value b15, to the output pin j
  Bank1.digitalWrite(j, b15);

  a4 = Bank1.digitalRead(j);
  Serial.print("Bank1: Output j"); Serial.print(j); Serial.print(": ");  Serial.println(a4);

  // Turn on/off LED connected to Arduino pin 7 through resistor to ground
  digitalWrite(pin7, a4);
}


//
// Read and Write Port values
//
void RWport() {

  Serial.print("\n -- RWport() --"); Serial.println("");

  // set the port pin modes
  setPortPins(); // all Bank1 pins are OUTPUT but set as Ports

  // clear the port pin values to 0
  uint8_t port = 0; // Port A
  uint8_t val = 0x00; // set to 0000 0000
  Bank1.writePort(port, val);
  port = 1; // Port B
  Bank1.writePort(port, val); // set to 0000 0000

  // read the port pin values
  uint8_t valueA = Bank1.readPort(0);
  Serial.print("\nBank1: Port A BIN: "); print8Bits(valueA); Serial.println("");
  uint8_t valueB = Bank1.readPort(1);
  Serial.print("Bank1: Port B BIN: "); print8Bits(valueB); Serial.println("");

  // set the port pin values
  port = 0; // Port A
  val = 0xF4; // set to 1111 0100
  Bank1.writePort(port, val);
  port = 1; // Port B
  val = 0x0B; // set to 0000 1011
  //val = 0xB0; // set to 1011 0000
  Bank1.writePort(port, val);

  // read the port pin values
  valueA = Bank1.readPort(0);
  Serial.print("\nBank1: Port A BIN: "); print8Bits(valueA);
  Serial.print("  DEC: "); Serial.println(valueA, DEC);

  valueB = Bank1.readPort(1);
  Serial.print("Bank1: Port B BIN: "); print8Bits(valueB);
  Serial.print("  DEC: "); Serial.println(valueB, DEC);
}


void RWlongPortValue() {

  Serial.print("\n -- RWlongPortValue() --"); Serial.println("");

  // Read the Bank1 Port pin values as a combined long value
  uint16_t valueLong = Bank1.readPort();
  Serial.print("\nBank1: Port A & B BIN: "); print16Bits(valueLong);
  Serial.print("  HEX: "); crPrintHEX(valueLong, 4);
  Serial.print("  DEC: "); Serial.println(valueLong, DEC);
}


void RWlongPort() {

  Serial.print("\n -- RWlongPort() --"); Serial.println("");

  // Write the Bank1 Port pin values as a combined long value
  uint16_t valueLong = 0xB942;
  Bank1.writePort(valueLong);

  // Read the Bank1 Port pin values as a combined long value
  uint16_t valueLongIn = Bank1.readPort();
  Serial.print("\nBank1: Port A & B BIN: "); print16Bits(valueLongIn);
  Serial.print("  HEX: "); crPrintHEX(valueLongIn, 4);
  Serial.print("  DEC: "); Serial.println(valueLongIn, DEC);
}


//
// Cycle through OUTPUT pins with count-up count-down
//
void CyclePins() {

  Serial.print("\n -- CyclePins() --"); Serial.println("\n");

  // Set all Bank1 pins to be OUTPUT
  for (uint8_t i = 0; i <= 15; i++)
    Bank1.pinMode(i, OUTPUT);

  // clear Bank1 using writePort
  uint16_t valueLong = 0x0000;
  Bank1.writePort(valueLong);

  // Read the Bank1 Port pin values as a combined long value
  for (int8_t i = -1; i <= 15; i++) {
    if (i >= 0) Bank1.digitalWrite(i, 1); // i=-1 allows print of 0 data
    valueLong = Bank1.readPort(); // read 16 bits
    Serial.print("Bank1: Port A & B BIN: "); print16Bits(valueLong);
    Serial.print("  HEX: "); crPrintHEX(valueLong, 4);
    Serial.print("  DEC: "); Serial.println(valueLong, DEC);
  }

  Serial.println("");

  for (int8_t i = 15; i >= -1; i--) { // i=-1 allows print of 0 data
    // decrement after the read while reading down the values
    valueLong = Bank1.readPort(); //  read 16 bits
    Serial.print("Bank1: Port A & B BIN: "); print16Bits(valueLong);
    Serial.print("  HEX: "); crPrintHEX(valueLong, 4);
    Serial.print("  DEC: "); Serial.println(valueLong, DEC);
    Bank1.digitalWrite(i, 0);
  }
}


void loop() {

  // Change LED On/Off with button push
  RWpins();

  // Read and Write Port pins as a group
  RWport();

  // Read the Bank1 Port pin values as a combined long value
  RWlongPortValue();

  // Read and Write Chip 16 pins as a group
  RWlongPort();

  // Cycle through OUTPUT pins with count-up count-down
  CyclePins();

  delay(1000);

}

// print 8-bit byte as 8 bit binary string
void print8Bits(uint8_t myByte) {
  for (byte mask = 0x80; mask; mask >>= 1) {
    if (mask  & myByte)
      Serial.print('1');
    else
      Serial.print('0');
  }
}

// print 16-bit word as 16 bit binary string
void print16Bits(uint16_t myWord) {
  for (uint16_t mask = 0x8000; mask; mask >>= 1) {
    if (mask  & myWord)
      Serial.print('1');
    else
      Serial.print('0');
  }
}


//---------------------------------------------------------------------------------
// crPrintHEX print value as hex with specified number of digits
//---------------------------------------------------------------------------------

void crPrintHEX(unsigned long DATA, unsigned char numChars) {
  unsigned long mask  = 0x0000000F;
  mask = mask << 4 * (numChars - 1);
  Serial.print("0x");
  for (unsigned int i = numChars; i > 0; --i) {
    Serial.print(((DATA & mask) >> (i - 1) * 4), HEX);
    mask = mask >> 4;
  }

  Serial.print("  ");
}
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.