This library provides simplified I2C access to a Microchip MCP23x17 GPIO expender device, including a general interface for any GPIO expender
MCP23017_I2C.cpp
00001 /* mbed simplified access to Microchip MCP23x17 GPIO expender devices (I2C) 00002 * Copyright (c) 2010-2012 ygarcia, MIT License 00003 * 00004 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 00005 * and associated documentation files (the "Software"), to deal in the Software without restriction, 00006 * including without limitation the rights to use, copy, modify, merge, publish, distribute, 00007 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 00008 * furnished to do so, subject to the following conditions: 00009 * 00010 * The above copyright notice and this permission notice shall be included in all copies or 00011 * substantial pinions of the Software. 00012 * 00013 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 00014 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 00015 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 00016 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00017 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 00018 */ 00019 #include <iostream> 00020 #include <sstream> 00021 00022 #include "MCP23017_I2C.h" 00023 00024 #define IODIRA 0x00 00025 #define IODIRB 0x01 00026 #define IPOLA 0x02 00027 #define IPOLB 0x03 00028 #define GPINTENA 0x04 00029 #define GPINTENB 0x05 00030 #define DEFVALA 0x06 00031 #define DEFVALB 0x07 00032 #define INTCONA 0x08 00033 #define INTCONB 0x09 00034 #define IOCONA 0x0a 00035 #define IOCONB 0x0b 00036 #define GPPUA 0x0c 00037 #define GPPUB 0x0d 00038 #define INTFA 0x0e 00039 #define INTFB 0x0f 00040 #define INTCAPA 0x10 00041 #define INTCAPB 0x11 00042 #define GPIOA 0x12 00043 #define GPIOB 0x13 00044 #define OLATA 0x14 00045 #define OLATB 0x15 00046 00047 namespace MCP23017_I2C { 00048 00049 unsigned char CMCP23017_I2C::I2CModuleRefCounter = 0; 00050 00051 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("") { 00052 // DEBUG_ENTER("CMCP23017_I2C") 00053 00054 if (CMCP23017_I2C::I2CModuleRefCounter != 0) { 00055 error("CMCP23017_I2C: Wrong params"); 00056 } 00057 #ifdef __DEBUG 00058 std::ostringstream out(std::ostringstream::out); 00059 out << "CMCP23017_I2C #" << CMCP23017_I2C::I2CModuleRefCounter; 00060 _internalId.assign(out.str()); 00061 // DEBUG("CMCP23017_I2C: _internalId='%s'", _internalId.c_str()) 00062 #endif // __DEBUG 00063 _i2cInstance = new I2C(p_sda, p_scl); 00064 CMCP23017_I2C::I2CModuleRefCounter += 1; 00065 // DEBUG_ENTER("CMCP23017_I2C: refCounter=%d", CMCP23017_I2C::I2CModuleRefCounter) 00066 00067 _slaveAddress = (p_address << 1) | 0x40; // Slave address format is: 0 0 1 0 A3 A2 A1 R/W 00068 // DEBUG("CMCP23017_I2C: I2C slave adress: 0x%02x", _slaveAddress) 00069 _i2cInstance->frequency(p_frequency); // Set the frequency of the I2C interface 00070 00071 if (p_intA != NC) { 00072 // DEBUG("CMCP23017_I2C: INTA managed"); 00073 _intA = new InterruptIn(p_intA); 00074 if (p_internalPullUp) _intA->mode(::PullDown); 00075 _intA->enable_irq(); // Enable interrupt 00076 } else { 00077 // DEBUG("CMCP23017_I2C: INTA not managed"); 00078 _intA = NULL; // Not used 00079 } 00080 if (p_intB != NC) { 00081 // DEBUG("CMCP23017_I2C: INTB managed"); 00082 _intB = new InterruptIn(p_intB); 00083 if (p_internalPullUp) _intB->mode(::PullDown); 00084 _intB->enable_irq(); // Enable interrupt 00085 } else { 00086 // DEBUG("CMCP23017_I2C: INTB not managed"); 00087 _intB = NULL; // Not used 00088 } 00089 if (p_reset != NC) { 00090 // DEBUG("CMCP23017_I2C: RESET managed"); 00091 _reset = new DigitalOut(p_reset); 00092 _reset->write(1); // Disable reset 00093 } else { 00094 // DEBUG("CMCP23017_I2C: RESET not managed"); 00095 _reset = NULL; // Not used 00096 } 00097 00098 // DEBUG_LEAVE("CMCP23017_I2C") 00099 } 00100 00101 CMCP23017_I2C::~CMCP23017_I2C() { 00102 // DEBUG_ENTER("~CMCP23017_I2C") 00103 00104 // Release I2C instance 00105 // DEBUG("~CMCP23017_I2C: refCounter=%d", CMCP23017_I2C::I2CModuleRefCounter) 00106 CMCP23017_I2C::I2CModuleRefCounter -= 1; 00107 if (CMCP23017_I2C::I2CModuleRefCounter == 0) { 00108 delete _i2cInstance; 00109 _i2cInstance = NULL; 00110 } 00111 // Release _wp if required 00112 if (_intA != NULL) { 00113 delete _intA; 00114 } 00115 if (_intB != NULL) { 00116 delete _intB; 00117 } 00118 if (_reset != NULL) { 00119 delete _reset; 00120 } 00121 00122 // DEBUG_LEAVE("~CMCP23017_I2C") 00123 } 00124 00125 bool CMCP23017_I2C::Initialize(const unsigned char p_gpioAFlags, const unsigned char p_gpioBFlags) { 00126 00127 // Configure default behavior 00128 _gpioAFlags = p_gpioAFlags; 00129 _gpioBFlags = p_gpioBFlags; 00130 configure(_gpioAFlags, _gpioBFlags); 00131 00132 return true; 00133 } 00134 00135 void CMCP23017_I2C::configure(const unsigned char p_gpioAFlags, const unsigned char p_gpioBFlags) { // TODO Optimization with sequential access 00136 // DEBUG_ENTER("CMCP23017_I2C::configure: 0x%02x 0x%02x", p_gpioAFlags, p_gpioBFlags) 00137 00138 // Setup IOCON - See REGISTER 1-6: IOCON – I/O EXPANDER CONFIGURATION REGISTER 00139 writeRegister(IOCONA, 0x10); // Sequential operation disabled 00140 writeRegister(IOCONB, 0x10); // Sequential operation disabled 00141 // Setup IODIR - See REGISTER 1-1: IODIR – I/O DIRECTION REGISTER (ADDR 0x00) 00142 writeRegister(IODIRA, p_gpioAFlags); 00143 writeRegister(IODIRB, p_gpioBFlags); 00144 // Setup IPOL - See REGISTER 1-2: IPOL – INPUT POLARITY PORT REGISTER 00145 writeRegister(IPOLA, 0x00); // GPIO register bit will reflect the same logic state of the input pin 00146 writeRegister(IPOLB, 0x00); 00147 // Setup GPPU - See REGISTER 1-7: GPPU – GPIO PULL-UP RESISTOR REGISTER 00148 writeRegister(GPPUA, 0x00); 00149 writeRegister(GPPUB, 0x00); 00150 00151 // Setup interrupt 00152 if (_intA != NULL) { 00153 // DEBUG("CMCP23017_I2C::configure: Setup INTA") 00154 // Setup GPINTEN - See GPINTEN – INTERRUPT-ON-CHANGE PINS 00155 writeRegister(GPINTENA, 0x00); // Disable GPIO interrupt-on-change events 00156 // Setup DEFVAL - See REGISTER 1-4: DEFVAL – DEFAULT VALUE REGISTER 00157 writeRegister(DEFVALA, 0x00); // Pin level change from 0 to 1 raises an interrupt 00158 // Setup INTCON - REGISTER 1-5: INTCON – INTERRUPT-ON-CHANGE CONTROL REGISTER 00159 writeRegister(INTCONA, 0xff); // Pin level change from 0 to 1 raises an interrupt 00160 } 00161 if (_intB != NULL) { 00162 // DEBUG("CMCP23017_I2C::configure: Setup INTB") 00163 // Setup GPINTEN - See GPINTEN – INTERRUPT-ON-CHANGE PINS 00164 writeRegister(GPINTENB, 0x00); // Disable GPIO interrupt-on-change events 00165 // Setup DEFVAL - See REGISTER 1-4: DEFVAL – DEFAULT VALUE REGISTER 00166 writeRegister(DEFVALB, 0x00); // Pin level change from 0 to 1 raises an interrupt 00167 // Setup INTCON - REGISTER 1-5: INTCON – INTERRUPT-ON-CHANGE CONTROL REGISTER 00168 writeRegister(INTCONB, 0xff); // Pin level change from 0 to 1 raises an interrupt 00169 } 00170 00171 // DumpRegisters(); 00172 00173 // DEBUG_LEAVE("CMCP23017_I2C::configure") 00174 } 00175 00176 void CMCP23017_I2C::reset() { 00177 // DEBUG_ENTER("CMCP23017_I2C::reset") 00178 if (_reset != NULL) { 00179 _reset->write(0); 00180 wait_us(1); 00181 _reset->write(1); 00182 wait_us(1); 00183 if ((_gpioAFlags != 0x00) || (_gpioBFlags != 0x00)) { // Apply configuration 00184 configure(_gpioAFlags, _gpioBFlags); 00185 } // else, POR reset values, see DS21952B-page 10 Clause 1.6 Configuration and Control Registers 00186 } 00187 // DEBUG_LEAVE("CMCP23017_I2C::reset") 00188 } 00189 00190 void CMCP23017_I2C::setIntrACallback(void (* p_fptr)(void)) { 00191 if (_intA != NULL) { 00192 unsigned char vregister; 00193 if (!readRegister(IOCONA, &vregister)) { 00194 return; 00195 } 00196 if (isBitSet(vregister, 1)) { 00197 _intA->rise(p_fptr); 00198 } else { 00199 _intA->fall(p_fptr); 00200 } 00201 } 00202 } 00203 00204 void CMCP23017_I2C::setIntrBCallback(void (* p_fptr)(void)) { 00205 if (_intB != NULL) { 00206 unsigned char vregister; 00207 if (!readRegister(IOCONB, &vregister)) { 00208 return; 00209 } 00210 if (isBitSet(vregister, 1)) { 00211 _intB->rise(p_fptr); 00212 } else { 00213 _intB->fall(p_fptr); 00214 } 00215 } 00216 } 00217 00218 template<typename T> 00219 void CMCP23017_I2C::setIntrACallback (const T * p_tptr, void(T::* p_mptr)(void)) { 00220 if (_intA != NULL) { 00221 unsigned char vregister; 00222 if (!readRegister(IOCONA, &vregister)) { 00223 return; 00224 } 00225 if (isBitSet(vregister, 1)) { 00226 _intA->rise(p_tptr, p_mptr); 00227 } else { 00228 _intA->fall(p_tptr, p_mptr); 00229 } 00230 } 00231 } 00232 00233 template<typename T> 00234 void CMCP23017_I2C::setIntrBCallback (const T * p_tptr, void(T::* p_mptr)(void)) { 00235 unsigned char vregister; 00236 if (!readRegister(IOCONB, &vregister)) { 00237 return; 00238 } 00239 if (isBitSet(vregister, 1)) { 00240 _intB->rise(p_tptr, p_mptr); 00241 } else { 00242 _intB->fall(p_tptr, p_mptr); 00243 } 00244 } 00245 00246 void CMCP23017_I2C::setupInterrupts(const unsigned char p_mirroring, const unsigned char p_openDrain, const unsigned char p_polarity) { 00247 DEBUG_ENTER("CMCP23017_I2C::setupInterrupts: %02x, %02x, %02x", p_mirroring, p_openDrain, p_polarity) 00248 00249 // Setup IOCONA 00250 unsigned char vregister; 00251 if (!readRegister(INTCONA, &vregister)) { 00252 return; 00253 } 00254 // Setup INTCON - REGISTER 1-5: INTCON – INTERRUPT-ON-CHANGE CONTROL REGISTER 00255 vregister = setBit(vregister, 6, p_mirroring); 00256 vregister = setBit(vregister, 2, p_openDrain); 00257 vregister = setBit(vregister, 1, p_polarity); 00258 writeRegister(INTCONA, vregister); 00259 00260 // Setup IOCONB 00261 if (!readRegister(INTCONB, &vregister)) { 00262 return; 00263 } 00264 // Setup INTCON - REGISTER 1-5: INTCON – INTERRUPT-ON-CHANGE CONTROL REGISTER 00265 vregister = setBit(vregister, 6, p_mirroring); 00266 vregister = setBit(vregister, 2, p_openDrain); 00267 vregister = setBit(vregister, 1, p_polarity); 00268 writeRegister(INTCONB, vregister); 00269 00270 } 00271 00272 int CMCP23017_I2C::setupInterruptPin(const unsigned char p_gpioId, const InterruptModes p_mode) { 00273 DEBUG_ENTER("CMCP23017_I2C::setupInterruptPin: %02x, %02x", p_gpioId, p_mode) 00274 00275 // Retrieve the register address 00276 unsigned char gpioIntconId, gpioDefvalId, gpioGpintenId; 00277 if (!registerIdFromGpioId(p_gpioId, &gpioIntconId)) { 00278 // DEBUG_LEAVE("CMCP23017_I2C::setupInterruptPin: -1") 00279 return -1; 00280 } 00281 unsigned char gpioFlags; 00282 if (gpioIntconId == GPIOA) { 00283 gpioIntconId = INTCONA; 00284 gpioDefvalId = DEFVALA; 00285 gpioGpintenId = GPINTENA; 00286 gpioFlags = _gpioAFlags; 00287 } else { 00288 gpioIntconId = INTCONB; 00289 gpioDefvalId = DEFVALB; 00290 gpioGpintenId = GPINTENB; 00291 gpioFlags = _gpioBFlags; 00292 } 00293 DEBUG("CMCP23017_I2C::setupInterruptPin: gpioIntconId=%02x gpioDefvalId=%02x gpioGpintenId=%02x gpioFlags=%02x", gpioIntconId, gpioDefvalId, gpioGpintenId, gpioFlags) 00294 00295 // Retrieve the GPIO pin number 00296 unsigned char gpioBit = gpioBitFromGpioId(p_gpioId); 00297 DEBUG("CMCP23017_I2C::setupInterruptPin: gpioBit=%02x", gpioBit) 00298 if (!isBitEqual(gpioFlags, gpioBit, 0x01)) { // Port pin is not configure as input 00299 // DEBUG_LEAVE("CMCP23017_I2C::setupPullPin: -1") 00300 return -1; 00301 } 00302 // Read it 00303 unsigned char gpioIntconValue, gpioDefvalValue, gpioGpintenValue; 00304 if (!readRegister(gpioIntconId, &gpioIntconValue)) { 00305 // DEBUG_LEAVE("CMCP23017_I2C::setupInterruptPin: -2") 00306 return -2; 00307 } 00308 if (!readRegister(gpioDefvalId, &gpioDefvalValue)) { 00309 // DEBUG_LEAVE("CMCP23017_I2C::setupInterruptPin: -2") 00310 return -2; 00311 } 00312 if (!readRegister(gpioGpintenId, &gpioGpintenValue)) { 00313 // DEBUG_LEAVE("CMCP23017_I2C::setupInterruptPin: -2") 00314 return -2; 00315 } 00316 DEBUG("CMCP23017_I2C::setupInterruptPin: gpioIntconValue=%02x gpioDefvalValue=%02x gpioGpintenValue=%02x", gpioIntconValue, gpioDefvalValue, gpioGpintenValue) 00317 00318 // 00319 switch (static_cast<unsigned char>(p_mode)) { 00320 case static_cast<unsigned char>(OnChange): 00321 gpioIntconValue = setBit(gpioIntconValue, gpioBit, 0x00); 00322 gpioDefvalValue = setBit(gpioDefvalValue, gpioBit, 0x00); 00323 break; 00324 case static_cast<unsigned char>(OnRising): 00325 gpioIntconValue = setBit(gpioIntconValue, gpioBit, 0x01); 00326 gpioDefvalValue = setBit(gpioDefvalValue, gpioBit, 0x00); 00327 break; 00328 case static_cast<unsigned char>(OnFalling): 00329 gpioIntconValue = setBit(gpioIntconValue, gpioBit, 0x01); 00330 gpioDefvalValue = setBit(gpioDefvalValue, gpioBit, 0x01); 00331 break; 00332 } // End of 'switch' statement 00333 00334 // Enable interrupt 00335 gpioGpintenValue = setBit(gpioGpintenValue, gpioBit, 0x01); 00336 00337 // Write register 00338 DEBUG("CMCP23017_I2C::setupInterruptPin: gpioIntconValue=%02x gpioDefvalValue=%02x gpioGpintenValue=%02x", gpioIntconValue, gpioDefvalValue, gpioGpintenValue) 00339 writeRegister(gpioDefvalId, gpioDefvalValue); 00340 writeRegister(gpioIntconId, gpioIntconValue); 00341 writeRegister(gpioGpintenId, gpioGpintenValue); 00342 00343 // DEBUG_LEAVE("CMCP23017_I2C::setupInterruptPin: 0") 00344 return 0; 00345 } 00346 00347 int CMCP23017_I2C::setupPullPin(const unsigned char p_gpioId, const PullModes p_mode) { 00348 // DEBUG_ENTER("CMCP23017_I2C::setupPullPin: %02x, %02x", p_gpioId, p_mode) 00349 00350 // Retrieve the register address 00351 unsigned char gpioGppuId; 00352 if (!registerIdFromGpioId(p_gpioId, &gpioGppuId)) { 00353 // DEBUG_LEAVE("CMCP23017_I2C::setupPullPin: -1") 00354 return -1; 00355 } 00356 unsigned char gpioFlags; 00357 if (gpioGppuId == GPIOA) { 00358 gpioGppuId = GPPUA; 00359 gpioFlags = _gpioAFlags; 00360 } else { 00361 gpioGppuId = GPPUB; 00362 gpioFlags = _gpioBFlags; 00363 } 00364 // DEBUG("CMCP23017_I2C::setupPullPin: gpioGppuId=%02x gpioFlags=%02x", gpioGppuId, gpioFlags) 00365 00366 // Retrieve the GPIO pin number 00367 unsigned char gpioBit = gpioBitFromGpioId(p_gpioId); 00368 // DEBUG("CMCP23017_I2C::setupPullPin: gpioBit=%02x", gpioBit) 00369 if (!isBitEqual(gpioFlags, gpioBit, 0x01)) { // Port pin is not configure as input 00370 // DEBUG_LEAVE("CMCP23017_I2C::setupPullPin: -1") 00371 return -1; 00372 } 00373 00374 // Read it 00375 unsigned char gpioGppuValue; 00376 if (!readRegister(gpioGppuId, &gpioGppuValue)) { 00377 // DEBUG_LEAVE("CMCP23017_I2C::setupPullPin: -2") 00378 return -2; 00379 } 00380 // DEBUG("CMCP23017_I2C::setupPullPin: gpioGppuId=%02x", gpioGppuId) 00381 00382 // 00383 switch (static_cast<unsigned char>(p_mode)) { 00384 case static_cast<unsigned char>(AbstractGpioExpender::PullOff): 00385 gpioGppuValue = setBit(gpioGppuValue, gpioBit, 0x00); 00386 break; 00387 case static_cast<unsigned char>(AbstractGpioExpender::PullUp): 00388 gpioGppuValue = setBit(gpioGppuValue, gpioBit, 0x01); 00389 break; 00390 case static_cast<unsigned char>(AbstractGpioExpender::PullDown): 00391 // Not supporte, nothing to do 00392 break; 00393 } // End of 'switch' statement 00394 00395 // Write register 00396 // DEBUG("CMCP23017_I2C::setupPullPin: gpioGppuValue=%02x", gpioGppuValue) 00397 writeRegister(gpioGppuId, gpioGppuValue); 00398 00399 00400 // DEBUG_LEAVE("CMCP23017_I2C::setupPullPin: 0") 00401 return 0; 00402 } 00403 00404 int CMCP23017_I2C::getLastInterruptPinAndValue(unsigned char * p_gpioId, unsigned char * p_value) { 00405 // DEBUG_ENTER("CMCP23017_I2C::getLastInterruptPinAndValue") 00406 00407 // Read first INTFA if required 00408 unsigned char vregister; 00409 if (_gpioAFlags != 0x00) { 00410 if (!readRegister(INTFA, &vregister)) { 00411 // DEBUG_LEAVE("CMCP23017_I2C::setupInterruptPin: -1") 00412 return -1; 00413 } 00414 vregister &= _gpioAFlags; // Cannot have interrupt on output port 00415 for (unsigned char bit = 0; bit < GPIO_SIZE; bit++) { 00416 if (isBitSet(vregister, bit)) { 00417 *p_gpioId = bit; 00418 readRegister(INTCAPA, p_value); 00419 *p_value = (*p_value >> bit) & 0x01; 00420 00421 // DEBUG_LEAVE("CMCP23017_I2C::getLastInterruptPinAndValue (A): %02x %02x", *p_gpioId, *p_value) 00422 return 0; 00423 } 00424 } // End of 'for' statement 00425 } 00426 00427 // If not interrupt on GPIOA, try with GPIOB 00428 if (_gpioBFlags != 0x00) { 00429 if (!readRegister(INTFB, &vregister)) { 00430 // DEBUG_LEAVE("CMCP23017_I2C::setupInterruptPin: -2") 00431 return -2; 00432 } 00433 vregister &= _gpioBFlags; // Cannot have interrupt on output port 00434 for (unsigned char bit = 0; bit < GPIO_SIZE; bit++) { 00435 if (isBitSet(vregister, bit)) { 00436 *p_gpioId = bit + GPIO_SIZE; 00437 readRegister(INTCAPB, p_value); 00438 *p_value = (*p_value >> bit) & 0x01; 00439 00440 // DEBUG_LEAVE("CMCP23017_I2C::getLastInterruptPinAndValue (B): %02x %02x", *p_gpioId, *p_value) 00441 return 0; 00442 } 00443 } // End of 'for' statement 00444 } 00445 00446 // DEBUG_LEAVE("CMCP23017_I2C::getLastInterruptPinAndValue: 0") 00447 return 0; 00448 } 00449 00450 int CMCP23017_I2C::read(const unsigned char p_gpioId, unsigned char * p_value) { 00451 // DEBUG_ENTER("CMCP23017_I2C::read: 0x%02x", p_gpioId) 00452 00453 // Retrieve the register address 00454 unsigned char gpioRegisterId; 00455 if (!registerIdFromGpioId(p_gpioId, &gpioRegisterId)) { 00456 // DEBUG_LEAVE("CMCP23017_I2C::read: -1") 00457 return -1; 00458 } 00459 // DEBUG("CMCP23017_I2C::read: gpioRegisterId=%02x", gpioRegisterId) 00460 unsigned char gpioBit = gpioBitFromGpioId(p_gpioId); 00461 // DEBUG("CMCP23017_I2C::read: gpioBit=%02x", gpioBit) 00462 00463 // Read it 00464 unsigned char gpioRegisterValue; 00465 if (!readRegister(gpioRegisterId, &gpioRegisterValue)) { 00466 // DEBUG_LEAVE("CMCP23017_I2C::read: -2") 00467 return -2; 00468 } 00469 // DEBUG("CMCP23017_I2C::read: gpioRegisterValue=%02x", gpioRegisterValue) 00470 00471 *p_value = (isBitSet(gpioRegisterValue, gpioBit)) ? 0x01 : 0x00; 00472 // DEBUG("CMCP23017_I2C::read: p_value=%02x", *p_value) 00473 00474 // DEBUG_LEAVE("CMCP23017_I2C::read: 0") 00475 return 0; 00476 } 00477 00478 bool CMCP23017_I2C::registerIdFromGpioId(const unsigned char p_gpioId, unsigned char * p_gpioRegisterId) { 00479 // DEBUG_ENTER("CMCP23017_I2C::registerIdFromGpioId: 0x%02x", p_gpioId) 00480 00481 // Sanity check 00482 if (p_gpioId > GPIO_MAX) { 00483 // DEBUG_ENTER("CMCP23017_I2C::registerIdFromGpioId: false") 00484 return false; 00485 } 00486 00487 *p_gpioRegisterId = (p_gpioId < GPIO_MED) ? GPIOA : GPIOB; 00488 00489 // DEBUG_ENTER("CMCP23017_I2C::registerIdFromGpioId: true") 00490 return true; 00491 } 00492 00493 int CMCP23017_I2C::write(const unsigned char p_gpioId, const unsigned char p_value) { 00494 // DEBUG_ENTER("CMCP23017_I2C::write: 0x%02x 0x%02x", p_gpioId, p_value) 00495 00496 // Retrieve the register address 00497 unsigned char gpioRegisterId; 00498 if (!registerIdFromGpioId(p_gpioId, &gpioRegisterId)) { 00499 // DEBUG_LEAVE("CMCP23017_I2C::write: -1") 00500 return -1; 00501 } 00502 // DEBUG("CMCP23017_I2C::write: gpioRegisterId=%02x", gpioRegisterId) 00503 00504 // Retrieve the GPIO pin number 00505 unsigned char gpioBit = gpioBitFromGpioId(p_gpioId); 00506 // DEBUG("CMCP23017_I2C::write: gpioBit=%02x", gpioBit) 00507 00508 // Read it 00509 unsigned char gpioRegisterValue; 00510 if (!readRegister(gpioRegisterId, &gpioRegisterValue)) { 00511 // DEBUG_LEAVE("CMCP23017_I2C::write: -2") 00512 return -2; 00513 } 00514 // DEBUG("CMCP23017_I2C::write: gpioRegisterValue=%02x", gpioRegisterValue) 00515 00516 // Update GPIO bit 00517 if (!isBitEqual(gpioRegisterValue, gpioBit, p_value)) { 00518 // Write it if required 00519 gpioRegisterValue = setBit(gpioRegisterValue, gpioBit, p_value); 00520 // DEBUG("CMCP23017_I2C::write: New gpioRegisterValue=%02x", gpioRegisterValue) 00521 if (!writeRegister(gpioRegisterId, gpioRegisterValue)) { 00522 // DEBUG_LEAVE("CMCP23017_I2C::write: -3") 00523 return -3; 00524 } 00525 } 00526 00527 // DEBUG_LEAVE("CMCP23017_I2C::write: 0") 00528 return 0; 00529 } 00530 00531 unsigned char CMCP23017_I2C::createBus(const std::list<unsigned char> p_lines, const PinMode p_mode) { 00532 unsigned char busId = _busesIndex++; 00533 00534 _buses.insert(_buses.end(), std::pair<unsigned char, std::list<unsigned char> >(busId, p_lines)); 00535 00536 return busId; 00537 } 00538 00539 void CMCP23017_I2C::deleteBus(const unsigned char p_busId) { 00540 // Sanity check 00541 std::map<unsigned char, std::list<unsigned char> >::iterator result = _buses.find(p_busId); 00542 if (result == _buses.end()) { // Invalid bus identifier 00543 return; 00544 } 00545 00546 _buses.erase(p_busId); 00547 } 00548 00549 int CMCP23017_I2C::busRead(const unsigned char p_busId, unsigned short * p_value) { 00550 // DEBUG_ENTER("CMCP23017_I2C::busRead: 0x%02x", p_busId) 00551 00552 // Sanity checks 00553 if (_buses.size() == 0) { 00554 // DEBUG_LEAVE("CMCP23017_I2C::busRead: -1") 00555 return -1; 00556 } 00557 std::map<unsigned char, std::list<unsigned char> >::iterator result = _buses.find(p_busId); 00558 if (result == _buses.end()) { // Invalid bus identifier 00559 // DEBUG_LEAVE("CMCP23017_I2C::busRead: -1") 00560 return -1; 00561 } 00562 00563 std::list<unsigned char>::reverse_iterator rit; 00564 for (std::list<unsigned char>::reverse_iterator rit = result->second.rbegin(); rit != result->second.rend(); ++rit) { 00565 unsigned char regvalue; 00566 if (read(*rit, ®value) == 0) { 00567 *p_value = (*p_value | regvalue) << 1; 00568 } else { 00569 *p_value <<= 1; 00570 } 00571 } // End of 'for' statement 00572 00573 // DEBUG_LEAVE("CMCP23017_I2C::busRead: 0") 00574 return 0; 00575 } 00576 00577 int CMCP23017_I2C::busWrite(const unsigned char p_busId, const unsigned short p_value) { 00578 // DEBUG_ENTER("CMCP23017_I2C::busWrite: 0x%02x - 0x%02x", p_busId, p_value) 00579 00580 // Sanity checks 00581 if (_buses.size() == 0) { 00582 return -1; 00583 } 00584 std::map<unsigned char, std::list<unsigned char> >::iterator result = _buses.find(p_busId); 00585 if (result == _buses.end()) { // Invalid bus identifier 00586 // DEBUG_LEAVE("CMCP23017_I2C::busWrite: -1") 00587 return -1; 00588 } 00589 00590 std::list<unsigned char>::reverse_iterator rit; 00591 unsigned short value = p_value; 00592 for (std::list<unsigned char>::reverse_iterator rit = result->second.rbegin(); rit != result->second.rend(); ++rit) { 00593 write(*rit, value & 0x01); 00594 value >>= 1; 00595 } // End of 'for' statement 00596 00597 // DEBUG_LEAVE("CMCP23017_I2C::busWrite: 0") 00598 return 0; 00599 } 00600 00601 bool CMCP23017_I2C::writeRegister(const unsigned char p_registerId, const unsigned char p_value) { 00602 // DEBUG_ENTER("CMCP23017_I2C::writeRegister: Memory address: 0x%02x - 0x%02x", p_registerId, p_value) 00603 00604 // 1.Prepare buffer 00605 char i2cBuffer[2]; // Register address + one byte of data 00606 // 1.1. Memory address 00607 i2cBuffer[0] = p_registerId; 00608 // 1.2. Datas 00609 i2cBuffer[1] = p_value; 00610 // DEBUG("CMCP23017_I2C::writeRegister: Data=0x%02x 0x%02x", i2cBuffer[0], i2cBuffer[1]) 00611 00612 // 2. Send I2C start + I2C address + Memory Address + Datas + I2C stop 00613 int result = _i2cInstance->write(_slaveAddress, i2cBuffer, 2); 00614 // wait(0.02); 00615 00616 // DEBUG_LEAVE("CMCP23017_I2C::writeRegister %x", (bool)(result == 0)) 00617 return (bool)(result == 0); 00618 } 00619 00620 bool CMCP23017_I2C::readRegister(const unsigned char p_registerId, unsigned char * p_value) { 00621 // DEBUG_ENTER("CMCP23017_I2C::readRegister: Memory address: 0x%02x", p_registerId) 00622 00623 // 1.Prepare buffer 00624 char i2cBuffer[1]; // Register address + one byte of data 00625 // 1.1. Memory address 00626 i2cBuffer[0] = p_registerId; 00627 // DEBUG("CMCP23017_I2C::readRegister: Data=0x%02x", i2cBuffer[0]) 00628 00629 // 2. Send I2C start + memory address 00630 if (_i2cInstance->write(_slaveAddress, i2cBuffer, 1, true) == 0) { 00631 // wait(0.02); 00632 // DEBUG("CMCP23017_I2C::readRegister: Write memory done") 00633 // 2. Read data + I2C stop 00634 int result = _i2cInstance->read(_slaveAddress, (char *)p_value, 1); 00635 // wait(0.02); 00636 00637 // DEBUG_LEAVE("C24LCXX_I2C::readRegister (byte): %x", (bool)(result == 0)) 00638 return (bool)(result == 0); 00639 } 00640 00641 // DEBUG_LEAVE("CMCP23017_I2C::readRegister false") 00642 return false; 00643 } 00644 00645 void CMCP23017_I2C::DumpRegisters() { 00646 00647 unsigned char value; 00648 for (unsigned int registerId = 0; registerId < 0x16; registerId++) { 00649 readRegister(registerId, &value); 00650 // DEBUG("CMCP23017_I2C::DumpRegisters: register[%d] = 0x%02x", registerId, value) 00651 } 00652 } 00653 00654 void CMCP23017_I2C::DumpRegister(unsigned int p_registerId) { 00655 00656 unsigned char value; 00657 readRegister(p_registerId, &value); 00658 // DEBUG("CMCP23017_I2C::DumpRegister: register[%d] = 0x%02x", p_registerId, value) 00659 } 00660 00661 } // End of namespace MCP23017_I2C
Generated on Tue Jul 12 2022 15:16:48 by 1.7.2