Update housing and code

--add local timezone
--add sunrise/sunset calculation and LED illumination accordingly
--remove touch sensor check
--change mqtt messages
This commit is contained in:
admin committed 2025-05-13 19:07:14 +02:00
1 parent 6435550e29
commit 379b4887c3
47 files changed
+26343 -2850

No files matched your search

@@ -0,0 +1,860 @@
/******************************************************************************
SparkFunSX1509.cpp
SparkFun SX1509 I/O Expander Library Source File
Jim Lindblom @ SparkFun Electronics
Original Creation Date: September 21, 2015
https://github.com/sparkfun/SparkFun_SX1509_Arduino_Library
Here you'll find the Arduino code used to interface with the SX1509 I2C
16 I/O expander. There are functions to take advantage of everything the
SX1509 provides - input/output setting, writing pins high/low, reading
the input value of pins, LED driver utilities (blink, breath, pwm), and
keypad engine utilites.
Development environment specifics:
IDE: Arduino 1.6.5
Hardware Platform: Arduino Uno
SX1509 Breakout Version: v2.0
This code is beerware; if you see me (or any other SparkFun employee) at the
local, and you've found our code helpful, please buy us a round!
Distributed as-is; no warranty is given.
******************************************************************************/
#include <Wire.h>
#include "Arduino.h"
#include "SparkFunSX1509.h"
#include "util/sx1509_registers.h"
SX1509::SX1509()
{
_clkX = 0;
}
SX1509::SX1509(uint8_t address, uint8_t resetPin, uint8_t interruptPin, uint8_t oscillatorPin)
{
// Store the received parameters into member variables
deviceAddress = address;
pinInterrupt = interruptPin;
pinOscillator = oscillatorPin;
pinReset = resetPin;
}
uint8_t SX1509::begin(uint8_t address, TwoWire &wirePort, uint8_t resetPin)
{
// Store the received parameters into member variables
_i2cPort = &wirePort;
deviceAddress = address;
pinReset = resetPin;
return init();
}
uint8_t SX1509::init(void)
{
// Begin I2C should be done externally, before beginning SX1509
//Wire.begin();
// If the reset pin is connected
if (pinReset != 255)
reset(1);
else
reset(0);
// Communication test. We'll read from two registers with different
// default values to verify communication.
uint16_t testRegisters = 0;
testRegisters = readWord(REG_INTERRUPT_MASK_A); // This should return 0xFF00
// Then read a byte that should be 0x00
if (testRegisters == 0xFF00)
{
// Set the clock to a default of 2MHz using internal
clock(INTERNAL_CLOCK_2MHZ);
return 1;
}
return 0;
}
void SX1509::reset(bool hardware)
{
// if hardware bool is set
if (hardware)
{
// Check if bit 2 of REG_MISC is set
// if so nReset will not issue a POR, we'll need to clear that bit first
uint8_t regMisc = readByte(REG_MISC);
if (regMisc & (1 << 2))
{
regMisc &= ~(1 << 2);
writeByte(REG_MISC, regMisc);
}
// Reset the SX1509, the pin is active low
::pinMode(pinReset, OUTPUT); // set reset pin as output
::digitalWrite(pinReset, LOW); // pull reset pin low
delay(1); // Wait for the pin to settle
::digitalWrite(pinReset, HIGH); // pull reset pin back high
}
else
{
// Software reset command sequence:
writeByte(REG_RESET, 0x12);
writeByte(REG_RESET, 0x34);
}
}
void SX1509::pinDir(uint8_t pin, uint8_t inOut, uint8_t initialLevel)
{
// The SX1509 RegDir registers: REG_DIR_B, REG_DIR_A
// 0: IO is configured as an output
// 1: IO is configured as an input
uint8_t modeBit;
if ((inOut == OUTPUT) || (inOut == ANALOG_OUTPUT))
{
uint16_t tempRegData = readWord(REG_DATA_B);
if (initialLevel == LOW)
{
tempRegData &= ~(1 << pin);
writeWord(REG_DATA_B, tempRegData);
}
modeBit = 0;
}
else
{
modeBit = 1;
}
uint16_t tempRegDir = readWord(REG_DIR_B);
if (modeBit)
tempRegDir |= (1 << pin);
else
tempRegDir &= ~(1 << pin);
writeWord(REG_DIR_B, tempRegDir);
// If INPUT_PULLUP was called, set up the pullup too:
if (inOut == INPUT_PULLUP)
writePin(pin, HIGH);
if (inOut == ANALOG_OUTPUT)
{
ledDriverInit(pin);
}
}
void SX1509::pinMode(uint8_t pin, uint8_t inOut, uint8_t initialLevel)
{
pinDir(pin, inOut, initialLevel);
}
bool SX1509::writePin(uint8_t pin, uint8_t highLow)
{
uint16_t tempRegDir = readWord(REG_DIR_B);
if ((0xFFFF ^ tempRegDir) & (1 << pin)) // If the pin is an output, write high/low
{
uint16_t tempRegData = readWord(REG_DATA_B);
if (highLow)
tempRegData |= (1 << pin);
else
tempRegData &= ~(1 << pin);
return writeWord(REG_DATA_B, tempRegData);
}
else // Otherwise the pin is an input, pull-up/down
{
uint16_t tempPullUp = readWord(REG_PULL_UP_B);
uint16_t tempPullDown = readWord(REG_PULL_DOWN_B);
if (highLow) // if HIGH, do pull-up, disable pull-down
{
tempPullUp |= (1 << pin);
tempPullDown &= ~(1 << pin);
return writeWord(REG_PULL_UP_B, tempPullUp) && writeWord(REG_PULL_DOWN_B, tempPullDown);
}
else // If LOW do pull-down, disable pull-up
{
tempPullDown |= (1 << pin);
tempPullUp &= ~(1 << pin);
return writeWord(REG_PULL_UP_B, tempPullUp) && writeWord(REG_PULL_DOWN_B, tempPullDown);
}
}
}
bool SX1509::digitalWrite(uint8_t pin, uint8_t highLow)
{
return writePin(pin, highLow);
}
uint8_t SX1509::readPin(uint8_t pin)
{
uint16_t tempRegDir = readWord(REG_DIR_B);
if (tempRegDir & (1 << pin)) // If the pin is an input
{
uint16_t tempRegData = readWord(REG_DATA_B);
if (tempRegData & (1 << pin))
return 1;
}
else
{
// log_d("Pin %d not INPUT, REG_DIR_B: %d", pin, tempRegDir);
}
return 0;
}
bool SX1509::readPin(const uint8_t pin, bool *value)
{
uint16_t tempRegDir;
if (readWord(REG_DIR_B, &tempRegDir))
{
if (tempRegDir & (1 << pin))
{ // If the pin is an input
uint16_t tempRegData;
if (readWord(REG_DATA_B, &tempRegData))
{
*value = (tempRegData & (1 << pin)) != 0;
return true;
};
}
else
{
*value = false;
return true;
}
}
return false;
}
uint8_t SX1509::digitalRead(uint8_t pin)
{
return readPin(pin);
}
bool SX1509::digitalRead(uint8_t pin, bool *value)
{
return readPin(pin, value);
}
void SX1509::ledDriverInit(uint8_t pin, uint8_t freq /*= 1*/, bool log /*= false*/)
{
uint16_t tempWord;
uint8_t tempByte;
// Disable input buffer
// Writing a 1 to the pin bit will disable that pins input buffer
tempWord = readWord(REG_INPUT_DISABLE_B);
tempWord |= (1 << pin);
writeWord(REG_INPUT_DISABLE_B, tempWord);
// Disable pull-up
// Writing a 0 to the pin bit will disable that pull-up resistor
tempWord = readWord(REG_PULL_UP_B);
tempWord &= ~(1 << pin);
writeWord(REG_PULL_UP_B, tempWord);
// Set direction to output (REG_DIR_B)
tempWord = readWord(REG_DIR_B);
tempWord &= ~(1 << pin); // 0=output
writeWord(REG_DIR_B, tempWord);
// Enable oscillator (REG_CLOCK)
tempByte = readByte(REG_CLOCK);
tempByte |= (1 << 6); // Internal 2MHz oscillator part 1 (set bit 6)
tempByte &= ~(1 << 5); // Internal 2MHz oscillator part 2 (clear bit 5)
writeByte(REG_CLOCK, tempByte);
// Configure LED driver clock and mode (REG_MISC)
tempByte = readByte(REG_MISC);
if (log)
{
tempByte |= (1 << 7); // set logarithmic mode bank B
tempByte |= (1 << 3); // set logarithmic mode bank A
}
else
{
tempByte &= ~(1 << 7); // set linear mode bank B
tempByte &= ~(1 << 3); // set linear mode bank A
}
// Use configClock to setup the clock divder
if (_clkX == 0) // Make clckX non-zero
{
// _clkX = 2000000.0 / (1 << (1 - 1)); // Update private clock variable
_clkX = 2000000.0;
// uint8_t freq = (1 & 0x07) << 4; // freq should only be 3 bits from 6:4
// tempByte |= freq;
}
freq = (freq & 0x7) << 4; // mask only 3 bits and shift to bit position 6:4
tempByte |= freq;
writeByte(REG_MISC, tempByte);
// Enable LED driver operation (REG_LED_DRIVER_ENABLE)
tempWord = readWord(REG_LED_DRIVER_ENABLE_B);
tempWord |= (1 << pin);
writeWord(REG_LED_DRIVER_ENABLE_B, tempWord);
// Set REG_DATA bit low ~ LED driver started
tempWord = readWord(REG_DATA_B);
tempWord &= ~(1 << pin);
writeWord(REG_DATA_B, tempWord);
}
void SX1509::pwm(uint8_t pin, uint8_t iOn)
{
// Write the on intensity of pin
// Linear mode: Ion = iOn
// Log mode: Ion = f(iOn)
writeByte(REG_I_ON[pin], iOn);
}
void SX1509::analogWrite(uint8_t pin, uint8_t iOn)
{
pwm(pin, iOn);
}
void SX1509::blink(uint8_t pin, unsigned long tOn, unsigned long tOff, uint8_t onIntensity, uint8_t offIntensity)
{
uint8_t onReg = calculateLEDTRegister(tOn);
uint8_t offReg = calculateLEDTRegister(tOff);
setupBlink(pin, onReg, offReg, onIntensity, offIntensity, 0, 0);
}
void SX1509::breathe(uint8_t pin, unsigned long tOn, unsigned long tOff, unsigned long rise, unsigned long fall, uint8_t onInt, uint8_t offInt, bool log)
{
offInt = constrain(offInt, 0, 7);
uint8_t onReg = calculateLEDTRegister(tOn);
uint8_t offReg = calculateLEDTRegister(tOff);
uint8_t riseTime = calculateSlopeRegister(rise, onInt, offInt);
uint8_t fallTime = calculateSlopeRegister(fall, onInt, offInt);
setupBlink(pin, onReg, offReg, onInt, offInt, riseTime, fallTime, log);
}
void SX1509::setupBlink(uint8_t pin, uint8_t tOn, uint8_t tOff, uint8_t onIntensity, uint8_t offIntensity, uint8_t tRise, uint8_t tFall, bool log)
{
ledDriverInit(pin, log);
// Keep parameters within their limits:
tOn &= 0x1F; // tOn should be a 5-bit value
tOff &= 0x1F; // tOff should be a 5-bit value
offIntensity &= 0x07;
// Write the time on
// 1-15: TON = 64 * tOn * (255/ClkX)
// 16-31: TON = 512 * tOn * (255/ClkX)
writeByte(REG_T_ON[pin], tOn);
// Write the time/intensity off register
// 1-15: TOFF = 64 * tOff * (255/ClkX)
// 16-31: TOFF = 512 * tOff * (255/ClkX)
// linear Mode - IOff = 4 * offIntensity
// log mode - Ioff = f(4 * offIntensity)
writeByte(REG_OFF[pin], (tOff << 3) | offIntensity);
// Write the on intensity:
writeByte(REG_I_ON[pin], onIntensity);
// Prepare tRise and tFall
tRise &= 0x1F; // tRise is a 5-bit value
tFall &= 0x1F; // tFall is a 5-bit value
// Write regTRise
// 0: Off
// 1-15: TRise = (regIOn - (4 * offIntensity)) * tRise * (255/ClkX)
// 16-31: TRise = 16 * (regIOn - (4 * offIntensity)) * tRise * (255/ClkX)
if (REG_T_RISE[pin] != 0xFF)
writeByte(REG_T_RISE[pin], tRise);
// Write regTFall
// 0: off
// 1-15: TFall = (regIOn - (4 * offIntensity)) * tFall * (255/ClkX)
// 16-31: TFall = 16 * (regIOn - (4 * offIntensity)) * tFall * (255/ClkX)
if (REG_T_FALL[pin] != 0xFF)
writeByte(REG_T_FALL[pin], tFall);
}
void SX1509::keypad(uint8_t rows, uint8_t columns, uint16_t sleepTime, uint8_t scanTime, uint8_t debounceTime)
{
uint16_t tempWord;
uint8_t tempByte;
// If clock hasn't been set up, set it to internal 2MHz
if (_clkX == 0)
clock(INTERNAL_CLOCK_2MHZ);
// Set regDir 0:7 outputs, 8:15 inputs:
tempWord = readWord(REG_DIR_B);
for (uint8_t i = 0; i < rows; i++)
tempWord &= ~(1 << i);
for (uint8_t i = 8; i < (columns * 2); i++)
tempWord |= (1 << i);
writeWord(REG_DIR_B, tempWord);
// Set regOpenDrain on 0:7:
tempByte = readByte(REG_OPEN_DRAIN_A);
for (uint8_t i = 0; i < rows; i++)
tempByte |= (1 << i);
writeByte(REG_OPEN_DRAIN_A, tempByte);
// Set regPullUp on 8:15:
tempByte = readByte(REG_PULL_UP_B);
for (uint8_t i = 0; i < columns; i++)
tempByte |= (1 << i);
writeByte(REG_PULL_UP_B, tempByte);
// Debounce Time must be less than scan time
debounceTime = constrain(debounceTime, 1, 64);
scanTime = constrain(scanTime, 1, 128);
if (debounceTime >= scanTime)
{
debounceTime = scanTime >> 1; // Force debounceTime to be less than scanTime
}
debounceKeypad(debounceTime, rows, columns);
// Calculate scanTimeBits, based on scanTime
uint8_t scanTimeBits = 0;
for (uint8_t i = 7; i > 0; i--)
{
if (scanTime & (1 << i))
{
scanTimeBits = i;
break;
}
}
// Calculate sleepTimeBits, based on sleepTime
uint8_t sleepTimeBits = 0;
if (sleepTime != 0)
{
for (uint8_t i = 7; i > 0; i--)
{
if (sleepTime & ((uint16_t)1 << (i + 6)))
{
sleepTimeBits = i;
break;
}
}
// If sleepTime was non-zero, but less than 128,
// assume we wanted to turn sleep on, set it to minimum:
if (sleepTimeBits == 0)
sleepTimeBits = 1;
}
// RegKeyConfig1 sets the auto sleep time and scan time per row
sleepTimeBits = (sleepTimeBits & 0b111) << 4;
scanTimeBits &= 0b111; // Scan time is bits 2:0
tempByte = sleepTime | scanTimeBits;
writeByte(REG_KEY_CONFIG_1, tempByte);
// RegKeyConfig2 tells the SX1509 how many rows and columns we've got going
rows = (rows - 1) & 0b111; // 0 = off, 0b001 = 2 rows, 0b111 = 8 rows, etc.
columns = (columns - 1) & 0b111; // 0b000 = 1 column, ob111 = 8 columns, etc.
writeByte(REG_KEY_CONFIG_2, (rows << 3) | columns);
}
uint16_t SX1509::readKeypad()
{
return readKeyData();
}
uint16_t SX1509::readKeyData()
{
return (0xFFFF ^ readWord(REG_KEY_DATA_1));
}
uint8_t SX1509::getRow(uint16_t keyData)
{
uint8_t rowData = uint8_t(keyData & 0x00FF);
for (uint8_t i = 0; i < 8; i++)
{
if (rowData & (1 << i))
return i;
}
return 0;
}
uint8_t SX1509::getCol(uint16_t keyData)
{
uint8_t colData = uint8_t((keyData & 0xFF00) >> 8);
for (uint8_t i = 0; i < 8; i++)
{
if (colData & (1 << i))
return i;
}
return 0;
}
void SX1509::sync(void)
{
// First check if nReset functionality is set
uint8_t regMisc = readByte(REG_MISC);
if (!(regMisc & 0x04))
{
regMisc |= (1 << 2);
writeByte(REG_MISC, regMisc);
}
// Toggle nReset pin to sync LED timers
::pinMode(pinReset, OUTPUT); // set reset pin as output
::digitalWrite(pinReset, LOW); // pull reset pin low
delay(1); // Wait for the pin to settle
::digitalWrite(pinReset, HIGH); // pull reset pin back high
// Return nReset to POR functionality
writeByte(REG_MISC, (regMisc & ~(1 << 2)));
}
void SX1509::debounceConfig(uint8_t configValue)
{
// First make sure clock is configured
uint8_t tempByte = readByte(REG_MISC);
if ((tempByte & 0x70) == 0)
{
tempByte |= (1 << 4); // Just default to no divider if not set
writeByte(REG_MISC, tempByte);
}
tempByte = readByte(REG_CLOCK);
if ((tempByte & 0x60) == 0)
{
tempByte |= (1 << 6); // default to internal osc.
writeByte(REG_CLOCK, tempByte);
}
configValue &= 0b111; // 3-bit value
writeByte(REG_DEBOUNCE_CONFIG, configValue);
}
void SX1509::debounceTime(uint8_t time)
{
if (_clkX == 0) // If clock hasn't been set up.
clock(INTERNAL_CLOCK_2MHZ, 1); // Set clock to 2MHz.
// Debounce time-to-byte map: (assuming fOsc = 2MHz)
// 0: 0.5ms 1: 1ms
// 2: 2ms 3: 4ms
// 4: 8ms 5: 16ms
// 6: 32ms 7: 64ms
// 2^(n-1)
uint8_t configValue = 0;
// We'll check for the highest set bit position,
// and use that for debounceConfig
for (int8_t i = 7; i >= 0; i--)
{
if (time & (1 << i))
{
configValue = i + 1;
break;
}
}
configValue = constrain(configValue, 0, 7);
debounceConfig(configValue);
}
void SX1509::debounceEnable(uint8_t pin)
{
uint16_t debounceEnable = readWord(REG_DEBOUNCE_ENABLE_B);
debounceEnable |= (1 << pin);
writeWord(REG_DEBOUNCE_ENABLE_B, debounceEnable);
}
void SX1509::debouncePin(uint8_t pin)
{
debounceEnable(pin);
}
void SX1509::debounceKeypad(uint8_t time, uint8_t numRows, uint8_t numCols)
{
// Set up debounce time:
debounceTime(time);
// Set up debounce pins:
for (uint8_t i = 0; i < numRows; i++)
debouncePin(i);
for (uint8_t i = 0; i < (8 + numCols); i++)
debouncePin(i);
}
void SX1509::enableInterrupt(uint8_t pin, uint8_t riseFall)
{
// Set REG_INTERRUPT_MASK
uint16_t tempWord = readWord(REG_INTERRUPT_MASK_B);
tempWord &= ~(1 << pin); // 0 = event on IO will trigger interrupt
writeWord(REG_INTERRUPT_MASK_B, tempWord);
uint8_t sensitivity = 0;
switch (riseFall)
{
case CHANGE:
sensitivity = 0b11;
break;
case FALLING:
sensitivity = 0b10;
break;
case RISING:
sensitivity = 0b01;
break;
}
// Set REG_SENSE_XXX
// Sensitivity is set as follows:
// 00: None
// 01: Rising
// 10: Falling
// 11: Both
uint8_t pinMask = (pin & 0x07) * 2;
uint8_t senseRegister;
// Need to select between two words. One for bank A, one for B.
if (pin >= 8)
senseRegister = REG_SENSE_HIGH_B;
else
senseRegister = REG_SENSE_HIGH_A;
tempWord = readWord(senseRegister);
tempWord &= ~(0b11 << pinMask); // Mask out the bits we want to write
tempWord |= (sensitivity << pinMask); // Add our new bits
writeWord(senseRegister, tempWord);
}
uint16_t SX1509::interruptSource(bool clear /* =true*/)
{
uint16_t intSource = readWord(REG_INTERRUPT_SOURCE_B);
if (clear)
writeWord(REG_INTERRUPT_SOURCE_B, 0xFFFF); // Clear interrupts
return intSource;
}
bool SX1509::checkInterrupt(uint8_t pin)
{
if (interruptSource(false) & (1 << pin))
return true;
return false;
}
void SX1509::clock(uint8_t oscSource, uint8_t oscDivider, uint8_t oscPinFunction, uint8_t oscFreqOut)
{
configClock(oscSource, oscPinFunction, oscFreqOut, oscDivider);
}
void SX1509::configClock(uint8_t oscSource /*= 2*/, uint8_t oscPinFunction /*= 0*/, uint8_t oscFreqOut /*= 0*/, uint8_t oscDivider /*= 1*/)
{
// RegClock constructed as follows:
// 6:5 - Oscillator frequency souce
// 00: off, 01: external input, 10: internal 2MHz, 1: reserved
// 4 - OSCIO pin function
// 0: input, 1 ouptut
// 3:0 - Frequency of oscout pin
// 0: LOW, 0xF: high, else fOSCOUT = FoSC/(2^(RegClock[3:0]-1))
oscSource = (oscSource & 0b11) << 5; // 2-bit value, bits 6:5
oscPinFunction = (oscPinFunction & 1) << 4; // 1-bit value bit 4
oscFreqOut = (oscFreqOut & 0b1111); // 4-bit value, bits 3:0
uint8_t regClock = oscSource | oscPinFunction | oscFreqOut;
writeByte(REG_CLOCK, regClock);
// Config RegMisc[6:4] with oscDivider
// 0: off, else ClkX = fOSC / (2^(RegMisc[6:4] -1))
oscDivider = constrain(oscDivider, 1, 7);
_clkX = 2000000.0 / (1 << (oscDivider - 1)); // Update private clock variable
oscDivider = (oscDivider & 0b111) << 4; // 3-bit value, bits 6:4
uint8_t regMisc = readByte(REG_MISC);
regMisc &= ~(0b111 << 4);
regMisc |= oscDivider;
writeByte(REG_MISC, regMisc);
}
uint8_t SX1509::calculateLEDTRegister(unsigned long ms)
{
uint8_t regOn1, regOn2;
float timeOn1, timeOn2;
if (_clkX == 0)
return 0;
regOn1 = (float)(ms / 1000.0) / (64.0 * 255.0 / (float)_clkX);
regOn2 = regOn1 / 8;
regOn1 = constrain(regOn1, 1, 15);
regOn2 = constrain(regOn2, 16, 31);
timeOn1 = 64.0 * regOn1 * 255.0 / _clkX * 1000.0;
timeOn2 = 512.0 * regOn2 * 255.0 / _clkX * 1000.0;
if (abs(timeOn1 - ms) < abs(timeOn2 - ms))
return regOn1;
else
return regOn2;
}
uint8_t SX1509::calculateSlopeRegister(unsigned long ms, uint8_t onIntensity, uint8_t offIntensity)
{
uint16_t regSlope1, regSlope2;
float regTime1, regTime2;
if (_clkX == 0)
return 0;
float tFactor = ((float)onIntensity - (4.0 * (float)offIntensity)) * 255.0 / (float)_clkX;
float timeS = float(ms) / 1000.0;
regSlope1 = timeS / tFactor;
regSlope2 = regSlope1 / 16;
regSlope1 = constrain(regSlope1, 1, 15);
regSlope2 = constrain(regSlope2, 16, 31);
regTime1 = regSlope1 * tFactor * 1000.0;
regTime2 = 16 * regTime1;
if (abs(regTime1 - ms) < abs(regTime2 - ms))
return regSlope1;
else
return regSlope2;
}
// readByte(uint8_t registerAddress)
// This function reads a single byte located at the registerAddress register.
// - deviceAddress should already be set by the constructor.
// - Return value is the byte read from registerAddress
// - Currently returns 0 if communication has timed out
uint8_t SX1509::readByte(uint8_t registerAddress)
{
uint8_t readValue;
// Commented the line as variable seems unused;
//uint16_t timeout = RECEIVE_TIMEOUT_VALUE;
_i2cPort->beginTransmission(deviceAddress);
_i2cPort->write(registerAddress);
_i2cPort->endTransmission();
_i2cPort->requestFrom(deviceAddress, (uint8_t)1);
readValue = _i2cPort->read();
return readValue;
}
// readWord(uint8_t registerAddress)
// This function will read a two-byte word beginning at registerAddress
// - A 16-bit uint16_t will be returned.
// - The msb of the return value will contain the value read from registerAddress
// - The lsb of the return value will contain the value read from registerAddress + 1
uint16_t SX1509::readWord(uint8_t registerAddress)
{
uint16_t readValue;
uint16_t msb, lsb;
// Commented the line as variable seems unused;
//uint16_t timeout = RECEIVE_TIMEOUT_VALUE * 2;
_i2cPort->beginTransmission(deviceAddress);
_i2cPort->write(registerAddress);
_i2cPort->endTransmission();
_i2cPort->requestFrom(deviceAddress, (uint8_t)2);
msb = (_i2cPort->read() & 0x00FF) << 8;
lsb = (_i2cPort->read() & 0x00FF);
readValue = msb | lsb;
return readValue;
}
bool SX1509::readByte(uint8_t registerAddress, uint8_t *value)
{
return readBytes(registerAddress, value, 1);
}
// readWord(uint8_t registerAddress)
// This function will read a two-byte word beginning at registerAddress
// - A 16-bit uint16_t will be set in value.
// - The msb of the return value will contain the value read from registerAddress
// - The lsb of the return value will contain the value read from registerAddress + 1
// - Return boolean true if succesfull
bool SX1509::readWord(uint8_t registerAddress, uint16_t *value)
{
uint8_t dest[2];
if (readBytes(registerAddress, dest, 2))
{
*value = dest[1] | dest[0] << 8;
return true;
}
return false;
}
// readBytes(uint8_t firstRegisterAddress, uint8_t * destination, uint8_t length)
// This function reads a series of bytes incrementing from a given address
// - firstRegisterAddress is the first address to be read
// - destination is an array of bytes where the read values will be stored into
// - length is the number of bytes to be read
// - Return boolean true if succesfull
bool SX1509::readBytes(uint8_t firstRegisterAddress, uint8_t *destination, uint8_t length)
{
_i2cPort->beginTransmission(deviceAddress);
_i2cPort->write(firstRegisterAddress);
uint8_t endResult = _i2cPort->endTransmission();
bool result = (endResult == I2C_ERROR_OK) && (_i2cPort->requestFrom(deviceAddress, length) == length);
if (result)
{
for (uint8_t i = 0; i < length; i++)
{
destination[i] = _i2cPort->read();
}
}
return result;
}
// writeByte(uint8_t registerAddress, uint8_t writeValue)
// This function writes a single byte to a single register on the SX509.
// - writeValue is written to registerAddress
// - deviceAddres should already be set from the constructor
// - Return value: true if succeeded, false if failed
bool SX1509::writeByte(uint8_t registerAddress, uint8_t writeValue)
{
_i2cPort->beginTransmission(deviceAddress);
bool result = _i2cPort->write(registerAddress) && _i2cPort->write(writeValue);
uint8_t endResult = _i2cPort->endTransmission();
return result && (endResult == I2C_ERROR_OK);
}
// writeWord(uint8_t registerAddress, uint16_t writeValue)
// This function writes a two-byte word to registerAddress and registerAddress + 1
// - the upper byte of writeValue is written to registerAddress
// - the lower byte of writeValue is written to registerAddress + 1
// - Return value: true if succeeded, false if failed
bool SX1509::writeWord(uint8_t registerAddress, uint16_t writeValue)
{
uint8_t msb, lsb;
msb = ((writeValue & 0xFF00) >> 8);
lsb = (writeValue & 0x00FF);
_i2cPort->beginTransmission(deviceAddress);
bool result = _i2cPort->write(registerAddress) && _i2cPort->write(msb) && _i2cPort->write(lsb);
uint8_t endResult = _i2cPort->endTransmission();
return result && (endResult == I2C_ERROR_OK);
}
// writeBytes(uint8_t firstRegisterAddress, uint8_t * writeArray, uint8_t length)
// This function writes an array of bytes, beggining at a specific adddress
// - firstRegisterAddress is the initial register to be written.
// - All writes following will be at incremental register addresses.
// - writeArray should be an array of byte values to be written.
// - length should be the number of bytes to be written.
// - Return value: true if succeeded, false if failed
bool SX1509::writeBytes(uint8_t firstRegisterAddress, uint8_t *writeArray, uint8_t length)
{
_i2cPort->beginTransmission(deviceAddress);
bool result = _i2cPort->write(firstRegisterAddress);
result = _i2cPort->write(writeArray, length);
uint8_t endResult = _i2cPort->endTransmission();
return result && (endResult == I2C_ERROR_OK);
}
@@ -0,0 +1,458 @@
/******************************************************************************
SparkFunSX1509.h
SparkFun SX1509 I/O Expander Library Header File
Jim Lindblom @ SparkFun Electronics
Original Creation Date: September 21, 2015
https://github.com/sparkfun/SparkFun_SX1509_Arduino_Library
Here you'll find the Arduino code used to interface with the SX1509 I2C
16 I/O expander. There are functions to take advantage of everything the
SX1509 provides - input/output setting, writing pins high/low, reading
the input value of pins, LED driver utilities (blink, breath, pwm), and
keypad engine utilites.
Development environment specifics:
IDE: Arduino 1.6.5
Hardware Platform: Arduino Uno
SX1509 Breakout Version: v2.0
This code is beerware; if you see me (or any other SparkFun employee) at the
local, and you've found our code helpful, please buy us a round!
Distributed as-is; no warranty is given.
******************************************************************************/
#include "Arduino.h"
#ifndef SparkFunSX1509_H
#define SparkFunSX1509_H
#ifndef I2C_ERROR_OK
#define I2C_ERROR_OK 0
#endif
#define RECEIVE_TIMEOUT_VALUE 1000 // Timeout for I2C receive
// These are used for setting LED driver to linear or log mode:
#define LINEAR 0
#define LOGARITHMIC 1
// These are used for clock config:
#define INTERNAL_CLOCK_2MHZ 2
#define EXTERNAL_CLOCK 1
#define SOFTWARE_RESET 0
#define HARDWARE_RESET 1
#define ANALOG_OUTPUT 0x3 // To set a pin mode for PWM output
class SX1509
{
private: // These private functions are not available to Arduino sketches.
// If you need to read or write directly to registers, consider
// putting the writeByte, readByte functions in the public section
TwoWire *_i2cPort;
uint8_t deviceAddress; // I2C Address of SX1509
// Pin definitions:
uint8_t pinInterrupt;
uint8_t pinOscillator;
uint8_t pinReset;
// Misc variables:
unsigned long _clkX;
// Read Functions:
uint8_t readByte(uint8_t registerAddress);
uint16_t readWord(uint8_t registerAddress);
// Read Functions returning success or failure:
bool readBytes(uint8_t firstRegisterAddress, uint8_t *destination, uint8_t length);
bool readByte(uint8_t registerAddress, uint8_t *value);
bool readWord(uint8_t registerAddress, uint16_t *value);
// Write functions, returning success or failure:
bool writeByte(uint8_t registerAddress, uint8_t writeValue);
bool writeWord(uint8_t registerAddress, uint16_t writeValue);
bool writeBytes(uint8_t firstRegisterAddress, uint8_t *writeArray, uint8_t length);
// Helper functions:
// calculateLEDTRegister - Try to estimate an LED on/off duration register,
// given the number of milliseconds and LED clock frequency.
uint8_t calculateLEDTRegister(unsigned long ms);
// calculateSlopeRegister - Try to estimate an LED rise/fall duration
// register, given the number of milliseconds and LED clock frequency.
uint8_t calculateSlopeRegister(unsigned long ms, uint8_t onIntensity, uint8_t offIntensity);
public:
// -----------------------------------------------------------------------------
// Constructor - SX1509: This function sets up the pins connected to the
// SX1509, and sets up the private deviceAddress variable.
// -----------------------------------------------------------------------------
SX1509();
// Legacy below. Use 0-parameter constructor, and set these parameters in the
// begin function:
SX1509(uint8_t address, uint8_t resetPin = 255, uint8_t interruptPin = 255, uint8_t oscillatorPin = 255);
// -----------------------------------------------------------------------------
// begin(uint8_t address, uint8_t resetPin): This function initializes the SX1509.
// It requires wire to already be begun (previous versions did not do this), resets the IC, and tries to read some
// registers to prove it's connected.
// Inputs:
// - address: should be the 7-bit address of the SX1509. This should be
// one of four values - 0x3E, 0x3F, 0x70, 0x71 - all depending on what the
// ADDR0 and ADDR1 pins ar se to. This variable is required.
// - resetPin: This is the Arduino pin tied to the SX1509 RST pin. This
// pin is optional. If not declared, the library will attempt to
// software reset the SX1509.
// Output: Returns a 1 if communication is successful, 0 on error.
// -----------------------------------------------------------------------------
uint8_t begin(uint8_t address = 0x3E, TwoWire &wirePort = Wire, uint8_t resetPin = 0xFF);
uint8_t init(void); // Legacy -- use begin now
// -----------------------------------------------------------------------------
// reset(bool hardware): This function resets the SX1509 - either a hardware
// reset or software. A hardware reset (hardware parameter = 1) pulls the
// reset line low, pausing, then pulling the reset line high. A software
// reset writes a 0x12 then 0x34 to the REG_RESET as outlined in the
// datasheet.
//
// Input:
// - hardware: 0 executes a software reset, 1 executes a hardware reset
// -----------------------------------------------------------------------------
void reset(bool hardware);
// -----------------------------------------------------------------------------
// pinMode(uint8_t pin, uint8_t inOut): This function sets one of the SX1509's 16
// outputs to either an INPUT or OUTPUT.
//
// Inputs:
// - pin: should be a value between 0 and 15
// - inOut: The Arduino INPUT and OUTPUT constants should be used for the
// inOut parameter. They do what they say!
// -----------------------------------------------------------------------------
void pinMode(uint8_t pin, uint8_t inOut, uint8_t initialLevel = HIGH);
void pinDir(uint8_t pin, uint8_t inOut, uint8_t initialLevel = HIGH); // Legacy - use pinMode
// -----------------------------------------------------------------------------
// digitalWrite(uint8_t pin, uint8_t highLow): This function writes a pin to either high
// or low if it's configured as an OUTPUT. If the pin is configured as an
// INPUT, this method will activate either the PULL-UP or PULL-DOWN
// resistor (HIGH or LOW respectively).
//
// Inputs:
// - pin: The SX1509 pin number. Should be a value between 0 and 15.
// - highLow: should be Arduino's defined HIGH or LOW constants.
// -----------------------------------------------------------------------------
bool digitalWrite(uint8_t pin, uint8_t highLow);
bool writePin(uint8_t pin, uint8_t highLow); // Legacy - use digitalWrite
// -----------------------------------------------------------------------------
// digitalRead(uint8_t pin): This function reads the HIGH/LOW status of a pin.
// The pin should be configured as an INPUT, using the pinDir function.
//
// Inputs:
// - pin: The SX1509 pin to be read. should be a value between 0 and 15.
// Outputs:
// This function returns a 1 if HIGH, 0 if LOW
// -----------------------------------------------------------------------------
uint8_t digitalRead(uint8_t pin);
bool digitalRead(uint8_t pin, bool *value);
uint8_t readPin(uint8_t pin); // Legacy - use digitalRead
bool readPin(const uint8_t pin, bool *value);
// -----------------------------------------------------------------------------
// ledDriverInit(uint8_t pin, uint8_t freq, bool log): This function initializes LED
// driving on a pin. It must be called if you want to use the pwm or blink
// functions on that pin.
//
// Inputs:
// - pin: The SX1509 pin connected to an LED. Should be 0-15.
// - freq: Sets LED clock frequency divider.
// - log: selects either linear or logarithmic mode on the LED drivers
// - log defaults to 0, linear mode
// - currently log sets both bank A and B to the same mode
// Note: this function automatically decides to use the internal 2MHz osc.
// -----------------------------------------------------------------------------
void ledDriverInit(uint8_t pin, uint8_t freq = 1, bool log = false);
// -----------------------------------------------------------------------------
// analogWrite(uint8_t pin, uint8_t iOn): This function can be used to control the intensity
// of an output pin connected to an LED.
//
// Inputs:
// - pin: The SX1509 pin connecte to an LED.Should be 0-15.
// - iOn: should be a 0-255 value setting the intensity of the LED
// - 0 is completely off, 255 is 100% on.
//
// Note: ledDriverInit should be called on the pin before calling this.
// -----------------------------------------------------------------------------
void analogWrite(uint8_t pin, uint8_t iOn);
void pwm(uint8_t pin, uint8_t iOn); // Legacy - use analogWrite
// -----------------------------------------------------------------------------
// setupBlink(uint8_t pin, uint8_t tOn, uint8_t tOff, uint8_t offIntensity, uint8_t tRise, uint8_t
// tFall): blink performs both the blink and breath LED driver functions.
//
// Inputs:
// - pin: the SX1509 pin (0-15) you want to set blinking/breathing.
// - tOn: the amount of time the pin is HIGH
// - This value should be between 1 and 31. 0 is off.
// - tOff: the amount of time the pin is at offIntensity
// - This value should be between 1 and 31. 0 is off.
// - offIntensity: How dim the LED is during the off period.
// - This value should be between 0 and 7. 0 is completely off.
// - onIntensity: How bright the LED will be when completely on.
// - This value can be between 0 (0%) and 255 (100%).
// - tRise: This sets the time the LED takes to fade in.
// - This value should be between 1 and 31. 0 is off.
// - This value is used with tFall to make the LED breath.
// - tFall: This sets the time the LED takes to fade out.
// - This value should be between 1 and 31. 0 is off.
// Notes:
// - The breathable pins are 4, 5, 6, 7, 12, 13, 14, 15 only. If tRise and
// tFall are set on 0-3 or 8-11 those pins will still only blink.
// - ledDriverInit should be called on the pin to be blinked before this.
// -----------------------------------------------------------------------------
void setupBlink(uint8_t pin, uint8_t tOn, uint8_t toff, uint8_t onIntensity = 255, uint8_t offIntensity = 0, uint8_t tRise = 0, uint8_t tFall = 0, bool log = false);
// -----------------------------------------------------------------------------
// blink(uint8_t pin, unsigned long tOn, unsigned long tOff, uint8_t onIntensity, uint8_t offIntensity);
// Set a pin to blink output for estimated on/off millisecond durations.
//
// Inputs:
// - pin: the SX1509 pin (0-15) you want to set blinking
// - tOn: estimated number of milliseconds the pin is LOW (LED sinking current will be on)
// - tOff: estimated number of milliseconds the pin is HIGH (LED sinking current will be off)
// - onIntensity: 0-255 value determining LED on brightness
// - offIntensity: 0-255 value determining LED off brightness
// Notes:
// - The breathable pins are 4, 5, 6, 7, 12, 13, 14, 15 only. If tRise and
// tFall are set on 0-3 or 8-11 those pins will still only blink.
// - ledDriverInit should be called on the pin to be blinked before this.
// -----------------------------------------------------------------------------
void blink(uint8_t pin, unsigned long tOn, unsigned long tOff, uint8_t onIntensity = 255, uint8_t offIntensity = 0);
// -----------------------------------------------------------------------------
// breathe(uint8_t pin, unsigned long tOn, unsigned long tOff, unsigned long rise, unsigned long fall, uint8_t onInt, uint8_t offInt, bool log);
// Set a pin to breathe output for estimated on/off millisecond durations, with
// estimated rise and fall durations.
//
// Inputs:
// - pin: the SX1509 pin (0-15) you want to set blinking
// - tOn: estimated number of milliseconds the pin is LOW (LED sinking current will be on)
// - tOff: estimated number of milliseconds the pin is HIGH (LED sinking current will be off)
// - rise: estimated number of milliseconds the pin rises from LOW to HIGH
// - falll: estimated number of milliseconds the pin falls from HIGH to LOW
// - onIntensity: 0-255 value determining LED on brightness
// - offIntensity: 0-255 value determining LED off brightness
// Notes:
// - The breathable pins are 4, 5, 6, 7, 12, 13, 14, 15 only. If tRise and
// tFall are set on 0-3 or 8-11 those pins will still only blink.
// - ledDriverInit should be called on the pin to be blinked before this,
// Or call pinMode(<pin>, ANALOG_OUTPUT);
// -----------------------------------------------------------------------------
void breathe(uint8_t pin, unsigned long tOn, unsigned long tOff, unsigned long rise, unsigned long fall, uint8_t onInt = 255, uint8_t offInt = 0, bool log = LINEAR);
// -----------------------------------------------------------------------------
// keypad(uint8_t rows, uint8_t columns, uint8_t sleepTime, uint8_t scanTime, uint8_t debounceTime)
// Initializes the keypad function on the SX1509. Millisecond durations for sleep,
// scan, and debounce can be set.
//
// Inputs:
// - rows: The number of rows in the button matrix.
// - This value must be between 1 and 7. 0 will turn it off.
// - eg: 1 = 2 rows, 2 = 3 rows, 7 = 8 rows, etc.
// - columns: The number of columns in the button matrix
// - This value should be between 0 and 7.
// - 0 = 1 column, 7 = 8 columns, etc.
// - sleepTime: Sets the auto-sleep time of the keypad engine.
// Should be a millisecond duration between 0 (OFF) and 8000 (8 seconds).
// Possible values are 0, 128, 256, 512, 1000, 2000, 4000, 8000
// - scanTime: Sets the scan time per row. Must be set above debounce.
// Should be a millisecond duration between 1 and 128.
// Possible values are 1, 2, 4, 8, 16, 32, 64, 128.
// - debounceTime: Sets the debounc time per button. Must be set below scan.
// Should be a millisecond duration between 0 and 64.
// Possible values are 0 (0.5), 1, 2, 4, 8, 16, 32, 64.
// -----------------------------------------------------------------------------
void keypad(uint8_t rows, uint8_t columns, uint16_t sleepTime = 0, uint8_t scanTime = 1, uint8_t debounceTime = 0);
// -----------------------------------------------------------------------------
// readKeypad(): This function returns a 16-bit value containing the status of
// keypad engine.
//
// Output:
// A 16-bit value is returned. The lower 8 bits represent the up-to 8 rows,
// while the MSB represents the up-to 8 columns. Bit-values of 1 indicate a
// button in that row or column is being pressed. As such, at least two
// bits should be set.
// -----------------------------------------------------------------------------
uint16_t readKeypad();
uint16_t readKeyData(); // Legacy: use readKeypad();
// -----------------------------------------------------------------------------
// getRow(): This function returns the first active row from the return value of
// readKeypad().
//
// Input:
// - keyData: Should be the uint16_t value returned from readKeypad().
// Output:
// A 16-bit value is returned. The lower 8 bits represent the up-to 8 rows,
// while the MSB represents the up-to 8 columns. Bit-values of 1 indicate a
// button in that row or column is being pressed. As such, at least two
// bits should be set.
// -----------------------------------------------------------------------------
uint8_t getRow(uint16_t keyData);
// -----------------------------------------------------------------------------
// getCol(): This function returns the first active column from the return value of
// readKeypad().
//
// Input:
// - keyData: Should be the uint16_t value returned from readKeypad().
// Output:
// A 16-bit value is returned. The lower 8 bits represent the up-to 8 rows,
// while the MSB represents the up-to 8 columns. Bit-values of 1 indicate a
// button in that row or column is being pressed. As such, at least two
// bits should be set.
// -----------------------------------------------------------------------------
uint8_t getCol(uint16_t keyData);
// -----------------------------------------------------------------------------
// sync(void): this function resets the PWM/Blink/Fade counters, syncing any
// blinking LEDs. Bit 2 of REG_MISC is set, which alters the functionality
// of the nReset pin. The nReset pin is toggled low->high, which should
// reset all LED counters. Bit 2 of REG_MISC is again cleared, returning
// nReset pin to POR functionality
// -----------------------------------------------------------------------------
void sync(void);
// -----------------------------------------------------------------------------
// debounceConfig(uint8_t configValue): This method configures the debounce time of
// every input.
//
// Input:
// - configValue: A 3-bit value configuring the debounce time.
// 000: 0.5ms * 2MHz/fOSC
// 001: 1ms * 2MHz/fOSC
// 010: 2ms * 2MHz/fOSC
// 011: 4ms * 2MHz/fOSC
// 100: 8ms * 2MHz/fOSC
// 101: 16ms * 2MHz/fOSC
// 110: 32ms * 2MHz/fOSC
// 111: 64ms * 2MHz/fOSC
//
// Note: fOSC is set with the configClock function. It defaults to 2MHz.
// -----------------------------------------------------------------------------
void debounceConfig(uint8_t configVaule);
// -----------------------------------------------------------------------------
// debounceTime(uint8_t configValue): This method configures the debounce time of
// every input to an estimated millisecond time duration.
//
// Input:
// - time: A millisecond duration estimating the debounce time. Actual
// debounce time will depend on fOSC. Assuming it's 2MHz, debounce will
// be set to the 0.5, 1, 2, 4, 8, 16, 32, or 64 ms (whatever's closest)
//
// Note: fOSC is set with the configClock function. It defaults to 2MHz.
// -----------------------------------------------------------------------------
void debounceTime(uint8_t time);
// -----------------------------------------------------------------------------
// debouncePin(uint8_t pin): This method enables debounce on SX1509 input pin.
//
// Input:
// - pin: The SX1509 pin to be debounced. Should be between 0 and 15.
// -----------------------------------------------------------------------------
void debouncePin(uint8_t pin);
void debounceEnable(uint8_t pin); // Legacy, use debouncePin
// -----------------------------------------------------------------------------
// debounceKeypad(uint8_t pin): This method enables debounce on all pins connected
// to a row/column keypad matrix.
//
// Input:
// - time: Millisecond time estimate for debounce (see debounceTime()).
// - numRows: The number of rows in the keypad matrix.
// - numCols: The number of columns in the keypad matrix.
// -----------------------------------------------------------------------------
void debounceKeypad(uint8_t time, uint8_t numRows, uint8_t numCols);
// -----------------------------------------------------------------------------
// enableInterrupt(uint8_t pin, uint8_t riseFall): This function sets up an interrupt
// on a pin. Interrupts can occur on all SX1509 pins, and can be generated
// on rising, falling, or both.
//
// Inputs:
// -pin: SX1509 input pin that will generate an input. Should be 0-15.
// -riseFall: Configures if you want an interrupt generated on rise fall or
// both. For this param, send the pin-change values previously defined
// by Arduino:
// #define CHANGE 1 <-Both
// #define FALLING 2 <- Falling
// #define RISING 3 <- Rising
//
// Note: This function does not set up a pin as an input, or configure its
// pull-up/down resistors! Do that before (or after).
// -----------------------------------------------------------------------------
void enableInterrupt(uint8_t pin, uint8_t riseFall);
// -----------------------------------------------------------------------------
// interruptSource(void): Returns an uint16_t representing which pin caused
// an interrupt.
//
// Output: 16-bit value, with a single bit set representing the pin(s) that
// generated an interrupt. E.g. a return value of 0x0104 would mean pins 8
// and 3 (bits 8 and 3) have generated an interrupt.
// Input:
// - clear: boolean commanding whether the interrupt should be cleared
// after reading or not.
// -----------------------------------------------------------------------------
uint16_t interruptSource(bool clear = true);
// -----------------------------------------------------------------------------
// checkInterrupt(void): Checks if a single pin generated an interrupt.
//
// Output: Boolean value. True if the requested pin has triggered an interrupt/
// Input:
// - pin: Pin to be checked for generating an input.
// -----------------------------------------------------------------------------
bool checkInterrupt(uint8_t pin);
// -----------------------------------------------------------------------------
// configClock(uint8_t oscSource, uint8_t oscPinFunction, uint8_t oscFreqOut, uint8_t oscDivider)
// This function configures the oscillator source/speed
// and the clock, which is used to drive LEDs and time debounces.
//
// Inputs:
// - oscSource: Choose either internal 2MHz oscillator or an external signal
// applied to the OSCIO pin.
// - INTERNAL_CLOCK and EXTERNAL_CLOCK are defined in the header file.
// Use those.
// - This value defaults to internal.
// - oscDivider: Sets the clock divider in REG_MISC.
// - ClkX = fOSC / (2^(RegMisc[6:4] -1))
// - This value defaults to 1.
// - oscPinFunction: Allows you to set OSCIO as an input or output.
// - You can use Arduino's INPUT, OUTPUT defines for this value
// - This value defaults to input
// - oscFreqOut: If oscio is configured as an output, this will set the output
// frequency
// - This should be a 4-bit value. 0=0%, 0xF=100%, else
// fOSCOut = FOSC / (2^(RegClock[3:0]-1))
// - This value defaults to 0.
// -----------------------------------------------------------------------------
void configClock(uint8_t oscSource = 2, uint8_t oscPinFunction = 0, uint8_t oscFreqOut = 0, uint8_t oscDivider = 1); // Legacy, use clock();
// -----------------------------------------------------------------------------
// clock(uint8_t oscSource, uint8_t oscDivider, uint8_t oscPinFunction, uint8_t oscFreqOut)
// This function configures the oscillator source/speed
// and the clock, which is used to drive LEDs and time debounces.
// This is just configClock in a bit more sane order.
//
// -----------------------------------------------------------------------------
void clock(uint8_t oscSource = 2, uint8_t oscDivider = 1, uint8_t oscPinFunction = 0, uint8_t oscFreqOut = 0);
};
// Add backwards compatibility for the old class name: sx1509Class
typedef SX1509 sx1509Class;
#endif // SX1509_library_H
@@ -0,0 +1,163 @@
/******************************************************************************
sx1509_registers.h
Register definitions for SX1509.
Jim Lindblom @ SparkFun Electronics
Original Creation Date: September 21, 2015
https://github.com/sparkfun/SparkFun_SX1509_Arduino_Library
Here you'll find the Arduino code used to interface with the SX1509 I2C
16 I/O expander. There are functions to take advantage of everything the
SX1509 provides - input/output setting, writing pins high/low, reading
the input value of pins, LED driver utilities (blink, breath, pwm), and
keypad engine utilites.
Development environment specifics:
IDE: Arduino 1.6.5
Hardware Platform: Arduino Uno
SX1509 Breakout Version: v2.0
This code is beerware; if you see me (or any other SparkFun employee) at the
local, and you've found our code helpful, please buy us a round!
Distributed as-is; no warranty is given.
******************************************************************************/
#define REG_INPUT_DISABLE_B 0x00 // RegInputDisableB Input buffer disable register _ I/O[15_8] (Bank B) 0000 0000
#define REG_INPUT_DISABLE_A 0x01 // RegInputDisableA Input buffer disable register _ I/O[7_0] (Bank A) 0000 0000
#define REG_LONG_SLEW_B 0x02 // RegLongSlewB Output buffer long slew register _ I/O[15_8] (Bank B) 0000 0000
#define REG_LONG_SLEW_A 0x03 // RegLongSlewA Output buffer long slew register _ I/O[7_0] (Bank A) 0000 0000
#define REG_LOW_DRIVE_B 0x04 // RegLowDriveB Output buffer low drive register _ I/O[15_8] (Bank B) 0000 0000
#define REG_LOW_DRIVE_A 0x05 // RegLowDriveA Output buffer low drive register _ I/O[7_0] (Bank A) 0000 0000
#define REG_PULL_UP_B 0x06 // RegPullUpB Pull_up register _ I/O[15_8] (Bank B) 0000 0000
#define REG_PULL_UP_A 0x07 // RegPullUpA Pull_up register _ I/O[7_0] (Bank A) 0000 0000
#define REG_PULL_DOWN_B 0x08 // RegPullDownB Pull_down register _ I/O[15_8] (Bank B) 0000 0000
#define REG_PULL_DOWN_A 0x09 // RegPullDownA Pull_down register _ I/O[7_0] (Bank A) 0000 0000
#define REG_OPEN_DRAIN_B 0x0A // RegOpenDrainB Open drain register _ I/O[15_8] (Bank B) 0000 0000
#define REG_OPEN_DRAIN_A 0x0B // RegOpenDrainA Open drain register _ I/O[7_0] (Bank A) 0000 0000
#define REG_POLARITY_B 0x0C // RegPolarityB Polarity register _ I/O[15_8] (Bank B) 0000 0000
#define REG_POLARITY_A 0x0D // RegPolarityA Polarity register _ I/O[7_0] (Bank A) 0000 0000
#define REG_DIR_B 0x0E // RegDirB Direction register _ I/O[15_8] (Bank B) 1111 1111
#define REG_DIR_A 0x0F // RegDirA Direction register _ I/O[7_0] (Bank A) 1111 1111
#define REG_DATA_B 0x10 // RegDataB Data register _ I/O[15_8] (Bank B) 1111 1111*
#define REG_DATA_A 0x11 // RegDataA Data register _ I/O[7_0] (Bank A) 1111 1111*
#define REG_INTERRUPT_MASK_B 0x12 // RegInterruptMaskB Interrupt mask register _ I/O[15_8] (Bank B) 1111 1111
#define REG_INTERRUPT_MASK_A 0x13 // RegInterruptMaskA Interrupt mask register _ I/O[7_0] (Bank A) 1111 1111
#define REG_SENSE_HIGH_B 0x14 // RegSenseHighB Sense register for I/O[15:12] 0000 0000
#define REG_SENSE_LOW_B 0x15 // RegSenseLowB Sense register for I/O[11:8] 0000 0000
#define REG_SENSE_HIGH_A 0x16 // RegSenseHighA Sense register for I/O[7:4] 0000 0000
#define REG_SENSE_LOW_A 0x17 // RegSenseLowA Sense register for I/O[3:0] 0000 0000
#define REG_INTERRUPT_SOURCE_B 0x18 // RegInterruptSourceB Interrupt source register _ I/O[15_8] (Bank B) 0000 0000
#define REG_INTERRUPT_SOURCE_A 0x19 // RegInterruptSourceA Interrupt source register _ I/O[7_0] (Bank A) 0000 0000
#define REG_EVENT_STATUS_B 0x1A // RegEventStatusB Event status register _ I/O[15_8] (Bank B) 0000 0000
#define REG_EVENT_STATUS_A 0x1B // RegEventStatusA Event status register _ I/O[7_0] (Bank A) 0000 0000
#define REG_LEVEL_SHIFTER_1 0x1C // RegLevelShifter1 Level shifter register 0000 0000
#define REG_LEVEL_SHIFTER_2 0x1D // RegLevelShifter2 Level shifter register 0000 0000
#define REG_CLOCK 0x1E // RegClock Clock management register 0000 0000
#define REG_MISC 0x1F // RegMisc Miscellaneous device settings register 0000 0000
#define REG_LED_DRIVER_ENABLE_B 0x20 // RegLEDDriverEnableB LED driver enable register _ I/O[15_8] (Bank B) 0000 0000
#define REG_LED_DRIVER_ENABLE_A 0x21 // RegLEDDriverEnableA LED driver enable register _ I/O[7_0] (Bank A) 0000 0000
// Debounce and Keypad Engine
#define REG_DEBOUNCE_CONFIG 0x22 // RegDebounceConfig Debounce configuration register 0000 0000
#define REG_DEBOUNCE_ENABLE_B 0x23 // RegDebounceEnableB Debounce enable register _ I/O[15_8] (Bank B) 0000 0000
#define REG_DEBOUNCE_ENABLE_A 0x24 // RegDebounceEnableA Debounce enable register _ I/O[7_0] (Bank A) 0000 0000
#define REG_KEY_CONFIG_1 0x25 // RegKeyConfig1 Key scan configuration register 0000 0000
#define REG_KEY_CONFIG_2 0x26 // RegKeyConfig2 Key scan configuration register 0000 0000
#define REG_KEY_DATA_1 0x27 // RegKeyData1 Key value (column) 1111 1111
#define REG_KEY_DATA_2 0x28 // RegKeyData2 Key value (row) 1111 1111
// LED Driver (PWM, blinking, breathing)
#define REG_T_ON_0 0x29 // RegTOn0 ON time register for I/O[0] 0000 0000
#define REG_I_ON_0 0x2A // RegIOn0 ON intensity register for I/O[0] 1111 1111
#define REG_OFF_0 0x2B // RegOff0 OFF time/intensity register for I/O[0] 0000 0000
#define REG_T_ON_1 0x2C // RegTOn1 ON time register for I/O[1] 0000 0000
#define REG_I_ON_1 0x2D // RegIOn1 ON intensity register for I/O[1] 1111 1111
#define REG_OFF_1 0x2E // RegOff1 OFF time/intensity register for I/O[1] 0000 0000
#define REG_T_ON_2 0x2F // RegTOn2 ON time register for I/O[2] 0000 0000
#define REG_I_ON_2 0x30 // RegIOn2 ON intensity register for I/O[2] 1111 1111
#define REG_OFF_2 0x31 // RegOff2 OFF time/intensity register for I/O[2] 0000 0000
#define REG_T_ON_3 0x32 // RegTOn3 ON time register for I/O[3] 0000 0000
#define REG_I_ON_3 0x33 // RegIOn3 ON intensity register for I/O[3] 1111 1111
#define REG_OFF_3 0x34 // RegOff3 OFF time/intensity register for I/O[3] 0000 0000
#define REG_T_ON_4 0x35 // RegTOn4 ON time register for I/O[4] 0000 0000
#define REG_I_ON_4 0x36 // RegIOn4 ON intensity register for I/O[4] 1111 1111
#define REG_OFF_4 0x37 // RegOff4 OFF time/intensity register for I/O[4] 0000 0000
#define REG_T_RISE_4 0x38 // RegTRise4 Fade in register for I/O[4] 0000 0000
#define REG_T_FALL_4 0x39 // RegTFall4 Fade out register for I/O[4] 0000 0000
#define REG_T_ON_5 0x3A // RegTOn5 ON time register for I/O[5] 0000 0000
#define REG_I_ON_5 0x3B // RegIOn5 ON intensity register for I/O[5] 1111 1111
#define REG_OFF_5 0x3C // RegOff5 OFF time/intensity register for I/O[5] 0000 0000
#define REG_T_RISE_5 0x3D // RegTRise5 Fade in register for I/O[5] 0000 0000
#define REG_T_FALL_5 0x3E // RegTFall5 Fade out register for I/O[5] 0000 0000
#define REG_T_ON_6 0x3F // RegTOn6 ON time register for I/O[6] 0000 0000
#define REG_I_ON_6 0x40 // RegIOn6 ON intensity register for I/O[6] 1111 1111
#define REG_OFF_6 0x41 // RegOff6 OFF time/intensity register for I/O[6] 0000 0000
#define REG_T_RISE_6 0x42 // RegTRise6 Fade in register for I/O[6] 0000 0000
#define REG_T_FALL_6 0x43 // RegTFall6 Fade out register for I/O[6] 0000 0000
#define REG_T_ON_7 0x44 // RegTOn7 ON time register for I/O[7] 0000 0000
#define REG_I_ON_7 0x45 // RegIOn7 ON intensity register for I/O[7] 1111 1111
#define REG_OFF_7 0x46 // RegOff7 OFF time/intensity register for I/O[7] 0000 0000
#define REG_T_RISE_7 0x47 // RegTRise7 Fade in register for I/O[7] 0000 0000
#define REG_T_FALL_7 0x48 // RegTFall7 Fade out register for I/O[7] 0000 0000
#define REG_T_ON_8 0x49 // RegTOn8 ON time register for I/O[8] 0000 0000
#define REG_I_ON_8 0x4A // RegIOn8 ON intensity register for I/O[8] 1111 1111
#define REG_OFF_8 0x4B // RegOff8 OFF time/intensity register for I/O[8] 0000 0000
#define REG_T_ON_9 0x4C // RegTOn9 ON time register for I/O[9] 0000 0000
#define REG_I_ON_9 0x4D // RegIOn9 ON intensity register for I/O[9] 1111 1111
#define REG_OFF_9 0x4E // RegOff9 OFF time/intensity register for I/O[9] 0000 0000
#define REG_T_ON_10 0x4F // RegTOn10 ON time register for I/O[10] 0000 0000
#define REG_I_ON_10 0x50 // RegIOn10 ON intensity register for I/O[10] 1111 1111
#define REG_OFF_10 0x51 // RegOff10 OFF time/intensity register for I/O[10] 0000 0000
#define REG_T_ON_11 0x52 // RegTOn11 ON time register for I/O[11] 0000 0000
#define REG_I_ON_11 0x53 // RegIOn11 ON intensity register for I/O[11] 1111 1111
#define REG_OFF_11 0x54 // RegOff11 OFF time/intensity register for I/O[11] 0000 0000
#define REG_T_ON_12 0x55 // RegTOn12 ON time register for I/O[12] 0000 0000
#define REG_I_ON_12 0x56 // RegIOn12 ON intensity register for I/O[12] 1111 1111
#define REG_OFF_12 0x57 // RegOff12 OFF time/intensity register for I/O[12] 0000 0000
#define REG_T_RISE_12 0x58 // RegTRise12 Fade in register for I/O[12] 0000 0000
#define REG_T_FALL_12 0x59 // RegTFall12 Fade out register for I/O[12] 0000 0000
#define REG_T_ON_13 0x5A // RegTOn13 ON time register for I/O[13] 0000 0000
#define REG_I_ON_13 0x5B // RegIOn13 ON intensity register for I/O[13] 1111 1111
#define REG_OFF_13 0x5C // RegOff13 OFF time/intensity register for I/O[13] 0000 0000
#define REG_T_RISE_13 0x5D // RegTRise13 Fade in register for I/O[13] 0000 0000
#define REG_T_FALL_13 0x5E // RegTFall13 Fade out register for I/O[13] 0000 0000
#define REG_T_ON_14 0x5F // RegTOn14 ON time register for I/O[14] 0000 0000
#define REG_I_ON_14 0x60 // RegIOn14 ON intensity register for I/O[14] 1111 1111
#define REG_OFF_14 0x61 // RegOff14 OFF time/intensity register for I/O[14] 0000 0000
#define REG_T_RISE_14 0x62 // RegTRise14 Fade in register for I/O[14] 0000 0000
#define REG_T_FALL_14 0x63 // RegTFall14 Fade out register for I/O[14] 0000 0000
#define REG_T_ON_15 0x64 // RegTOn15 ON time register for I/O[15] 0000 0000
#define REG_I_ON_15 0x65 // RegIOn15 ON intensity register for I/O[15] 1111 1111
#define REG_OFF_15 0x66 // RegOff15 OFF time/intensity register for I/O[15] 0000 0000
#define REG_T_RISE_15 0x67 // RegTRise15 Fade in register for I/O[15] 0000 0000
#define REG_T_FALL_15 0x68 // RegTFall15 Fade out register for I/O[15] 0000 0000
// Miscellaneous
#define REG_HIGH_INPUT_B 0x69 // RegHighInputB High input enable register _ I/O[15_8] (Bank B) 0000 0000
#define REG_HIGH_INPUT_A 0x6A // RegHighInputA High input enable register _ I/O[7_0] (Bank A) 0000 0000
// Software Reset
#define REG_RESET 0x7D // RegReset Software reset register 0000 0000
#define REG_TEST_1 0x7E // RegTest1 Test register 0000 0000
#define REG_TEST_2 0x7F // RegTest2 Test register 0000 0000
byte REG_I_ON[16] = {REG_I_ON_0, REG_I_ON_1, REG_I_ON_2, REG_I_ON_3,
REG_I_ON_4, REG_I_ON_5, REG_I_ON_6, REG_I_ON_7,
REG_I_ON_8, REG_I_ON_9, REG_I_ON_10, REG_I_ON_11,
REG_I_ON_12, REG_I_ON_13, REG_I_ON_14, REG_I_ON_15};
byte REG_T_ON[16] = {REG_T_ON_0, REG_T_ON_1, REG_T_ON_2, REG_T_ON_3,
REG_T_ON_4, REG_T_ON_5, REG_T_ON_6, REG_T_ON_7,
REG_T_ON_8, REG_T_ON_9, REG_T_ON_10, REG_T_ON_11,
REG_T_ON_12, REG_T_ON_13, REG_T_ON_14, REG_T_ON_15};
byte REG_OFF[16] = {REG_OFF_0, REG_OFF_1, REG_OFF_2, REG_OFF_3,
REG_OFF_4, REG_OFF_5, REG_OFF_6, REG_OFF_7,
REG_OFF_8, REG_OFF_9, REG_OFF_10, REG_OFF_11,
REG_OFF_12, REG_OFF_13, REG_OFF_14, REG_OFF_15};
byte REG_T_RISE[16] = {0xFF, 0xFF, 0xFF, 0xFF,
REG_T_RISE_4, REG_T_RISE_5, REG_T_RISE_6, REG_T_RISE_7,
0xFF, 0xFF, 0xFF, 0xFF,
REG_T_RISE_12, REG_T_RISE_13, REG_T_RISE_14, REG_T_RISE_15};
byte REG_T_FALL[16] = {0xFF, 0xFF, 0xFF, 0xFF,
REG_T_FALL_4, REG_T_FALL_5, REG_T_FALL_6, REG_T_FALL_7,
0xFF, 0xFF, 0xFF, 0xFF,
REG_T_FALL_12, REG_T_FALL_13, REG_T_FALL_14, REG_T_FALL_15};