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

Dependents:   AKDP-RevD7_014

tca9554a.h

Committer:
coisme
Date:
2016-05-26
Revision:
2:0d772298e874
Parent:
1:e02d9e33b9f3

File content as of revision 2:0d772298e874:

#ifndef __TCA9554A_H__
#define __TCA9554A_H__

#include "mbed.h"

/**
 * Device driver for TCA9554A.
 * @note TCA9554A is a GPIO expander with I2C interface.
 * Example:
 * @code
 * #include "mbed.h"
 * #include "tca9554a.h"
 *
 * #define I2C_SPEED_100KHZ    100000
 * #define I2C_SPEED_400KHZ    400000
 * 
 * int main(void) {
 *     // Instanciate I2C
 *     I2C i2c(I2C_SDA0, I2C_SCL0);
 *     i2c.frequency(I2C_SPEED_400KHZ);
 *
 *     // Instanciate TCA9554A
 *     // Suppose that the slave address of TCA9554A on your board is 38H.
 *     TCA9554A tca9554a(&i2c, TCA9554A::SLAVE_ADDRESS_38H);
 *     
 *     // Configure the GPIO ports. 
 *     // Default direction of the ports are input and polarity inversion is disabled.
 *     // Here, sets port 3 to output and port 5 to input with polarity inversion.
 *     if (tca9554a.configurePort(TCA9554A::PORT_3, TCA9554A::DIR_OUTPUT)!= TCA9554A::SUCCESS) {
 *         // @TODO: error handling
 *     }
 *     if (tca9554a.configurePort(TCA9554A::PORT_5, TCA9554A::DIR_INPUT, TCA9554A::INVERTING) != TCA9554A::SUCCESS) {
 *         // @TODO: error handling
 *     }
 * 
 *     while(true) {
 *         LogicLevel val = TCA9554A::LOW;
 *         // Reads the value from port 5 and sets the read value to port 3.
 *         // Note that the read value is inverted from the actual input level, 
 *         // because the port 5 is configured as INVERTING at the initialization process above.
 *         if (tca9554a.getPortLevel(&val, TCA9554A::PORT_5) != SUCCESS) {
 *             // @TODO: error handling
 *         }
 *         if (tca9554a.setPortLevel(TCA9554A::PORT_3, val) != SUCCESS) {
 *             // @TODO: error handling
 *         }
 *     }
 * }
 * @endcode
 */
class TCA9554A 
{
public:
    /**
     * Device's slave address.
     */
    typedef enum {
        SLAVE_ADDRESS_38H = 0x38,         /**< Slave address 0x38, when (A2)(A1)(A0) = 000. */
        SLAVE_ADDRESS_39H = 0x39,         /**< Slave address 0x39, when (A2)(A1)(A0) = 001. */
        SLAVE_ADDRESS_3AH = 0x3A,         /**< Slave address 0x3A, when (A2)(A1)(A0) = 010. */
        SLAVE_ADDRESS_3BH = 0x3B,         /**< Slave address 0x3B, when (A2)(A1)(A0) = 011. */
        SLAVE_ADDRESS_3CH = 0x3C,         /**< Slave address 0x3C, when (A2)(A1)(A0) = 100. */
        SLAVE_ADDRESS_3DH = 0x3D,         /**< Slave address 0x3D, when (A2)(A1)(A0) = 101. */
        SLAVE_ADDRESS_3EH = 0x3E,         /**< Slave address 0x3E, when (A2)(A1)(A0) = 110. */
        SLAVE_ADDRESS_3FH = 0x3F,         /**< Slave address 0x3F, when (A2)(A1)(A0) = 111. */
    } SlaveAddress;

    /**
     * Result status of function execution. 
     */
    typedef enum {
        SUCCESS,               /**< The function processed successfully. */
        ERROR_I2C_READ,        /**< Error related to I2C read. */
        ERROR_I2C_WRITE,       /**< Error related to I2C write. */
        ERROR,                 /**< General Error */
    } Status;

    /**
     * GPIO port number.
     */
    typedef enum {
        PORT_0 = 0x01,         /**< Port 0. */
        PORT_1 = 0x02,         /**< Port 1. */
        PORT_2 = 0x04,         /**< Port 2. */
        PORT_3 = 0x08,         /**< Port 3. */
        PORT_4 = 0x10,         /**< Port 4. */
        PORT_5 = 0x20,         /**< Port 5. */
        PORT_6 = 0x40,         /**< Port 6. */
        PORT_7 = 0x80,         /**< Port 7. */
    } Port;
    
    /**
     * Port value.
     */
    typedef enum {
        LOW = 0,              /**< Indicates low level. */
        HIGH = 1,             /**< Indicates high level. */
    } LogicLevel;
    
    /**
     * Direction of a port.
     */    
    typedef enum {
        DIR_OUTPUT = 0x00,    /**< Output. */
        DIR_INPUT = 0x01,     /**< Input. */
    } Direction;

    /**
     * Flag for enabling input polarity inversion.
     */
    typedef enum {
        NON_INVERTING = 0x00,  /**< Input polarity is not inverted. */
        INVERTING = 0x01,      /**< Input polarity is inverted. */
    } PolarityInversion;

    /**
     * Constructor. In default, all the ports are set as input.
     * @param conn Pointer to an instance of I2C.
     * @param addr Slave address of this device.
     */
    TCA9554A(I2C *conn, SlaveAddress addr);


    /**
     * Sets port properties.
     * @param port Port number to be configured.
     * @param dir Direction to be set for the specified port.
     * @param pol Polarity inversion to be set for the specified port.
     * @return SUCCESS when succeeded. Other value will be returned when error.
     */
    Status configurePort(Port port, Direction dir, PolarityInversion pol = NON_INVERTING);

    /**
     * Gets the logic level from the specified port. If the polarity inversion is enabled at the port, 
     * this function returns the inverted value. For example, the input voltage of a port is high level
     * and polarity inversion setting for the port is enabled, then LOW will be obtained from this function.
     * @param val Logic level of the specified port.
     * @param port Port to be read.
     * @return SUCCESS when succeeded. Other value will be returned when error.
     */    
    Status getPortLevel(LogicLevel *val, Port port);
    
    /**
     * Sets output level of the specified port. If the direction of the specified port is input,
     * this operation has no effect.
     * @param port Port to be set.
     * @param val Logic level to be set.
     * @return SUCCESS when succeeded. Other value will be returned when error.
     */
    Status setPortLevel(Port port, LogicLevel val);
    
    /**
     * Gets port direction of the specified port.
     * @param dir Pointer to the buffer direction to be stored.
     * @param port Port to be checked direction.
     * @return SUCCESS when succeeded. Other value will be returned when error.
     */
    Status getPortDirection(Direction *dir, Port port);

private:
    I2C *connection;               /**< Pointer to an I2C object. */
    uint8_t slaveAddress;          /**< Holds the device's slave address. */
    
    typedef enum {
        REG_ADDR_INPUT = 0x00,
        REG_ADDR_OUTPUT = 0x01,
        REG_ADDR_POLARITY = 0x02,
        REG_ADDR_CONFIG = 0x03,
    } RegisterAddress;
    
    /**
     * Reads one byte from the specified register address.
     * @param addr Register address to be read.
     * @param buf Buffer to store the read value.
     * @return SUCCESS when succeeded. Other value will be returned when error.
     */
    Status read(RegisterAddress addr, uint8_t *buf);
    
    /**
     * Write one byte to the specified register address.
     * @param addr Register address to be read.
     * @param buf Value to be written into the specified register.
     * @return SUCCESS when succeeded. Other value will be returned when error.
     */
    Status write(RegisterAddress addr, uint8_t val);
};

#endif