Coder Social home page Coder Social logo

gpio_expander's Introduction

gpio_expander library

Universal GPIO library for Arduinos, Teensy 2/3/3.x, Teensy LC


An attempt to create an universal library that works with many common GPIO chips and can be used with Arduino's and Teensy's (my preferred choice)
Here's a list of the GPIO's chip managed:

chipcompanypinsprotocolfeaturesstatus
mcp23s17Microchip16SPIHAEN/INTdone
mcp23017Microchip16I2CINTdone
mcp2308Microchip8I2CINTdone
mcp23s08Microchip8SPIHAEN/INTdone
mcp23s18Microchip16SPIOPEN DRAIN/INTdone
mcp23018Microchip16I2CINTdone
mcp23016Microchip16I2CINTdone
pcf8574NTX8I2CINTdone
pcf8574aNTX8I2CINT/different address rangedone
pcf8575NTX8I2CINTplanned
pca9698NTX40I2CINT/64adrsplanned
pca9555NTX16I2CINT/64adrstesting
tca9555TI16I2CINT/64adrstesting
pca9655ON16I2CINT/64adrs/1Mhz I2Ctesting
max6957TI20/28I2CINT/64adrstesting
max7301TI20/28I2CINT/64adrstesting
max7311TI16I2CINT/64adrs/hot insertiontesting
max7318TI16I2CINT/64adrs/hot insertiontesting
rd1073LATTICE16SPIINTplanned
xra1200EXAR8I2CINTplanned
xra1201EXAR16I2CINTplanned
xra1405EXAR16SPIINT/24Mhz SPIdev
fxl6408FAIRCHILD8I2CINTplanned
bu1852guwROHM20I2CINTplanned
cy8C9560CYPRESS60I2CINT/EEPROM/max 100Khz I2Cplanned
sx1505SEMTECH8I2CINT/Indipendent railsdev
sx1506SEMTECH16I2CINT/Indipendent railsdev
sx1509SEMTECH16I2CINT/LED driver/Level Shifterdev

Status Legend:

done:
fully working.
dev:
currently in development.
testing:
currently in testing, may works or partially.
planned:
will be developed soon and added before the release.
planned[R2]:
will not included in the release but planned for version 2.

When working with microcontrollers it's common run quickly out of I/O's, that because these small chips have few pins and some periferal (like LCD) uses many pins. For this reason I use a lot external GPIO's chips.

Microchip series MCP23xxx GPIO expanders are great chips but they can be a nightmare if you want to deal with registers, timings, etc., for these reasons a lot of coders prefere the supereasy to use PCF series from NTX.
I personally prefere the Microchip series because I can choose from I2C and SPI and they have an extra feature called HAEN that allow me to share CS pin between 8 different chips in SPI mode!
This library it's an improvement of my old MCP23xxx library since it's smaller, faster and deal with all MCP23xx series plus PCF series from NTX.
I designed as a small and easy library that can be easily expanded but still have the ability to handle directly the registers for special purposes.
If you need a simple expander, use this library and choose between many GPIO's chip by using really simply commands, but if you need a specialized GPIO you can still use this library and use the direct access to chip registers (see the keypad demo).
The MCP23xxx registers are stored in each chip library extension so you can share demos between different chips (there's some exceptions like the MCP23016 that has limited features and you cannot share some features between NTX and MCP ones since they are internally very different).
Library is modular, every chip it's an extension of the same library so it's easy to expand.
Why create an unified library? It's better create single libraries for chip families? Seems no!
Almost all GPIO chips have really similar programming, only Microchip families has more features and looks more complicated but the access it's almost the same for all so it have sense to build up an unified way to access these chips with common commands so you can easily use the chip you like without have to recode anithing, just be sure you don't need some special features of some particular chip.

[TIP] I got a compile error with a chip library I'm not plan to use!

Since there are many chip drivers inside library, the compiler open every file but optimizations cause that unused stuff will not be included so do not worry if you see compiler include all the files, at the end it will not do this!. But for the same reason if there's any error or uncompatible stuff inside any of those files, the whole library will not compile! To solve this it's really simple, just move out from the library folder the driver .cpp and .h files that give the error, close and reopen IDE and try to compile again! Do not forget to drop me a note and I will fix it!

[TIP] Can I update many pins individually in a fast way?

Yes! This library have an internal mirror of the pin registers so you can use the new function gpioDigitalWriteFast, you can use a lot since it will not communicate with te chip, once you have updated all pins you call gpioPortUpdate and the whole register will be sent to the chip in one cicle (or 2 for 16 bit ones).

[TIP] I will like to use the library inside another library, it's possible?

Yes! I've a special initialization command called postSetup. Follow instructions below...

[TIP] What about SPI transactions?

The library it's fully compatible with SPI transactions! But it's not automatic since many users use this library inside other libraries so you can still use in legacy mode even if you have a SPI Transaction compatible IDE. You need to add a parameter to the instance to force SPI Transaction! es. mcp23s17 mcp(gpio_cs_pin,gpio_adrs,30000000); I've added a 30Mhz parameter to the end, Teensy will automatically select the higher frequency but you can use any frequency (supported) you want in relation tho the chip you are using, the lenght of SPI lines, etc. If you use SPI transactions remember that the other SPI devices have to use SPI Transaction compatible libraries too!

How To Use:

Library it's unified so you just need toi include the chip and his protocol, example for mcp23017

 #include <Wire.h>
 #include <mcp23017.h>

then you need an instance:

 mcp23017 gpio(address);//instance
 // NOTE: If you need to include library in other libraries you can use mcp23017 gpio(); (empty address)
 // then call postSetup!!

where the address it's specific to the chip (read chip.h file)

From below the commands are the same for all chip with some exceptions:

  • Some chip it's 8 bit so it doesn't have the writeWord command
  • Some chip has limited features so not all registers are accessible, take a look to the chip.h file)

Commands are:

 gpio.postSetup(depends of chip);//Useful when you want include in other libraries
 gpio.begin();//gpio.begin(1); will not init the protocol (useful when multiple chip are used or you want to manually init it
 
 gpio.gpioPinMode(INPUT or OUTPUT or data);//set all pin accordly
 gpio.gpioPinMode(pin,mode);//set an individual pin as INPUT or OUTPUT
 gpio.port(data or HIGH or LOW);//data=8..xx bits, depends of chip. set all pins at once
 gpio.port(low byte,high byte);//useful for 16 bit GPIOs that have 2 ports of 8 bit
 gpio.readGpioPort();//read the state of all pins, it returns 8...xx bits depending of chip
 gpio.readGpioPortFast();//experimental. Read the state of the library buffer instead of the chip.
 gpio.gpioDigitalWrite(pin,state);//set individual pin HIGH or LOW
 gpio.gpioDigitalRead(pin);//read the state of one pin
 gpio.gpioDigitalReadFast(pin);//experimental. Read the state of a pin from the library pin register buffer
 gpio.gpioRegisterReadByte(register);//not available to all chip, read a byte from the specific register
 gpio.gpioRegisterReadWord(register);//not available to all chip, read a word from the specific register
 gpio.gpioRegisterWriteByte(register,data);//write byte directly in chip register
 gpio.gpioRegisterWriteWord(register,data);//write word directly in chip register(not 8 bit chip)
 gpio.portPullup(HIGH or LOW or data);//Set pullup on input pin (not all chip!)
 //new commands from release 0.8b3
 gpio.gpioDigitalWriteFast(pin,Val);//It updates only the library pin register buffer! It do not send data to the GPIO
 //this actually update only the mirrored register in library and act really fast since no communication with the chip
 //so you can use to update many pins, when you call the command gpioPortUpdate you will send the updates to the chip!
 gpio.gpioPortUpdate();//this will effectively send the pin register to the GPIO chip! 

Another example: How to include in another library?

Here's how to inlude and use this library inside an existing one. In the .h file of your existing library add this lines just after the aruino.h include or library protection declaration:

#ifndef _YOURLIB_H_
#define _YOURLIB_H_

#include <inttypes.h>

#include "yourlib.h"

//here start the include
#include <../SPI/SPI.h>//this chip needs SPI
#include <../gpio_expander/mcp23s17.h>
//here ends

Now you have to provide an instance! Go to the private section of your library .h file and add to existings:

 private:
    bla
    bla
    
    uint8_t 		_cs;//needed for this chip
    uint8_t 		_adrs;//needed for this chip (if you using HAEN)

   mcp23s17		mygpio;//here the instance
 As you noticed I have included also the _cs pin var and _adrs var needed for the chip I choose for demo.
 Now open the .cpp file of your library and add these lines to your initialization function:
	 void myLibrary::begin(bla, bla){
	     bla
	     bla
	     
	      mygpio.postSetup(_cs,_adrs);//you should set these 2 vars before! (I2C use ALWAYS this)
	      //if you want use SPI.Transactions you have another parameter...
	      //mygpio.postSetup(_cs,_adrs,30000000);//set SPI transaction speed (Only for SPI!!!)
	      mygpio.begin();//put true if you want to init SPI (or I2C, depends of chip) manually!
	      mygpio.gpioPinMode(OUTPUT);//es.
	      mygpio.gpioPort(0xFFFF);//es.
	      etc...
	 }

Since the library was already instanced and inited you can use the library function inside your library where you want but not forget to initialize it as I show above!

version 0.8b4 - beta release - only some driver released and partially tested!!!

coded by Max MC Costa for s.u.m.o.t.o.y [sumotoy(at)gmail.com]


gpio_expander's People

Contributors

maprata avatar sumotoy avatar

Stargazers

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

Watchers

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

gpio_expander's Issues

Path to Wire.h

Hello sumotoy,

when using the library with the current Arduino IDE v1.6.8, the library won't compile because of the following include line:

include <../../Wire.h>

If ../../ is omitted, it works fine.

Also, it would be nice if the "gpio" in Object.gpioDigitalRead() and Object.gpioDigitalWrite() wasn't there. Does it come out of necessity?

Best wishes, great work compiling all those GPIO ICs. ๐Ÿ‘

Inconsistent behaviour in mcp23s08 (and others)

The function mcp23s08::gpioPinMode uses the Arduino.h defines INPUT and OUTPUT for explicit setting of 'all input' and 'all output', but this usage restricts the freedom to set any combination of input/output, as INPUT has the value 0 and OUTPUT has the value 1.

If I try to set the combination 0b00000001 (GP0 input and GP1-7 as output), it will be interpreted as OUTPUT and all GP0-7 will be outputs.

Two new defines/constants would solve this problem, ALL_INPUT with value 0xFF and ALL_OUTPUT with value 0x00.

The same problem shows in functions mcp23s08::gpioPort and mcp23s08::portPullup, but here the defines HIGH with value 1 and LOW with value 0 are the problem.

Two new defines/constants would solve this problem, ALL_HIGH with value 0xFF and ALL_LOW with value 0x00.

The same problem shows also in the solutions with 16 GPIO, in those cases the defines/constants need to be 0xFFFF or 0x0000

MCP23S18 just doesn't work.

If the title doesn't already explain it, the MCP23S18 interface just doesn't work. I think I found the issue, though. Mainly the problem is that it actually doesn't support HAEN. This library appears to be just a slightly modified version of the MCP28S17 library. However, I only found two differences - the pins are in different orders and that the A0, A1, and A2 pins are replaced by NC pins. The address will always be 000, so 0x20 should always work as the address.
Difference between MCP23S17 and MCP23S18 control byte format
Anyways, even using mcp23s18 mcp(GPIO_PIN, 0x20);, I still can't access any of the pins. By the way, in the datasheet the pins are labelled as GPA0...7 and GPB0...7, but in your library, they're accessed as numbers. If you could define constants for each pin, that would also make it a lot less confusing. One last thing - there are both "A" and "B" registers for the chip. Son instead of there being one GPIO register, there is a GPIOA and a GPIOB register. All of this info can be found on the datasheet.

Pin assignments?

Good evening sumotoy, I'm testing the gpioDigitalRead on the MCP23S17 and getting the pins (not in order) and number squared..
pinconfig

i cant seem to figure it out, and im actually worried if i should attempt the digitalwrite commands hehe
thanks
tony

Undeclared NOT_AN_INTERRUPT for Nordic NRF52 plateform

Hello @sumotoy

Thx for your work :)

I submitted a fix for relative path of Wire.h and SPI.h headers. This enables me to build correctly on atmelavr plateform but still have an issue on nordicnrf52.

Environment    Status    Duration
-------------  --------  ------------
nanoatmega328  SUCCESS   00:00:03.300
nordicnrf52    FAILED    00:00:02.831

Here are my project confs :

[env:nanoatmega328]
platform = atmelavr
board = nanoatmega328
framework = arduino
lib_deps =
    Wire
    SPI
    gpio_expander

[env:nordicnrf52]
lib_deps =
    Wire
    SPI
    gpio_expander
framework = arduino
platform = nordicnrf52
board = nrf52_dk
debug_tool = jlink

And here is the error part of my console output ๐Ÿ‘

.pio/libdeps/nordicnrf52/gpio_expander_ID973/max6957.cpp: In member function 'int max6957::getInterruptNumber(byte)':
.pio/libdeps/nordicnrf52/gpio_expander_ID973/max6957.cpp:49:16: error: 'NOT_AN_INTERRUPT' was not declared in this scope
  if (intNum != NOT_AN_INTERRUPT) {
                ^~~~~~~~~~~~~~~~
Compiling .pio/build/nordicnrf52/lib499/gpio_expander_ID973/mcp23016.cpp.o
.pio/libdeps/nordicnrf52/gpio_expander_ID973/max6957.cpp:49:16: note: suggested alternative: '_WIRING_INTERRUPTS_'
  if (intNum != NOT_AN_INTERRUPT) {
                ^~~~~~~~~~~~~~~~
                _WIRING_INTERRUPTS_
Archiving .pio/build/nordicnrf52/liba99/libSPI.a
.pio/libdeps/nordicnrf52/gpio_expander_ID973/max7301.cpp: In member function 'int max7301::getInterruptNumber(byte)':
.pio/libdeps/nordicnrf52/gpio_expander_ID973/max7301.cpp:48:16: error: 'NOT_AN_INTERRUPT' was not declared in this scope
  if (intNum != NOT_AN_INTERRUPT) {
                ^~~~~~~~~~~~~~~~
*** [.pio/build/nordicnrf52/lib499/gpio_expander_ID973/max6957.cpp.o] Error 1
.pio/libdeps/nordicnrf52/gpio_expander_ID973/max7301.cpp:48:16: note: suggested alternative: '_WIRING_INTERRUPTS_'
  if (intNum != NOT_AN_INTERRUPT) {
                ^~~~~~~~~~~~~~~~
                _WIRING_INTERRUPTS_
Indexing .pio/build/nordicnrf52/liba99/libSPI.a
*** [.pio/build/nordicnrf52/lib499/gpio_expander_ID973/max7301.cpp.o] Error 1

Do you have any clue ?

Thx a lot :)

Is xra1405 support available yet

I see that xra1405 is listed as in development. Is there some code available yet?

I' going to be working with the xra1405 in the next week or so and it would be helpful to have some functional code for testing, even if it is limited.

I didn't see anything leaping out at me in the master tree.

Thanks,
Burt

Not working...

Please, let me know if i made some mistake in circuit
ccc

example code for MAX7318

Do you have sample code for the max7318 I/O expander? Trying to compile this for the arduino Mega 2560 and run into some issues.

Much appreciate any help.

thanks,

Sophronis

Mirroring error on mcl in chain higher than 6

Hi there,

It seems that the addressing bits do not prevent mirroring when using addresses seven and eight.
I am using the following for all mcl (mcp0 to mcp7) with mixed input and output. A simple test I ran showed that not declaring mcl.begin still allowed mirrored bits.
mcp5.gpioRegisterWriteByte(mcp0.IOCON, 0b00101000);//HAEN,SEQOP,MIRROR -remove mirror (ie INT pin connection)
mcp5.gpioRegisterWriteByte(mcp0.GPPU, 0xff, true);//pull-up only required input pins???
mcp5.gpioRegisterWriteWord(mcp0.GPINTEN, 0x1f1f);// enable interrupts on these
mcp5.gpioRegisterReadByte(mcp0.INTCAP); //read interrupt capture port A (it clear port)
mcp5.gpioRegisterReadByte(mcp0.INTCAP + 1);//read interrupt capture port B (it clear port)

REQ: ESP32 compability for the MCP23S08

I managed to get the MCP23S08 lib working for a ESP32 (WEMOS LOLIN with OLED) but i have a problem:

When setting ALL pins as OUTPUTS (mcp.gpioPinMode(OUTPUT)), and set a specific PIN HIGH (mcp.gpioDigitalWrite(3, HIGH)) it works (result GP3 = HIGH).

BUT

When setting a specific pin as OUPUT (mcp.gpioPinMode(3, OUTPUT)) and set this specific PIN HIGH (mcp.gpioDigitalWrite(3, HIGH)) it does NOT work (result GP3 = LOW).

I think it has to do with this line in the lib code. Maybe something specific (BitWise) for AVR?:
mode == INPUT ? _gpioDirection |= (1 << pin) :_gpioDirection &= ~(1 << pin);

Any idea what would be wrong?

Does this library work on ESP8266?

I'm designing a board around the ESP-WROOM-02 and have and am planning on using the MPC23S18 as IO expansion due to it's small size 4x4mm and I only needing 3 outputs (1 IRDA shutdown and 2 outputs though an optoisolator). If I had needed more outputs I probably would not have used the open drain version despite it's small size.

I forgot the pullup resistors on my 2 optoisolator outputs but I'll just hack them on for testing once I have the boards in hand. I'll be sure you let you know how it goes.

cy8C9560

hello.
you library looks very interesting. thanks for making it.

did you have a chance to see if it works with the cy8C9560 60 port IC or PCA9698 40 port IC?
thanks.

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.