This library provides simplified I2C access to a Microchip MCP23x17 GPIO expender device, including a general interface for any GPIO expender

Dependents:   MCP23017App

Committer:
Yann
Date:
Tue Jan 13 10:20:02 2015 +0000
Revision:
3:b902729a1675
Parent:
2:3bea48e1505c
Remove DEBUG info

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Yann 1:ec9e770173d5 1 /* mbed simplified access to Microchip MCP23x17 GPIO expender devices (I2C)
Yann 0:ebd3a7cc9b92 2 * Copyright (c) 2014-2015 ygarcia, MIT License
Yann 0:ebd3a7cc9b92 3 *
Yann 0:ebd3a7cc9b92 4 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
Yann 0:ebd3a7cc9b92 5 * and associated documentation files (the "Software"), to deal in the Software without restriction,
Yann 0:ebd3a7cc9b92 6 * including without limitation the rights to use, copy, modify, merge, publish, distribute,
Yann 0:ebd3a7cc9b92 7 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
Yann 0:ebd3a7cc9b92 8 * furnished to do so, subject to the following conditions:
Yann 0:ebd3a7cc9b92 9 *
Yann 0:ebd3a7cc9b92 10 * The above copyright notice and this permission notice shall be included in all copies or
Yann 0:ebd3a7cc9b92 11 * substantial portions of the Software.
Yann 0:ebd3a7cc9b92 12 *
Yann 0:ebd3a7cc9b92 13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
Yann 0:ebd3a7cc9b92 14 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
Yann 0:ebd3a7cc9b92 15 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
Yann 0:ebd3a7cc9b92 16 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
Yann 0:ebd3a7cc9b92 17 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Yann 0:ebd3a7cc9b92 18 */
Yann 0:ebd3a7cc9b92 19 #pragma once
Yann 0:ebd3a7cc9b92 20
Yann 0:ebd3a7cc9b92 21 #include <map>
Yann 0:ebd3a7cc9b92 22
Yann 0:ebd3a7cc9b92 23 #include "Debug.h"
Yann 0:ebd3a7cc9b92 24
Yann 0:ebd3a7cc9b92 25 #include "AbstractGpioExpender.h"
Yann 0:ebd3a7cc9b92 26
Yann 0:ebd3a7cc9b92 27 namespace MCP23017_I2C {
Yann 0:ebd3a7cc9b92 28 /** This class provides simplified I2C access to a Microchip 2MCP28x17 GPIO expender. V0.0.0.1
Yann 0:ebd3a7cc9b92 29 *
Yann 0:ebd3a7cc9b92 30 * Note that if the LPC1768 is powered in 3.3V and Microchip MCP28x17 GPIO expender device could be powered at 3.3V or 5V.
Yann 0:ebd3a7cc9b92 31 * In this case, you shall use a bi-directional level shifter for I2C-bus. Please refer to AN97055 (http://ics.nxp.com/support/documents/interface/pdf/an97055.pdf)
Yann 0:ebd3a7cc9b92 32 * Microchip MCP28x17 GPIO expender device reference: DS21952B
Yann 0:ebd3a7cc9b92 33 *
Yann 0:ebd3a7cc9b92 34 * Note that for I2C details, please visit http://www.datelec.fr/fiches/I2C.htm
Yann 0:ebd3a7cc9b92 35 *
Yann 0:ebd3a7cc9b92 36 * Note that this header file include following headers:
Yann 0:ebd3a7cc9b92 37 * - <string>
Yann 0:ebd3a7cc9b92 38 * - <vector>
Yann 0:ebd3a7cc9b92 39 * - <mbed.h>
Yann 0:ebd3a7cc9b92 40 *
Yann 0:ebd3a7cc9b92 41 * @author Yann Garcia (Don't hesitate to contact me: garcia.yann@gmail.com)
Yann 0:ebd3a7cc9b92 42 */
Yann 0:ebd3a7cc9b92 43 class CMCP23017_I2C : public AbstractGpioExpender {
Yann 2:3bea48e1505c 44
Yann 0:ebd3a7cc9b92 45 /** Reference counter used to guarentee unicity of the instance of I2C class
Yann 0:ebd3a7cc9b92 46 */
Yann 0:ebd3a7cc9b92 47 static unsigned char I2CModuleRefCounter;
Yann 0:ebd3a7cc9b92 48
Yann 0:ebd3a7cc9b92 49 /** Device address input: A0, A1, A2 (Pins <1,3>). See DS21203K/DS21189D - Figure 5-1: Control Byte Format for address format details
Yann 0:ebd3a7cc9b92 50 */
Yann 0:ebd3a7cc9b92 51 unsigned char _slaveAddress;
Yann 2:3bea48e1505c 52
Yann 0:ebd3a7cc9b92 53 /** Interrupt on GPIOA
Yann 0:ebd3a7cc9b92 54 */
Yann 0:ebd3a7cc9b92 55 InterruptIn *_intA;
Yann 2:3bea48e1505c 56
Yann 0:ebd3a7cc9b92 57 /** Interrupt on GPIOB
Yann 0:ebd3a7cc9b92 58 */
Yann 0:ebd3a7cc9b92 59 InterruptIn *_intB;
Yann 2:3bea48e1505c 60
Yann 0:ebd3a7cc9b92 61 /** Device reset pin
Yann 0:ebd3a7cc9b92 62 */
Yann 0:ebd3a7cc9b92 63 DigitalOut *_reset;
Yann 2:3bea48e1505c 64
Yann 0:ebd3a7cc9b92 65 /** PortA config
Yann 0:ebd3a7cc9b92 66 */
Yann 0:ebd3a7cc9b92 67 unsigned char _gpioAFlags;
Yann 2:3bea48e1505c 68
Yann 0:ebd3a7cc9b92 69 /** PortB config
Yann 0:ebd3a7cc9b92 70 */
Yann 0:ebd3a7cc9b92 71 unsigned char _gpioBFlags;
Yann 0:ebd3a7cc9b92 72
Yann 2:3bea48e1505c 73 /** Map of declared buses
Yann 2:3bea48e1505c 74 */
Yann 0:ebd3a7cc9b92 75 std::map<unsigned char, std::list<unsigned char> > _buses;
Yann 0:ebd3a7cc9b92 76
Yann 2:3bea48e1505c 77 /** Buses identifier index
Yann 2:3bea48e1505c 78 */
Yann 0:ebd3a7cc9b92 79 unsigned char _busesIndex;
Yann 0:ebd3a7cc9b92 80
Yann 0:ebd3a7cc9b92 81 /** An unique instance of I2C class
Yann 0:ebd3a7cc9b92 82 */
Yann 0:ebd3a7cc9b92 83 I2C *_i2cInstance;
Yann 0:ebd3a7cc9b92 84
Yann 0:ebd3a7cc9b92 85 public:
Yann 0:ebd3a7cc9b92 86 /** Constructor with Write Protect command pin wired. Use it to manage the first I2C module on 3.3V or 5V network
Yann 0:ebd3a7cc9b92 87 *
Yann 0:ebd3a7cc9b92 88 * @param p_sda: MBed pin for SDA
Yann 0:ebd3a7cc9b92 89 * @param p_scl: MBed pin for SCL
Yann 0:ebd3a7cc9b92 90 * @param p_address: Device address input: A0, A1, A2 (Pins <1,3>)
Yann 0:ebd3a7cc9b92 91 * @param p_intA: MBed pin to manage interrupt on GPIOA, default value is NC, not connected
Yann 0:ebd3a7cc9b92 92 * @param p_intB: MBed pin to manage device reset. If NC, WP is not managed, default value is NC, not connected
Yann 0:ebd3a7cc9b92 93 * @param p_reset: MBed pin to manage Write Protect input. If NC, WP is not managed, default value is NC, not connected
Yann 0:ebd3a7cc9b92 94 * @param p_internalPullUp: Set to true to use internal pull-up resistor, default value is true
Yann 0:ebd3a7cc9b92 95 * @param p_frequency: Frequency of the I2C interface (SCL), default value is 400KHz
Yann 0:ebd3a7cc9b92 96 * Example:
Yann 0:ebd3a7cc9b92 97 * - If A1 and A2 pins are tired to Vdd and A0 is tired to Vss, address shall '00000110'B
Yann 0:ebd3a7cc9b92 98 * - If A0 and A1 pins are tired to Vss and A2 is tired to Vdd, address shall '00000100'B
Yann 0:ebd3a7cc9b92 99 */
Yann 0:ebd3a7cc9b92 100 CMCP23017_I2C(const PinName p_sda, const PinName p_scl, const unsigned char p_address, const PinName p_intA = NC, const PinName p_intB = NC, const PinName p_reset = NC, const bool p_internalPullUp = true, const unsigned int p_frequency = 400000);
Yann 0:ebd3a7cc9b92 101
Yann 0:ebd3a7cc9b92 102 /** Destructor
Yann 0:ebd3a7cc9b92 103 */
Yann 0:ebd3a7cc9b92 104 virtual ~CMCP23017_I2C();
Yann 0:ebd3a7cc9b92 105
Yann 0:ebd3a7cc9b92 106 /** Initialize the module, configuring the module and starting the clock
Yann 0:ebd3a7cc9b92 107 * @param p_gpioAFlags GPIO A port configuration: bit set for input mode, 0 for output mode. Default: ports as outputs
Yann 0:ebd3a7cc9b92 108 * @param p_gpioBFlags GPIO B port configuration: bit set for input mode, 0 for output mode. Default: ports as outputs
Yann 0:ebd3a7cc9b92 109 *
Yann 0:ebd3a7cc9b92 110 * @return true on success, false otherwise
Yann 0:ebd3a7cc9b92 111 */
Yann 0:ebd3a7cc9b92 112 bool Initialize(const unsigned char p_gpioAFlags = 0x00, const unsigned char p_gpioBFlags = 0x00);
Yann 0:ebd3a7cc9b92 113
Yann 0:ebd3a7cc9b92 114 /** Used to return the unique instance of I2C instance
Yann 0:ebd3a7cc9b92 115 */
Yann 0:ebd3a7cc9b92 116 inline const I2C * operator * () { return (const I2C *)_i2cInstance; };
Yann 0:ebd3a7cc9b92 117
Yann 0:ebd3a7cc9b92 118 /** Reset the device
Yann 0:ebd3a7cc9b92 119 */
Yann 0:ebd3a7cc9b92 120 virtual void reset();
Yann 0:ebd3a7cc9b92 121
Yann 2:3bea48e1505c 122 /** Setup device interrupt mechanism
Yann 2:3bea48e1505c 123 * @param p_mirroring Set to 0x00 to disable INTA/B mirroring, 0x01 otherwise. Default: 0x00
Yann 2:3bea48e1505c 124 * @param p_openDrain Set to 0x00 for active driver output, 0x01 for opn drain output. Default: 0x00
Yann 2:3bea48e1505c 125 * @param p_polarity Set to 0x00 for interrupt active low, 0x01 otherwise. Default: 0x00
Yann 2:3bea48e1505c 126 */
Yann 0:ebd3a7cc9b92 127 virtual void setupInterrupts(const unsigned char mirroring = 0x00, const unsigned char p_openDrain = 0x00, const unsigned char polarity = 0x00);
Yann 2:3bea48e1505c 128
Yann 0:ebd3a7cc9b92 129 /** Setup interrupt for a specific IO port
Yann 0:ebd3a7cc9b92 130 * @param p_pinId The IO port identifier
Yann 0:ebd3a7cc9b92 131 * @param p_mode The interrupt mode
Yann 2:3bea48e1505c 132 * @return 0 on success, -1 on wrong parameters and -2 otherwise
Yann 0:ebd3a7cc9b92 133 */
Yann 0:ebd3a7cc9b92 134 virtual int setupInterruptPin(const unsigned char p_gpioId, const InterruptModes p_mode = OnRising);
Yann 1:ec9e770173d5 135
Yann 2:3bea48e1505c 136 /** Setup pull mode for a specific IO port
Yann 2:3bea48e1505c 137 * @param p_gpioId The IO port identifier
Yann 2:3bea48e1505c 138 * @param p_mode The interrupt mode
Yann 2:3bea48e1505c 139 * @return 0 on success, -1 on wrong parameters and -2 otherwise
Yann 2:3bea48e1505c 140 */
Yann 2:3bea48e1505c 141 virtual int setupPullPin(const unsigned char p_gpioId, const PullModes p_mode = PullOff);
Yann 2:3bea48e1505c 142
Yann 1:ec9e770173d5 143 /** Get interrupt information and clear it
Yann 1:ec9e770173d5 144 * @param p_gpioId The IO port identifier where the interrupt occured
Yann 1:ec9e770173d5 145 * @param p_value The logic value on the pin port where the interrupt occured
Yann 2:3bea48e1505c 146 * @return 0 on success, -1 on wrong parameters and -2 otherwise
Yann 1:ec9e770173d5 147 */
Yann 2:3bea48e1505c 148 virtual int getLastInterruptPinAndValue(unsigned char * p_gpioId, unsigned char * p_value);
Yann 0:ebd3a7cc9b92 149
Yann 2:3bea48e1505c 150 /** Read the specific GPIO port pin
Yann 2:3bea48e1505c 151 * @param p_gpioId The GPIO port pin to be read
Yann 2:3bea48e1505c 152 * @param p_value The GPIO port pin value
Yann 2:3bea48e1505c 153 * @return 0 on success, -1 on wrong parameters and -2 otherwise
Yann 2:3bea48e1505c 154 */
Yann 2:3bea48e1505c 155 virtual int read(const unsigned char p_gpioId, unsigned char * p_value);
Yann 2:3bea48e1505c 156
Yann 2:3bea48e1505c 157 /** Write value to the specific GPIO port pin
Yann 2:3bea48e1505c 158 * @param p_gpioId The GPIO port pin to be written
Yann 2:3bea48e1505c 159 * @param p_value The GPIO port pin value
Yann 2:3bea48e1505c 160 * @return 0 on success, -1 on wrong parameters and -2 otherwise
Yann 2:3bea48e1505c 161 */
Yann 0:ebd3a7cc9b92 162 virtual int write(const unsigned char p_gpioId, const unsigned char p_value);
Yann 0:ebd3a7cc9b92 163
Yann 0:ebd3a7cc9b92 164 virtual unsigned char createBus(const std::list<unsigned char> p_lines, const PinMode p_mode = PullNone);
Yann 0:ebd3a7cc9b92 165 virtual void deleteBus(const unsigned char p_busId);
Yann 1:ec9e770173d5 166 virtual int busRead(const unsigned char p_busId, unsigned short * p_value);
Yann 1:ec9e770173d5 167 virtual int busWrite(const unsigned char p_busId, const unsigned short p_value);
Yann 0:ebd3a7cc9b92 168
Yann 0:ebd3a7cc9b92 169 /** Attach a function to call when a interrupt occurs on the GPIOA input ports
Yann 2:3bea48e1505c 170 * @param p_fptr The pointer to the "C" callback function
Yann 0:ebd3a7cc9b92 171 */
Yann 0:ebd3a7cc9b92 172 virtual void setIntrACallback(void (* p_fptr)(void));
Yann 0:ebd3a7cc9b92 173
Yann 2:3bea48e1505c 174 /** Attach a function to call when a interrupt occurs on the GPIOB input ports
Yann 2:3bea48e1505c 175 * @param p_fptr The pointer to the "C" callback function
Yann 0:ebd3a7cc9b92 176 */
Yann 0:ebd3a7cc9b92 177 virtual void setIntrBCallback(void (* p_fptr)(void));
Yann 0:ebd3a7cc9b92 178
Yann 0:ebd3a7cc9b92 179 /** Attach a member function to call when a interrupt occurs on the GPIOA input ports
Yann 0:ebd3a7cc9b92 180 */
Yann 0:ebd3a7cc9b92 181 template<typename T>
Yann 0:ebd3a7cc9b92 182 void setIntrACallback(const T * p_tptr, void(T::* p_mptr)(void));
Yann 0:ebd3a7cc9b92 183
Yann 0:ebd3a7cc9b92 184 /** Attach a member function to call when a rising edge occurs on the input
Yann 0:ebd3a7cc9b92 185 */
Yann 0:ebd3a7cc9b92 186 template<typename T>
Yann 0:ebd3a7cc9b92 187 void setIntrBCallback(const T * p_tptr, void(T::* p_mptr)(void));
Yann 0:ebd3a7cc9b92 188
Yann 0:ebd3a7cc9b92 189 private:
Yann 0:ebd3a7cc9b92 190
Yann 0:ebd3a7cc9b92 191 /** Configure the device:
Yann 0:ebd3a7cc9b92 192 * BANK0 (A register followed by B register)
Yann 0:ebd3a7cc9b92 193 * INTs: active low
Yann 0:ebd3a7cc9b92 194 * INTs for all ports
Yann 0:ebd3a7cc9b92 195 * INTs are not mirrored
Yann 0:ebd3a7cc9b92 196 * @param p_gpioAFlags GPIO A port configuration: bit set for input mode, 0 for output mode. Default: ports as outputs
Yann 0:ebd3a7cc9b92 197 * @param p_gpioBFlags GPIO B port configuration: bit set for input mode, 0 for output mode. Default: ports as outputs
Yann 0:ebd3a7cc9b92 198 */
Yann 0:ebd3a7cc9b92 199 void configure(const unsigned char p_gpioAFlags, const unsigned char p_gpioBFlags);
Yann 0:ebd3a7cc9b92 200
Yann 0:ebd3a7cc9b92 201 bool registerIdFromGpioId(const unsigned char p_gpioId, unsigned char * p_gpioRegisterId);
Yann 0:ebd3a7cc9b92 202
Yann 0:ebd3a7cc9b92 203 inline unsigned char gpioBitFromGpioId(const unsigned char p_gpioId) {
Yann 0:ebd3a7cc9b92 204 return static_cast<unsigned char>((p_gpioId < GPIO_MED) ? p_gpioId : (p_gpioId - GPIO_MED));
Yann 0:ebd3a7cc9b92 205 };
Yann 0:ebd3a7cc9b92 206 inline bool isBitSet(const unsigned char p_gpioRegisterValue, const unsigned char p_gpioBit) {
Yann 0:ebd3a7cc9b92 207 return (bool)((unsigned char)(p_gpioRegisterValue >> p_gpioBit) == 0x01);
Yann 0:ebd3a7cc9b92 208 };
Yann 0:ebd3a7cc9b92 209 inline bool isBitEqual(const unsigned char p_gpioRegisterValue, const unsigned char p_gpioBit, const unsigned char p_value) {
Yann 0:ebd3a7cc9b92 210 return (bool)((unsigned char)(p_gpioRegisterValue >> p_gpioBit) == (p_value & 0x01));
Yann 0:ebd3a7cc9b92 211 };
Yann 0:ebd3a7cc9b92 212 inline unsigned char setBit(unsigned char p_gpioRegisterValue, const unsigned char p_gpioBit, const unsigned char p_value) {
Yann 0:ebd3a7cc9b92 213 return (p_gpioRegisterValue & ~(1 << p_gpioBit)) | ((p_value & 0x01) << p_gpioBit);
Yann 0:ebd3a7cc9b92 214 };
Yann 0:ebd3a7cc9b92 215
Yann 0:ebd3a7cc9b92 216 protected:
Yann 0:ebd3a7cc9b92 217
Yann 0:ebd3a7cc9b92 218 /** Write value to a register
Yann 0:ebd3a7cc9b92 219 * @param p_address The register address
Yann 0:ebd3a7cc9b92 220 * @param p_byte The value to write to the register
Yann 0:ebd3a7cc9b92 221 * @return 1 on success, false otherwise
Yann 0:ebd3a7cc9b92 222 */
Yann 0:ebd3a7cc9b92 223 virtual bool writeRegister(const unsigned char p_registerId, const unsigned char p_value);
Yann 0:ebd3a7cc9b92 224
Yann 0:ebd3a7cc9b92 225 virtual bool readRegister(const unsigned char p_registerId, unsigned char * p_value);
Yann 0:ebd3a7cc9b92 226
Yann 0:ebd3a7cc9b92 227 private:
Yann 0:ebd3a7cc9b92 228 /** Internal reference identifier
Yann 0:ebd3a7cc9b92 229 */
Yann 0:ebd3a7cc9b92 230 std::string _internalId;
Yann 0:ebd3a7cc9b92 231
Yann 0:ebd3a7cc9b92 232 void DumpRegisters();
Yann 0:ebd3a7cc9b92 233 void DumpRegister(unsigned int p_registerId);
Yann 0:ebd3a7cc9b92 234
Yann 0:ebd3a7cc9b92 235 }; // End of class CMCP23017_I2C
Yann 0:ebd3a7cc9b92 236
Yann 0:ebd3a7cc9b92 237 } // End of namespace _MCP23017_I2C
Yann 0:ebd3a7cc9b92 238
Yann 0:ebd3a7cc9b92 239 using namespace MCP23017_I2C;