SX1509 16 Output I/O Expander / LED Driver Library

Dependents:   SX1509_HelloWorld

SX1509.cpp

Committer:
jjones646
Date:
2014-10-21
Revision:
1:9ab20d13c44e
Parent:
0:893f387bda9f
Child:
2:330355f546b0

File content as of revision 1:9ab20d13c44e:


#include "SX1509.h"
#include "mbed.h"


// Constructors
SX1509::SX1509()
{
    error("You must supply 2 pin names. (Serial Data Pin [sda], Serial Clock Pin [scl])");
}

SX1509::SX1509(PinName sda)
{
    SX1509();
}

SX1509::SX1509(PinName sda, PinName scl, PinName intN, PinName resetN)
{
    init(sda, scl, intN, resetN);
}

// initilization method here is called from the constructors
void SX1509::init(PinName sda, PinName scl, PinName intN, PinName resetN)
{

    // if an interrupt pin was passed in, assign it
    if (intN != NC) {
        _intN = new DigitalIn(intN);
        hasInt = true;
    } else {
        hasInt = false;
    }

    // if a reset pin was passed in, assign it
    if (resetN != NC) {
        _resetN = new DigitalOut(resetN);
        *_resetN = 1;   // bring high to enable device
        hasReset = true;
    } else {
        hasReset = false;
    }

    // setup the I2C data bus lines
    _i2c = new I2C(sda, scl);
    _i2c->frequency(SX1509_FREQUENCY);

    // default to outputs
    directionA(OUT);
    directionB(OUT);

    // initialize all the outputs by setting them all to zero
    setA(0x00);
    setB(0x00);

    dirA = OUT;
    dirB = OUT;
}

// generic method for sending data among the I2C bus
int SX1509::transfer_data(char const reg_addr, char const reg_val, Transfer_t transfer)
{
    int value = 0;

    _i2c->start();
    if(_i2c->write(SX1509_ADDRESS_1<<1)) {
        if (_i2c->write(reg_addr)) {
            switch(transfer) {
                case WRITE:
                    value = _i2c->write(reg_val);
                    break;
                case READ:
                    _i2c->start();
                    if(_i2c->write((SX1509_ADDRESS_1<<1)|READ)) {
                        value = _i2c->read(0);
                    }
                    break;
                default:
                    break;
            }

        } else {
            std::printf("Slave did not acknowledge the register's address.\r\n");
        }
    } else {
        std::printf("Nothing worked...\r\n");
    }
    _i2c->stop();

    return value;
}

// generic method for writing data to one of the chip's registers
void SX1509::write_register(char const reg_addr, char const reg_val)
{
    transfer_data(reg_addr, reg_val, WRITE);
}

// generic method for reading a single char from one of the chip's registers
int SX1509::read_register(char const reg_addr)
{
    return transfer_data(reg_addr, NULL, READ);
}

// generic method for setting the direction of a side's outputs
void SX1509::direction(Direction_t dir, Side_t side)
{
    char set_byte = 0;
    char address = 0;

    // determine what bytes to write based on the passed inputs
    switch (dir) {
        case OUT:
            set_byte = 0x00;
            break;
        case IN:
            set_byte = 0xFF;
            break;
        default:
            break;
    }

    // determine what side's registers to write to
    switch (side) {
        case A:
            address = REGDIRA;
            dirA = dir;
            break;
        case B:
            address = REGDIRB;
            dirB = dir;
            break;
        default:
            break;
    }

    write_register(address, set_byte);
}


// Set the direction (IN or OUT) for side A
void SX1509::directionA(Direction_t dir)
{
    direction(dir,A);
}

// Set the direction (IN or OUT) for side B
void SX1509::directionB(Direction_t dir)
{
    direction(dir,B);
}

// Set a hex value to the I/O pins for side A
void SX1509::setA(char const val)
{
    transfer_data(REGDATAA, val, WRITE);
}

// Set a hex value to the I/O pins for side B
void SX1509::setB(char const val)
{
    transfer_data(REGDATAB, val, WRITE);
}

void SX1509::clearAll(Side_t side)
{
    switch(side) {
        case A:
            setA(0x00);
            break;
        case B:
            setB(0x00);
            break;
        default:
            break;
    }
}


// Read a hex value from SideA
int SX1509::readA()
{
    int a = read_register(REGDATAA);
    return a;
}

// Read a hex value from SideB
int SX1509::readB()
{
    return read_register(REGDATAB);
}

bool SX1509::get(int const i)
{
    uint8_t temp;

    if (i>=0 && i<8) {
        temp = readA();
        temp &= (1<<i);
    } else if (i>=8 && i<16) {
        temp = readB();
        temp &= (1<<(i-8));
    }

    return (temp > 0);
}

void SX1509::set(int const i)
{
    uint8_t temp;

    if (i>=0 && i<8) {
        temp = readA();
        temp |= (1<<i);
        setA(temp);
    } else if (i>=8 && i<16) {
        temp = readB();
        temp |= (1<<(i-8));
        setB(temp);
    }
}

void SX1509::clear(int const i)
{
    uint8_t temp;

    if (i>=0 && i<8) {
        temp = readA();
        temp &= ~(1<<i);
        setA(temp);
    } else if (i>=8 && i<16) {
        temp = readB();
        temp &= ~(1<<(i-8));
        setB(temp);
    }
}

void SX1509::toggle(int const i)
{
    uint8_t temp;

    if (i>=0 && i<8) {
        temp = readA();
        temp ^= 1<<i;
        setA(temp);
    } else if (i>=8 && i<16) {
        temp = readB();
        temp ^= 1<<(i-8);
        setB(temp);
    }
}

Direction_t SX1509::getDirection(Side_t side)
{
    Direction_t dir;

    switch(side) {
        case A:
            dir = dirA;
        case B:
            dir = dirB;
        default:
            break;
    }
    return dir;
}

void SX1509::setBuffer(Side_t side, State_t state)
{
    uint8_t invert = ~state;

    switch (side) {
        case A:
            write_register(REGINPUTDISABLEA, invert);
            break;
        case B:
            write_register(REGINPUTDISABLEB, invert);
            break;
        default:
            break;
    }
}

void SX1509::setPull(Side_t side, Pull_t pull, State_t state)
{
    switch (side) {
        case A:
            if (pull == PULLUP) {
                write_register(REGPULLDOWNA, ~state);
                write_register(REGPULLUPA, state);
            } else if (pull == PULLDOWN) {
                write_register(REGPULLUPA, ~state);
                write_register(REGPULLDOWNA, state);
            }
            break;

        case B:
            if (pull == PULLUP) {
                write_register(REGPULLDOWNB, ~state);
                write_register(REGPULLUPB, state);
            } else if (pull == PULLDOWN) {
                write_register(REGPULLUPB, ~state);
                write_register(REGPULLDOWNB, state);
            }
            break;
        default:
            break;
    }
}

void SX1509::setOpenDrain(Side_t side, State_t state)
{
    switch (side) {
        case A:
            write_register(REGOPENDRAINA, state);
            break;
        case B:
            write_register(REGOPENDRAINB, state);
            break;
        default:
            break;
    }
}

void SX1509::setClock(State_t state)
{
    uint8_t new_state = read_register(REGCLOCK);

    if (state == ON) {
        new_state |= 0x40;
    } else if (state == OFF) {
        new_state &= ~(0x60);
    }

    write_register(REGCLOCK, new_state);
}

void SX1509::setFreq(Freq_t freq)
{
    uint8_t new_state = read_register(REGMISC);
    new_state |= ((1<<4)<<freq);
    write_register(REGMISC, new_state);
}

void SX1509::setLedDrive(Side_t side, State_t state)
{
    switch (side) {
        case A:
            write_register(REGLEDDRIVERENABLEA, state);
            break;
        case B:
            write_register(REGLEDDRIVERENABLEB, state);
            break;
        default:
            break;
    }
}

void SX1509::enableLED(Side_t side)
{
    setBuffer(side, OFF);
    setPull(side, PULLUP, OFF);
    setOpenDrain(side, ON);
    setClock(ON);
    setFreq(MED);
    setLedDrive(side, ON);
    clearAll(side);
}

void SX1509::setupLED(LED_t led)
{
    int i = 0;
    write_register(led + i++, 0x00); // T_on
    write_register(led + i++, 0x0A); // Intensity
    write_register(led + i++, (0x01<<3)|(0x00)); // T_off
    write_register(led + i++, 0x01); // T_rise
    write_register(led + i, 0x01); // T_fall
}