This library provides simplified I2C access to a Microchip MCP23x17 GPIO expender device, including a general interface for any GPIO expender
MCP23017_I2C.cpp@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) 2010-2012 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 pinions 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 | #include <iostream> |
Yann | 0:ebd3a7cc9b92 | 20 | #include <sstream> |
Yann | 0:ebd3a7cc9b92 | 21 | |
Yann | 0:ebd3a7cc9b92 | 22 | #include "MCP23017_I2C.h" |
Yann | 0:ebd3a7cc9b92 | 23 | |
Yann | 0:ebd3a7cc9b92 | 24 | #define IODIRA 0x00 |
Yann | 0:ebd3a7cc9b92 | 25 | #define IODIRB 0x01 |
Yann | 0:ebd3a7cc9b92 | 26 | #define IPOLA 0x02 |
Yann | 0:ebd3a7cc9b92 | 27 | #define IPOLB 0x03 |
Yann | 0:ebd3a7cc9b92 | 28 | #define GPINTENA 0x04 |
Yann | 0:ebd3a7cc9b92 | 29 | #define GPINTENB 0x05 |
Yann | 0:ebd3a7cc9b92 | 30 | #define DEFVALA 0x06 |
Yann | 0:ebd3a7cc9b92 | 31 | #define DEFVALB 0x07 |
Yann | 0:ebd3a7cc9b92 | 32 | #define INTCONA 0x08 |
Yann | 0:ebd3a7cc9b92 | 33 | #define INTCONB 0x09 |
Yann | 0:ebd3a7cc9b92 | 34 | #define IOCONA 0x0a |
Yann | 0:ebd3a7cc9b92 | 35 | #define IOCONB 0x0b |
Yann | 0:ebd3a7cc9b92 | 36 | #define GPPUA 0x0c |
Yann | 0:ebd3a7cc9b92 | 37 | #define GPPUB 0x0d |
Yann | 0:ebd3a7cc9b92 | 38 | #define INTFA 0x0e |
Yann | 0:ebd3a7cc9b92 | 39 | #define INTFB 0x0f |
Yann | 0:ebd3a7cc9b92 | 40 | #define INTCAPA 0x10 |
Yann | 0:ebd3a7cc9b92 | 41 | #define INTCAPB 0x11 |
Yann | 0:ebd3a7cc9b92 | 42 | #define GPIOA 0x12 |
Yann | 0:ebd3a7cc9b92 | 43 | #define GPIOB 0x13 |
Yann | 0:ebd3a7cc9b92 | 44 | #define OLATA 0x14 |
Yann | 0:ebd3a7cc9b92 | 45 | #define OLATB 0x15 |
Yann | 0:ebd3a7cc9b92 | 46 | |
Yann | 0:ebd3a7cc9b92 | 47 | namespace MCP23017_I2C { |
Yann | 0:ebd3a7cc9b92 | 48 | |
Yann | 0:ebd3a7cc9b92 | 49 | unsigned char CMCP23017_I2C::I2CModuleRefCounter = 0; |
Yann | 0:ebd3a7cc9b92 | 50 | |
Yann | 0:ebd3a7cc9b92 | 51 | CMCP23017_I2C::CMCP23017_I2C(const PinName p_sda, const PinName p_scl, const unsigned char p_address, const PinName p_intA, const PinName p_intB, const PinName p_reset, const bool p_internalPullUp, const unsigned int p_frequency) : _gpioAFlags(0x00), _gpioBFlags(0x00), _buses(), _busesIndex(0x00), _internalId("") { |
Yann | 3:b902729a1675 | 52 | // DEBUG_ENTER("CMCP23017_I2C") |
Yann | 0:ebd3a7cc9b92 | 53 | |
Yann | 0:ebd3a7cc9b92 | 54 | if (CMCP23017_I2C::I2CModuleRefCounter != 0) { |
Yann | 0:ebd3a7cc9b92 | 55 | error("CMCP23017_I2C: Wrong params"); |
Yann | 0:ebd3a7cc9b92 | 56 | } |
Yann | 0:ebd3a7cc9b92 | 57 | #ifdef __DEBUG |
Yann | 0:ebd3a7cc9b92 | 58 | std::ostringstream out(std::ostringstream::out); |
Yann | 0:ebd3a7cc9b92 | 59 | out << "CMCP23017_I2C #" << CMCP23017_I2C::I2CModuleRefCounter; |
Yann | 0:ebd3a7cc9b92 | 60 | _internalId.assign(out.str()); |
Yann | 3:b902729a1675 | 61 | // DEBUG("CMCP23017_I2C: _internalId='%s'", _internalId.c_str()) |
Yann | 0:ebd3a7cc9b92 | 62 | #endif // __DEBUG |
Yann | 0:ebd3a7cc9b92 | 63 | _i2cInstance = new I2C(p_sda, p_scl); |
Yann | 0:ebd3a7cc9b92 | 64 | CMCP23017_I2C::I2CModuleRefCounter += 1; |
Yann | 3:b902729a1675 | 65 | // DEBUG_ENTER("CMCP23017_I2C: refCounter=%d", CMCP23017_I2C::I2CModuleRefCounter) |
Yann | 0:ebd3a7cc9b92 | 66 | |
Yann | 0:ebd3a7cc9b92 | 67 | _slaveAddress = (p_address << 1) | 0x40; // Slave address format is: 0 0 1 0 A3 A2 A1 R/W |
Yann | 3:b902729a1675 | 68 | // DEBUG("CMCP23017_I2C: I2C slave adress: 0x%02x", _slaveAddress) |
Yann | 0:ebd3a7cc9b92 | 69 | _i2cInstance->frequency(p_frequency); // Set the frequency of the I2C interface |
Yann | 0:ebd3a7cc9b92 | 70 | |
Yann | 0:ebd3a7cc9b92 | 71 | if (p_intA != NC) { |
Yann | 3:b902729a1675 | 72 | // DEBUG("CMCP23017_I2C: INTA managed"); |
Yann | 0:ebd3a7cc9b92 | 73 | _intA = new InterruptIn(p_intA); |
Yann | 2:3bea48e1505c | 74 | if (p_internalPullUp) _intA->mode(::PullDown); |
Yann | 0:ebd3a7cc9b92 | 75 | _intA->enable_irq(); // Enable interrupt |
Yann | 0:ebd3a7cc9b92 | 76 | } else { |
Yann | 3:b902729a1675 | 77 | // DEBUG("CMCP23017_I2C: INTA not managed"); |
Yann | 0:ebd3a7cc9b92 | 78 | _intA = NULL; // Not used |
Yann | 0:ebd3a7cc9b92 | 79 | } |
Yann | 0:ebd3a7cc9b92 | 80 | if (p_intB != NC) { |
Yann | 3:b902729a1675 | 81 | // DEBUG("CMCP23017_I2C: INTB managed"); |
Yann | 0:ebd3a7cc9b92 | 82 | _intB = new InterruptIn(p_intB); |
Yann | 2:3bea48e1505c | 83 | if (p_internalPullUp) _intB->mode(::PullDown); |
Yann | 0:ebd3a7cc9b92 | 84 | _intB->enable_irq(); // Enable interrupt |
Yann | 0:ebd3a7cc9b92 | 85 | } else { |
Yann | 3:b902729a1675 | 86 | // DEBUG("CMCP23017_I2C: INTB not managed"); |
Yann | 0:ebd3a7cc9b92 | 87 | _intB = NULL; // Not used |
Yann | 0:ebd3a7cc9b92 | 88 | } |
Yann | 0:ebd3a7cc9b92 | 89 | if (p_reset != NC) { |
Yann | 3:b902729a1675 | 90 | // DEBUG("CMCP23017_I2C: RESET managed"); |
Yann | 0:ebd3a7cc9b92 | 91 | _reset = new DigitalOut(p_reset); |
Yann | 0:ebd3a7cc9b92 | 92 | _reset->write(1); // Disable reset |
Yann | 0:ebd3a7cc9b92 | 93 | } else { |
Yann | 3:b902729a1675 | 94 | // DEBUG("CMCP23017_I2C: RESET not managed"); |
Yann | 0:ebd3a7cc9b92 | 95 | _reset = NULL; // Not used |
Yann | 0:ebd3a7cc9b92 | 96 | } |
Yann | 0:ebd3a7cc9b92 | 97 | |
Yann | 3:b902729a1675 | 98 | // DEBUG_LEAVE("CMCP23017_I2C") |
Yann | 0:ebd3a7cc9b92 | 99 | } |
Yann | 0:ebd3a7cc9b92 | 100 | |
Yann | 0:ebd3a7cc9b92 | 101 | CMCP23017_I2C::~CMCP23017_I2C() { |
Yann | 3:b902729a1675 | 102 | // DEBUG_ENTER("~CMCP23017_I2C") |
Yann | 0:ebd3a7cc9b92 | 103 | |
Yann | 0:ebd3a7cc9b92 | 104 | // Release I2C instance |
Yann | 3:b902729a1675 | 105 | // DEBUG("~CMCP23017_I2C: refCounter=%d", CMCP23017_I2C::I2CModuleRefCounter) |
Yann | 0:ebd3a7cc9b92 | 106 | CMCP23017_I2C::I2CModuleRefCounter -= 1; |
Yann | 0:ebd3a7cc9b92 | 107 | if (CMCP23017_I2C::I2CModuleRefCounter == 0) { |
Yann | 0:ebd3a7cc9b92 | 108 | delete _i2cInstance; |
Yann | 0:ebd3a7cc9b92 | 109 | _i2cInstance = NULL; |
Yann | 0:ebd3a7cc9b92 | 110 | } |
Yann | 0:ebd3a7cc9b92 | 111 | // Release _wp if required |
Yann | 0:ebd3a7cc9b92 | 112 | if (_intA != NULL) { |
Yann | 0:ebd3a7cc9b92 | 113 | delete _intA; |
Yann | 0:ebd3a7cc9b92 | 114 | } |
Yann | 0:ebd3a7cc9b92 | 115 | if (_intB != NULL) { |
Yann | 0:ebd3a7cc9b92 | 116 | delete _intB; |
Yann | 0:ebd3a7cc9b92 | 117 | } |
Yann | 0:ebd3a7cc9b92 | 118 | if (_reset != NULL) { |
Yann | 0:ebd3a7cc9b92 | 119 | delete _reset; |
Yann | 0:ebd3a7cc9b92 | 120 | } |
Yann | 0:ebd3a7cc9b92 | 121 | |
Yann | 3:b902729a1675 | 122 | // DEBUG_LEAVE("~CMCP23017_I2C") |
Yann | 0:ebd3a7cc9b92 | 123 | } |
Yann | 0:ebd3a7cc9b92 | 124 | |
Yann | 0:ebd3a7cc9b92 | 125 | bool CMCP23017_I2C::Initialize(const unsigned char p_gpioAFlags, const unsigned char p_gpioBFlags) { |
Yann | 0:ebd3a7cc9b92 | 126 | |
Yann | 0:ebd3a7cc9b92 | 127 | // Configure default behavior |
Yann | 0:ebd3a7cc9b92 | 128 | _gpioAFlags = p_gpioAFlags; |
Yann | 0:ebd3a7cc9b92 | 129 | _gpioBFlags = p_gpioBFlags; |
Yann | 0:ebd3a7cc9b92 | 130 | configure(_gpioAFlags, _gpioBFlags); |
Yann | 0:ebd3a7cc9b92 | 131 | |
Yann | 0:ebd3a7cc9b92 | 132 | return true; |
Yann | 0:ebd3a7cc9b92 | 133 | } |
Yann | 0:ebd3a7cc9b92 | 134 | |
Yann | 0:ebd3a7cc9b92 | 135 | void CMCP23017_I2C::configure(const unsigned char p_gpioAFlags, const unsigned char p_gpioBFlags) { // TODO Optimization with sequential access |
Yann | 0:ebd3a7cc9b92 | 136 | // DEBUG_ENTER("CMCP23017_I2C::configure: 0x%02x 0x%02x", p_gpioAFlags, p_gpioBFlags) |
Yann | 0:ebd3a7cc9b92 | 137 | |
Yann | 0:ebd3a7cc9b92 | 138 | // Setup IOCON - See REGISTER 1-6: IOCON – I/O EXPANDER CONFIGURATION REGISTER |
Yann | 0:ebd3a7cc9b92 | 139 | writeRegister(IOCONA, 0x10); // Sequential operation disabled |
Yann | 0:ebd3a7cc9b92 | 140 | writeRegister(IOCONB, 0x10); // Sequential operation disabled |
Yann | 0:ebd3a7cc9b92 | 141 | // Setup IODIR - See REGISTER 1-1: IODIR – I/O DIRECTION REGISTER (ADDR 0x00) |
Yann | 0:ebd3a7cc9b92 | 142 | writeRegister(IODIRA, p_gpioAFlags); |
Yann | 0:ebd3a7cc9b92 | 143 | writeRegister(IODIRB, p_gpioBFlags); |
Yann | 0:ebd3a7cc9b92 | 144 | // Setup IPOL - See REGISTER 1-2: IPOL – INPUT POLARITY PORT REGISTER |
Yann | 0:ebd3a7cc9b92 | 145 | writeRegister(IPOLA, 0x00); // GPIO register bit will reflect the same logic state of the input pin |
Yann | 0:ebd3a7cc9b92 | 146 | writeRegister(IPOLB, 0x00); |
Yann | 0:ebd3a7cc9b92 | 147 | // Setup GPPU - See REGISTER 1-7: GPPU – GPIO PULL-UP RESISTOR REGISTER |
Yann | 0:ebd3a7cc9b92 | 148 | writeRegister(GPPUA, 0x00); |
Yann | 0:ebd3a7cc9b92 | 149 | writeRegister(GPPUB, 0x00); |
Yann | 0:ebd3a7cc9b92 | 150 | |
Yann | 0:ebd3a7cc9b92 | 151 | // Setup interrupt |
Yann | 0:ebd3a7cc9b92 | 152 | if (_intA != NULL) { |
Yann | 3:b902729a1675 | 153 | // DEBUG("CMCP23017_I2C::configure: Setup INTA") |
Yann | 0:ebd3a7cc9b92 | 154 | // Setup GPINTEN - See GPINTEN – INTERRUPT-ON-CHANGE PINS |
Yann | 0:ebd3a7cc9b92 | 155 | writeRegister(GPINTENA, 0x00); // Disable GPIO interrupt-on-change events |
Yann | 0:ebd3a7cc9b92 | 156 | // Setup DEFVAL - See REGISTER 1-4: DEFVAL – DEFAULT VALUE REGISTER |
Yann | 0:ebd3a7cc9b92 | 157 | writeRegister(DEFVALA, 0x00); // Pin level change from 0 to 1 raises an interrupt |
Yann | 0:ebd3a7cc9b92 | 158 | // Setup INTCON - REGISTER 1-5: INTCON – INTERRUPT-ON-CHANGE CONTROL REGISTER |
Yann | 0:ebd3a7cc9b92 | 159 | writeRegister(INTCONA, 0xff); // Pin level change from 0 to 1 raises an interrupt |
Yann | 0:ebd3a7cc9b92 | 160 | } |
Yann | 0:ebd3a7cc9b92 | 161 | if (_intB != NULL) { |
Yann | 3:b902729a1675 | 162 | // DEBUG("CMCP23017_I2C::configure: Setup INTB") |
Yann | 0:ebd3a7cc9b92 | 163 | // Setup GPINTEN - See GPINTEN – INTERRUPT-ON-CHANGE PINS |
Yann | 0:ebd3a7cc9b92 | 164 | writeRegister(GPINTENB, 0x00); // Disable GPIO interrupt-on-change events |
Yann | 0:ebd3a7cc9b92 | 165 | // Setup DEFVAL - See REGISTER 1-4: DEFVAL – DEFAULT VALUE REGISTER |
Yann | 0:ebd3a7cc9b92 | 166 | writeRegister(DEFVALB, 0x00); // Pin level change from 0 to 1 raises an interrupt |
Yann | 0:ebd3a7cc9b92 | 167 | // Setup INTCON - REGISTER 1-5: INTCON – INTERRUPT-ON-CHANGE CONTROL REGISTER |
Yann | 0:ebd3a7cc9b92 | 168 | writeRegister(INTCONB, 0xff); // Pin level change from 0 to 1 raises an interrupt |
Yann | 0:ebd3a7cc9b92 | 169 | } |
Yann | 0:ebd3a7cc9b92 | 170 | |
Yann | 0:ebd3a7cc9b92 | 171 | // DumpRegisters(); |
Yann | 0:ebd3a7cc9b92 | 172 | |
Yann | 0:ebd3a7cc9b92 | 173 | // DEBUG_LEAVE("CMCP23017_I2C::configure") |
Yann | 0:ebd3a7cc9b92 | 174 | } |
Yann | 0:ebd3a7cc9b92 | 175 | |
Yann | 0:ebd3a7cc9b92 | 176 | void CMCP23017_I2C::reset() { |
Yann | 0:ebd3a7cc9b92 | 177 | // DEBUG_ENTER("CMCP23017_I2C::reset") |
Yann | 0:ebd3a7cc9b92 | 178 | if (_reset != NULL) { |
Yann | 0:ebd3a7cc9b92 | 179 | _reset->write(0); |
Yann | 0:ebd3a7cc9b92 | 180 | wait_us(1); |
Yann | 0:ebd3a7cc9b92 | 181 | _reset->write(1); |
Yann | 0:ebd3a7cc9b92 | 182 | wait_us(1); |
Yann | 0:ebd3a7cc9b92 | 183 | if ((_gpioAFlags != 0x00) || (_gpioBFlags != 0x00)) { // Apply configuration |
Yann | 0:ebd3a7cc9b92 | 184 | configure(_gpioAFlags, _gpioBFlags); |
Yann | 0:ebd3a7cc9b92 | 185 | } // else, POR reset values, see DS21952B-page 10 Clause 1.6 Configuration and Control Registers |
Yann | 0:ebd3a7cc9b92 | 186 | } |
Yann | 0:ebd3a7cc9b92 | 187 | // DEBUG_LEAVE("CMCP23017_I2C::reset") |
Yann | 0:ebd3a7cc9b92 | 188 | } |
Yann | 0:ebd3a7cc9b92 | 189 | |
Yann | 0:ebd3a7cc9b92 | 190 | void CMCP23017_I2C::setIntrACallback(void (* p_fptr)(void)) { |
Yann | 0:ebd3a7cc9b92 | 191 | if (_intA != NULL) { |
Yann | 0:ebd3a7cc9b92 | 192 | unsigned char vregister; |
Yann | 0:ebd3a7cc9b92 | 193 | if (!readRegister(IOCONA, &vregister)) { |
Yann | 0:ebd3a7cc9b92 | 194 | return; |
Yann | 0:ebd3a7cc9b92 | 195 | } |
Yann | 0:ebd3a7cc9b92 | 196 | if (isBitSet(vregister, 1)) { |
Yann | 0:ebd3a7cc9b92 | 197 | _intA->rise(p_fptr); |
Yann | 0:ebd3a7cc9b92 | 198 | } else { |
Yann | 0:ebd3a7cc9b92 | 199 | _intA->fall(p_fptr); |
Yann | 0:ebd3a7cc9b92 | 200 | } |
Yann | 0:ebd3a7cc9b92 | 201 | } |
Yann | 0:ebd3a7cc9b92 | 202 | } |
Yann | 0:ebd3a7cc9b92 | 203 | |
Yann | 0:ebd3a7cc9b92 | 204 | void CMCP23017_I2C::setIntrBCallback(void (* p_fptr)(void)) { |
Yann | 0:ebd3a7cc9b92 | 205 | if (_intB != NULL) { |
Yann | 0:ebd3a7cc9b92 | 206 | unsigned char vregister; |
Yann | 0:ebd3a7cc9b92 | 207 | if (!readRegister(IOCONB, &vregister)) { |
Yann | 0:ebd3a7cc9b92 | 208 | return; |
Yann | 0:ebd3a7cc9b92 | 209 | } |
Yann | 0:ebd3a7cc9b92 | 210 | if (isBitSet(vregister, 1)) { |
Yann | 0:ebd3a7cc9b92 | 211 | _intB->rise(p_fptr); |
Yann | 0:ebd3a7cc9b92 | 212 | } else { |
Yann | 0:ebd3a7cc9b92 | 213 | _intB->fall(p_fptr); |
Yann | 0:ebd3a7cc9b92 | 214 | } |
Yann | 0:ebd3a7cc9b92 | 215 | } |
Yann | 0:ebd3a7cc9b92 | 216 | } |
Yann | 0:ebd3a7cc9b92 | 217 | |
Yann | 0:ebd3a7cc9b92 | 218 | template<typename T> |
Yann | 0:ebd3a7cc9b92 | 219 | void CMCP23017_I2C::setIntrACallback (const T * p_tptr, void(T::* p_mptr)(void)) { |
Yann | 0:ebd3a7cc9b92 | 220 | if (_intA != NULL) { |
Yann | 0:ebd3a7cc9b92 | 221 | unsigned char vregister; |
Yann | 0:ebd3a7cc9b92 | 222 | if (!readRegister(IOCONA, &vregister)) { |
Yann | 0:ebd3a7cc9b92 | 223 | return; |
Yann | 0:ebd3a7cc9b92 | 224 | } |
Yann | 0:ebd3a7cc9b92 | 225 | if (isBitSet(vregister, 1)) { |
Yann | 0:ebd3a7cc9b92 | 226 | _intA->rise(p_tptr, p_mptr); |
Yann | 0:ebd3a7cc9b92 | 227 | } else { |
Yann | 0:ebd3a7cc9b92 | 228 | _intA->fall(p_tptr, p_mptr); |
Yann | 0:ebd3a7cc9b92 | 229 | } |
Yann | 0:ebd3a7cc9b92 | 230 | } |
Yann | 0:ebd3a7cc9b92 | 231 | } |
Yann | 0:ebd3a7cc9b92 | 232 | |
Yann | 0:ebd3a7cc9b92 | 233 | template<typename T> |
Yann | 0:ebd3a7cc9b92 | 234 | void CMCP23017_I2C::setIntrBCallback (const T * p_tptr, void(T::* p_mptr)(void)) { |
Yann | 0:ebd3a7cc9b92 | 235 | unsigned char vregister; |
Yann | 0:ebd3a7cc9b92 | 236 | if (!readRegister(IOCONB, &vregister)) { |
Yann | 0:ebd3a7cc9b92 | 237 | return; |
Yann | 0:ebd3a7cc9b92 | 238 | } |
Yann | 0:ebd3a7cc9b92 | 239 | if (isBitSet(vregister, 1)) { |
Yann | 0:ebd3a7cc9b92 | 240 | _intB->rise(p_tptr, p_mptr); |
Yann | 0:ebd3a7cc9b92 | 241 | } else { |
Yann | 0:ebd3a7cc9b92 | 242 | _intB->fall(p_tptr, p_mptr); |
Yann | 0:ebd3a7cc9b92 | 243 | } |
Yann | 0:ebd3a7cc9b92 | 244 | } |
Yann | 0:ebd3a7cc9b92 | 245 | |
Yann | 0:ebd3a7cc9b92 | 246 | void CMCP23017_I2C::setupInterrupts(const unsigned char p_mirroring, const unsigned char p_openDrain, const unsigned char p_polarity) { |
Yann | 0:ebd3a7cc9b92 | 247 | DEBUG_ENTER("CMCP23017_I2C::setupInterrupts: %02x, %02x, %02x", p_mirroring, p_openDrain, p_polarity) |
Yann | 0:ebd3a7cc9b92 | 248 | |
Yann | 0:ebd3a7cc9b92 | 249 | // Setup IOCONA |
Yann | 0:ebd3a7cc9b92 | 250 | unsigned char vregister; |
Yann | 0:ebd3a7cc9b92 | 251 | if (!readRegister(INTCONA, &vregister)) { |
Yann | 0:ebd3a7cc9b92 | 252 | return; |
Yann | 0:ebd3a7cc9b92 | 253 | } |
Yann | 0:ebd3a7cc9b92 | 254 | // Setup INTCON - REGISTER 1-5: INTCON – INTERRUPT-ON-CHANGE CONTROL REGISTER |
Yann | 0:ebd3a7cc9b92 | 255 | vregister = setBit(vregister, 6, p_mirroring); |
Yann | 0:ebd3a7cc9b92 | 256 | vregister = setBit(vregister, 2, p_openDrain); |
Yann | 0:ebd3a7cc9b92 | 257 | vregister = setBit(vregister, 1, p_polarity); |
Yann | 0:ebd3a7cc9b92 | 258 | writeRegister(INTCONA, vregister); |
Yann | 0:ebd3a7cc9b92 | 259 | |
Yann | 0:ebd3a7cc9b92 | 260 | // Setup IOCONB |
Yann | 0:ebd3a7cc9b92 | 261 | if (!readRegister(INTCONB, &vregister)) { |
Yann | 0:ebd3a7cc9b92 | 262 | return; |
Yann | 0:ebd3a7cc9b92 | 263 | } |
Yann | 0:ebd3a7cc9b92 | 264 | // Setup INTCON - REGISTER 1-5: INTCON – INTERRUPT-ON-CHANGE CONTROL REGISTER |
Yann | 0:ebd3a7cc9b92 | 265 | vregister = setBit(vregister, 6, p_mirroring); |
Yann | 0:ebd3a7cc9b92 | 266 | vregister = setBit(vregister, 2, p_openDrain); |
Yann | 0:ebd3a7cc9b92 | 267 | vregister = setBit(vregister, 1, p_polarity); |
Yann | 0:ebd3a7cc9b92 | 268 | writeRegister(INTCONB, vregister); |
Yann | 0:ebd3a7cc9b92 | 269 | |
Yann | 0:ebd3a7cc9b92 | 270 | } |
Yann | 0:ebd3a7cc9b92 | 271 | |
Yann | 0:ebd3a7cc9b92 | 272 | int CMCP23017_I2C::setupInterruptPin(const unsigned char p_gpioId, const InterruptModes p_mode) { |
Yann | 0:ebd3a7cc9b92 | 273 | DEBUG_ENTER("CMCP23017_I2C::setupInterruptPin: %02x, %02x", p_gpioId, p_mode) |
Yann | 0:ebd3a7cc9b92 | 274 | |
Yann | 2:3bea48e1505c | 275 | // Retrieve the register address |
Yann | 0:ebd3a7cc9b92 | 276 | unsigned char gpioIntconId, gpioDefvalId, gpioGpintenId; |
Yann | 0:ebd3a7cc9b92 | 277 | if (!registerIdFromGpioId(p_gpioId, &gpioIntconId)) { |
Yann | 3:b902729a1675 | 278 | // DEBUG_LEAVE("CMCP23017_I2C::setupInterruptPin: -1") |
Yann | 0:ebd3a7cc9b92 | 279 | return -1; |
Yann | 0:ebd3a7cc9b92 | 280 | } |
Yann | 2:3bea48e1505c | 281 | unsigned char gpioFlags; |
Yann | 0:ebd3a7cc9b92 | 282 | if (gpioIntconId == GPIOA) { |
Yann | 0:ebd3a7cc9b92 | 283 | gpioIntconId = INTCONA; |
Yann | 0:ebd3a7cc9b92 | 284 | gpioDefvalId = DEFVALA; |
Yann | 0:ebd3a7cc9b92 | 285 | gpioGpintenId = GPINTENA; |
Yann | 2:3bea48e1505c | 286 | gpioFlags = _gpioAFlags; |
Yann | 0:ebd3a7cc9b92 | 287 | } else { |
Yann | 0:ebd3a7cc9b92 | 288 | gpioIntconId = INTCONB; |
Yann | 0:ebd3a7cc9b92 | 289 | gpioDefvalId = DEFVALB; |
Yann | 0:ebd3a7cc9b92 | 290 | gpioGpintenId = GPINTENB; |
Yann | 2:3bea48e1505c | 291 | gpioFlags = _gpioBFlags; |
Yann | 0:ebd3a7cc9b92 | 292 | } |
Yann | 2:3bea48e1505c | 293 | DEBUG("CMCP23017_I2C::setupInterruptPin: gpioIntconId=%02x gpioDefvalId=%02x gpioGpintenId=%02x gpioFlags=%02x", gpioIntconId, gpioDefvalId, gpioGpintenId, gpioFlags) |
Yann | 0:ebd3a7cc9b92 | 294 | |
Yann | 2:3bea48e1505c | 295 | // Retrieve the GPIO pin number |
Yann | 0:ebd3a7cc9b92 | 296 | unsigned char gpioBit = gpioBitFromGpioId(p_gpioId); |
Yann | 0:ebd3a7cc9b92 | 297 | DEBUG("CMCP23017_I2C::setupInterruptPin: gpioBit=%02x", gpioBit) |
Yann | 2:3bea48e1505c | 298 | if (!isBitEqual(gpioFlags, gpioBit, 0x01)) { // Port pin is not configure as input |
Yann | 3:b902729a1675 | 299 | // DEBUG_LEAVE("CMCP23017_I2C::setupPullPin: -1") |
Yann | 2:3bea48e1505c | 300 | return -1; |
Yann | 2:3bea48e1505c | 301 | } |
Yann | 0:ebd3a7cc9b92 | 302 | // Read it |
Yann | 0:ebd3a7cc9b92 | 303 | unsigned char gpioIntconValue, gpioDefvalValue, gpioGpintenValue; |
Yann | 0:ebd3a7cc9b92 | 304 | if (!readRegister(gpioIntconId, &gpioIntconValue)) { |
Yann | 3:b902729a1675 | 305 | // DEBUG_LEAVE("CMCP23017_I2C::setupInterruptPin: -2") |
Yann | 0:ebd3a7cc9b92 | 306 | return -2; |
Yann | 0:ebd3a7cc9b92 | 307 | } |
Yann | 0:ebd3a7cc9b92 | 308 | if (!readRegister(gpioDefvalId, &gpioDefvalValue)) { |
Yann | 3:b902729a1675 | 309 | // DEBUG_LEAVE("CMCP23017_I2C::setupInterruptPin: -2") |
Yann | 0:ebd3a7cc9b92 | 310 | return -2; |
Yann | 0:ebd3a7cc9b92 | 311 | } |
Yann | 0:ebd3a7cc9b92 | 312 | if (!readRegister(gpioGpintenId, &gpioGpintenValue)) { |
Yann | 3:b902729a1675 | 313 | // DEBUG_LEAVE("CMCP23017_I2C::setupInterruptPin: -2") |
Yann | 0:ebd3a7cc9b92 | 314 | return -2; |
Yann | 0:ebd3a7cc9b92 | 315 | } |
Yann | 0:ebd3a7cc9b92 | 316 | DEBUG("CMCP23017_I2C::setupInterruptPin: gpioIntconValue=%02x gpioDefvalValue=%02x gpioGpintenValue=%02x", gpioIntconValue, gpioDefvalValue, gpioGpintenValue) |
Yann | 0:ebd3a7cc9b92 | 317 | |
Yann | 0:ebd3a7cc9b92 | 318 | // |
Yann | 0:ebd3a7cc9b92 | 319 | switch (static_cast<unsigned char>(p_mode)) { |
Yann | 0:ebd3a7cc9b92 | 320 | case static_cast<unsigned char>(OnChange): |
Yann | 0:ebd3a7cc9b92 | 321 | gpioIntconValue = setBit(gpioIntconValue, gpioBit, 0x00); |
Yann | 0:ebd3a7cc9b92 | 322 | gpioDefvalValue = setBit(gpioDefvalValue, gpioBit, 0x00); |
Yann | 0:ebd3a7cc9b92 | 323 | break; |
Yann | 0:ebd3a7cc9b92 | 324 | case static_cast<unsigned char>(OnRising): |
Yann | 0:ebd3a7cc9b92 | 325 | gpioIntconValue = setBit(gpioIntconValue, gpioBit, 0x01); |
Yann | 0:ebd3a7cc9b92 | 326 | gpioDefvalValue = setBit(gpioDefvalValue, gpioBit, 0x00); |
Yann | 0:ebd3a7cc9b92 | 327 | break; |
Yann | 0:ebd3a7cc9b92 | 328 | case static_cast<unsigned char>(OnFalling): |
Yann | 0:ebd3a7cc9b92 | 329 | gpioIntconValue = setBit(gpioIntconValue, gpioBit, 0x01); |
Yann | 0:ebd3a7cc9b92 | 330 | gpioDefvalValue = setBit(gpioDefvalValue, gpioBit, 0x01); |
Yann | 0:ebd3a7cc9b92 | 331 | break; |
Yann | 0:ebd3a7cc9b92 | 332 | } // End of 'switch' statement |
Yann | 0:ebd3a7cc9b92 | 333 | |
Yann | 0:ebd3a7cc9b92 | 334 | // Enable interrupt |
Yann | 0:ebd3a7cc9b92 | 335 | gpioGpintenValue = setBit(gpioGpintenValue, gpioBit, 0x01); |
Yann | 0:ebd3a7cc9b92 | 336 | |
Yann | 0:ebd3a7cc9b92 | 337 | // Write register |
Yann | 0:ebd3a7cc9b92 | 338 | DEBUG("CMCP23017_I2C::setupInterruptPin: gpioIntconValue=%02x gpioDefvalValue=%02x gpioGpintenValue=%02x", gpioIntconValue, gpioDefvalValue, gpioGpintenValue) |
Yann | 0:ebd3a7cc9b92 | 339 | writeRegister(gpioDefvalId, gpioDefvalValue); |
Yann | 0:ebd3a7cc9b92 | 340 | writeRegister(gpioIntconId, gpioIntconValue); |
Yann | 0:ebd3a7cc9b92 | 341 | writeRegister(gpioGpintenId, gpioGpintenValue); |
Yann | 0:ebd3a7cc9b92 | 342 | |
Yann | 3:b902729a1675 | 343 | // DEBUG_LEAVE("CMCP23017_I2C::setupInterruptPin: 0") |
Yann | 0:ebd3a7cc9b92 | 344 | return 0; |
Yann | 0:ebd3a7cc9b92 | 345 | } |
Yann | 0:ebd3a7cc9b92 | 346 | |
Yann | 2:3bea48e1505c | 347 | int CMCP23017_I2C::setupPullPin(const unsigned char p_gpioId, const PullModes p_mode) { |
Yann | 3:b902729a1675 | 348 | // DEBUG_ENTER("CMCP23017_I2C::setupPullPin: %02x, %02x", p_gpioId, p_mode) |
Yann | 2:3bea48e1505c | 349 | |
Yann | 2:3bea48e1505c | 350 | // Retrieve the register address |
Yann | 2:3bea48e1505c | 351 | unsigned char gpioGppuId; |
Yann | 2:3bea48e1505c | 352 | if (!registerIdFromGpioId(p_gpioId, &gpioGppuId)) { |
Yann | 3:b902729a1675 | 353 | // DEBUG_LEAVE("CMCP23017_I2C::setupPullPin: -1") |
Yann | 2:3bea48e1505c | 354 | return -1; |
Yann | 2:3bea48e1505c | 355 | } |
Yann | 2:3bea48e1505c | 356 | unsigned char gpioFlags; |
Yann | 2:3bea48e1505c | 357 | if (gpioGppuId == GPIOA) { |
Yann | 2:3bea48e1505c | 358 | gpioGppuId = GPPUA; |
Yann | 2:3bea48e1505c | 359 | gpioFlags = _gpioAFlags; |
Yann | 2:3bea48e1505c | 360 | } else { |
Yann | 2:3bea48e1505c | 361 | gpioGppuId = GPPUB; |
Yann | 2:3bea48e1505c | 362 | gpioFlags = _gpioBFlags; |
Yann | 2:3bea48e1505c | 363 | } |
Yann | 3:b902729a1675 | 364 | // DEBUG("CMCP23017_I2C::setupPullPin: gpioGppuId=%02x gpioFlags=%02x", gpioGppuId, gpioFlags) |
Yann | 2:3bea48e1505c | 365 | |
Yann | 2:3bea48e1505c | 366 | // Retrieve the GPIO pin number |
Yann | 2:3bea48e1505c | 367 | unsigned char gpioBit = gpioBitFromGpioId(p_gpioId); |
Yann | 3:b902729a1675 | 368 | // DEBUG("CMCP23017_I2C::setupPullPin: gpioBit=%02x", gpioBit) |
Yann | 2:3bea48e1505c | 369 | if (!isBitEqual(gpioFlags, gpioBit, 0x01)) { // Port pin is not configure as input |
Yann | 3:b902729a1675 | 370 | // DEBUG_LEAVE("CMCP23017_I2C::setupPullPin: -1") |
Yann | 2:3bea48e1505c | 371 | return -1; |
Yann | 2:3bea48e1505c | 372 | } |
Yann | 2:3bea48e1505c | 373 | |
Yann | 2:3bea48e1505c | 374 | // Read it |
Yann | 2:3bea48e1505c | 375 | unsigned char gpioGppuValue; |
Yann | 2:3bea48e1505c | 376 | if (!readRegister(gpioGppuId, &gpioGppuValue)) { |
Yann | 3:b902729a1675 | 377 | // DEBUG_LEAVE("CMCP23017_I2C::setupPullPin: -2") |
Yann | 2:3bea48e1505c | 378 | return -2; |
Yann | 2:3bea48e1505c | 379 | } |
Yann | 3:b902729a1675 | 380 | // DEBUG("CMCP23017_I2C::setupPullPin: gpioGppuId=%02x", gpioGppuId) |
Yann | 2:3bea48e1505c | 381 | |
Yann | 2:3bea48e1505c | 382 | // |
Yann | 2:3bea48e1505c | 383 | switch (static_cast<unsigned char>(p_mode)) { |
Yann | 2:3bea48e1505c | 384 | case static_cast<unsigned char>(AbstractGpioExpender::PullOff): |
Yann | 2:3bea48e1505c | 385 | gpioGppuValue = setBit(gpioGppuValue, gpioBit, 0x00); |
Yann | 2:3bea48e1505c | 386 | break; |
Yann | 2:3bea48e1505c | 387 | case static_cast<unsigned char>(AbstractGpioExpender::PullUp): |
Yann | 2:3bea48e1505c | 388 | gpioGppuValue = setBit(gpioGppuValue, gpioBit, 0x01); |
Yann | 2:3bea48e1505c | 389 | break; |
Yann | 2:3bea48e1505c | 390 | case static_cast<unsigned char>(AbstractGpioExpender::PullDown): |
Yann | 2:3bea48e1505c | 391 | // Not supporte, nothing to do |
Yann | 2:3bea48e1505c | 392 | break; |
Yann | 2:3bea48e1505c | 393 | } // End of 'switch' statement |
Yann | 2:3bea48e1505c | 394 | |
Yann | 2:3bea48e1505c | 395 | // Write register |
Yann | 3:b902729a1675 | 396 | // DEBUG("CMCP23017_I2C::setupPullPin: gpioGppuValue=%02x", gpioGppuValue) |
Yann | 2:3bea48e1505c | 397 | writeRegister(gpioGppuId, gpioGppuValue); |
Yann | 2:3bea48e1505c | 398 | |
Yann | 2:3bea48e1505c | 399 | |
Yann | 3:b902729a1675 | 400 | // DEBUG_LEAVE("CMCP23017_I2C::setupPullPin: 0") |
Yann | 2:3bea48e1505c | 401 | return 0; |
Yann | 2:3bea48e1505c | 402 | } |
Yann | 2:3bea48e1505c | 403 | |
Yann | 2:3bea48e1505c | 404 | int CMCP23017_I2C::getLastInterruptPinAndValue(unsigned char * p_gpioId, unsigned char * p_value) { |
Yann | 3:b902729a1675 | 405 | // DEBUG_ENTER("CMCP23017_I2C::getLastInterruptPinAndValue") |
Yann | 0:ebd3a7cc9b92 | 406 | |
Yann | 0:ebd3a7cc9b92 | 407 | // Read first INTFA if required |
Yann | 0:ebd3a7cc9b92 | 408 | unsigned char vregister; |
Yann | 0:ebd3a7cc9b92 | 409 | if (_gpioAFlags != 0x00) { |
Yann | 0:ebd3a7cc9b92 | 410 | if (!readRegister(INTFA, &vregister)) { |
Yann | 3:b902729a1675 | 411 | // DEBUG_LEAVE("CMCP23017_I2C::setupInterruptPin: -1") |
Yann | 0:ebd3a7cc9b92 | 412 | return -1; |
Yann | 0:ebd3a7cc9b92 | 413 | } |
Yann | 0:ebd3a7cc9b92 | 414 | vregister &= _gpioAFlags; // Cannot have interrupt on output port |
Yann | 0:ebd3a7cc9b92 | 415 | for (unsigned char bit = 0; bit < GPIO_SIZE; bit++) { |
Yann | 0:ebd3a7cc9b92 | 416 | if (isBitSet(vregister, bit)) { |
Yann | 0:ebd3a7cc9b92 | 417 | *p_gpioId = bit; |
Yann | 0:ebd3a7cc9b92 | 418 | readRegister(INTCAPA, p_value); |
Yann | 0:ebd3a7cc9b92 | 419 | *p_value = (*p_value >> bit) & 0x01; |
Yann | 0:ebd3a7cc9b92 | 420 | |
Yann | 3:b902729a1675 | 421 | // DEBUG_LEAVE("CMCP23017_I2C::getLastInterruptPinAndValue (A): %02x %02x", *p_gpioId, *p_value) |
Yann | 0:ebd3a7cc9b92 | 422 | return 0; |
Yann | 0:ebd3a7cc9b92 | 423 | } |
Yann | 0:ebd3a7cc9b92 | 424 | } // End of 'for' statement |
Yann | 0:ebd3a7cc9b92 | 425 | } |
Yann | 0:ebd3a7cc9b92 | 426 | |
Yann | 0:ebd3a7cc9b92 | 427 | // If not interrupt on GPIOA, try with GPIOB |
Yann | 0:ebd3a7cc9b92 | 428 | if (_gpioBFlags != 0x00) { |
Yann | 0:ebd3a7cc9b92 | 429 | if (!readRegister(INTFB, &vregister)) { |
Yann | 3:b902729a1675 | 430 | // DEBUG_LEAVE("CMCP23017_I2C::setupInterruptPin: -2") |
Yann | 0:ebd3a7cc9b92 | 431 | return -2; |
Yann | 0:ebd3a7cc9b92 | 432 | } |
Yann | 0:ebd3a7cc9b92 | 433 | vregister &= _gpioBFlags; // Cannot have interrupt on output port |
Yann | 0:ebd3a7cc9b92 | 434 | for (unsigned char bit = 0; bit < GPIO_SIZE; bit++) { |
Yann | 0:ebd3a7cc9b92 | 435 | if (isBitSet(vregister, bit)) { |
Yann | 0:ebd3a7cc9b92 | 436 | *p_gpioId = bit + GPIO_SIZE; |
Yann | 0:ebd3a7cc9b92 | 437 | readRegister(INTCAPB, p_value); |
Yann | 0:ebd3a7cc9b92 | 438 | *p_value = (*p_value >> bit) & 0x01; |
Yann | 0:ebd3a7cc9b92 | 439 | |
Yann | 3:b902729a1675 | 440 | // DEBUG_LEAVE("CMCP23017_I2C::getLastInterruptPinAndValue (B): %02x %02x", *p_gpioId, *p_value) |
Yann | 0:ebd3a7cc9b92 | 441 | return 0; |
Yann | 0:ebd3a7cc9b92 | 442 | } |
Yann | 0:ebd3a7cc9b92 | 443 | } // End of 'for' statement |
Yann | 0:ebd3a7cc9b92 | 444 | } |
Yann | 0:ebd3a7cc9b92 | 445 | |
Yann | 3:b902729a1675 | 446 | // DEBUG_LEAVE("CMCP23017_I2C::getLastInterruptPinAndValue: 0") |
Yann | 0:ebd3a7cc9b92 | 447 | return 0; |
Yann | 0:ebd3a7cc9b92 | 448 | } |
Yann | 0:ebd3a7cc9b92 | 449 | |
Yann | 0:ebd3a7cc9b92 | 450 | int CMCP23017_I2C::read(const unsigned char p_gpioId, unsigned char * p_value) { |
Yann | 3:b902729a1675 | 451 | // DEBUG_ENTER("CMCP23017_I2C::read: 0x%02x", p_gpioId) |
Yann | 0:ebd3a7cc9b92 | 452 | |
Yann | 2:3bea48e1505c | 453 | // Retrieve the register address |
Yann | 0:ebd3a7cc9b92 | 454 | unsigned char gpioRegisterId; |
Yann | 0:ebd3a7cc9b92 | 455 | if (!registerIdFromGpioId(p_gpioId, &gpioRegisterId)) { |
Yann | 3:b902729a1675 | 456 | // DEBUG_LEAVE("CMCP23017_I2C::read: -1") |
Yann | 0:ebd3a7cc9b92 | 457 | return -1; |
Yann | 0:ebd3a7cc9b92 | 458 | } |
Yann | 3:b902729a1675 | 459 | // DEBUG("CMCP23017_I2C::read: gpioRegisterId=%02x", gpioRegisterId) |
Yann | 0:ebd3a7cc9b92 | 460 | unsigned char gpioBit = gpioBitFromGpioId(p_gpioId); |
Yann | 3:b902729a1675 | 461 | // DEBUG("CMCP23017_I2C::read: gpioBit=%02x", gpioBit) |
Yann | 0:ebd3a7cc9b92 | 462 | |
Yann | 0:ebd3a7cc9b92 | 463 | // Read it |
Yann | 0:ebd3a7cc9b92 | 464 | unsigned char gpioRegisterValue; |
Yann | 0:ebd3a7cc9b92 | 465 | if (!readRegister(gpioRegisterId, &gpioRegisterValue)) { |
Yann | 3:b902729a1675 | 466 | // DEBUG_LEAVE("CMCP23017_I2C::read: -2") |
Yann | 0:ebd3a7cc9b92 | 467 | return -2; |
Yann | 0:ebd3a7cc9b92 | 468 | } |
Yann | 3:b902729a1675 | 469 | // DEBUG("CMCP23017_I2C::read: gpioRegisterValue=%02x", gpioRegisterValue) |
Yann | 0:ebd3a7cc9b92 | 470 | |
Yann | 1:ec9e770173d5 | 471 | *p_value = (isBitSet(gpioRegisterValue, gpioBit)) ? 0x01 : 0x00; |
Yann | 3:b902729a1675 | 472 | // DEBUG("CMCP23017_I2C::read: p_value=%02x", *p_value) |
Yann | 1:ec9e770173d5 | 473 | |
Yann | 3:b902729a1675 | 474 | // DEBUG_LEAVE("CMCP23017_I2C::read: 0") |
Yann | 0:ebd3a7cc9b92 | 475 | return 0; |
Yann | 0:ebd3a7cc9b92 | 476 | } |
Yann | 0:ebd3a7cc9b92 | 477 | |
Yann | 0:ebd3a7cc9b92 | 478 | bool CMCP23017_I2C::registerIdFromGpioId(const unsigned char p_gpioId, unsigned char * p_gpioRegisterId) { |
Yann | 3:b902729a1675 | 479 | // DEBUG_ENTER("CMCP23017_I2C::registerIdFromGpioId: 0x%02x", p_gpioId) |
Yann | 0:ebd3a7cc9b92 | 480 | |
Yann | 0:ebd3a7cc9b92 | 481 | // Sanity check |
Yann | 0:ebd3a7cc9b92 | 482 | if (p_gpioId > GPIO_MAX) { |
Yann | 3:b902729a1675 | 483 | // DEBUG_ENTER("CMCP23017_I2C::registerIdFromGpioId: false") |
Yann | 0:ebd3a7cc9b92 | 484 | return false; |
Yann | 0:ebd3a7cc9b92 | 485 | } |
Yann | 0:ebd3a7cc9b92 | 486 | |
Yann | 0:ebd3a7cc9b92 | 487 | *p_gpioRegisterId = (p_gpioId < GPIO_MED) ? GPIOA : GPIOB; |
Yann | 0:ebd3a7cc9b92 | 488 | |
Yann | 3:b902729a1675 | 489 | // DEBUG_ENTER("CMCP23017_I2C::registerIdFromGpioId: true") |
Yann | 0:ebd3a7cc9b92 | 490 | return true; |
Yann | 0:ebd3a7cc9b92 | 491 | } |
Yann | 0:ebd3a7cc9b92 | 492 | |
Yann | 0:ebd3a7cc9b92 | 493 | int CMCP23017_I2C::write(const unsigned char p_gpioId, const unsigned char p_value) { |
Yann | 3:b902729a1675 | 494 | // DEBUG_ENTER("CMCP23017_I2C::write: 0x%02x 0x%02x", p_gpioId, p_value) |
Yann | 0:ebd3a7cc9b92 | 495 | |
Yann | 2:3bea48e1505c | 496 | // Retrieve the register address |
Yann | 0:ebd3a7cc9b92 | 497 | unsigned char gpioRegisterId; |
Yann | 0:ebd3a7cc9b92 | 498 | if (!registerIdFromGpioId(p_gpioId, &gpioRegisterId)) { |
Yann | 3:b902729a1675 | 499 | // DEBUG_LEAVE("CMCP23017_I2C::write: -1") |
Yann | 0:ebd3a7cc9b92 | 500 | return -1; |
Yann | 0:ebd3a7cc9b92 | 501 | } |
Yann | 3:b902729a1675 | 502 | // DEBUG("CMCP23017_I2C::write: gpioRegisterId=%02x", gpioRegisterId) |
Yann | 0:ebd3a7cc9b92 | 503 | |
Yann | 2:3bea48e1505c | 504 | // Retrieve the GPIO pin number |
Yann | 0:ebd3a7cc9b92 | 505 | unsigned char gpioBit = gpioBitFromGpioId(p_gpioId); |
Yann | 3:b902729a1675 | 506 | // DEBUG("CMCP23017_I2C::write: gpioBit=%02x", gpioBit) |
Yann | 0:ebd3a7cc9b92 | 507 | |
Yann | 0:ebd3a7cc9b92 | 508 | // Read it |
Yann | 0:ebd3a7cc9b92 | 509 | unsigned char gpioRegisterValue; |
Yann | 0:ebd3a7cc9b92 | 510 | if (!readRegister(gpioRegisterId, &gpioRegisterValue)) { |
Yann | 3:b902729a1675 | 511 | // DEBUG_LEAVE("CMCP23017_I2C::write: -2") |
Yann | 0:ebd3a7cc9b92 | 512 | return -2; |
Yann | 0:ebd3a7cc9b92 | 513 | } |
Yann | 3:b902729a1675 | 514 | // DEBUG("CMCP23017_I2C::write: gpioRegisterValue=%02x", gpioRegisterValue) |
Yann | 0:ebd3a7cc9b92 | 515 | |
Yann | 0:ebd3a7cc9b92 | 516 | // Update GPIO bit |
Yann | 0:ebd3a7cc9b92 | 517 | if (!isBitEqual(gpioRegisterValue, gpioBit, p_value)) { |
Yann | 0:ebd3a7cc9b92 | 518 | // Write it if required |
Yann | 0:ebd3a7cc9b92 | 519 | gpioRegisterValue = setBit(gpioRegisterValue, gpioBit, p_value); |
Yann | 3:b902729a1675 | 520 | // DEBUG("CMCP23017_I2C::write: New gpioRegisterValue=%02x", gpioRegisterValue) |
Yann | 0:ebd3a7cc9b92 | 521 | if (!writeRegister(gpioRegisterId, gpioRegisterValue)) { |
Yann | 3:b902729a1675 | 522 | // DEBUG_LEAVE("CMCP23017_I2C::write: -3") |
Yann | 0:ebd3a7cc9b92 | 523 | return -3; |
Yann | 0:ebd3a7cc9b92 | 524 | } |
Yann | 0:ebd3a7cc9b92 | 525 | } |
Yann | 0:ebd3a7cc9b92 | 526 | |
Yann | 3:b902729a1675 | 527 | // DEBUG_LEAVE("CMCP23017_I2C::write: 0") |
Yann | 0:ebd3a7cc9b92 | 528 | return 0; |
Yann | 0:ebd3a7cc9b92 | 529 | } |
Yann | 0:ebd3a7cc9b92 | 530 | |
Yann | 0:ebd3a7cc9b92 | 531 | unsigned char CMCP23017_I2C::createBus(const std::list<unsigned char> p_lines, const PinMode p_mode) { |
Yann | 0:ebd3a7cc9b92 | 532 | unsigned char busId = _busesIndex++; |
Yann | 0:ebd3a7cc9b92 | 533 | |
Yann | 0:ebd3a7cc9b92 | 534 | _buses.insert(_buses.end(), std::pair<unsigned char, std::list<unsigned char> >(busId, p_lines)); |
Yann | 0:ebd3a7cc9b92 | 535 | |
Yann | 0:ebd3a7cc9b92 | 536 | return busId; |
Yann | 0:ebd3a7cc9b92 | 537 | } |
Yann | 0:ebd3a7cc9b92 | 538 | |
Yann | 0:ebd3a7cc9b92 | 539 | void CMCP23017_I2C::deleteBus(const unsigned char p_busId) { |
Yann | 0:ebd3a7cc9b92 | 540 | // Sanity check |
Yann | 0:ebd3a7cc9b92 | 541 | std::map<unsigned char, std::list<unsigned char> >::iterator result = _buses.find(p_busId); |
Yann | 0:ebd3a7cc9b92 | 542 | if (result == _buses.end()) { // Invalid bus identifier |
Yann | 0:ebd3a7cc9b92 | 543 | return; |
Yann | 0:ebd3a7cc9b92 | 544 | } |
Yann | 0:ebd3a7cc9b92 | 545 | |
Yann | 0:ebd3a7cc9b92 | 546 | _buses.erase(p_busId); |
Yann | 0:ebd3a7cc9b92 | 547 | } |
Yann | 0:ebd3a7cc9b92 | 548 | |
Yann | 1:ec9e770173d5 | 549 | int CMCP23017_I2C::busRead(const unsigned char p_busId, unsigned short * p_value) { |
Yann | 2:3bea48e1505c | 550 | // DEBUG_ENTER("CMCP23017_I2C::busRead: 0x%02x", p_busId) |
Yann | 2:3bea48e1505c | 551 | |
Yann | 1:ec9e770173d5 | 552 | // Sanity checks |
Yann | 1:ec9e770173d5 | 553 | if (_buses.size() == 0) { |
Yann | 3:b902729a1675 | 554 | // DEBUG_LEAVE("CMCP23017_I2C::busRead: -1") |
Yann | 1:ec9e770173d5 | 555 | return -1; |
Yann | 1:ec9e770173d5 | 556 | } |
Yann | 1:ec9e770173d5 | 557 | std::map<unsigned char, std::list<unsigned char> >::iterator result = _buses.find(p_busId); |
Yann | 1:ec9e770173d5 | 558 | if (result == _buses.end()) { // Invalid bus identifier |
Yann | 3:b902729a1675 | 559 | // DEBUG_LEAVE("CMCP23017_I2C::busRead: -1") |
Yann | 1:ec9e770173d5 | 560 | return -1; |
Yann | 1:ec9e770173d5 | 561 | } |
Yann | 1:ec9e770173d5 | 562 | |
Yann | 1:ec9e770173d5 | 563 | std::list<unsigned char>::reverse_iterator rit; |
Yann | 1:ec9e770173d5 | 564 | for (std::list<unsigned char>::reverse_iterator rit = result->second.rbegin(); rit != result->second.rend(); ++rit) { |
Yann | 1:ec9e770173d5 | 565 | unsigned char regvalue; |
Yann | 1:ec9e770173d5 | 566 | if (read(*rit, ®value) == 0) { |
Yann | 1:ec9e770173d5 | 567 | *p_value = (*p_value | regvalue) << 1; |
Yann | 1:ec9e770173d5 | 568 | } else { |
Yann | 1:ec9e770173d5 | 569 | *p_value <<= 1; |
Yann | 1:ec9e770173d5 | 570 | } |
Yann | 1:ec9e770173d5 | 571 | } // End of 'for' statement |
Yann | 1:ec9e770173d5 | 572 | |
Yann | 2:3bea48e1505c | 573 | // DEBUG_LEAVE("CMCP23017_I2C::busRead: 0") |
Yann | 1:ec9e770173d5 | 574 | return 0; |
Yann | 0:ebd3a7cc9b92 | 575 | } |
Yann | 0:ebd3a7cc9b92 | 576 | |
Yann | 1:ec9e770173d5 | 577 | int CMCP23017_I2C::busWrite(const unsigned char p_busId, const unsigned short p_value) { |
Yann | 2:3bea48e1505c | 578 | // DEBUG_ENTER("CMCP23017_I2C::busWrite: 0x%02x - 0x%02x", p_busId, p_value) |
Yann | 2:3bea48e1505c | 579 | |
Yann | 1:ec9e770173d5 | 580 | // Sanity checks |
Yann | 1:ec9e770173d5 | 581 | if (_buses.size() == 0) { |
Yann | 1:ec9e770173d5 | 582 | return -1; |
Yann | 1:ec9e770173d5 | 583 | } |
Yann | 1:ec9e770173d5 | 584 | std::map<unsigned char, std::list<unsigned char> >::iterator result = _buses.find(p_busId); |
Yann | 1:ec9e770173d5 | 585 | if (result == _buses.end()) { // Invalid bus identifier |
Yann | 3:b902729a1675 | 586 | // DEBUG_LEAVE("CMCP23017_I2C::busWrite: -1") |
Yann | 1:ec9e770173d5 | 587 | return -1; |
Yann | 1:ec9e770173d5 | 588 | } |
Yann | 1:ec9e770173d5 | 589 | |
Yann | 1:ec9e770173d5 | 590 | std::list<unsigned char>::reverse_iterator rit; |
Yann | 1:ec9e770173d5 | 591 | unsigned short value = p_value; |
Yann | 1:ec9e770173d5 | 592 | for (std::list<unsigned char>::reverse_iterator rit = result->second.rbegin(); rit != result->second.rend(); ++rit) { |
Yann | 1:ec9e770173d5 | 593 | write(*rit, value & 0x01); |
Yann | 1:ec9e770173d5 | 594 | value >>= 1; |
Yann | 1:ec9e770173d5 | 595 | } // End of 'for' statement |
Yann | 1:ec9e770173d5 | 596 | |
Yann | 2:3bea48e1505c | 597 | // DEBUG_LEAVE("CMCP23017_I2C::busWrite: 0") |
Yann | 1:ec9e770173d5 | 598 | return 0; |
Yann | 0:ebd3a7cc9b92 | 599 | } |
Yann | 0:ebd3a7cc9b92 | 600 | |
Yann | 0:ebd3a7cc9b92 | 601 | bool CMCP23017_I2C::writeRegister(const unsigned char p_registerId, const unsigned char p_value) { |
Yann | 0:ebd3a7cc9b92 | 602 | // DEBUG_ENTER("CMCP23017_I2C::writeRegister: Memory address: 0x%02x - 0x%02x", p_registerId, p_value) |
Yann | 0:ebd3a7cc9b92 | 603 | |
Yann | 0:ebd3a7cc9b92 | 604 | // 1.Prepare buffer |
Yann | 0:ebd3a7cc9b92 | 605 | char i2cBuffer[2]; // Register address + one byte of data |
Yann | 0:ebd3a7cc9b92 | 606 | // 1.1. Memory address |
Yann | 0:ebd3a7cc9b92 | 607 | i2cBuffer[0] = p_registerId; |
Yann | 0:ebd3a7cc9b92 | 608 | // 1.2. Datas |
Yann | 0:ebd3a7cc9b92 | 609 | i2cBuffer[1] = p_value; |
Yann | 0:ebd3a7cc9b92 | 610 | // DEBUG("CMCP23017_I2C::writeRegister: Data=0x%02x 0x%02x", i2cBuffer[0], i2cBuffer[1]) |
Yann | 0:ebd3a7cc9b92 | 611 | |
Yann | 0:ebd3a7cc9b92 | 612 | // 2. Send I2C start + I2C address + Memory Address + Datas + I2C stop |
Yann | 0:ebd3a7cc9b92 | 613 | int result = _i2cInstance->write(_slaveAddress, i2cBuffer, 2); |
Yann | 0:ebd3a7cc9b92 | 614 | // wait(0.02); |
Yann | 0:ebd3a7cc9b92 | 615 | |
Yann | 0:ebd3a7cc9b92 | 616 | // DEBUG_LEAVE("CMCP23017_I2C::writeRegister %x", (bool)(result == 0)) |
Yann | 0:ebd3a7cc9b92 | 617 | return (bool)(result == 0); |
Yann | 0:ebd3a7cc9b92 | 618 | } |
Yann | 0:ebd3a7cc9b92 | 619 | |
Yann | 0:ebd3a7cc9b92 | 620 | bool CMCP23017_I2C::readRegister(const unsigned char p_registerId, unsigned char * p_value) { |
Yann | 0:ebd3a7cc9b92 | 621 | // DEBUG_ENTER("CMCP23017_I2C::readRegister: Memory address: 0x%02x", p_registerId) |
Yann | 0:ebd3a7cc9b92 | 622 | |
Yann | 0:ebd3a7cc9b92 | 623 | // 1.Prepare buffer |
Yann | 0:ebd3a7cc9b92 | 624 | char i2cBuffer[1]; // Register address + one byte of data |
Yann | 0:ebd3a7cc9b92 | 625 | // 1.1. Memory address |
Yann | 0:ebd3a7cc9b92 | 626 | i2cBuffer[0] = p_registerId; |
Yann | 0:ebd3a7cc9b92 | 627 | // DEBUG("CMCP23017_I2C::readRegister: Data=0x%02x", i2cBuffer[0]) |
Yann | 0:ebd3a7cc9b92 | 628 | |
Yann | 0:ebd3a7cc9b92 | 629 | // 2. Send I2C start + memory address |
Yann | 0:ebd3a7cc9b92 | 630 | if (_i2cInstance->write(_slaveAddress, i2cBuffer, 1, true) == 0) { |
Yann | 0:ebd3a7cc9b92 | 631 | // wait(0.02); |
Yann | 0:ebd3a7cc9b92 | 632 | // DEBUG("CMCP23017_I2C::readRegister: Write memory done") |
Yann | 0:ebd3a7cc9b92 | 633 | // 2. Read data + I2C stop |
Yann | 0:ebd3a7cc9b92 | 634 | int result = _i2cInstance->read(_slaveAddress, (char *)p_value, 1); |
Yann | 0:ebd3a7cc9b92 | 635 | // wait(0.02); |
Yann | 0:ebd3a7cc9b92 | 636 | |
Yann | 0:ebd3a7cc9b92 | 637 | // DEBUG_LEAVE("C24LCXX_I2C::readRegister (byte): %x", (bool)(result == 0)) |
Yann | 0:ebd3a7cc9b92 | 638 | return (bool)(result == 0); |
Yann | 0:ebd3a7cc9b92 | 639 | } |
Yann | 0:ebd3a7cc9b92 | 640 | |
Yann | 0:ebd3a7cc9b92 | 641 | // DEBUG_LEAVE("CMCP23017_I2C::readRegister false") |
Yann | 0:ebd3a7cc9b92 | 642 | return false; |
Yann | 0:ebd3a7cc9b92 | 643 | } |
Yann | 0:ebd3a7cc9b92 | 644 | |
Yann | 0:ebd3a7cc9b92 | 645 | void CMCP23017_I2C::DumpRegisters() { |
Yann | 0:ebd3a7cc9b92 | 646 | |
Yann | 0:ebd3a7cc9b92 | 647 | unsigned char value; |
Yann | 0:ebd3a7cc9b92 | 648 | for (unsigned int registerId = 0; registerId < 0x16; registerId++) { |
Yann | 0:ebd3a7cc9b92 | 649 | readRegister(registerId, &value); |
Yann | 3:b902729a1675 | 650 | // DEBUG("CMCP23017_I2C::DumpRegisters: register[%d] = 0x%02x", registerId, value) |
Yann | 0:ebd3a7cc9b92 | 651 | } |
Yann | 0:ebd3a7cc9b92 | 652 | } |
Yann | 0:ebd3a7cc9b92 | 653 | |
Yann | 0:ebd3a7cc9b92 | 654 | void CMCP23017_I2C::DumpRegister(unsigned int p_registerId) { |
Yann | 0:ebd3a7cc9b92 | 655 | |
Yann | 0:ebd3a7cc9b92 | 656 | unsigned char value; |
Yann | 0:ebd3a7cc9b92 | 657 | readRegister(p_registerId, &value); |
Yann | 3:b902729a1675 | 658 | // DEBUG("CMCP23017_I2C::DumpRegister: register[%d] = 0x%02x", p_registerId, value) |
Yann | 0:ebd3a7cc9b92 | 659 | } |
Yann | 0:ebd3a7cc9b92 | 660 | |
Yann | 0:ebd3a7cc9b92 | 661 | } // End of namespace MCP23017_I2C |