Device driver for TCA9554A, which is I2C GPIO expander IC.

Dependents:   AKDP-RevD7_014

tca9554a.cpp

Committer:
coisme
Date:
2016-05-26
Revision:
2:0d772298e874
Parent:
0:402147fa55f6

File content as of revision 2:0d772298e874:

#include "tca9554a.h"

#define LEN_ONE_BYTE     1
#define LEN_TWO_BYTE     2

TCA9554A::TCA9554A(I2C *conn, SlaveAddress addr) {
    connection = conn;
    slaveAddress = addr;
}

TCA9554A::Status TCA9554A::read(RegisterAddress addr, uint8_t *buf) {
    char regAddr = (char)addr;
    
    // Sets the register address to be read.
    if (connection->write((slaveAddress << 1), &regAddr, LEN_ONE_BYTE) != 0) {
        return ERROR_I2C_WRITE;
    }
    
    // Reads the register value.
    char val = 0;
    if (connection->read(((slaveAddress << 1) | 0x01), &val, LEN_ONE_BYTE) != 0) {
        return ERROR_I2C_READ;
    }
    
    *buf = (uint8_t)val;
    
    return SUCCESS;
}

TCA9554A::Status TCA9554A::write(RegisterAddress addr, uint8_t val) {
    char buf[LEN_TWO_BYTE];
    
    buf[0] = (char)addr;
    buf[1] = (char)val;
    
    // Writes to the devices.
    if (connection->write((slaveAddress << 1), buf, LEN_TWO_BYTE) != 0) {
        return ERROR_I2C_WRITE;
    }
        
    return SUCCESS;
}

TCA9554A::Status TCA9554A::configurePort(Port port, Direction dir, PolarityInversion pol) {
    Status status;
    uint8_t buf = 0;
    
    // Reads the current configuration register value.
    if ((status=read(REG_ADDR_CONFIG, &buf)) != SUCCESS) {
        return status;
    }
    
    // Modifies the specified bit.
    buf = (((~port) & buf) | dir);
    
    // Writes back to the configuration register.
    if ((status=write(REG_ADDR_CONFIG, buf)) != SUCCESS) {
        return status;
    }
    
    // Reads the current polarity inversion register value.
    if ((status=read(REG_ADDR_POLARITY, &buf)) != SUCCESS) {
        return status;
    }
    
    // Modifies the specified bit.
    buf = (((~port) & buf) | pol);
    
    // Writes back to the polarity inversion register.
    if ((status=write(REG_ADDR_POLARITY, buf)) != SUCCESS) {
        return status;
    }

    return status;    
}

TCA9554A::Status TCA9554A::getPortLevel(LogicLevel *val, Port port) {
    Status status;
    uint8_t buf = 0;
    
    // Reads the input register
    if ((status=read(REG_ADDR_INPUT, &buf)) != SUCCESS) {
        return status;
    }
    
    *val = (((port & buf) > 0) ? HIGH : LOW);
    
    return status;
}

TCA9554A::Status TCA9554A::setPortLevel(Port port, LogicLevel val) {
    Status status;
    
    // Get the current register setting.
    uint8_t buf = 0;
    if ((status=read(REG_ADDR_OUTPUT, &buf)) != SUCCESS) {
        return status;
    }
    
    // Modify the specified bit by port.
    buf = ((buf & (~port) | (port * val)));
    
    // Write back the modified value to the register.
    if ((status=write(REG_ADDR_OUTPUT, buf)) != SUCCESS) {
        return status;
    }
    
    return status;
}

TCA9554A::Status TCA9554A::getPortDirection(Direction *dir, Port port) {
    Status status;
    
    // Get the current register setting.
    uint8_t buf = 0;
    if ((status=read(REG_ADDR_OUTPUT, &buf)) != SUCCESS) {
        return status;
    }
    
    // Gets the value of the specified port.
    *dir = ((buf & port) > 0) ?  DIR_INPUT : DIR_OUTPUT;
    
    return status;
}