Giter VIP home page Giter VIP logo

mcp23s17's Introduction

Arduino CI Arduino-lint JSON check GitHub issues

License: MIT GitHub release PlatformIO Registry

MCP23S17

Arduino library for MCP23S17 16 channel SPI port expander.

Description

This library gives easy control over the 16 pins of a (SPI) MCP23S17 chip.

This IC is strongly related to the MCP23017 I2C port expander - https://github.com/RobTillaart/MCP23017_RT Programming Interface is kept the same as much as possible.

0.5.0 Breaking change

Version 0.5.0 introduced a breaking change to improve handling the SPI dependency. The user has to call SPI.begin() or equivalent before calling MCP.begin(). Optionally the user can provide parameters to the SPI.begin(...)

0.4.0 Breaking change

The version 0.4.0 has breaking changes in the interface. The rationale is that the programming environment of the Arduino ESP32 S3 board uses a remapping by means of the include file io_pin_remap.h. This file remaps the pins of several core Arduino functions. The remapping is implemented by #define macros and these implement "hard" text replacements without considering context. The effect is that methods from this class (and several others) which have the same name as those Arduino core functions will be remapped into something not working.

The following library functions have been renamed:

old name new name notes
analogRead() read()
analogWrite() write()
pinMode() pinMode1()
digitalRead() read1()
digitalWrite() write1()

0.3.0 Breaking change

The version 0.3.0 has breaking changes in the interface. The essence is removal of ESP32 specific code from the library. This makes it possible to support the ESP32-S3 and other processors in the future. Also it makes the library a bit simpler to maintain.

Related

16 bit port expanders

8 bit port expanders

Interface

#include "MCP23S17.h"

Constructor

  • MCP23S17(uint8_t select, uint8_t dataIn, uint8_t dataOut, uint8_t clock, uint8_t address = 0x00) constructor SOFTWARE SPI.
  • MCP23S17(int select, SPIClassRP2040* spi) constructor HARDWARE SPI with explicit SPI interface selected.
  • MCP23S17(int select, SPIClass* spi) constructor HARDWARE SPI with explicit SPI interface selected.
  • MCP23S17(int select, int address = 0x00, SPIClassRP2040* spi = &SPI) constructor HARDWARE SPI with optional address pins and SPI interface.
  • MCP23S17(int select, int address = 0x00, SPIClass* spi = &SPI) constructor HARDWARE SPI with optional address pins and SPI interface.
  • bool begin(bool pullup = true) initializes library, returns true if successful. Default sets the pins to INPUT PULLUP. Returns false if not connected or a register could not be set.
  • bool isConnected() returns true if connected, false otherwise. (dummy for compatibility reasons)
  • uint8_t getAddress() returns the address set in the constructor. Default = 0, range = 0..7.

The two hardware constructors allow to call 4 different constructors.

- MCP23S17(10);            // select pin only
- MCP23S17(10, 7);         // select pin + address pins
- MCP23S17(10, 7, &SPI2);  // select pin + address pins + SPI port
- MCP23S17(10, &SPI2);     // select pin + SPI port

Sharing SELECT lines

(verified in #19)
Technically two chips could use the same SELECT pin and a different address. Since 0.2.5 the constructors allow to setup such a configuration. The added value is that one can use up to 8 devices (= 128 IO lines) with only four lines (MISO, MOSI, CLOCK, SELECT).

I assume that this configuration is less used and IMHO not recommended. NB it is more difficult to detect which device is selected when debugging.

To use the hardware addresses the Hardware Address ENable register must be set. See datasheet 3.3.2 ADDRESSING SPI DEVICES, need to set IOCON.HAEN.

The library supports two ways:

MCP.enableControlRegister(MCP23S17_IOCR_HAEN);  //  or 0x08
or
MCP.enableHardwareAddress();  //  0.2.5 version and up

See also IO Control Register section below.

Single pin interface

  • bool pinMode1(uint8_t pin, uint8_t mode) pin = 0..15, mode = INPUT, OUTPUT. Returns true if successful.
  • bool write1(uint8_t pin, uint8_t value) pin = 0..15, value = LOW(0) HIGH (!0). Returns true if successful.
  • uint8_t read1(uint8_t pin) pin = 0..15, returns LOW or HIGH, might set the lastError();
  • bool setPolarity(uint8_t pin, bool reversed) pin = 0..15, set reversed flag. Returns true if successful.
  • bool getPolarity(uint8_t pin, bool &reversed) pin = 0..15, reads reversed flag. Returns true if successful.
  • bool setPullup(uint8_t pin, bool pullup) pin = 0..15, set pull-up flag. Returns true if successful.
  • bool getPullup(uint8_t pin, bool &pullup) pin = 0..15, reads pull-up flag. Returns true if successful.

8 pins interface

  • bool pinMode8(uint8_t port, uint8_t value) port = 0..1, value = 0..255. Returns true if successful.
  • bool write8(uint8_t port, uint8_t value) port = 0..1, value = 0..255. Returns true if successful.
  • uint8_t read8(uint8_t port) port = 0..1, reads 8 pins into one byte.
  • bool setPolarity8(uint8_t port, uint8_t mask) port = 0..1, sets polarity for 8 channels at once. Returns true if successful.
  • bool getPolarity8(uint8_t port, uint8_t &mask) port = 0..1, reads polarity of 8 channels at once. Returns true if successful.
  • bool setPullup8(uint8_t port, uint8_t mask) port = 0..1, sets pull-up for 8 channels at once. Returns true if successful.
  • bool getPullup8(uint8_t port, uint8_t &mask) port = 0..1, reads pull-up for 8 channels at once. Returns true if successful.

16 pins interface

  • bool pinMode16(uint16_t value) value = 0..0xFFFF, returns true if successful. Returns true if successful.
  • bool write16(uint16_t value) value = 0..0xFFFF, returns true if successful. Returns true if successful.
  • uint16_t read16() reads 16 pins into an uint16_t.
  • bool setPolarity16(uint16_t mask) sets polarity for 16 channels. Returns true if successful.
  • bool getPolarity16(uint16_t &mask) reads polarity of 16 channels. Returns true if successful.
  • bool setPullup16(uint16_t mask) sets pull-up for 16 channels. Returns true if successful.
  • bool getPullup16(uint16_t &mask) reads pull-up for 16 channels. Returns true if successful.

Since 0.2.6 the reading and writing to registers have been performance optimized for the 16 bit interface. If there are problems please open an issue.

IO Control Register

Since 0.2.3 the library supports setting bit fields in the IO control register. Read the datasheet carefully!

  • void enableControlRegister(uint8_t mask)
  • void disableControlRegister(uint8_t mask)
constant mask description
MCP23S17_IOCR_BANK 0x80 Controls how the registers are addressed.
MCP23S17_IOCR_MIRROR 0x40 INT Pins Mirror bit.
MCP23S17_IOCR_SEQOP 0x20 Sequential Operation mode bit.
MCP23S17_IOCR_DISSLW 0x10 Slew Rate control bit for SDA output.
MCP23S17_IOCR_HAEN 0x08 Hardware Address Enable bit (MCP23S17 only).
MCP23S17_IOCR_ODR 0x04 Configures the INT pin as an open-drain output.
MCP23S17_IOCR_INTPOL 0x02 This bit sets the polarity of the INT output pin.
MCP23S17_IOCR_NI 0x01 Not implemented.

Two dedicated functions are added since 0.2.5.

  • void enableHardwareAddress() set IOCR_HAEN bit.
  • void disableHardwareAddress() clear IOCR_HAEN bit.

Error codes

If one of the above functions return false, there might be an error.

  • int lastError() Above functions set an error flag that can be read with this function.
    Reading it will reset the flag to MCP23S17_OK.
name value description
MCP23S17_OK 0x00 No error
MCP23S17_PIN_ERROR 0x81
MCP23S17_I2C_ERROR 0x82 (compatibility)
MCP23S17_VALUE_ERROR 0x83
MCP23S17_PORT_ERROR 0x84
MCP23S17_REGISTER_ERROR 0xFF low level.

Operation

See examples.

Future

Must

  • improve documentation

Should

  • buy additional hardware
  • keep functional in sync with MCP23017_RT
  • test with multiple devices.
    • multi SELECT lines
  • add example with interrupts
    • test
  • IOCON.HAEN, Hardware Address ENable.
    • should this be enabled in begin() by default? 0.3.0
    • check address range in constructor.

Could

  • check need for writing in all functions (Polarity / Pull-up)
    • check if bit mask changes.
    • what is performance gain vs footprint?
  • investigate and reimplement the INPUT_PULLUP for pinMode() ?
  • RP2040 support for SPI, setGPIOpins() etc
    • See MCP_DAC
  • AVR software SPI optimize
    • dao and clock - see fastShiftOut.

Wont

Support

If you appreciate my libraries, you can support the development and maintenance. Improve the quality of the libraries by providing issues and Pull Requests, or donate through PayPal or GitHub sponsors.

Thank you,

mcp23s17's People

Contributors

alx-uta avatar robtillaart avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

mcp23s17's Issues

Could I contact you with a help request for once?

Dear Rob, I've been falling into despair with an attempt to control FSYNC pins of AD9833 boards via an MCP23S17.

PJRC forum isn't much help because not many users there are fluent with the MCP23S17. Plus: My problem may be pretty n00b, so it isn't too interesting.

If you're not interested, please just drop it here and delete this "issue". I just don't know how else to contact you, that's why I write here.

The main problem, I think, is that AD9833 need SPI_MODE2, while the MCP23S17 is content with SPI_MODE0.

I'd be ready to send you some AD9833 boards (or pay for them on Amazon) if you could find the motivation and some of your valulable time to help an analog synthesizer freak with this.

I have a simple working example code where I write the AD9833 directly from the Teensy 4.1:
https://github.com/KarenColumbo/AD9833-DCO8/blob/main/src/main.cpp

There's some code of what i want to do, but it doesn't work:
https://github.com/KarenColumbo/AD9833-DCO8/blob/main/test/AD9833_Repo/MCPToggle-WithLibrary-Tillaart.cpp

Goal is to control the FSYNC pins of up to 16 AD9833 boards. I'm buffering all 4 SPI line between Teensy 4.1 and the rest of the chips with an 74HC125 buffer.

I'd, of course, be willing to further sponsor your great work here on Github. it's the least i can do.

If you use E-Mail, I'm at [email protected]

Thank you for reading this and for your work for the community!

Use of Interrupt Pins

hello,

how do i configure the Pins that the INT-Pins react on a change of the Gpio-Values ? Is there any Example ?

Support for multiple Chips missing?

Thank you for the Library.
With one Chip(=mcp23s17) at a Time, i could get to run. When i tried to Add a Second or Third Chip, the adressing didn’t work.
Could you please Provide an example with 2+ Chips- maybe a copy from Chip 1 to Chip 2?
Thank you very much
Felix

ESP32-C3 and MCP23S17

I experienced two errors in ESP32-C3 and two MCP23S17 configurations:

  1. Only the constructor instance "MCP23S17(10)" works. In the other cases (Connect A: -5; Connect B: -5) there are error signals.
  2. In the case of a working constructor, there is no error signal (Connect A: 0; Connect B: 0), but in the case of MCP_A.read16() and MCP_B.read16(), the status of GPA7 is simply missing from the list if its value is LOW. For MCP_x.read8(0) and MCP_x.read8(1), the GPA7 and GPB7 states are missing, but only if their value is LOW.

adding possibility to have à chipselect that is not directly from MCU but with though a chipselect decoder

I try to modify the MCP23S17 with the addition of a chip selector between MCU and MCP23S17.
74HC138 is perfect for making 7 chipselect with 3 output of the MCU . I made this library 74HC138 v1.0.zip

I am not an expert in CPP and I try this but I have an error

in your MCP23S17.h library I modify this

#ifdef _74HC138_H_
  #define __DECODE1ON8__                  decode3to8
#endif


#ifndef __SPI_CLASS__
  #if defined(ARDUINO_ARCH_RP2040)
  #define __SPI_CLASS__   SPIClassRP2040
  #else
  #define __SPI_CLASS__   SPIClass
  #endif
#endif


const uint32_t MCP23S17_TYP_SPI_SPEED =  8000000;
const uint32_t MCP23S17_MAX_SPI_SPEED = 10000000;


class MCP23S17
{
public:
  //  SOFTWARE SPI
  MCP23S17(uint8_t select, uint8_t dataIn, uint8_t dataOut, uint8_t clock, uint8_t address = 0x00);
  //  HARDWARE SPI

//  MCP23S17(uint8_t select, __SPI_CLASS__ * spi);
  MCP23S17(uint8_t select,__DECODE1ON8__ * decode3to8, __SPI_CLASS__ * spi);

//  MCP23S17(uint8_t select, uint8_t address = 0x00, __SPI_CLASS__ * spi = &SPI);
  MCP23S17(uint8_t select, uint8_t address, __DECODE1ON8__ * decode3to8 = &dec3t8, __SPI_CLASS__ * spi = &SPI);

and this at the end of the MCP23S17.h

  bool     _hwSPI = true;

  decode3to8     * _mydec3to8 ;
  //  10 MHz is maximum, 8 is a better clock divider on AVR.
  uint32_t    _SPIspeed = MCP23S17_TYP_SPI_SPEED;
  __SPI_CLASS__ * _mySPI;
  SPISettings     _spi_settings;

I modify the MCP23S17.cpp by this

//  HARDWARE SPI
MCP23S17::MCP23S17(uint8_t select,__DECODE1ON8__ * decode3to8, __SPI_CLASS__ * spi)
{
  MCP23S17(select, 0x00, decode3to8, spi );
}


MCP23S17::MCP23S17(uint8_t select, uint8_t address,__DECODE1ON8__ * decode3to8 = &dec3t8 , __SPI_CLASS__ * spi = &SPI )
{
  _address = (address << 1);
  _select  = select;
  _error   = MCP23S17_OK;
  _mySPI   = spi;
  _hwSPI   = true;
  _mydec3to8 = decode3to8 ;
}

and on the rest of cpp code I change evey:

all  // ::digitalWrite(_select, HIGH);  are replaced by
  _mydec3to8->set_cs_high(_select);
and   //::digitalWrite(_select, LOW); are replaced by
  _mydec3to8->set_cs_low(_select);

But I have an error with VScode and I don't understant what is?

[{
	"resource": "/c:/Users/joell/Desktop/VScode_Workbench/12-ESP32-S3_DAB_Radio/lib/MCP23S17-0.5.0/MCP23S17_via_74HC138.cpp",
	"owner": "cpp",
	"severity": 8,
	"message": "default argument given for parameter 3 of 'MCP23S17::MCP23S17(uint8_t, uint8_t, decode3to8*, SPIClass*)' [-fpermissive]",
	"startLineNumber": 33,
	"startColumn": 119,
	"endLineNumber": 33,
	"endColumn": 119
}]

Have you ideas ? where I do wrong?

(updated code tags for readability)

Compilation for Arduino Nano 33 BLE fails

When I compile for the Arduino Nano 33 BLE (an ARM derived Arduino), compilations fails. The logging doesn't even mention my code, but fails on the MCP23S17 library. When I explicitly cast to the PinStatus-type, like "::digitalWrite(dao, ((PinStatus)(val & mask)));", compilation succeeds. Haven't tested the result yet, as other troubles bricked my Arduino. This is with Arduino IDE 1.8.19.

.../libraries/MCP23S17/MCP23S17.cpp: In member function 'uint8_t MCP23S17::swSPI_transfer(uint8_t)':
.../libraries/MCP23S17/MCP23S17.cpp:652:30: error: invalid conversion from 'int' to 'PinStatus' [-fpermissive]
::digitalWrite(dao, (val & mask));
~~~~~^~~~~~~
In file included from .../.arduino15/packages/arduino/hardware/mbed_nano/3.0.1/variants/ARDUINO_NANO33BLE/pinmode_arduino.h:23:0,
from .../.arduino15/packages/arduino/hardware/mbed_nano/3.0.1/cores/arduino/Arduino.h:26,
from .../ArduinoSketchbook/libraries/MCP23S17/MCP23S17.cpp:16:
.../.arduino15/packages/arduino/hardware/mbed_nano/3.0.1/cores/arduino/api/Common.h:96:6: note: initializing argument 2 of 'void digitalWrite(pin_size_t, PinStatus)'
void digitalWrite(pin_size_t pinNumber, PinStatus status);
^~~~~~~~~~~~
exit status 1
Error compiling for board Arduino Nano 33 BLE.

Sharing a single select pin

The readme mentions:

(not tested) Technically two chips could use the same select pin and a different address. The constructors would allow to setup such a configuration. I assume that this is less used and IMHO not recommended.

Why is this not recommended?

MCP.read(pin) always returns 1

Hello Thanks for the great library
I have a problem when using all read functions with the MCP23S17.
I have a switch on a dev board and pull PA 0-2 and PA 0-2 to either VCC(3.3V) or GND.
Im using your lib example(digital read). I changed one line. SPI.begin(); to SPI.begin(12, 11, 13, 42);
Im using the MIRKOE EXPAND click from mirkoe end an esp32s3
The serial output looks like this

MCP23S17_LIB_VERSION: 0.5.0
true
1
1
HWSPI: 1
TEST read1(pin)
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 
TEST read1(pin)
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 
TEST read1(pin)

Best and thank you

Is the hardware address correct?

check the datasheet of the 'microchip' company, the hardware address will be as shown in the image.
2024-02-24 233625

The hardware address is 0x00 0x01... Is this correct?
0x20 0x21 0x22... is correct?

x16() functions don't work

Can't be bothered to make a pr

bool MCP23S17::setPullup16(uint16_t mask)
{
  writeReg(MCP23S17_PUR_A, mask >> 8);
  //writeReg(MCP23S17_PUR_B, mask & 8); //this is the original line with an incorrect bit mask
  writeReg(MCP23S17_PUR_B, mask & 0xFF); //this fixes it

Otherwise only the 4th bit is actually written of the B register, so it does not set the correct bits

Problems are with the following functions:
setPullup16
setPolarity16
write16
pinMode16

derived classes for specific IO expanders?

The mcp23S17 is one from a family:

  • mcp23S17 16 bit
  • mcp23S18 16 bit single address pin.
  • mcp23S08 8 bit
  • mcp23S09 8 bit higher clock I2C

They can be controlled by the mcp23S17 class but the 8 bit ones do not need the 16 pins interface recently added.
So 23s08 can't be derived from 23s17
but the other way around means implementing all 23s17 code anyway

so a specific 23S08 class might be better.

idem for I2C variant.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.