User | Revision | Line number | New contents of line |
GobertPierre |
0:d76c38ee24ab
|
1
|
/* MCP23017 library for Arduino
|
GobertPierre |
0:d76c38ee24ab
|
2
|
Copyright (C) 2009 David Pye <davidmpye@gmail.com
|
GobertPierre |
0:d76c38ee24ab
|
3
|
Modified for use on the MBED ARM platform
|
GobertPierre |
0:d76c38ee24ab
|
4
|
|
GobertPierre |
0:d76c38ee24ab
|
5
|
This program is free software: you can redistribute it and/or modify
|
GobertPierre |
0:d76c38ee24ab
|
6
|
it under the terms of the GNU General Public License as published by
|
GobertPierre |
0:d76c38ee24ab
|
7
|
the Free Software Foundation, either version 3 of the License, or
|
GobertPierre |
0:d76c38ee24ab
|
8
|
(at your option) any later version.
|
GobertPierre |
0:d76c38ee24ab
|
9
|
|
GobertPierre |
0:d76c38ee24ab
|
10
|
This program is distributed in the hope that it will be useful,
|
GobertPierre |
0:d76c38ee24ab
|
11
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
GobertPierre |
0:d76c38ee24ab
|
12
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
GobertPierre |
0:d76c38ee24ab
|
13
|
GNU General Public License for more details.
|
GobertPierre |
0:d76c38ee24ab
|
14
|
|
GobertPierre |
0:d76c38ee24ab
|
15
|
You should have received a copy of the GNU General Public License
|
GobertPierre |
0:d76c38ee24ab
|
16
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
GobertPierre |
0:d76c38ee24ab
|
17
|
*/
|
GobertPierre |
0:d76c38ee24ab
|
18
|
|
GobertPierre |
0:d76c38ee24ab
|
19
|
#include "MCP23017.h"
|
GobertPierre |
0:d76c38ee24ab
|
20
|
#include "mbed.h"
|
GobertPierre |
0:d76c38ee24ab
|
21
|
|
GobertPierre |
0:d76c38ee24ab
|
22
|
union {
|
GobertPierre |
0:d76c38ee24ab
|
23
|
uint8_t value8[2];
|
GobertPierre |
0:d76c38ee24ab
|
24
|
uint16_t value16;
|
GobertPierre |
0:d76c38ee24ab
|
25
|
} tmp_data;
|
GobertPierre |
0:d76c38ee24ab
|
26
|
|
GobertPierre |
0:d76c38ee24ab
|
27
|
/*-----------------------------------------------------------------------------
|
GobertPierre |
0:d76c38ee24ab
|
28
|
*
|
GobertPierre |
0:d76c38ee24ab
|
29
|
*/
|
GobertPierre |
0:d76c38ee24ab
|
30
|
MCP23017::MCP23017(PinName sda, PinName scl, int i2cAddress) : _i2c(sda, scl) {
|
GobertPierre |
0:d76c38ee24ab
|
31
|
MCP23017_i2cAddress = i2cAddress;
|
GobertPierre |
0:d76c38ee24ab
|
32
|
reset(); // initialise chip to power-on condition
|
GobertPierre |
0:d76c38ee24ab
|
33
|
}
|
GobertPierre |
0:d76c38ee24ab
|
34
|
|
GobertPierre |
0:d76c38ee24ab
|
35
|
/*-----------------------------------------------------------------------------
|
GobertPierre |
0:d76c38ee24ab
|
36
|
* reset
|
GobertPierre |
0:d76c38ee24ab
|
37
|
* Set configuration (IOCON) and direction(IODIR) registers to initial state
|
GobertPierre |
0:d76c38ee24ab
|
38
|
*/
|
GobertPierre |
0:d76c38ee24ab
|
39
|
void MCP23017::reset() {
|
GobertPierre |
0:d76c38ee24ab
|
40
|
//
|
GobertPierre |
0:d76c38ee24ab
|
41
|
// First make sure that the device is in BANK=0 mode
|
GobertPierre |
0:d76c38ee24ab
|
42
|
//
|
GobertPierre |
0:d76c38ee24ab
|
43
|
writeRegister(0x05, (unsigned char)0x00);
|
GobertPierre |
0:d76c38ee24ab
|
44
|
//
|
GobertPierre |
0:d76c38ee24ab
|
45
|
// set direction registers to inputs
|
GobertPierre |
0:d76c38ee24ab
|
46
|
//
|
GobertPierre |
0:d76c38ee24ab
|
47
|
writeRegister(IODIR, (unsigned short)0xFFFF);
|
GobertPierre |
0:d76c38ee24ab
|
48
|
//
|
GobertPierre |
0:d76c38ee24ab
|
49
|
// set all other registers to zero (last of 10 registers is OLAT)
|
GobertPierre |
0:d76c38ee24ab
|
50
|
//
|
GobertPierre |
0:d76c38ee24ab
|
51
|
for (int reg_addr = 2 ; reg_addr <= OLAT ; reg_addr+=2) {
|
GobertPierre |
0:d76c38ee24ab
|
52
|
writeRegister(reg_addr, (unsigned short)0x0000);
|
GobertPierre |
0:d76c38ee24ab
|
53
|
}
|
GobertPierre |
0:d76c38ee24ab
|
54
|
//
|
GobertPierre |
0:d76c38ee24ab
|
55
|
// Set the shadow registers to power-on state
|
GobertPierre |
0:d76c38ee24ab
|
56
|
//
|
GobertPierre |
0:d76c38ee24ab
|
57
|
shadow_IODIR = 0xFFFF;
|
GobertPierre |
0:d76c38ee24ab
|
58
|
shadow_GPIO = 0;
|
GobertPierre |
0:d76c38ee24ab
|
59
|
shadow_GPPU = 0;
|
GobertPierre |
0:d76c38ee24ab
|
60
|
shadow_IPOL = 0;
|
GobertPierre |
0:d76c38ee24ab
|
61
|
}
|
GobertPierre |
0:d76c38ee24ab
|
62
|
|
GobertPierre |
0:d76c38ee24ab
|
63
|
/*-----------------------------------------------------------------------------
|
GobertPierre |
0:d76c38ee24ab
|
64
|
* write_bit
|
GobertPierre |
0:d76c38ee24ab
|
65
|
* Write a 1/0 to a single bit of the 16-bit port
|
GobertPierre |
0:d76c38ee24ab
|
66
|
*/
|
GobertPierre |
0:d76c38ee24ab
|
67
|
void MCP23017::write_bit(int value, int bit_number) {
|
GobertPierre |
0:d76c38ee24ab
|
68
|
if (value == 0) {
|
GobertPierre |
0:d76c38ee24ab
|
69
|
shadow_GPIO &= ~(1 << bit_number);
|
GobertPierre |
0:d76c38ee24ab
|
70
|
} else {
|
GobertPierre |
0:d76c38ee24ab
|
71
|
shadow_GPIO |= 1 << bit_number;
|
GobertPierre |
0:d76c38ee24ab
|
72
|
}
|
GobertPierre |
0:d76c38ee24ab
|
73
|
writeRegister(GPIO, (unsigned short)shadow_GPIO);
|
GobertPierre |
0:d76c38ee24ab
|
74
|
}
|
GobertPierre |
0:d76c38ee24ab
|
75
|
|
GobertPierre |
0:d76c38ee24ab
|
76
|
/*-----------------------------------------------------------------------------
|
GobertPierre |
0:d76c38ee24ab
|
77
|
* Write a combination of bits to the 16-bit port
|
GobertPierre |
0:d76c38ee24ab
|
78
|
*/
|
GobertPierre |
0:d76c38ee24ab
|
79
|
void MCP23017::write_mask(unsigned short data, unsigned short mask) {
|
GobertPierre |
0:d76c38ee24ab
|
80
|
shadow_GPIO = (shadow_GPIO & ~mask) | data;
|
GobertPierre |
0:d76c38ee24ab
|
81
|
writeRegister(GPIO, (unsigned short)shadow_GPIO);
|
GobertPierre |
0:d76c38ee24ab
|
82
|
}
|
GobertPierre |
0:d76c38ee24ab
|
83
|
|
GobertPierre |
0:d76c38ee24ab
|
84
|
/*-----------------------------------------------------------------------------
|
GobertPierre |
0:d76c38ee24ab
|
85
|
* read_bit
|
GobertPierre |
0:d76c38ee24ab
|
86
|
* Read a single bit from the 16-bit port
|
GobertPierre |
0:d76c38ee24ab
|
87
|
*/
|
GobertPierre |
0:d76c38ee24ab
|
88
|
int MCP23017::read_bit(int bit_number) {
|
GobertPierre |
0:d76c38ee24ab
|
89
|
shadow_GPIO = readRegister(GPIO);
|
GobertPierre |
0:d76c38ee24ab
|
90
|
return ((shadow_GPIO >> bit_number) & 0x0001);
|
GobertPierre |
0:d76c38ee24ab
|
91
|
}
|
GobertPierre |
0:d76c38ee24ab
|
92
|
|
GobertPierre |
0:d76c38ee24ab
|
93
|
/*-----------------------------------------------------------------------------
|
GobertPierre |
0:d76c38ee24ab
|
94
|
* read_mask
|
GobertPierre |
0:d76c38ee24ab
|
95
|
*/
|
GobertPierre |
0:d76c38ee24ab
|
96
|
int MCP23017::read_mask(unsigned short mask) {
|
GobertPierre |
0:d76c38ee24ab
|
97
|
shadow_GPIO = readRegister(GPIO);
|
GobertPierre |
0:d76c38ee24ab
|
98
|
return (shadow_GPIO & mask);
|
GobertPierre |
0:d76c38ee24ab
|
99
|
}
|
GobertPierre |
0:d76c38ee24ab
|
100
|
|
GobertPierre |
0:d76c38ee24ab
|
101
|
/*-----------------------------------------------------------------------------
|
GobertPierre |
0:d76c38ee24ab
|
102
|
* Config
|
GobertPierre |
0:d76c38ee24ab
|
103
|
* set direction and pull-up registers
|
GobertPierre |
0:d76c38ee24ab
|
104
|
*/
|
GobertPierre |
0:d76c38ee24ab
|
105
|
void MCP23017::config(unsigned short dir_config, unsigned short pullup_config, unsigned short polarity_config) {
|
GobertPierre |
0:d76c38ee24ab
|
106
|
shadow_IODIR = dir_config;
|
GobertPierre |
0:d76c38ee24ab
|
107
|
writeRegister(IODIR, (unsigned short)shadow_IODIR);
|
GobertPierre |
0:d76c38ee24ab
|
108
|
shadow_GPPU = pullup_config;
|
GobertPierre |
0:d76c38ee24ab
|
109
|
writeRegister(GPPU, (unsigned short)shadow_GPPU);
|
GobertPierre |
0:d76c38ee24ab
|
110
|
shadow_IPOL = polarity_config;
|
GobertPierre |
0:d76c38ee24ab
|
111
|
writeRegister(IPOL, (unsigned short)shadow_IPOL);
|
GobertPierre |
0:d76c38ee24ab
|
112
|
}
|
GobertPierre |
0:d76c38ee24ab
|
113
|
|
GobertPierre |
0:d76c38ee24ab
|
114
|
/*-----------------------------------------------------------------------------
|
GobertPierre |
0:d76c38ee24ab
|
115
|
* writeRegister
|
GobertPierre |
0:d76c38ee24ab
|
116
|
* write a byte
|
GobertPierre |
0:d76c38ee24ab
|
117
|
*/
|
GobertPierre |
0:d76c38ee24ab
|
118
|
void MCP23017::writeRegister(int regAddress, unsigned char data) {
|
GobertPierre |
0:d76c38ee24ab
|
119
|
char buffer[2];
|
GobertPierre |
0:d76c38ee24ab
|
120
|
|
GobertPierre |
0:d76c38ee24ab
|
121
|
buffer[0] = regAddress;
|
GobertPierre |
0:d76c38ee24ab
|
122
|
buffer[1] = data;
|
GobertPierre |
0:d76c38ee24ab
|
123
|
_i2c.write(MCP23017_i2cAddress, buffer, 2);
|
GobertPierre |
0:d76c38ee24ab
|
124
|
}
|
GobertPierre |
0:d76c38ee24ab
|
125
|
|
GobertPierre |
0:d76c38ee24ab
|
126
|
/*----------------------------------------------------------------------------
|
GobertPierre |
0:d76c38ee24ab
|
127
|
* write Register
|
GobertPierre |
0:d76c38ee24ab
|
128
|
* write two bytes
|
GobertPierre |
0:d76c38ee24ab
|
129
|
*/
|
GobertPierre |
0:d76c38ee24ab
|
130
|
void MCP23017::writeRegister(int regAddress, unsigned short data) {
|
GobertPierre |
0:d76c38ee24ab
|
131
|
char buffer[3];
|
GobertPierre |
0:d76c38ee24ab
|
132
|
|
GobertPierre |
0:d76c38ee24ab
|
133
|
buffer[0] = regAddress;
|
GobertPierre |
0:d76c38ee24ab
|
134
|
tmp_data.value16 = data;
|
GobertPierre |
0:d76c38ee24ab
|
135
|
buffer[1] = tmp_data.value8[0];
|
GobertPierre |
0:d76c38ee24ab
|
136
|
buffer[2] = tmp_data.value8[1];
|
GobertPierre |
0:d76c38ee24ab
|
137
|
|
GobertPierre |
0:d76c38ee24ab
|
138
|
_i2c.write(MCP23017_i2cAddress, buffer, 3);
|
GobertPierre |
0:d76c38ee24ab
|
139
|
}
|
GobertPierre |
0:d76c38ee24ab
|
140
|
|
GobertPierre |
0:d76c38ee24ab
|
141
|
/*-----------------------------------------------------------------------------
|
GobertPierre |
0:d76c38ee24ab
|
142
|
* readRegister
|
GobertPierre |
0:d76c38ee24ab
|
143
|
*/
|
GobertPierre |
0:d76c38ee24ab
|
144
|
int MCP23017::readRegister(int regAddress) {
|
GobertPierre |
0:d76c38ee24ab
|
145
|
char buffer[2];
|
GobertPierre |
0:d76c38ee24ab
|
146
|
|
GobertPierre |
0:d76c38ee24ab
|
147
|
buffer[0] = regAddress;
|
GobertPierre |
0:d76c38ee24ab
|
148
|
_i2c.write(MCP23017_i2cAddress, buffer, 1);
|
GobertPierre |
0:d76c38ee24ab
|
149
|
_i2c.read(MCP23017_i2cAddress, buffer, 2);
|
GobertPierre |
0:d76c38ee24ab
|
150
|
|
GobertPierre |
0:d76c38ee24ab
|
151
|
return ((int)(buffer[0] + (buffer[1]<<8)));
|
GobertPierre |
0:d76c38ee24ab
|
152
|
}
|
GobertPierre |
0:d76c38ee24ab
|
153
|
|
GobertPierre |
0:d76c38ee24ab
|
154
|
/*-----------------------------------------------------------------------------
|
GobertPierre |
0:d76c38ee24ab
|
155
|
* pinMode
|
GobertPierre |
0:d76c38ee24ab
|
156
|
*/
|
GobertPierre |
0:d76c38ee24ab
|
157
|
void MCP23017::pinMode(int pin, int mode) {
|
GobertPierre |
0:d76c38ee24ab
|
158
|
if (DIR_INPUT) {
|
GobertPierre |
0:d76c38ee24ab
|
159
|
shadow_IODIR |= 1 << pin;
|
GobertPierre |
0:d76c38ee24ab
|
160
|
} else {
|
GobertPierre |
0:d76c38ee24ab
|
161
|
shadow_IODIR &= ~(1 << pin);
|
GobertPierre |
0:d76c38ee24ab
|
162
|
}
|
GobertPierre |
0:d76c38ee24ab
|
163
|
writeRegister(IODIR, (unsigned short)shadow_IODIR);
|
GobertPierre |
0:d76c38ee24ab
|
164
|
}
|
GobertPierre |
0:d76c38ee24ab
|
165
|
|
GobertPierre |
0:d76c38ee24ab
|
166
|
/*-----------------------------------------------------------------------------
|
GobertPierre |
0:d76c38ee24ab
|
167
|
* digitalRead
|
GobertPierre |
0:d76c38ee24ab
|
168
|
*/
|
GobertPierre |
0:d76c38ee24ab
|
169
|
int MCP23017::digitalRead(int pin) {
|
GobertPierre |
0:d76c38ee24ab
|
170
|
shadow_GPIO = readRegister(GPIO);
|
GobertPierre |
0:d76c38ee24ab
|
171
|
if ( shadow_GPIO & (1 << pin)) {
|
GobertPierre |
0:d76c38ee24ab
|
172
|
return 1;
|
GobertPierre |
0:d76c38ee24ab
|
173
|
} else {
|
GobertPierre |
0:d76c38ee24ab
|
174
|
return 0;
|
GobertPierre |
0:d76c38ee24ab
|
175
|
}
|
GobertPierre |
0:d76c38ee24ab
|
176
|
}
|
GobertPierre |
0:d76c38ee24ab
|
177
|
|
GobertPierre |
0:d76c38ee24ab
|
178
|
/*-----------------------------------------------------------------------------
|
GobertPierre |
0:d76c38ee24ab
|
179
|
* digitalWrite
|
GobertPierre |
0:d76c38ee24ab
|
180
|
*/
|
GobertPierre |
0:d76c38ee24ab
|
181
|
void MCP23017::digitalWrite(int pin, int val) {
|
GobertPierre |
0:d76c38ee24ab
|
182
|
//If this pin is an INPUT pin, a write here will
|
GobertPierre |
0:d76c38ee24ab
|
183
|
//enable the internal pullup
|
GobertPierre |
0:d76c38ee24ab
|
184
|
//otherwise, it will set the OUTPUT voltage
|
GobertPierre |
0:d76c38ee24ab
|
185
|
//as appropriate.
|
GobertPierre |
0:d76c38ee24ab
|
186
|
bool isOutput = !(shadow_IODIR & 1<<pin);
|
GobertPierre |
0:d76c38ee24ab
|
187
|
|
GobertPierre |
0:d76c38ee24ab
|
188
|
if (isOutput) {
|
GobertPierre |
0:d76c38ee24ab
|
189
|
//This is an output pin so just write the value
|
GobertPierre |
0:d76c38ee24ab
|
190
|
if (val) shadow_GPIO |= 1 << pin;
|
GobertPierre |
0:d76c38ee24ab
|
191
|
else shadow_GPIO &= ~(1 << pin);
|
GobertPierre |
0:d76c38ee24ab
|
192
|
writeRegister(GPIO, (unsigned short)shadow_GPIO);
|
GobertPierre |
0:d76c38ee24ab
|
193
|
} else {
|
GobertPierre |
0:d76c38ee24ab
|
194
|
//This is an input pin, so we need to enable the pullup
|
GobertPierre |
0:d76c38ee24ab
|
195
|
if (val) {
|
GobertPierre |
0:d76c38ee24ab
|
196
|
shadow_GPPU |= 1 << pin;
|
GobertPierre |
0:d76c38ee24ab
|
197
|
} else {
|
GobertPierre |
0:d76c38ee24ab
|
198
|
shadow_GPPU &= ~(1 << pin);
|
GobertPierre |
0:d76c38ee24ab
|
199
|
}
|
GobertPierre |
0:d76c38ee24ab
|
200
|
writeRegister(GPPU, (unsigned short)shadow_GPPU);
|
GobertPierre |
0:d76c38ee24ab
|
201
|
}
|
GobertPierre |
0:d76c38ee24ab
|
202
|
}
|
GobertPierre |
0:d76c38ee24ab
|
203
|
|
GobertPierre |
0:d76c38ee24ab
|
204
|
/*-----------------------------------------------------------------------------
|
GobertPierre |
0:d76c38ee24ab
|
205
|
* digitalWordRead
|
GobertPierre |
0:d76c38ee24ab
|
206
|
*/
|
GobertPierre |
0:d76c38ee24ab
|
207
|
unsigned short MCP23017::digitalWordRead() {
|
GobertPierre |
0:d76c38ee24ab
|
208
|
shadow_GPIO = readRegister(GPIO);
|
GobertPierre |
0:d76c38ee24ab
|
209
|
return shadow_GPIO;
|
GobertPierre |
0:d76c38ee24ab
|
210
|
}
|
GobertPierre |
0:d76c38ee24ab
|
211
|
|
GobertPierre |
0:d76c38ee24ab
|
212
|
/*-----------------------------------------------------------------------------
|
GobertPierre |
0:d76c38ee24ab
|
213
|
* digitalWordWrite
|
GobertPierre |
0:d76c38ee24ab
|
214
|
*/
|
GobertPierre |
0:d76c38ee24ab
|
215
|
void MCP23017::digitalWordWrite(unsigned short w) {
|
GobertPierre |
0:d76c38ee24ab
|
216
|
shadow_GPIO = w;
|
GobertPierre |
0:d76c38ee24ab
|
217
|
writeRegister(GPIO, (unsigned short)shadow_GPIO);
|
GobertPierre |
0:d76c38ee24ab
|
218
|
}
|
GobertPierre |
0:d76c38ee24ab
|
219
|
|
GobertPierre |
0:d76c38ee24ab
|
220
|
/*-----------------------------------------------------------------------------
|
GobertPierre |
0:d76c38ee24ab
|
221
|
* inputPolarityMask
|
GobertPierre |
0:d76c38ee24ab
|
222
|
*/
|
GobertPierre |
0:d76c38ee24ab
|
223
|
void MCP23017::inputPolarityMask(unsigned short mask) {
|
GobertPierre |
0:d76c38ee24ab
|
224
|
writeRegister(IPOL, mask);
|
GobertPierre |
0:d76c38ee24ab
|
225
|
}
|
GobertPierre |
0:d76c38ee24ab
|
226
|
|
GobertPierre |
0:d76c38ee24ab
|
227
|
/*-----------------------------------------------------------------------------
|
GobertPierre |
0:d76c38ee24ab
|
228
|
* inputoutputMask
|
GobertPierre |
0:d76c38ee24ab
|
229
|
*/
|
GobertPierre |
0:d76c38ee24ab
|
230
|
void MCP23017::inputOutputMask(unsigned short mask) {
|
GobertPierre |
0:d76c38ee24ab
|
231
|
shadow_IODIR = mask;
|
GobertPierre |
0:d76c38ee24ab
|
232
|
writeRegister(IODIR, (unsigned short)shadow_IODIR);
|
GobertPierre |
0:d76c38ee24ab
|
233
|
}
|
GobertPierre |
0:d76c38ee24ab
|
234
|
|
GobertPierre |
0:d76c38ee24ab
|
235
|
/*-----------------------------------------------------------------------------
|
GobertPierre |
0:d76c38ee24ab
|
236
|
* internalPullupMask
|
GobertPierre |
0:d76c38ee24ab
|
237
|
*/
|
GobertPierre |
0:d76c38ee24ab
|
238
|
void MCP23017::internalPullupMask(unsigned short mask) {
|
GobertPierre |
0:d76c38ee24ab
|
239
|
shadow_GPPU = mask;
|
GobertPierre |
0:d76c38ee24ab
|
240
|
writeRegister(GPPU, (unsigned short)shadow_GPPU);
|
GobertPierre |
0:d76c38ee24ab
|
241
|
}
|
GobertPierre |
0:d76c38ee24ab
|
242
|
|