This library provides simplified I2C access to a Microchip MCP23x17 GPIO expender device, including a general interface for any GPIO expender
MCP23017_I2C.h@3:b902729a1675, 2015-01-13 (annotated)
- 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?
User | Revision | Line number | New 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; |