Basic library to interface to a Microchip MCP23016 I/O expander using I2C
Testing code to blink 2 lights
#include "mbed.h" #include "MCP23016.h" MCP23016 PortExpand(D4, D5, 0); DigitalOut myled(LED1); int main() { PortExpand.pinMode(0, DIR_OUTPUT); PortExpand.pinMode(8, DIR_OUTPUT); while(1) { PortExpand.digitalWrite(0, 1); PortExpand.digitalWrite(8, 0); myled = 1; // LED is ON wait(1); // 200 ms PortExpand.digitalWrite(0, 0); PortExpand.digitalWrite(8, 1); myled = 0; // LED is OFF wait(1); // 1 sec } }
MCP23016.cpp@0:133b7e09bbe7, 2016-01-19 (annotated)
- Committer:
- davidr99
- Date:
- Tue Jan 19 23:50:23 2016 +0000
- Revision:
- 0:133b7e09bbe7
MCP23016 Library
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
davidr99 | 0:133b7e09bbe7 | 1 | /* MCP23016 library |
davidr99 | 0:133b7e09bbe7 | 2 | Based on MCP23017 library for arduino by David Pye <davidmpye@gmail.com> |
davidr99 | 0:133b7e09bbe7 | 3 | |
davidr99 | 0:133b7e09bbe7 | 4 | This program is free software: you can redistribute it and/or modify |
davidr99 | 0:133b7e09bbe7 | 5 | it under the terms of the GNU General Public License as published by |
davidr99 | 0:133b7e09bbe7 | 6 | the Free Software Foundation, either version 3 of the License, or |
davidr99 | 0:133b7e09bbe7 | 7 | (at your option) any later version. |
davidr99 | 0:133b7e09bbe7 | 8 | |
davidr99 | 0:133b7e09bbe7 | 9 | This program is distributed in the hope that it will be useful, |
davidr99 | 0:133b7e09bbe7 | 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
davidr99 | 0:133b7e09bbe7 | 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
davidr99 | 0:133b7e09bbe7 | 12 | GNU General Public License for more details. |
davidr99 | 0:133b7e09bbe7 | 13 | |
davidr99 | 0:133b7e09bbe7 | 14 | You should have received a copy of the GNU General Public License |
davidr99 | 0:133b7e09bbe7 | 15 | along with this program. If not, see <http://www.gnu.org/licenses/>. |
davidr99 | 0:133b7e09bbe7 | 16 | */ |
davidr99 | 0:133b7e09bbe7 | 17 | |
davidr99 | 0:133b7e09bbe7 | 18 | #include "MCP23016.h" |
davidr99 | 0:133b7e09bbe7 | 19 | #include "mbed.h" |
davidr99 | 0:133b7e09bbe7 | 20 | |
davidr99 | 0:133b7e09bbe7 | 21 | union { |
davidr99 | 0:133b7e09bbe7 | 22 | uint8_t value8[2]; |
davidr99 | 0:133b7e09bbe7 | 23 | uint16_t value16; |
davidr99 | 0:133b7e09bbe7 | 24 | } tmp_data; |
davidr99 | 0:133b7e09bbe7 | 25 | |
davidr99 | 0:133b7e09bbe7 | 26 | /*----------------------------------------------------------------------------- |
davidr99 | 0:133b7e09bbe7 | 27 | * |
davidr99 | 0:133b7e09bbe7 | 28 | */ |
davidr99 | 0:133b7e09bbe7 | 29 | MCP23016::MCP23016(PinName sda, PinName scl, int i2cAddress) : _i2c(sda, scl) { |
davidr99 | 0:133b7e09bbe7 | 30 | MCP23016_i2cAddress = I2C_BASE_ADDRESS + i2cAddress; |
davidr99 | 0:133b7e09bbe7 | 31 | reset(); // initialise chip to power-on condition |
davidr99 | 0:133b7e09bbe7 | 32 | } |
davidr99 | 0:133b7e09bbe7 | 33 | |
davidr99 | 0:133b7e09bbe7 | 34 | /*----------------------------------------------------------------------------- |
davidr99 | 0:133b7e09bbe7 | 35 | * reset |
davidr99 | 0:133b7e09bbe7 | 36 | * Set configuration (IOCON) and direction(IODIR) registers to initial state |
davidr99 | 0:133b7e09bbe7 | 37 | */ |
davidr99 | 0:133b7e09bbe7 | 38 | void MCP23016::reset() { |
davidr99 | 0:133b7e09bbe7 | 39 | // |
davidr99 | 0:133b7e09bbe7 | 40 | // set direction registers to inputs |
davidr99 | 0:133b7e09bbe7 | 41 | // |
davidr99 | 0:133b7e09bbe7 | 42 | writeRegister(IODIR0, (unsigned short)0xFFFF); |
davidr99 | 0:133b7e09bbe7 | 43 | // |
davidr99 | 0:133b7e09bbe7 | 44 | // set all other registers to zero (last of 10 registers is OLAT) |
davidr99 | 0:133b7e09bbe7 | 45 | // |
davidr99 | 0:133b7e09bbe7 | 46 | for (int reg_addr = OLAT0 ; reg_addr <= IPOL1 ; reg_addr+=2) { |
davidr99 | 0:133b7e09bbe7 | 47 | writeRegister(reg_addr, (unsigned short)0x0000); |
davidr99 | 0:133b7e09bbe7 | 48 | } |
davidr99 | 0:133b7e09bbe7 | 49 | // |
davidr99 | 0:133b7e09bbe7 | 50 | // Set the shadow registers to power-on state |
davidr99 | 0:133b7e09bbe7 | 51 | // |
davidr99 | 0:133b7e09bbe7 | 52 | shadow_IODIR = 0xFFFF; |
davidr99 | 0:133b7e09bbe7 | 53 | shadow_GPIO = 0; |
davidr99 | 0:133b7e09bbe7 | 54 | shadow_IPOL = 0; |
davidr99 | 0:133b7e09bbe7 | 55 | } |
davidr99 | 0:133b7e09bbe7 | 56 | |
davidr99 | 0:133b7e09bbe7 | 57 | /*----------------------------------------------------------------------------- |
davidr99 | 0:133b7e09bbe7 | 58 | * write_bit |
davidr99 | 0:133b7e09bbe7 | 59 | * Write a 1/0 to a single bit of the 16-bit port |
davidr99 | 0:133b7e09bbe7 | 60 | */ |
davidr99 | 0:133b7e09bbe7 | 61 | void MCP23016::write_bit(int value, int bit_number) { |
davidr99 | 0:133b7e09bbe7 | 62 | if (value == 0) { |
davidr99 | 0:133b7e09bbe7 | 63 | shadow_GPIO &= ~(1 << bit_number); |
davidr99 | 0:133b7e09bbe7 | 64 | } else { |
davidr99 | 0:133b7e09bbe7 | 65 | shadow_GPIO |= 1 << bit_number; |
davidr99 | 0:133b7e09bbe7 | 66 | } |
davidr99 | 0:133b7e09bbe7 | 67 | writeRegister(OLAT0, (unsigned short)shadow_GPIO); |
davidr99 | 0:133b7e09bbe7 | 68 | } |
davidr99 | 0:133b7e09bbe7 | 69 | |
davidr99 | 0:133b7e09bbe7 | 70 | /*----------------------------------------------------------------------------- |
davidr99 | 0:133b7e09bbe7 | 71 | * Write a combination of bits to the 16-bit port |
davidr99 | 0:133b7e09bbe7 | 72 | */ |
davidr99 | 0:133b7e09bbe7 | 73 | void MCP23016::write_mask(unsigned short data, unsigned short mask) { |
davidr99 | 0:133b7e09bbe7 | 74 | shadow_GPIO = (shadow_GPIO & ~mask) | data; |
davidr99 | 0:133b7e09bbe7 | 75 | writeRegister(OLAT0, (unsigned short)shadow_GPIO); |
davidr99 | 0:133b7e09bbe7 | 76 | } |
davidr99 | 0:133b7e09bbe7 | 77 | |
davidr99 | 0:133b7e09bbe7 | 78 | /*----------------------------------------------------------------------------- |
davidr99 | 0:133b7e09bbe7 | 79 | * read_bit |
davidr99 | 0:133b7e09bbe7 | 80 | * Read a single bit from the 16-bit port |
davidr99 | 0:133b7e09bbe7 | 81 | */ |
davidr99 | 0:133b7e09bbe7 | 82 | int MCP23016::read_bit(int bit_number) { |
davidr99 | 0:133b7e09bbe7 | 83 | shadow_GPIO = readRegister(GP0); |
davidr99 | 0:133b7e09bbe7 | 84 | return ((shadow_GPIO >> bit_number) & 0x0001); |
davidr99 | 0:133b7e09bbe7 | 85 | } |
davidr99 | 0:133b7e09bbe7 | 86 | |
davidr99 | 0:133b7e09bbe7 | 87 | /*----------------------------------------------------------------------------- |
davidr99 | 0:133b7e09bbe7 | 88 | * read_mask |
davidr99 | 0:133b7e09bbe7 | 89 | */ |
davidr99 | 0:133b7e09bbe7 | 90 | int MCP23016::read_mask(unsigned short mask) { |
davidr99 | 0:133b7e09bbe7 | 91 | shadow_GPIO = readRegister(GP0); |
davidr99 | 0:133b7e09bbe7 | 92 | return (shadow_GPIO & mask); |
davidr99 | 0:133b7e09bbe7 | 93 | } |
davidr99 | 0:133b7e09bbe7 | 94 | |
davidr99 | 0:133b7e09bbe7 | 95 | /*----------------------------------------------------------------------------- |
davidr99 | 0:133b7e09bbe7 | 96 | * Config |
davidr99 | 0:133b7e09bbe7 | 97 | * set direction and pull-up registers |
davidr99 | 0:133b7e09bbe7 | 98 | */ |
davidr99 | 0:133b7e09bbe7 | 99 | void MCP23016::config(unsigned short dir_config, unsigned short polarity_config) { |
davidr99 | 0:133b7e09bbe7 | 100 | shadow_IODIR = dir_config; |
davidr99 | 0:133b7e09bbe7 | 101 | writeRegister(IODIR0, (unsigned short)shadow_IODIR); |
davidr99 | 0:133b7e09bbe7 | 102 | shadow_IPOL = polarity_config; |
davidr99 | 0:133b7e09bbe7 | 103 | writeRegister(IPOL0, (unsigned short)shadow_IPOL); |
davidr99 | 0:133b7e09bbe7 | 104 | } |
davidr99 | 0:133b7e09bbe7 | 105 | |
davidr99 | 0:133b7e09bbe7 | 106 | /*----------------------------------------------------------------------------- |
davidr99 | 0:133b7e09bbe7 | 107 | * writeRegister |
davidr99 | 0:133b7e09bbe7 | 108 | * write a byte |
davidr99 | 0:133b7e09bbe7 | 109 | */ |
davidr99 | 0:133b7e09bbe7 | 110 | void MCP23016::writeRegister(int regAddress, unsigned char data) { |
davidr99 | 0:133b7e09bbe7 | 111 | char buffer[2]; |
davidr99 | 0:133b7e09bbe7 | 112 | |
davidr99 | 0:133b7e09bbe7 | 113 | buffer[0] = regAddress; |
davidr99 | 0:133b7e09bbe7 | 114 | buffer[1] = data; |
davidr99 | 0:133b7e09bbe7 | 115 | _i2c.write(MCP23016_i2cAddress, buffer, 2); |
davidr99 | 0:133b7e09bbe7 | 116 | } |
davidr99 | 0:133b7e09bbe7 | 117 | |
davidr99 | 0:133b7e09bbe7 | 118 | /*---------------------------------------------------------------------------- |
davidr99 | 0:133b7e09bbe7 | 119 | * write Register |
davidr99 | 0:133b7e09bbe7 | 120 | * write two bytes |
davidr99 | 0:133b7e09bbe7 | 121 | */ |
davidr99 | 0:133b7e09bbe7 | 122 | void MCP23016::writeRegister(int regAddress, unsigned short data) { |
davidr99 | 0:133b7e09bbe7 | 123 | char buffer[3]; |
davidr99 | 0:133b7e09bbe7 | 124 | |
davidr99 | 0:133b7e09bbe7 | 125 | buffer[0] = regAddress; |
davidr99 | 0:133b7e09bbe7 | 126 | tmp_data.value16 = data; |
davidr99 | 0:133b7e09bbe7 | 127 | buffer[1] = tmp_data.value8[0]; |
davidr99 | 0:133b7e09bbe7 | 128 | buffer[2] = tmp_data.value8[1]; |
davidr99 | 0:133b7e09bbe7 | 129 | |
davidr99 | 0:133b7e09bbe7 | 130 | _i2c.write(MCP23016_i2cAddress, buffer, 3); |
davidr99 | 0:133b7e09bbe7 | 131 | } |
davidr99 | 0:133b7e09bbe7 | 132 | |
davidr99 | 0:133b7e09bbe7 | 133 | /*----------------------------------------------------------------------------- |
davidr99 | 0:133b7e09bbe7 | 134 | * readRegister |
davidr99 | 0:133b7e09bbe7 | 135 | */ |
davidr99 | 0:133b7e09bbe7 | 136 | int MCP23016::readRegister(int regAddress) { |
davidr99 | 0:133b7e09bbe7 | 137 | char buffer[2]; |
davidr99 | 0:133b7e09bbe7 | 138 | |
davidr99 | 0:133b7e09bbe7 | 139 | buffer[0] = regAddress; |
davidr99 | 0:133b7e09bbe7 | 140 | _i2c.write(MCP23016_i2cAddress, buffer, 1); |
davidr99 | 0:133b7e09bbe7 | 141 | _i2c.read(MCP23016_i2cAddress, buffer, 2); |
davidr99 | 0:133b7e09bbe7 | 142 | |
davidr99 | 0:133b7e09bbe7 | 143 | return ((int)(buffer[0] + (buffer[1]<<8))); |
davidr99 | 0:133b7e09bbe7 | 144 | } |
davidr99 | 0:133b7e09bbe7 | 145 | |
davidr99 | 0:133b7e09bbe7 | 146 | /*----------------------------------------------------------------------------- |
davidr99 | 0:133b7e09bbe7 | 147 | * pinMode |
davidr99 | 0:133b7e09bbe7 | 148 | */ |
davidr99 | 0:133b7e09bbe7 | 149 | void MCP23016::pinMode(int pin, int mode) { |
davidr99 | 0:133b7e09bbe7 | 150 | if (mode == DIR_INPUT) { |
davidr99 | 0:133b7e09bbe7 | 151 | shadow_IODIR |= 1 << pin; |
davidr99 | 0:133b7e09bbe7 | 152 | } else { |
davidr99 | 0:133b7e09bbe7 | 153 | shadow_IODIR &= ~(1 << pin); |
davidr99 | 0:133b7e09bbe7 | 154 | } |
davidr99 | 0:133b7e09bbe7 | 155 | writeRegister(IODIR0, (unsigned short)shadow_IODIR); |
davidr99 | 0:133b7e09bbe7 | 156 | } |
davidr99 | 0:133b7e09bbe7 | 157 | |
davidr99 | 0:133b7e09bbe7 | 158 | /*----------------------------------------------------------------------------- |
davidr99 | 0:133b7e09bbe7 | 159 | * digitalRead |
davidr99 | 0:133b7e09bbe7 | 160 | */ |
davidr99 | 0:133b7e09bbe7 | 161 | int MCP23016::digitalRead(int pin) { |
davidr99 | 0:133b7e09bbe7 | 162 | shadow_GPIO = readRegister(GP0); |
davidr99 | 0:133b7e09bbe7 | 163 | if ( shadow_GPIO & (1 << pin)) { |
davidr99 | 0:133b7e09bbe7 | 164 | return 1; |
davidr99 | 0:133b7e09bbe7 | 165 | } else { |
davidr99 | 0:133b7e09bbe7 | 166 | return 0; |
davidr99 | 0:133b7e09bbe7 | 167 | } |
davidr99 | 0:133b7e09bbe7 | 168 | } |
davidr99 | 0:133b7e09bbe7 | 169 | |
davidr99 | 0:133b7e09bbe7 | 170 | /*----------------------------------------------------------------------------- |
davidr99 | 0:133b7e09bbe7 | 171 | * digitalWrite |
davidr99 | 0:133b7e09bbe7 | 172 | */ |
davidr99 | 0:133b7e09bbe7 | 173 | void MCP23016::digitalWrite(int pin, int val) { |
davidr99 | 0:133b7e09bbe7 | 174 | // This will set the OUTPUT voltage |
davidr99 | 0:133b7e09bbe7 | 175 | //as appropriate. |
davidr99 | 0:133b7e09bbe7 | 176 | bool isOutput = !(shadow_IODIR & 1<<pin); |
davidr99 | 0:133b7e09bbe7 | 177 | |
davidr99 | 0:133b7e09bbe7 | 178 | if (isOutput) { |
davidr99 | 0:133b7e09bbe7 | 179 | //This is an output pin so just write the value |
davidr99 | 0:133b7e09bbe7 | 180 | if (val) shadow_GPIO |= 1 << pin; |
davidr99 | 0:133b7e09bbe7 | 181 | else shadow_GPIO &= ~(1 << pin); |
davidr99 | 0:133b7e09bbe7 | 182 | writeRegister(OLAT0, (unsigned short)shadow_GPIO); |
davidr99 | 0:133b7e09bbe7 | 183 | } |
davidr99 | 0:133b7e09bbe7 | 184 | } |
davidr99 | 0:133b7e09bbe7 | 185 | |
davidr99 | 0:133b7e09bbe7 | 186 | /*----------------------------------------------------------------------------- |
davidr99 | 0:133b7e09bbe7 | 187 | * digitalWordRead |
davidr99 | 0:133b7e09bbe7 | 188 | */ |
davidr99 | 0:133b7e09bbe7 | 189 | unsigned short MCP23016::digitalWordRead() { |
davidr99 | 0:133b7e09bbe7 | 190 | shadow_GPIO = readRegister(GP0); |
davidr99 | 0:133b7e09bbe7 | 191 | return shadow_GPIO; |
davidr99 | 0:133b7e09bbe7 | 192 | } |
davidr99 | 0:133b7e09bbe7 | 193 | |
davidr99 | 0:133b7e09bbe7 | 194 | /*----------------------------------------------------------------------------- |
davidr99 | 0:133b7e09bbe7 | 195 | * digitalWordWrite |
davidr99 | 0:133b7e09bbe7 | 196 | */ |
davidr99 | 0:133b7e09bbe7 | 197 | void MCP23016::digitalWordWrite(unsigned short w) { |
davidr99 | 0:133b7e09bbe7 | 198 | shadow_GPIO = w; |
davidr99 | 0:133b7e09bbe7 | 199 | writeRegister(OLAT0, (unsigned short)shadow_GPIO); |
davidr99 | 0:133b7e09bbe7 | 200 | } |
davidr99 | 0:133b7e09bbe7 | 201 | |
davidr99 | 0:133b7e09bbe7 | 202 | /*----------------------------------------------------------------------------- |
davidr99 | 0:133b7e09bbe7 | 203 | * inputPolarityMask |
davidr99 | 0:133b7e09bbe7 | 204 | */ |
davidr99 | 0:133b7e09bbe7 | 205 | void MCP23016::inputPolarityMask(unsigned short mask) { |
davidr99 | 0:133b7e09bbe7 | 206 | writeRegister(IPOL0, mask); |
davidr99 | 0:133b7e09bbe7 | 207 | } |
davidr99 | 0:133b7e09bbe7 | 208 | |
davidr99 | 0:133b7e09bbe7 | 209 | /*----------------------------------------------------------------------------- |
davidr99 | 0:133b7e09bbe7 | 210 | * inputoutputMask |
davidr99 | 0:133b7e09bbe7 | 211 | */ |
davidr99 | 0:133b7e09bbe7 | 212 | void MCP23016::inputOutputMask(unsigned short mask) { |
davidr99 | 0:133b7e09bbe7 | 213 | shadow_IODIR = mask; |
davidr99 | 0:133b7e09bbe7 | 214 | writeRegister(IODIR0, (unsigned short)shadow_IODIR); |
davidr99 | 0:133b7e09bbe7 | 215 | } |
davidr99 | 0:133b7e09bbe7 | 216 |