MCP23S17 SPI Port Expander

https://github.com/n0mjs710/MCP23S17.git

Arduino Driver for Microchip MCP23S17

MCP23S17 Class for Arduino

Introduction:

This class is written to simplify using the Microchip MCP23S17 general purpose I/O expander IC in the Arduino environment. Some understanding of the MCP23S17 is required, so if you are not familiar with it, download the datasheet for it and have a look. The rest of this description will assume a basic understanding of the chip.

Implementation:

The goal of this implementation is to provide a software interface that mimics the existing Arduino I/O functions:

  • pinMode(pin, mode)

  • digitalWrite(pin, value)

  • digitalRead(pin)

The class does include several more methods that can be used to simplify configuration in the same “Arduino-ish” way, methods for writing/reading 8-bit registers (configuration and I/O ports) at once, as well as writing/reading consecutive registers (allowing all 16 bits to be read or written with one method call). The interrupt features of the chip are not directly supported with method for specifically configuring them, however, the byte and word read/write methods may be used to configure and use the interrupt features. These features can get somewhat complicated, and any user prepared to use them will likely prefer the more generic methods for controlling them.

Upon initialization of an MCP23S17 as an object, ALL MCP23S17s on the SPI bus (sharing the same slave select) will be placed into hardware addressing mode. This allows up to 8 MCP23S17s to be used with a single slave select.

**Methods:**

MCP()

Description

Instantiate an MCP23S17 device as an object.

Syntax

MCP object_name(address, slave_select)

Parameters

object_name: any arbitrary name given to create the object

address: address (0-7) of the device configured with address (pins A0, A1, A2)

slave_select: a valid *Arduino* pin number.

Returns

none

Example

MCP onechip(1, 10);    // create an object at address 1 called "onechip", using pin 10 as slave select
MCP twochip(2, 10); // create an object at address 2 called "twochip", using pin 10 as slave select

pinMode()

Description

Configure pin(s) as either input or output on the selected object (device specified by an address)

Syntax

object.name.pinMode(pin, mode);
  or
object.name.pinMode(mode);

Parameters

object_name: the name given when this object was created

pin: the pin number (1-16) on which to set as input or output

mode: if a pin is specified, either a "HIGH" (1) for input (default) or a "LOW" (0) for output. If a pin is not specified, mode should be a word indicating the mode of each of the 16 I/O pins on the chip.

Returns

none

Example

void setup() {
  onechip.pinMode(4, HIGH); // sets pin 4 as an input
  onechip.pinMode(16, LOW); // sets pin 16 as an output
  twochip.pinMode(0B0000111100001111); // sets pins 1-4 and 9-12 as input, 5-8 and 13-16 as output
}

pullupMode()

Description

Configure the weak pull-up resistors on pins defined as inputs

This has no effect on pins that are configured as outputs.

Syntax

object_name.pullupMode(pin, mode);
 or
object_name.pullupMode(mode);

Parameters

object_name: the name given when this object was created

pin: the pin number (1-16) on which to enable or disable the internal weak pull-up resistor

mode: if a pin is specified, either "HIGH" (1) to enable or "LOW" (0) to disable (default) the weak pull-up resistor on the specified pin. If a pin is not specified, mode should be a word indicating the pull-up mode of each of the 16 pins on the chip. Configuring pull-up has no effect on pins while they are configured as output.

Returns

none

Example

void setup() {
  onechip.pullupMode(4, HIGH); // enable the pull-up on pin 4
  twochip.pullupMode(0B0000111100000000); // enable the pull-ups on pins 9-12
}

inputInvert()

Description

Configure inversion on pins configured as inputs.

This will cause an inverted input pin to read as “LOW” (0) when it is actually in a high state, or as “HIGH” (1) when it is actually in a low state. This has no effect on pins that are configured as outputs.

Syntax

object_name.inputInvert(pin, inversion);
  or
object_name.inputInvert(inversion);

Parameters

object_name: the name given when this object was created

pin: the pin number (1-16) on which to set or clear inversion

inversion: if a pin is specified, either "HIGH" (1) is specified to enable, or "LOW" (0) to disable (default) inversion on the specified pin. If a pin is not specified, mode should be a word indicating the inversion state of each of the 16 pins on the chip. Configuring inversion has no effect on pins while they are configured as output.

Returns

none

Example

void setup() {
  onechip.inputInvert(4, LOW); // disable inversion on pin 4
  twochip.inputInvert(0B0000000000001111); // enable inversion on pins 1-4
}

digitalWrite()

Description

Write a “HIGH” or “LOW” value to a digital I/O pin(s)

Syntax

object_name.digitalWrite(pin, value);
  or
object_name.digitalWrite(value);

Parameters

object_name: the name given when this object was created

pin: the pin number (1-16) who's value will be set

value: if a pin is specified, either a "HIGH" (1) or a "LOW" (0) value may be set on the specified pin. If a pin is not specified, value should be a word indicating the output state of all 16 pins on the device. Writing pins configured as inputs has no effect.

Returns

none

Example

void loop() {
   onechip.digitalWrite(16, HIGH); // set pin 16 to "HIGH"
   twochip.digitalWrite(0B1100000000110000); // Set 5, 6, 15 & 16 to high, 7,8, 13 & 14 to low - inputs ignored
}

digitalRead()

Description

Reads the value of input pin(s), either “HIGH” (“1”) or “LOW” (“0)

Syntax

object_name.digitalRead(pin);
  or
object_name.digitalRead();

Parameters

object_name: the name given when this object was created

pin: the pin number (1-16) who's value will be read. If no pin number is supplied, a word will be read containing the input state of all pins. The values for pins configured as output should be disregarded if the "word-mode" version is used.

Returns

"HIGH" (1) or "LOW" (0) if a pin is supplied. a word (16 bits) is returned if no pin argument is given

Example

void loop() {
  int onevalue;
  int twovalue;

  onevalue = onechip.digitalRead(4); // assigns the value of pin4 to onevalue
  twovalue = twochip.digitalRead(); // assigns the value of all 16 I/O pins to twovalue
}

wordWrite()

Description:

This is an advanced method to write a register pair in the MCP23S17. This class operates the MCP23S17 in “BANK=0” mode. The intention is that a registers for both ports may be written by supplying a single word as an argument. The low byte is written to the register address supplied, and the high byte to the next higher register address.

Syntax”

object_name.wordWrite(base register, value);

Parameters:

object_name: the name given when this object was created

base register: the beginning register address to write, for example, if 0x02 is given, the low byte of "value" will be written to 0x02 and the high byte of "value" to the register at 0x03

value: a word (unsigned int) that will be broken into two bytes and written to two consecutive registers, starting with the "base register" address

Returns:

none

Example

void loop() {
  onechip.wordWrite(0x12, 0xFF00); // Set GPIOA to 0x00 and GPIOB to OxFF
}

byteWrite()

Description:

This is an advanced method to write any single register in the MCP23S17.

Syntax:

object_name.byteWrite(register, value);

Parameters:

object_name: the name given when this object was created

register: the register address to write

value: a byte (unsigned char) that will be written to the specified registers

Returns:

none

Example:

void loop() {
  twochip.byteWrite(0x13, 0xF0); // Set GPIOB (portB) to 0xF0 (0B11110000)
}

byteRead()

Description:

This is an advanced method to read any single register in the MCP23S17.

Syntax:

object_name.byteRead(register);

Parameters:

object_name: the name given when this object was created

register: the register address to be read

Returns:

unsigned char (uint8_t)

Example:

void loop() {
  int twovalue;
  twovalue = twochip.byteRead(0x12); // Read GPIOA (portA)
}

Full Example:

MCP onechip(1, 10);    // create an object at address 1 called "onechip", using pin 10 as slave select
MCP twochip(2, 10); // create an object at address 2 called "twochip", using pin 10 as slave select

void setup() {
    onechip.pinMode(4, HIGH); // sets pin 4 as an input
    onechip.pinMode(16, LOW); // sets pin 16 as an output
    twochip.pinMode(0B0000111100001111); // sets pins 1-4 and 9-12 as input, 5-8 and 13-16 as output

    onechip.pullupMode(4, HIGH); // enable the pull-up on pin 4
    twochip.pullupMode(0B0000111100000000); // enable the pull-ups on pins 9-1

    onechip.inputInvert(4, LOW); // disable inversion on pin 4
    twochip.inputInvert(0B0000000000001111); // enable inversion on pins 1-4
}

void loop() {
  int onevalue;
  int twovalue;

  onechip.digitalWrite(16, HIGH); // set pin 16 to "HIGH"
  twochip.digitalWrite(0B1100000000110000); // Set 5, 6, 15 & 16 to high, 7,8, 13 & 14 to low - inputs ignored

  onevalue = onechip.digitalRead(4); // assigns the value of pin4 to onevalue
  twovalue = twochip.digitalRead(); // assigns the value of all 16 I/O pins to twovalue

  /* These are for context only - use them only if you really know what you're doing
  onechip.wordWrite(0x12, 0xFF00); // Set GPIOA to 0x00 and GPIOB to OxFF
  twochip.byteWrite(0x13, 0xF0); // Set GPIOB (portB) to 0xF0 (0B11110000)
  twovalue = twochip.byteRead(0x12); // Read GPIOA (portA)
  */
}

References

Used by

SoC support

  • esp32

  • esp32c2

  • esp32c3

  • esp32s2

  • esp32s3

  • esp8266

  • host

  • rp2040

  • rp2350