3 * Extend wiringPi with the MCP 23s17 SPI GPIO expander chip
4 * Copyright (c) 2013 Gordon Henderson
5 ***********************************************************************
6 * This file is part of wiringPi:
7 * https://projects.drogon.net/raspberry-pi/wiringpi/
9 * wiringPi is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as
11 * published by the Free Software Foundation, either version 3 of the
12 * License, or (at your option) any later version.
14 * wiringPi is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with wiringPi.
21 * If not, see <http://www.gnu.org/licenses/>.
22 ***********************************************************************
29 #include "wiringPiSPI.h"
30 #include "mcp23x0817.h"
34 #define MCP_SPEED 4000000
40 * Write a byte to a register on the MCP23s17 on the SPI bus.
41 *********************************************************************************
44 static void writeByte (uint8_t spiPort, uint8_t devId, uint8_t reg, uint8_t data)
48 spiData [0] = CMD_WRITE | ((devId & 7) << 1) ;
52 wiringPiSPIDataRW (spiPort, spiData, 3) ;
57 * Read a byte from a register on the MCP23s17 on the SPI bus.
58 *********************************************************************************
61 static uint8_t readByte (uint8_t spiPort, uint8_t devId, uint8_t reg)
65 spiData [0] = CMD_READ | ((devId & 7) << 1) ;
68 wiringPiSPIDataRW (spiPort, spiData, 3) ;
76 *********************************************************************************
79 static void myPinMode (struct wiringPiNodeStruct *node, int pin, int mode)
83 pin -= node->pinBase ;
85 if (pin < 8) // Bank A
86 reg = MCP23x17_IODIRA ;
89 reg = MCP23x17_IODIRB ;
94 old = readByte (node->data0, node->data1, reg) ;
101 writeByte (node->data0, node->data1, reg, old) ;
107 *********************************************************************************
110 static void myPullUpDnControl (struct wiringPiNodeStruct *node, int pin, int mode)
114 pin -= node->pinBase ;
116 if (pin < 8) // Bank A
117 reg = MCP23x17_GPPUA ;
120 reg = MCP23x17_GPPUB ;
125 old = readByte (node->data0, node->data1, reg) ;
132 writeByte (node->data0, node->data1, reg, old) ;
138 *********************************************************************************
141 static void myDigitalWrite (struct wiringPiNodeStruct *node, int pin, int value)
145 pin -= node->pinBase ; // Pin now 0-15
147 bit = 1 << (pin & 7) ;
149 if (pin < 8) // Bank A
158 writeByte (node->data0, node->data1, MCP23x17_GPIOA, old) ;
170 writeByte (node->data0, node->data1, MCP23x17_GPIOB, old) ;
178 *********************************************************************************
181 static int myDigitalRead (struct wiringPiNodeStruct *node, int pin)
183 int mask, value, gpio ;
185 pin -= node->pinBase ;
187 if (pin < 8) // Bank A
188 gpio = MCP23x17_GPIOA ;
191 gpio = MCP23x17_GPIOB ;
196 value = readByte (node->data0, node->data1, gpio) ;
198 if ((value & mask) == 0)
207 * Create a new instance of an MCP23s17 SPI GPIO interface. We know it
208 * has 16 pins, so all we need to know here is the SPI address and the
209 * user-defined pin base.
210 *********************************************************************************
213 int mcp23s17Setup (const int pinBase, const int spiPort, const int devId)
216 struct wiringPiNodeStruct *node ;
218 if ((x = wiringPiSPISetup (spiPort, MCP_SPEED)) < 0)
221 writeByte (spiPort, devId, MCP23x17_IOCON, IOCON_INIT | IOCON_HAEN) ;
222 writeByte (spiPort, devId, MCP23x17_IOCONB, IOCON_INIT | IOCON_HAEN) ;
224 node = wiringPiNewNode (pinBase, 16) ;
226 node->data0 = spiPort ;
227 node->data1 = devId ;
228 node->pinMode = myPinMode ;
229 node->pullUpDnControl = myPullUpDnControl ;
230 node->digitalRead = myDigitalRead ;
231 node->digitalWrite = myDigitalWrite ;
232 node->data2 = readByte (spiPort, devId, MCP23x17_OLATA) ;
233 node->data3 = readByte (spiPort, devId, MCP23x17_OLATB) ;