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 } }
Revision 0:133b7e09bbe7, committed 2016-01-19
- Comitter:
- davidr99
- Date:
- Tue Jan 19 23:50:23 2016 +0000
- Commit message:
- MCP23016 Library
Changed in this revision
MCP23016.cpp | Show annotated file Show diff for this revision Revisions of this file |
MCP23016.h | Show annotated file Show diff for this revision Revisions of this file |
diff -r 000000000000 -r 133b7e09bbe7 MCP23016.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MCP23016.cpp Tue Jan 19 23:50:23 2016 +0000 @@ -0,0 +1,216 @@ +/* MCP23016 library + Based on MCP23017 library for arduino by David Pye <davidmpye@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "MCP23016.h" +#include "mbed.h" + +union { + uint8_t value8[2]; + uint16_t value16; +} tmp_data; + +/*----------------------------------------------------------------------------- + * + */ +MCP23016::MCP23016(PinName sda, PinName scl, int i2cAddress) : _i2c(sda, scl) { + MCP23016_i2cAddress = I2C_BASE_ADDRESS + i2cAddress; + reset(); // initialise chip to power-on condition +} + +/*----------------------------------------------------------------------------- + * reset + * Set configuration (IOCON) and direction(IODIR) registers to initial state + */ +void MCP23016::reset() { +// +// set direction registers to inputs +// + writeRegister(IODIR0, (unsigned short)0xFFFF); +// +// set all other registers to zero (last of 10 registers is OLAT) +// + for (int reg_addr = OLAT0 ; reg_addr <= IPOL1 ; reg_addr+=2) { + writeRegister(reg_addr, (unsigned short)0x0000); + } +// +// Set the shadow registers to power-on state +// + shadow_IODIR = 0xFFFF; + shadow_GPIO = 0; + shadow_IPOL = 0; +} + +/*----------------------------------------------------------------------------- + * write_bit + * Write a 1/0 to a single bit of the 16-bit port + */ +void MCP23016::write_bit(int value, int bit_number) { + if (value == 0) { + shadow_GPIO &= ~(1 << bit_number); + } else { + shadow_GPIO |= 1 << bit_number; + } + writeRegister(OLAT0, (unsigned short)shadow_GPIO); +} + +/*----------------------------------------------------------------------------- + * Write a combination of bits to the 16-bit port + */ +void MCP23016::write_mask(unsigned short data, unsigned short mask) { + shadow_GPIO = (shadow_GPIO & ~mask) | data; + writeRegister(OLAT0, (unsigned short)shadow_GPIO); +} + +/*----------------------------------------------------------------------------- + * read_bit + * Read a single bit from the 16-bit port + */ +int MCP23016::read_bit(int bit_number) { + shadow_GPIO = readRegister(GP0); + return ((shadow_GPIO >> bit_number) & 0x0001); +} + +/*----------------------------------------------------------------------------- + * read_mask + */ +int MCP23016::read_mask(unsigned short mask) { + shadow_GPIO = readRegister(GP0); + return (shadow_GPIO & mask); +} + +/*----------------------------------------------------------------------------- + * Config + * set direction and pull-up registers + */ +void MCP23016::config(unsigned short dir_config, unsigned short polarity_config) { + shadow_IODIR = dir_config; + writeRegister(IODIR0, (unsigned short)shadow_IODIR); + shadow_IPOL = polarity_config; + writeRegister(IPOL0, (unsigned short)shadow_IPOL); +} + +/*----------------------------------------------------------------------------- + * writeRegister + * write a byte + */ +void MCP23016::writeRegister(int regAddress, unsigned char data) { + char buffer[2]; + + buffer[0] = regAddress; + buffer[1] = data; + _i2c.write(MCP23016_i2cAddress, buffer, 2); +} + +/*---------------------------------------------------------------------------- + * write Register + * write two bytes + */ +void MCP23016::writeRegister(int regAddress, unsigned short data) { + char buffer[3]; + + buffer[0] = regAddress; + tmp_data.value16 = data; + buffer[1] = tmp_data.value8[0]; + buffer[2] = tmp_data.value8[1]; + + _i2c.write(MCP23016_i2cAddress, buffer, 3); +} + +/*----------------------------------------------------------------------------- + * readRegister + */ +int MCP23016::readRegister(int regAddress) { + char buffer[2]; + + buffer[0] = regAddress; + _i2c.write(MCP23016_i2cAddress, buffer, 1); + _i2c.read(MCP23016_i2cAddress, buffer, 2); + + return ((int)(buffer[0] + (buffer[1]<<8))); +} + +/*----------------------------------------------------------------------------- + * pinMode + */ +void MCP23016::pinMode(int pin, int mode) { + if (mode == DIR_INPUT) { + shadow_IODIR |= 1 << pin; + } else { + shadow_IODIR &= ~(1 << pin); + } + writeRegister(IODIR0, (unsigned short)shadow_IODIR); +} + +/*----------------------------------------------------------------------------- + * digitalRead + */ +int MCP23016::digitalRead(int pin) { + shadow_GPIO = readRegister(GP0); + if ( shadow_GPIO & (1 << pin)) { + return 1; + } else { + return 0; + } +} + +/*----------------------------------------------------------------------------- + * digitalWrite + */ +void MCP23016::digitalWrite(int pin, int val) { + // This will set the OUTPUT voltage + //as appropriate. + bool isOutput = !(shadow_IODIR & 1<<pin); + + if (isOutput) { + //This is an output pin so just write the value + if (val) shadow_GPIO |= 1 << pin; + else shadow_GPIO &= ~(1 << pin); + writeRegister(OLAT0, (unsigned short)shadow_GPIO); + } +} + +/*----------------------------------------------------------------------------- + * digitalWordRead + */ +unsigned short MCP23016::digitalWordRead() { + shadow_GPIO = readRegister(GP0); + return shadow_GPIO; +} + +/*----------------------------------------------------------------------------- + * digitalWordWrite + */ +void MCP23016::digitalWordWrite(unsigned short w) { + shadow_GPIO = w; + writeRegister(OLAT0, (unsigned short)shadow_GPIO); +} + +/*----------------------------------------------------------------------------- + * inputPolarityMask + */ +void MCP23016::inputPolarityMask(unsigned short mask) { + writeRegister(IPOL0, mask); +} + +/*----------------------------------------------------------------------------- + * inputoutputMask + */ +void MCP23016::inputOutputMask(unsigned short mask) { + shadow_IODIR = mask; + writeRegister(IODIR0, (unsigned short)shadow_IODIR); +} +
diff -r 000000000000 -r 133b7e09bbe7 MCP23016.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MCP23016.h Tue Jan 19 23:50:23 2016 +0000 @@ -0,0 +1,136 @@ +/* MCP23016 library + Based on MCP23017 library for arduino by David Pye <davidmpye@gmail.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef MBED_MCP23016_H +#define MBED_MCP23016_H + +#include "mbed.h" + +#define GP0 0x00 // Access to GP0 +#define GP1 0x01 // Access to GP1 +#define OLAT0 0x02 // Access to OLAT0 +#define OLAT1 0x03 // Access to OLAT1 +#define IPOL0 0x04 // Access to IPOL0 +#define IPOL1 0x05 // Access to IPOL1 +#define IODIR0 0x06 // Access to IODIR0 +#define IODIR1 0x07 // Access to IODIR1 +#define INTCAP0 0x08 // Access to INTCAP0 (Read-Only) +#define INTCAP1 0x09 // Access to INTCAP1 (Read-Only) +#define IOCON0 0x0A // Access to IOCON0 +#define IOCON1 0x0B // Access to IOCON1 + +#define I2C_BASE_ADDRESS 0x40 + +#define DIR_OUTPUT 0 +#define DIR_INPUT 1 + +/** MCP23016 class + * + * Allow access to an I2C connected MCP23016 16-bit I/O extender chip + * Example: + * @code + * MCP23016 *par_port; + * @endcode + * + */ +class MCP23016 { +public: + /** Constructor for the MCP23016 connected to specified I2C pins at a specific address + * + * 16-bit I/O expander with I2C interface + * + * @param sda I2C data pin + * @param scl I2C clock pin + * @param i2cAddress I2C address + */ + MCP23016(PinName sda, PinName scl, int i2cAddress); + + /** Reset MCP23016 device to its power-on state + */ + void reset(void); + + /** Write a 0/1 value to an output bit + * + * @param value 0 or 1 + * @param bit_number bit number range 0 --> 15 + */ + void write_bit(int value, int bit_number); + + /** Write a masked 16-bit value to the device + * + * @param data 16-bit data value + * @param mask 16-bit mask value + */ + void write_mask(unsigned short data, unsigned short mask); + + /** Read a 0/1 value from an input bit + * + * @param bit_number bit number range 0 --> 15 + * @return 0/1 value read + */ + int read_bit(int bit_number); + + /** Read a 16-bit value from the device and apply mask + * + * @param mask 16-bit mask value + * @return 16-bit data with mask applied + */ + int read_mask(unsigned short mask); + + /** Configure an MCP23016 device + * + * @param dir_config data direction value (1 = input, 0 = output) + * @param polarity_config polarity value (1 = flip, 0 = normal) + */ + void config(unsigned short dir_config, unsigned short polarity_config); + + void writeRegister(int regAddress, unsigned char val); + void writeRegister(int regAddress, unsigned short val); + int readRegister(int regAddress); + +/*----------------------------------------------------------------------------- + * pinmode + * Set units to sequential, bank0 mode + */ + void pinMode(int pin, int mode); + void digitalWrite(int pin, int val); + int digitalRead(int pin); + +// These provide a more advanced mapping of the chip functionality +// See the data sheet for more information on what they do + +//Returns a word with the current pin states (ie contents of the GPIO register) + unsigned short digitalWordRead(); +// Allows you to write a word to the GPIO register + void digitalWordWrite(unsigned short w); +// Sets up the polarity mask that the MCP23016 supports +// if set to 1, it will flip the actual pin value. + void inputPolarityMask(unsigned short mask); +//Sets which pins are inputs or outputs (1 = input, 0 = output) NB Opposite to arduino's +//definition for these + void inputOutputMask(unsigned short mask); + int read(void); + void write(int data); + +protected: + I2C _i2c; + int MCP23016_i2cAddress; // physical I2C address + unsigned short shadow_GPIO, shadow_IODIR, shadow_IPOL; // Cached copies of the register values + +}; + +#endif \ No newline at end of file