This library provides simplified I2C access to a Microchip MCP23x17 GPIO expender device, including a general interface for any GPIO expender
MCP23017_I2C.cpp
- Committer:
- Yann
- Date:
- 2015-01-13
- Revision:
- 2:3bea48e1505c
- Parent:
- 1:ec9e770173d5
- Child:
- 3:b902729a1675
File content as of revision 2:3bea48e1505c:
/* mbed simplified access to Microchip MCP23x17 GPIO expender devices (I2C)
* Copyright (c) 2010-2012 ygarcia, MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
* and associated documentation files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial pinions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <iostream>
#include <sstream>
#include "MCP23017_I2C.h"
#define IODIRA 0x00
#define IODIRB 0x01
#define IPOLA 0x02
#define IPOLB 0x03
#define GPINTENA 0x04
#define GPINTENB 0x05
#define DEFVALA 0x06
#define DEFVALB 0x07
#define INTCONA 0x08
#define INTCONB 0x09
#define IOCONA 0x0a
#define IOCONB 0x0b
#define GPPUA 0x0c
#define GPPUB 0x0d
#define INTFA 0x0e
#define INTFB 0x0f
#define INTCAPA 0x10
#define INTCAPB 0x11
#define GPIOA 0x12
#define GPIOB 0x13
#define OLATA 0x14
#define OLATB 0x15
namespace MCP23017_I2C {
unsigned char CMCP23017_I2C::I2CModuleRefCounter = 0;
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("") {
DEBUG_ENTER("CMCP23017_I2C")
if (CMCP23017_I2C::I2CModuleRefCounter != 0) {
error("CMCP23017_I2C: Wrong params");
}
#ifdef __DEBUG
std::ostringstream out(std::ostringstream::out);
out << "CMCP23017_I2C #" << CMCP23017_I2C::I2CModuleRefCounter;
_internalId.assign(out.str());
DEBUG("CMCP23017_I2C: _internalId='%s'", _internalId.c_str())
#endif // __DEBUG
_i2cInstance = new I2C(p_sda, p_scl);
CMCP23017_I2C::I2CModuleRefCounter += 1;
DEBUG_ENTER("CMCP23017_I2C: refCounter=%d", CMCP23017_I2C::I2CModuleRefCounter)
_slaveAddress = (p_address << 1) | 0x40; // Slave address format is: 0 0 1 0 A3 A2 A1 R/W
DEBUG("CMCP23017_I2C: I2C slave adress: 0x%02x", _slaveAddress)
_i2cInstance->frequency(p_frequency); // Set the frequency of the I2C interface
if (p_intA != NC) {
DEBUG("CMCP23017_I2C: INTA managed");
_intA = new InterruptIn(p_intA);
if (p_internalPullUp) _intA->mode(::PullDown);
_intA->enable_irq(); // Enable interrupt
} else {
DEBUG("CMCP23017_I2C: INTA not managed");
_intA = NULL; // Not used
}
if (p_intB != NC) {
DEBUG("CMCP23017_I2C: INTB managed");
_intB = new InterruptIn(p_intB);
if (p_internalPullUp) _intB->mode(::PullDown);
_intB->enable_irq(); // Enable interrupt
} else {
DEBUG("CMCP23017_I2C: INTB not managed");
_intB = NULL; // Not used
}
if (p_reset != NC) {
DEBUG("CMCP23017_I2C: RESET managed");
_reset = new DigitalOut(p_reset);
_reset->write(1); // Disable reset
} else {
DEBUG("CMCP23017_I2C: RESET not managed");
_reset = NULL; // Not used
}
DEBUG_LEAVE("CMCP23017_I2C")
}
CMCP23017_I2C::~CMCP23017_I2C() {
DEBUG_ENTER("~CMCP23017_I2C")
// Release I2C instance
DEBUG_ENTER("~CMCP23017_I2C: refCounter=%d", CMCP23017_I2C::I2CModuleRefCounter)
CMCP23017_I2C::I2CModuleRefCounter -= 1;
if (CMCP23017_I2C::I2CModuleRefCounter == 0) {
delete _i2cInstance;
_i2cInstance = NULL;
}
// Release _wp if required
if (_intA != NULL) {
delete _intA;
}
if (_intB != NULL) {
delete _intB;
}
if (_reset != NULL) {
delete _reset;
}
DEBUG_LEAVE("~CMCP23017_I2C")
}
bool CMCP23017_I2C::Initialize(const unsigned char p_gpioAFlags, const unsigned char p_gpioBFlags) {
// Configure default behavior
_gpioAFlags = p_gpioAFlags;
_gpioBFlags = p_gpioBFlags;
configure(_gpioAFlags, _gpioBFlags);
return true;
}
void CMCP23017_I2C::configure(const unsigned char p_gpioAFlags, const unsigned char p_gpioBFlags) { // TODO Optimization with sequential access
// DEBUG_ENTER("CMCP23017_I2C::configure: 0x%02x 0x%02x", p_gpioAFlags, p_gpioBFlags)
// Setup IOCON - See REGISTER 1-6: IOCON – I/O EXPANDER CONFIGURATION REGISTER
writeRegister(IOCONA, 0x10); // Sequential operation disabled
writeRegister(IOCONB, 0x10); // Sequential operation disabled
// Setup IODIR - See REGISTER 1-1: IODIR – I/O DIRECTION REGISTER (ADDR 0x00)
writeRegister(IODIRA, p_gpioAFlags);
writeRegister(IODIRB, p_gpioBFlags);
// Setup IPOL - See REGISTER 1-2: IPOL – INPUT POLARITY PORT REGISTER
writeRegister(IPOLA, 0x00); // GPIO register bit will reflect the same logic state of the input pin
writeRegister(IPOLB, 0x00);
// Setup GPPU - See REGISTER 1-7: GPPU – GPIO PULL-UP RESISTOR REGISTER
writeRegister(GPPUA, 0x00);
writeRegister(GPPUB, 0x00);
// Setup interrupt
if (_intA != NULL) {
DEBUG("CMCP23017_I2C::configure: Setup INTA")
// Setup GPINTEN - See GPINTEN – INTERRUPT-ON-CHANGE PINS
writeRegister(GPINTENA, 0x00); // Disable GPIO interrupt-on-change events
// Setup DEFVAL - See REGISTER 1-4: DEFVAL – DEFAULT VALUE REGISTER
writeRegister(DEFVALA, 0x00); // Pin level change from 0 to 1 raises an interrupt
// Setup INTCON - REGISTER 1-5: INTCON – INTERRUPT-ON-CHANGE CONTROL REGISTER
writeRegister(INTCONA, 0xff); // Pin level change from 0 to 1 raises an interrupt
}
if (_intB != NULL) {
DEBUG("CMCP23017_I2C::configure: Setup INTB")
// Setup GPINTEN - See GPINTEN – INTERRUPT-ON-CHANGE PINS
writeRegister(GPINTENB, 0x00); // Disable GPIO interrupt-on-change events
// Setup DEFVAL - See REGISTER 1-4: DEFVAL – DEFAULT VALUE REGISTER
writeRegister(DEFVALB, 0x00); // Pin level change from 0 to 1 raises an interrupt
// Setup INTCON - REGISTER 1-5: INTCON – INTERRUPT-ON-CHANGE CONTROL REGISTER
writeRegister(INTCONB, 0xff); // Pin level change from 0 to 1 raises an interrupt
}
// DumpRegisters();
// DEBUG_LEAVE("CMCP23017_I2C::configure")
}
void CMCP23017_I2C::reset() {
// DEBUG_ENTER("CMCP23017_I2C::reset")
if (_reset != NULL) {
_reset->write(0);
wait_us(1);
_reset->write(1);
wait_us(1);
if ((_gpioAFlags != 0x00) || (_gpioBFlags != 0x00)) { // Apply configuration
configure(_gpioAFlags, _gpioBFlags);
} // else, POR reset values, see DS21952B-page 10 Clause 1.6 Configuration and Control Registers
}
// DEBUG_LEAVE("CMCP23017_I2C::reset")
}
void CMCP23017_I2C::setIntrACallback(void (* p_fptr)(void)) {
if (_intA != NULL) {
unsigned char vregister;
if (!readRegister(IOCONA, &vregister)) {
return;
}
if (isBitSet(vregister, 1)) {
_intA->rise(p_fptr);
} else {
_intA->fall(p_fptr);
}
}
}
void CMCP23017_I2C::setIntrBCallback(void (* p_fptr)(void)) {
if (_intB != NULL) {
unsigned char vregister;
if (!readRegister(IOCONB, &vregister)) {
return;
}
if (isBitSet(vregister, 1)) {
_intB->rise(p_fptr);
} else {
_intB->fall(p_fptr);
}
}
}
template<typename T>
void CMCP23017_I2C::setIntrACallback (const T * p_tptr, void(T::* p_mptr)(void)) {
if (_intA != NULL) {
unsigned char vregister;
if (!readRegister(IOCONA, &vregister)) {
return;
}
if (isBitSet(vregister, 1)) {
_intA->rise(p_tptr, p_mptr);
} else {
_intA->fall(p_tptr, p_mptr);
}
}
}
template<typename T>
void CMCP23017_I2C::setIntrBCallback (const T * p_tptr, void(T::* p_mptr)(void)) {
unsigned char vregister;
if (!readRegister(IOCONB, &vregister)) {
return;
}
if (isBitSet(vregister, 1)) {
_intB->rise(p_tptr, p_mptr);
} else {
_intB->fall(p_tptr, p_mptr);
}
}
void CMCP23017_I2C::setupInterrupts(const unsigned char p_mirroring, const unsigned char p_openDrain, const unsigned char p_polarity) {
DEBUG_ENTER("CMCP23017_I2C::setupInterrupts: %02x, %02x, %02x", p_mirroring, p_openDrain, p_polarity)
// Setup IOCONA
unsigned char vregister;
if (!readRegister(INTCONA, &vregister)) {
return;
}
// Setup INTCON - REGISTER 1-5: INTCON – INTERRUPT-ON-CHANGE CONTROL REGISTER
vregister = setBit(vregister, 6, p_mirroring);
vregister = setBit(vregister, 2, p_openDrain);
vregister = setBit(vregister, 1, p_polarity);
writeRegister(INTCONA, vregister);
// Setup IOCONB
if (!readRegister(INTCONB, &vregister)) {
return;
}
// Setup INTCON - REGISTER 1-5: INTCON – INTERRUPT-ON-CHANGE CONTROL REGISTER
vregister = setBit(vregister, 6, p_mirroring);
vregister = setBit(vregister, 2, p_openDrain);
vregister = setBit(vregister, 1, p_polarity);
writeRegister(INTCONB, vregister);
}
int CMCP23017_I2C::setupInterruptPin(const unsigned char p_gpioId, const InterruptModes p_mode) {
DEBUG_ENTER("CMCP23017_I2C::setupInterruptPin: %02x, %02x", p_gpioId, p_mode)
// Retrieve the register address
unsigned char gpioIntconId, gpioDefvalId, gpioGpintenId;
if (!registerIdFromGpioId(p_gpioId, &gpioIntconId)) {
DEBUG_LEAVE("CMCP23017_I2C::setupInterruptPin: -1")
return -1;
}
unsigned char gpioFlags;
if (gpioIntconId == GPIOA) {
gpioIntconId = INTCONA;
gpioDefvalId = DEFVALA;
gpioGpintenId = GPINTENA;
gpioFlags = _gpioAFlags;
} else {
gpioIntconId = INTCONB;
gpioDefvalId = DEFVALB;
gpioGpintenId = GPINTENB;
gpioFlags = _gpioBFlags;
}
DEBUG("CMCP23017_I2C::setupInterruptPin: gpioIntconId=%02x gpioDefvalId=%02x gpioGpintenId=%02x gpioFlags=%02x", gpioIntconId, gpioDefvalId, gpioGpintenId, gpioFlags)
// Retrieve the GPIO pin number
unsigned char gpioBit = gpioBitFromGpioId(p_gpioId);
DEBUG("CMCP23017_I2C::setupInterruptPin: gpioBit=%02x", gpioBit)
if (!isBitEqual(gpioFlags, gpioBit, 0x01)) { // Port pin is not configure as input
DEBUG_LEAVE("CMCP23017_I2C::setupPullPin: -1")
return -1;
}
// Read it
unsigned char gpioIntconValue, gpioDefvalValue, gpioGpintenValue;
if (!readRegister(gpioIntconId, &gpioIntconValue)) {
DEBUG_LEAVE("CMCP23017_I2C::setupInterruptPin: -2")
return -2;
}
if (!readRegister(gpioDefvalId, &gpioDefvalValue)) {
DEBUG_LEAVE("CMCP23017_I2C::setupInterruptPin: -2")
return -2;
}
if (!readRegister(gpioGpintenId, &gpioGpintenValue)) {
DEBUG_LEAVE("CMCP23017_I2C::setupInterruptPin: -2")
return -2;
}
DEBUG("CMCP23017_I2C::setupInterruptPin: gpioIntconValue=%02x gpioDefvalValue=%02x gpioGpintenValue=%02x", gpioIntconValue, gpioDefvalValue, gpioGpintenValue)
//
switch (static_cast<unsigned char>(p_mode)) {
case static_cast<unsigned char>(OnChange):
gpioIntconValue = setBit(gpioIntconValue, gpioBit, 0x00);
gpioDefvalValue = setBit(gpioDefvalValue, gpioBit, 0x00);
break;
case static_cast<unsigned char>(OnRising):
gpioIntconValue = setBit(gpioIntconValue, gpioBit, 0x01);
gpioDefvalValue = setBit(gpioDefvalValue, gpioBit, 0x00);
break;
case static_cast<unsigned char>(OnFalling):
gpioIntconValue = setBit(gpioIntconValue, gpioBit, 0x01);
gpioDefvalValue = setBit(gpioDefvalValue, gpioBit, 0x01);
break;
} // End of 'switch' statement
// Enable interrupt
gpioGpintenValue = setBit(gpioGpintenValue, gpioBit, 0x01);
// Write register
DEBUG("CMCP23017_I2C::setupInterruptPin: gpioIntconValue=%02x gpioDefvalValue=%02x gpioGpintenValue=%02x", gpioIntconValue, gpioDefvalValue, gpioGpintenValue)
writeRegister(gpioDefvalId, gpioDefvalValue);
writeRegister(gpioIntconId, gpioIntconValue);
writeRegister(gpioGpintenId, gpioGpintenValue);
DEBUG_LEAVE("CMCP23017_I2C::setupInterruptPin: 0")
return 0;
}
int CMCP23017_I2C::setupPullPin(const unsigned char p_gpioId, const PullModes p_mode) {
DEBUG_ENTER("CMCP23017_I2C::setupPullPin: %02x, %02x", p_gpioId, p_mode)
// Retrieve the register address
unsigned char gpioGppuId;
if (!registerIdFromGpioId(p_gpioId, &gpioGppuId)) {
DEBUG_LEAVE("CMCP23017_I2C::setupPullPin: -1")
return -1;
}
unsigned char gpioFlags;
if (gpioGppuId == GPIOA) {
gpioGppuId = GPPUA;
gpioFlags = _gpioAFlags;
} else {
gpioGppuId = GPPUB;
gpioFlags = _gpioBFlags;
}
DEBUG("CMCP23017_I2C::setupPullPin: gpioGppuId=%02x gpioFlags=%02x", gpioGppuId, gpioFlags)
// Retrieve the GPIO pin number
unsigned char gpioBit = gpioBitFromGpioId(p_gpioId);
DEBUG("CMCP23017_I2C::setupPullPin: gpioBit=%02x", gpioBit)
if (!isBitEqual(gpioFlags, gpioBit, 0x01)) { // Port pin is not configure as input
DEBUG_LEAVE("CMCP23017_I2C::setupPullPin: -1")
return -1;
}
// Read it
unsigned char gpioGppuValue;
if (!readRegister(gpioGppuId, &gpioGppuValue)) {
DEBUG_LEAVE("CMCP23017_I2C::setupPullPin: -2")
return -2;
}
DEBUG("CMCP23017_I2C::setupPullPin: gpioGppuId=%02x", gpioGppuId)
//
switch (static_cast<unsigned char>(p_mode)) {
case static_cast<unsigned char>(AbstractGpioExpender::PullOff):
gpioGppuValue = setBit(gpioGppuValue, gpioBit, 0x00);
break;
case static_cast<unsigned char>(AbstractGpioExpender::PullUp):
gpioGppuValue = setBit(gpioGppuValue, gpioBit, 0x01);
break;
case static_cast<unsigned char>(AbstractGpioExpender::PullDown):
// Not supporte, nothing to do
break;
} // End of 'switch' statement
// Write register
DEBUG("CMCP23017_I2C::setupPullPin: gpioGppuValue=%02x", gpioGppuValue)
writeRegister(gpioGppuId, gpioGppuValue);
DEBUG_LEAVE("CMCP23017_I2C::setupPullPin: 0")
return 0;
}
int CMCP23017_I2C::getLastInterruptPinAndValue(unsigned char * p_gpioId, unsigned char * p_value) {
DEBUG_ENTER("CMCP23017_I2C::getLastInterruptPinAndValue")
// Read first INTFA if required
unsigned char vregister;
if (_gpioAFlags != 0x00) {
if (!readRegister(INTFA, &vregister)) {
DEBUG_LEAVE("CMCP23017_I2C::setupInterruptPin: -1")
return -1;
}
vregister &= _gpioAFlags; // Cannot have interrupt on output port
for (unsigned char bit = 0; bit < GPIO_SIZE; bit++) {
if (isBitSet(vregister, bit)) {
*p_gpioId = bit;
readRegister(INTCAPA, p_value);
*p_value = (*p_value >> bit) & 0x01;
DEBUG_LEAVE("CMCP23017_I2C::getLastInterruptPinAndValue (A): %02x %02x", *p_gpioId, *p_value)
return 0;
}
} // End of 'for' statement
}
// If not interrupt on GPIOA, try with GPIOB
if (_gpioBFlags != 0x00) {
if (!readRegister(INTFB, &vregister)) {
DEBUG_LEAVE("CMCP23017_I2C::setupInterruptPin: -2")
return -2;
}
vregister &= _gpioBFlags; // Cannot have interrupt on output port
for (unsigned char bit = 0; bit < GPIO_SIZE; bit++) {
if (isBitSet(vregister, bit)) {
*p_gpioId = bit + GPIO_SIZE;
readRegister(INTCAPB, p_value);
*p_value = (*p_value >> bit) & 0x01;
DEBUG_LEAVE("CMCP23017_I2C::getLastInterruptPinAndValue (B): %02x %02x", *p_gpioId, *p_value)
return 0;
}
} // End of 'for' statement
}
DEBUG_LEAVE("CMCP23017_I2C::getLastInterruptPinAndValue: 0")
return 0;
}
int CMCP23017_I2C::read(const unsigned char p_gpioId, unsigned char * p_value) {
DEBUG_ENTER("CMCP23017_I2C::read: 0x%02x", p_gpioId)
// Retrieve the register address
unsigned char gpioRegisterId;
if (!registerIdFromGpioId(p_gpioId, &gpioRegisterId)) {
DEBUG_LEAVE("CMCP23017_I2C::read: -1")
return -1;
}
DEBUG("CMCP23017_I2C::read: gpioRegisterId=%02x", gpioRegisterId)
unsigned char gpioBit = gpioBitFromGpioId(p_gpioId);
DEBUG("CMCP23017_I2C::read: gpioBit=%02x", gpioBit)
// Read it
unsigned char gpioRegisterValue;
if (!readRegister(gpioRegisterId, &gpioRegisterValue)) {
DEBUG_LEAVE("CMCP23017_I2C::read: -2")
return -2;
}
DEBUG("CMCP23017_I2C::read: gpioRegisterValue=%02x", gpioRegisterValue)
*p_value = (isBitSet(gpioRegisterValue, gpioBit)) ? 0x01 : 0x00;
DEBUG("CMCP23017_I2C::read: p_value=%02x", *p_value)
DEBUG_LEAVE("CMCP23017_I2C::read: 0")
return 0;
}
bool CMCP23017_I2C::registerIdFromGpioId(const unsigned char p_gpioId, unsigned char * p_gpioRegisterId) {
DEBUG_ENTER("CMCP23017_I2C::registerIdFromGpioId: 0x%02x", p_gpioId)
// Sanity check
if (p_gpioId > GPIO_MAX) {
DEBUG_ENTER("CMCP23017_I2C::registerIdFromGpioId: false")
return false;
}
*p_gpioRegisterId = (p_gpioId < GPIO_MED) ? GPIOA : GPIOB;
DEBUG_ENTER("CMCP23017_I2C::registerIdFromGpioId: true")
return true;
}
int CMCP23017_I2C::write(const unsigned char p_gpioId, const unsigned char p_value) {
DEBUG_ENTER("CMCP23017_I2C::write: 0x%02x 0x%02x", p_gpioId, p_value)
// Retrieve the register address
unsigned char gpioRegisterId;
if (!registerIdFromGpioId(p_gpioId, &gpioRegisterId)) {
DEBUG_LEAVE("CMCP23017_I2C::write: -1")
return -1;
}
DEBUG("CMCP23017_I2C::write: gpioRegisterId=%02x", gpioRegisterId)
// Retrieve the GPIO pin number
unsigned char gpioBit = gpioBitFromGpioId(p_gpioId);
DEBUG("CMCP23017_I2C::write: gpioBit=%02x", gpioBit)
// Read it
unsigned char gpioRegisterValue;
if (!readRegister(gpioRegisterId, &gpioRegisterValue)) {
DEBUG_LEAVE("CMCP23017_I2C::write: -2")
return -2;
}
DEBUG("CMCP23017_I2C::write: gpioRegisterValue=%02x", gpioRegisterValue)
// Update GPIO bit
if (!isBitEqual(gpioRegisterValue, gpioBit, p_value)) {
// Write it if required
gpioRegisterValue = setBit(gpioRegisterValue, gpioBit, p_value);
DEBUG("CMCP23017_I2C::write: New gpioRegisterValue=%02x", gpioRegisterValue)
if (!writeRegister(gpioRegisterId, gpioRegisterValue)) {
DEBUG_LEAVE("CMCP23017_I2C::write: -3")
return -3;
}
}
DEBUG_LEAVE("CMCP23017_I2C::write: 0")
return 0;
}
unsigned char CMCP23017_I2C::createBus(const std::list<unsigned char> p_lines, const PinMode p_mode) {
unsigned char busId = _busesIndex++;
_buses.insert(_buses.end(), std::pair<unsigned char, std::list<unsigned char> >(busId, p_lines));
return busId;
}
void CMCP23017_I2C::deleteBus(const unsigned char p_busId) {
// Sanity check
std::map<unsigned char, std::list<unsigned char> >::iterator result = _buses.find(p_busId);
if (result == _buses.end()) { // Invalid bus identifier
return;
}
_buses.erase(p_busId);
}
int CMCP23017_I2C::busRead(const unsigned char p_busId, unsigned short * p_value) {
// DEBUG_ENTER("CMCP23017_I2C::busRead: 0x%02x", p_busId)
// Sanity checks
if (_buses.size() == 0) {
DEBUG_LEAVE("CMCP23017_I2C::busRead: -1")
return -1;
}
std::map<unsigned char, std::list<unsigned char> >::iterator result = _buses.find(p_busId);
if (result == _buses.end()) { // Invalid bus identifier
DEBUG_LEAVE("CMCP23017_I2C::busRead: -1")
return -1;
}
std::list<unsigned char>::reverse_iterator rit;
for (std::list<unsigned char>::reverse_iterator rit = result->second.rbegin(); rit != result->second.rend(); ++rit) {
unsigned char regvalue;
if (read(*rit, ®value) == 0) {
*p_value = (*p_value | regvalue) << 1;
} else {
*p_value <<= 1;
}
} // End of 'for' statement
// DEBUG_LEAVE("CMCP23017_I2C::busRead: 0")
return 0;
}
int CMCP23017_I2C::busWrite(const unsigned char p_busId, const unsigned short p_value) {
// DEBUG_ENTER("CMCP23017_I2C::busWrite: 0x%02x - 0x%02x", p_busId, p_value)
// Sanity checks
if (_buses.size() == 0) {
return -1;
}
std::map<unsigned char, std::list<unsigned char> >::iterator result = _buses.find(p_busId);
if (result == _buses.end()) { // Invalid bus identifier
DEBUG_LEAVE("CMCP23017_I2C::busWrite: -1")
return -1;
}
std::list<unsigned char>::reverse_iterator rit;
unsigned short value = p_value;
for (std::list<unsigned char>::reverse_iterator rit = result->second.rbegin(); rit != result->second.rend(); ++rit) {
write(*rit, value & 0x01);
value >>= 1;
} // End of 'for' statement
// DEBUG_LEAVE("CMCP23017_I2C::busWrite: 0")
return 0;
}
bool CMCP23017_I2C::writeRegister(const unsigned char p_registerId, const unsigned char p_value) {
// DEBUG_ENTER("CMCP23017_I2C::writeRegister: Memory address: 0x%02x - 0x%02x", p_registerId, p_value)
// 1.Prepare buffer
char i2cBuffer[2]; // Register address + one byte of data
// 1.1. Memory address
i2cBuffer[0] = p_registerId;
// 1.2. Datas
i2cBuffer[1] = p_value;
// DEBUG("CMCP23017_I2C::writeRegister: Data=0x%02x 0x%02x", i2cBuffer[0], i2cBuffer[1])
// 2. Send I2C start + I2C address + Memory Address + Datas + I2C stop
int result = _i2cInstance->write(_slaveAddress, i2cBuffer, 2);
// wait(0.02);
// DEBUG_LEAVE("CMCP23017_I2C::writeRegister %x", (bool)(result == 0))
return (bool)(result == 0);
}
bool CMCP23017_I2C::readRegister(const unsigned char p_registerId, unsigned char * p_value) {
// DEBUG_ENTER("CMCP23017_I2C::readRegister: Memory address: 0x%02x", p_registerId)
// 1.Prepare buffer
char i2cBuffer[1]; // Register address + one byte of data
// 1.1. Memory address
i2cBuffer[0] = p_registerId;
// DEBUG("CMCP23017_I2C::readRegister: Data=0x%02x", i2cBuffer[0])
// 2. Send I2C start + memory address
if (_i2cInstance->write(_slaveAddress, i2cBuffer, 1, true) == 0) {
// wait(0.02);
// DEBUG("CMCP23017_I2C::readRegister: Write memory done")
// 2. Read data + I2C stop
int result = _i2cInstance->read(_slaveAddress, (char *)p_value, 1);
// wait(0.02);
// DEBUG_LEAVE("C24LCXX_I2C::readRegister (byte): %x", (bool)(result == 0))
return (bool)(result == 0);
}
// DEBUG_LEAVE("CMCP23017_I2C::readRegister false")
return false;
}
void CMCP23017_I2C::DumpRegisters() {
unsigned char value;
for (unsigned int registerId = 0; registerId < 0x16; registerId++) {
readRegister(registerId, &value);
DEBUG("CMCP23017_I2C::DumpRegisters: register[%d] = 0x%02x", registerId, value)
}
}
void CMCP23017_I2C::DumpRegister(unsigned int p_registerId) {
unsigned char value;
readRegister(p_registerId, &value);
DEBUG("CMCP23017_I2C::DumpRegister: register[%d] = 0x%02x", p_registerId, value)
}
} // End of namespace MCP23017_I2C
Yann Garcia