Skip to content

Commit d22ed78

Browse files
author
kolban
committed
Wed Jan 25 22:10:34 CST 2017
1 parent a05b622 commit d22ed78

File tree

2 files changed

+446
-0
lines changed

2 files changed

+446
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,363 @@
1+
/***************************************************
2+
This is a library for the MCP23017 i2c port expander
3+
4+
These displays use I2C to communicate, 2 pins are required to
5+
interface
6+
Adafruit invests time and resources providing this open source code,
7+
please support Adafruit and open-source hardware by purchasing
8+
products from Adafruit!
9+
10+
Written by Limor Fried/Ladyada for Adafruit Industries.
11+
BSD license, all text above must be included in any redistribution
12+
****************************************************/
13+
14+
#include <stdint.h>
15+
#include "Adafruit_MCP23017.h"
16+
#include <driver/gpio.h>
17+
#include <driver/i2c.h>
18+
19+
20+
21+
// minihelper to keep Arduino backward compatibility
22+
/*
23+
static inline void wiresend(uint8_t x) {
24+
//Wire.write((uint8_t) x);
25+
//i2c_master_write(cmd, &x, 1, 0);
26+
}
27+
*/
28+
29+
/*
30+
static inline uint8_t wirerecv(void) {
31+
32+
//return Wire.read();
33+
return 0;
34+
}
35+
*/
36+
37+
static int bitRead(uint32_t x, uint8_t n) {
38+
return ((x & 1<<n) != 0);
39+
}
40+
41+
static uint32_t bitWrite(uint32_t x, uint8_t n, uint8_t b) {
42+
return ((x & (~(1<< n))) | (b << n));
43+
}
44+
45+
/**
46+
* Bit number associated to a give Pin
47+
*/
48+
uint8_t Adafruit_MCP23017::bitForPin(uint8_t pin){
49+
return pin%8;
50+
}
51+
52+
/**
53+
* Register address, port dependent, for a given PIN
54+
*/
55+
uint8_t Adafruit_MCP23017::regForPin(uint8_t pin, uint8_t portAaddr, uint8_t portBaddr){
56+
return (pin<8)?portAaddr:portBaddr;
57+
}
58+
59+
/**
60+
* Reads a given register
61+
*/
62+
uint8_t Adafruit_MCP23017::readRegister(uint8_t addr){
63+
// read the current GPINTEN
64+
//Wire.beginTransmission(MCP23017_ADDRESS | i2caddr);
65+
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
66+
i2c_master_start(cmd);
67+
i2c_master_write_byte(cmd, (MCP23017_ADDRESS << 1) | I2C_MASTER_WRITE, 1 /* expect ack */);
68+
//wiresend(addr);
69+
i2c_master_write_byte(cmd, addr, 1);
70+
//Wire.endTransmission();
71+
i2c_master_stop(cmd);
72+
i2c_master_cmd_begin(I2C_NUM_0, cmd, 0);
73+
i2c_cmd_link_delete(cmd);
74+
//Wire.requestFrom(MCP23017_ADDRESS | i2caddr, 1);
75+
cmd = i2c_cmd_link_create();
76+
i2c_master_start(cmd);
77+
i2c_master_write_byte(cmd, (MCP23017_ADDRESS << 1) | I2C_MASTER_READ, 1 /* expect ack */);
78+
uint8_t tmpByte;
79+
i2c_master_read_byte(cmd, &tmpByte, 1);
80+
i2c_master_cmd_begin(I2C_NUM_0, cmd, 0);
81+
i2c_cmd_link_delete(cmd);
82+
return tmpByte;
83+
}
84+
85+
86+
/**
87+
* Writes a given register
88+
*/
89+
void Adafruit_MCP23017::writeRegister(uint8_t regAddr, uint8_t regValue){
90+
// Write the register
91+
//Wire.beginTransmission(MCP23017_ADDRESS | i2caddr);
92+
//wiresend(regAddr);
93+
//wiresend(regValue);
94+
//Wire.endTransmission();
95+
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
96+
i2c_master_start(cmd);
97+
i2c_master_write_byte(cmd, (MCP23017_ADDRESS << 1) | I2C_MASTER_WRITE, 1 /* expect ack */);
98+
i2c_master_write_byte(cmd, regAddr, 1);
99+
i2c_master_write_byte(cmd, regValue, 1);
100+
i2c_master_cmd_begin(I2C_NUM_0, cmd, 0);
101+
i2c_cmd_link_delete(cmd);
102+
}
103+
104+
105+
/**
106+
* Helper to update a single bit of an A/B register.
107+
* - Reads the current register value
108+
* - Writes the new register value
109+
*/
110+
void Adafruit_MCP23017::updateRegisterBit(uint8_t pin, uint8_t pValue, uint8_t portAaddr, uint8_t portBaddr) {
111+
uint8_t regValue;
112+
uint8_t regAddr=regForPin(pin,portAaddr,portBaddr);
113+
uint8_t bit=bitForPin(pin);
114+
regValue = readRegister(regAddr);
115+
116+
// set the value for the particular bit
117+
regValue = bitWrite(regValue,bit,pValue);
118+
119+
writeRegister(regAddr,regValue);
120+
}
121+
122+
////////////////////////////////////////////////////////////////////////////////
123+
124+
/**
125+
* Initializes the MCP23017 given its HW selected address, see datasheet for Address selection.
126+
*/
127+
void Adafruit_MCP23017::begin(uint8_t addr) {
128+
if (addr > 7) {
129+
addr = 7;
130+
}
131+
i2caddr = addr;
132+
133+
//Wire.begin();
134+
135+
// set defaults!
136+
// all inputs on port A and B
137+
writeRegister(MCP23017_IODIRA,0xff);
138+
writeRegister(MCP23017_IODIRB,0xff);
139+
}
140+
141+
/**
142+
* Initializes the default MCP23017, with 000 for the configurable part of the address
143+
*/
144+
void Adafruit_MCP23017::begin(void) {
145+
begin(0);
146+
}
147+
148+
/**
149+
* Sets the pin mode to either INPUT or OUTPUT
150+
*/
151+
void Adafruit_MCP23017::pinMode(uint8_t p, uint8_t d) {
152+
updateRegisterBit(p,(d==GPIO_MODE_INPUT),MCP23017_IODIRA,MCP23017_IODIRB);
153+
}
154+
155+
/**
156+
* Reads all 16 pins (port A and B) into a single 16 bits variable.
157+
*/
158+
uint16_t Adafruit_MCP23017::readGPIOAB() {
159+
uint16_t ba = 0;
160+
uint8_t a;
161+
162+
// read the current GPIO output latches
163+
/*
164+
Wire.beginTransmission(MCP23017_ADDRESS | i2caddr);
165+
wiresend(MCP23017_GPIOA);
166+
Wire.endTransmission();
167+
*/
168+
169+
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
170+
i2c_master_start(cmd);
171+
i2c_master_write_byte(cmd, (MCP23017_ADDRESS << 1) | I2C_MASTER_WRITE, 1 /* expect ack */);
172+
i2c_master_write_byte(cmd, MCP23017_GPIOA, 1);
173+
i2c_master_cmd_begin(I2C_NUM_0, cmd, 0);
174+
i2c_cmd_link_delete(cmd);
175+
176+
/*
177+
Wire.requestFrom(MCP23017_ADDRESS | i2caddr, 2);
178+
179+
a = wirerecv();
180+
ba = wirerecv();
181+
ba <<= 8;
182+
ba |= a;
183+
*/
184+
185+
cmd = i2c_cmd_link_create();
186+
i2c_master_start(cmd);
187+
i2c_master_write_byte(cmd, (MCP23017_ADDRESS << 1) | I2C_MASTER_READ, 1 /* expect ack */);
188+
i2c_master_read_byte(cmd, &a, 1);
189+
i2c_master_read_byte(cmd, (uint8_t *)&ba, 1);
190+
i2c_master_cmd_begin(I2C_NUM_0, cmd, 0);
191+
i2c_cmd_link_delete(cmd);
192+
193+
ba <<= 8;
194+
ba |= a;
195+
196+
return ba;
197+
}
198+
199+
/**
200+
* Read a single port, A or B, and return its current 8 bit value.
201+
* Parameter b should be 0 for GPIOA, and 1 for GPIOB.
202+
*/
203+
uint8_t Adafruit_MCP23017::readGPIO(uint8_t b) {
204+
205+
// read the current GPIO output latches
206+
/*
207+
Wire.beginTransmission(MCP23017_ADDRESS | i2caddr);
208+
if (b == 0)
209+
wiresend(MCP23017_GPIOA);
210+
else {
211+
wiresend(MCP23017_GPIOB);
212+
}
213+
Wire.endTransmission();
214+
*/
215+
216+
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
217+
i2c_master_start(cmd);
218+
i2c_master_write_byte(cmd, (MCP23017_ADDRESS << 1) | I2C_MASTER_WRITE, 1 /* expect ack */);
219+
if (b == 0) {
220+
i2c_master_write_byte(cmd, MCP23017_GPIOA, 1);
221+
} else {
222+
i2c_master_write_byte(cmd, MCP23017_GPIOB, 1);
223+
}
224+
i2c_master_cmd_begin(I2C_NUM_0, cmd, 0);
225+
i2c_cmd_link_delete(cmd);
226+
227+
/*
228+
Wire.requestFrom(MCP23017_ADDRESS | i2caddr, 1);
229+
return wirerecv();
230+
*/
231+
232+
uint8_t byte;
233+
cmd = i2c_cmd_link_create();
234+
i2c_master_start(cmd);
235+
i2c_master_write_byte(cmd, (MCP23017_ADDRESS << 1) | I2C_MASTER_READ, 1 /* expect ack */);
236+
i2c_master_read_byte(cmd, &byte, 1);
237+
i2c_master_cmd_begin(I2C_NUM_0, cmd, 0);
238+
i2c_cmd_link_delete(cmd);
239+
return byte;
240+
}
241+
242+
/**
243+
* Writes all the pins in one go. This method is very useful if you are implementing a multiplexed matrix and want to get a decent refresh rate.
244+
*/
245+
void Adafruit_MCP23017::writeGPIOAB(uint16_t ba) {
246+
/*
247+
Wire.beginTransmission(MCP23017_ADDRESS | i2caddr);
248+
wiresend(MCP23017_GPIOA);
249+
wiresend(ba & 0xFF);
250+
wiresend(ba >> 8);
251+
Wire.endTransmission();
252+
*/
253+
254+
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
255+
i2c_master_start(cmd);
256+
i2c_master_write_byte(cmd, (MCP23017_ADDRESS << 1) | I2C_MASTER_WRITE, 1 /* expect ack */);
257+
i2c_master_write_byte(cmd, MCP23017_GPIOA, 1);
258+
i2c_master_write_byte(cmd, ba & 0xFF, 1);
259+
i2c_master_write_byte(cmd, ba >> 8, 1);
260+
i2c_master_cmd_begin(I2C_NUM_0, cmd, 0);
261+
i2c_cmd_link_delete(cmd);
262+
}
263+
264+
void Adafruit_MCP23017::digitalWrite(uint8_t pin, uint8_t d) {
265+
uint8_t gpio;
266+
uint8_t bit=bitForPin(pin);
267+
268+
269+
// read the current GPIO output latches
270+
uint8_t regAddr=regForPin(pin,MCP23017_OLATA,MCP23017_OLATB);
271+
gpio = readRegister(regAddr);
272+
273+
// set the pin and direction
274+
gpio = bitWrite(gpio,bit,d);
275+
276+
// write the new GPIO
277+
regAddr=regForPin(pin,MCP23017_GPIOA,MCP23017_GPIOB);
278+
writeRegister(regAddr,gpio);
279+
}
280+
281+
void Adafruit_MCP23017::pullUp(uint8_t p, uint8_t d) {
282+
updateRegisterBit(p,d,MCP23017_GPPUA,MCP23017_GPPUB);
283+
}
284+
285+
uint8_t Adafruit_MCP23017::digitalRead(uint8_t pin) {
286+
uint8_t bit=bitForPin(pin);
287+
uint8_t regAddr=regForPin(pin,MCP23017_GPIOA,MCP23017_GPIOB);
288+
return (readRegister(regAddr) >> bit) & 0x1;
289+
}
290+
291+
/**
292+
* Configures the interrupt system. both port A and B are assigned the same configuration.
293+
* Mirroring will OR both INTA and INTB pins.
294+
* Opendrain will set the INT pin to value or open drain.
295+
* polarity will set LOW or HIGH on interrupt.
296+
* Default values after Power On Reset are: (false,flase, LOW)
297+
* If you are connecting the INTA/B pin to arduino 2/3, you should configure the interupt handling as FALLING with
298+
* the default configuration.
299+
*/
300+
void Adafruit_MCP23017::setupInterrupts(uint8_t mirroring, uint8_t openDrain, uint8_t polarity){
301+
// configure the port A
302+
uint8_t ioconfValue=readRegister(MCP23017_IOCONA);
303+
ioconfValue = bitWrite(ioconfValue,6,mirroring);
304+
ioconfValue = bitWrite(ioconfValue,2,openDrain);
305+
ioconfValue = bitWrite(ioconfValue,1,polarity);
306+
writeRegister(MCP23017_IOCONA,ioconfValue);
307+
308+
// Configure the port B
309+
ioconfValue=readRegister(MCP23017_IOCONB);
310+
ioconfValue = bitWrite(ioconfValue,6,mirroring);
311+
ioconfValue = bitWrite(ioconfValue,2,openDrain);
312+
ioconfValue = bitWrite(ioconfValue,1,polarity);
313+
writeRegister(MCP23017_IOCONB,ioconfValue);
314+
}
315+
316+
/**
317+
* Set's up a pin for interrupt. uses arduino MODEs: CHANGE, FALLING, RISING.
318+
*
319+
* Note that the interrupt condition finishes when you read the information about the port / value
320+
* that caused the interrupt or you read the port itself. Check the datasheet can be confusing.
321+
*
322+
*/
323+
void Adafruit_MCP23017::setupInterruptPin(uint8_t pin, uint8_t mode) {
324+
325+
// set the pin interrupt control (0 means change, 1 means compare against given value);
326+
// updateRegisterBit(pin,(mode!=CHANGE),MCP23017_INTCONA,MCP23017_INTCONB);
327+
// if the mode is not CHANGE, we need to set up a default value, different value triggers interrupt
328+
329+
// In a RISING interrupt the default value is 0, interrupt is triggered when the pin goes to 1.
330+
// In a FALLING interrupt the default value is 1, interrupt is triggered when pin goes to 0.
331+
// updateRegisterBit(pin,(mode==FALLING),MCP23017_DEFVALA,MCP23017_DEFVALB);
332+
333+
// enable the pin for interrupt
334+
// updateRegisterBit(pin,HIGH,MCP23017_GPINTENA,MCP23017_GPINTENB);
335+
336+
}
337+
338+
uint8_t Adafruit_MCP23017::getLastInterruptPin(){
339+
uint8_t intf;
340+
341+
// try port A
342+
intf=readRegister(MCP23017_INTFA);
343+
for(int i=0;i<8;i++) if (bitRead(intf,i)) return i;
344+
345+
// try port B
346+
intf=readRegister(MCP23017_INTFB);
347+
for(int i=0;i<8;i++) if (bitRead(intf,i)) return i+8;
348+
349+
return MCP23017_INT_ERR;
350+
351+
}
352+
uint8_t Adafruit_MCP23017::getLastInterruptPinValue(){
353+
uint8_t intPin=getLastInterruptPin();
354+
if(intPin!=MCP23017_INT_ERR){
355+
uint8_t intcapreg=regForPin(intPin,MCP23017_INTCAPA,MCP23017_INTCAPB);
356+
uint8_t bit=bitForPin(intPin);
357+
return (readRegister(intcapreg)>>bit) & (0x01);
358+
}
359+
360+
return MCP23017_INT_ERR;
361+
}
362+
363+

0 commit comments

Comments
 (0)