SX1509 16 Output I/O Expander / LED Driver Library
Diff: SX1509.cpp
- Revision:
- 0:893f387bda9f
- Child:
- 1:9ab20d13c44e
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SX1509.cpp Tue Oct 21 04:07:43 2014 +0000 @@ -0,0 +1,385 @@ + +#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++, 0x03); // T_on + write_register(led + i++, 0xFF); // Intensity + write_register(led + i++, (0x01<<3)|(0x00)); // T_off + write_register(led + i++, 0x01); // T_rise + write_register(led + i, 0x01); // T_fall + */ + + 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 +} \ No newline at end of file