2016-04-24 08:26:22 +02:00
|
|
|
//
|
|
|
|
// FILE: PCA9635.cpp
|
|
|
|
// AUTHOR: Rob Tillaart
|
|
|
|
// DATE: 23-apr-2016
|
2023-09-24 14:21:39 +02:00
|
|
|
// VERSION: 0.4.7
|
|
|
|
// PURPOSE: Arduino library for PCA9635 I2C LED driver, 16 channel PWM, 8 bit
|
2020-11-27 11:28:57 +01:00
|
|
|
// URL: https://github.com/RobTillaart/PCA9635
|
2016-04-24 08:26:22 +02:00
|
|
|
|
2022-06-02 12:11:57 +02:00
|
|
|
|
2021-01-29 12:31:58 +01:00
|
|
|
#include "PCA9635.h"
|
2016-04-24 08:26:22 +02:00
|
|
|
|
2020-11-27 11:28:57 +01:00
|
|
|
|
2021-01-29 12:31:58 +01:00
|
|
|
//////////////////////////////////////////////////////////////
|
|
|
|
//
|
2023-09-24 14:21:39 +02:00
|
|
|
// CONSTRUCTOR
|
2021-01-29 12:31:58 +01:00
|
|
|
//
|
|
|
|
PCA9635::PCA9635(const uint8_t deviceAddress, TwoWire *wire)
|
2016-04-24 08:26:22 +02:00
|
|
|
{
|
2023-03-07 16:18:49 +01:00
|
|
|
_address = deviceAddress;
|
|
|
|
_wire = wire;
|
|
|
|
_channelCount = 16;
|
2023-05-07 18:51:32 +02:00
|
|
|
_error = PCA963X_OK;
|
2023-03-07 16:18:49 +01:00
|
|
|
_OutputEnablePin = 255;
|
2020-11-27 11:28:57 +01:00
|
|
|
}
|
|
|
|
|
2021-01-29 12:31:58 +01:00
|
|
|
|
2020-11-27 11:28:57 +01:00
|
|
|
#if defined (ESP8266) || defined(ESP32)
|
2022-09-10 20:47:37 +02:00
|
|
|
bool PCA9635::begin(int sda, int scl, uint8_t mode1_mask, uint8_t mode2_mask)
|
2020-11-27 11:28:57 +01:00
|
|
|
{
|
2021-01-29 12:31:58 +01:00
|
|
|
if ((sda < 255) && (scl < 255))
|
|
|
|
{
|
|
|
|
_wire->begin(sda, scl);
|
|
|
|
} else {
|
|
|
|
_wire->begin();
|
|
|
|
}
|
|
|
|
if (! isConnected()) return false;
|
2022-06-02 12:11:57 +02:00
|
|
|
configure(mode1_mask, mode2_mask);
|
2021-01-29 12:31:58 +01:00
|
|
|
return true;
|
2020-11-27 11:28:57 +01:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2021-01-29 12:31:58 +01:00
|
|
|
|
2022-06-02 12:11:57 +02:00
|
|
|
bool PCA9635::begin(uint8_t mode1_mask, uint8_t mode2_mask)
|
2020-11-27 11:28:57 +01:00
|
|
|
{
|
2021-01-29 12:31:58 +01:00
|
|
|
_wire->begin();
|
|
|
|
if (! isConnected()) return false;
|
2022-06-02 12:11:57 +02:00
|
|
|
configure(mode1_mask, mode2_mask);
|
2021-01-29 12:31:58 +01:00
|
|
|
return true;
|
2020-11-27 11:28:57 +01:00
|
|
|
}
|
|
|
|
|
2021-01-29 12:31:58 +01:00
|
|
|
|
2023-05-07 18:51:32 +02:00
|
|
|
bool PCA9635::isConnected()
|
|
|
|
{
|
|
|
|
_wire->beginTransmission(_address);
|
|
|
|
_error = _wire->endTransmission();
|
|
|
|
return (_error == 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// CONFIGURATION
|
|
|
|
//
|
2023-03-07 16:18:49 +01:00
|
|
|
uint8_t PCA9635::configure(uint8_t mode1_mask, uint8_t mode2_mask)
|
|
|
|
{
|
2023-05-07 18:51:32 +02:00
|
|
|
_error = PCA963X_OK;
|
2023-03-07 16:18:49 +01:00
|
|
|
|
|
|
|
uint8_t r1 = setMode1(mode1_mask);
|
|
|
|
uint8_t r2 = setMode2(mode2_mask);
|
|
|
|
|
2023-05-07 18:51:32 +02:00
|
|
|
if ((r1 != PCA963X_OK) || (r2 != PCA963X_OK))
|
2023-03-07 16:18:49 +01:00
|
|
|
{
|
2023-05-07 18:51:32 +02:00
|
|
|
return PCA963X_ERROR;
|
2023-03-07 16:18:49 +01:00
|
|
|
}
|
|
|
|
return _error;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-05-07 18:51:32 +02:00
|
|
|
uint8_t PCA9635::channelCount()
|
2021-01-29 12:31:58 +01:00
|
|
|
{
|
2023-05-07 18:51:32 +02:00
|
|
|
return _channelCount;
|
2021-01-29 12:31:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-05-07 18:51:32 +02:00
|
|
|
/////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// LED DRIVER MODE
|
|
|
|
//
|
|
|
|
uint8_t PCA9635::setLedDriverMode(uint8_t channel, uint8_t mode)
|
2020-11-27 11:28:57 +01:00
|
|
|
{
|
2023-05-07 18:51:32 +02:00
|
|
|
if (channel >= _channelCount)
|
|
|
|
{
|
|
|
|
_error = PCA963X_ERR_CHAN;
|
|
|
|
return _error;
|
|
|
|
}
|
|
|
|
if (mode > 3)
|
|
|
|
{
|
|
|
|
_error = PCA963X_ERR_MODE;
|
|
|
|
return _error;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t reg = PCA963X_LEDOUT_BASE + (channel >> 2);
|
|
|
|
// some bit magic
|
|
|
|
uint8_t shift = (channel & 0x03) * 2; // 0,2,4,6 places
|
|
|
|
uint8_t setmask = mode << shift;
|
|
|
|
uint8_t clrmask = ~(0x03 << shift);
|
|
|
|
uint8_t value = (readReg(reg) & clrmask) | setmask;
|
|
|
|
writeReg(reg, value);
|
|
|
|
_error = PCA963X_OK;
|
|
|
|
return _error;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// returns 0..3 if OK, other values indicate an error
|
|
|
|
uint8_t PCA9635::getLedDriverMode(uint8_t channel)
|
|
|
|
{
|
|
|
|
if (channel >= _channelCount)
|
|
|
|
{
|
|
|
|
_error = PCA963X_ERR_CHAN;
|
|
|
|
return _error;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t reg = PCA963X_LEDOUT_BASE + (channel >> 2);
|
|
|
|
uint8_t shift = (channel & 0x03) * 2; // 0, 2, 4, 6 places
|
|
|
|
uint8_t value = (readReg(reg) >> shift ) & 0x03;
|
|
|
|
_error = PCA963X_OK;
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// WRITE MODE
|
|
|
|
//
|
|
|
|
uint8_t PCA9635::writeMode(uint8_t reg, uint8_t value)
|
|
|
|
{
|
|
|
|
if ((reg == PCA963X_MODE1) || (reg == PCA963X_MODE2))
|
|
|
|
{
|
|
|
|
writeReg(reg, value);
|
|
|
|
return PCA963X_OK;
|
|
|
|
}
|
|
|
|
_error = PCA963X_ERR_REG;
|
|
|
|
return _error;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Note 0xFF can also mean an error.... ==> check error flag
|
|
|
|
uint8_t PCA9635::readMode(uint8_t reg)
|
|
|
|
{
|
|
|
|
if ((reg == PCA963X_MODE1) || (reg == PCA963X_MODE2))
|
|
|
|
{
|
|
|
|
_error = PCA963X_OK;
|
|
|
|
uint8_t value = readReg(reg);
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
_error = PCA963X_ERR_REG;
|
|
|
|
return _error;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint8_t PCA9635::setMode1(uint8_t value)
|
|
|
|
{
|
|
|
|
return writeMode(PCA963X_MODE1, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint8_t PCA9635::setMode2(uint8_t value)
|
|
|
|
{
|
|
|
|
return writeMode(PCA963X_MODE2, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint8_t PCA9635::getMode1()
|
|
|
|
{
|
|
|
|
return readMode(PCA963X_MODE1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint8_t PCA9635::getMode2()
|
|
|
|
{
|
|
|
|
return readMode(PCA963X_MODE2);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// GROUP PWM
|
|
|
|
//
|
|
|
|
void PCA9635::setGroupPWM(uint8_t value)
|
|
|
|
{
|
|
|
|
writeReg(PCA963X_GRPPWM, value);
|
2016-04-24 08:26:22 +02:00
|
|
|
}
|
|
|
|
|
2021-01-29 12:31:58 +01:00
|
|
|
|
2023-05-07 18:51:32 +02:00
|
|
|
uint8_t PCA9635::getGroupPWM()
|
|
|
|
{
|
|
|
|
return readReg(PCA963X_GRPPWM);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void PCA9635::setGroupFREQ(uint8_t value)
|
|
|
|
{
|
|
|
|
writeReg(PCA963X_GRPFREQ, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint8_t PCA9635::getGroupFREQ()
|
|
|
|
{
|
|
|
|
return readReg(PCA963X_GRPFREQ);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// WRITE
|
|
|
|
//
|
2022-11-19 16:54:49 +01:00
|
|
|
// write value to single PWM registers
|
2020-11-27 11:28:57 +01:00
|
|
|
uint8_t PCA9635::write1(uint8_t channel, uint8_t value)
|
2016-04-24 08:26:22 +02:00
|
|
|
{
|
2020-11-27 11:28:57 +01:00
|
|
|
return writeN(channel, &value, 1);
|
2016-04-24 08:26:22 +02:00
|
|
|
}
|
|
|
|
|
2021-01-29 12:31:58 +01:00
|
|
|
|
2022-11-19 16:54:49 +01:00
|
|
|
// write three values in consecutive PWM registers
|
|
|
|
// typically for RGB values
|
2020-11-27 11:28:57 +01:00
|
|
|
uint8_t PCA9635::write3(uint8_t channel, uint8_t R, uint8_t G, uint8_t B)
|
2016-04-24 08:26:22 +02:00
|
|
|
{
|
2020-11-27 11:28:57 +01:00
|
|
|
uint8_t arr[3] = { R, G, B };
|
|
|
|
return writeN(channel, arr, 3);
|
2016-04-24 08:26:22 +02:00
|
|
|
}
|
|
|
|
|
2021-01-29 12:31:58 +01:00
|
|
|
|
2022-11-19 16:54:49 +01:00
|
|
|
// write count values in consecutive PWM registers
|
|
|
|
// checks if [channel + count - 1 > 15]
|
2020-11-27 11:28:57 +01:00
|
|
|
uint8_t PCA9635::writeN(uint8_t channel, uint8_t* arr, uint8_t count)
|
2016-04-24 08:26:22 +02:00
|
|
|
{
|
2022-01-06 20:19:35 +01:00
|
|
|
if (channel + count > _channelCount)
|
2020-11-27 11:28:57 +01:00
|
|
|
{
|
2023-05-07 18:51:32 +02:00
|
|
|
_error = PCA963X_ERR_CHAN;
|
|
|
|
return PCA963X_ERROR;
|
2020-11-27 11:28:57 +01:00
|
|
|
}
|
2023-05-07 18:51:32 +02:00
|
|
|
uint8_t base = PCA963X_PWM(channel);
|
2021-01-29 12:31:58 +01:00
|
|
|
_wire->beginTransmission(_address);
|
|
|
|
_wire->write(base);
|
2020-11-27 11:28:57 +01:00
|
|
|
for(uint8_t i = 0; i < count; i++)
|
|
|
|
{
|
2021-01-29 12:31:58 +01:00
|
|
|
_wire->write(arr[i]);
|
2020-11-27 11:28:57 +01:00
|
|
|
}
|
2021-01-29 12:31:58 +01:00
|
|
|
_error = _wire->endTransmission();
|
2020-11-27 11:28:57 +01:00
|
|
|
if (_error != 0)
|
|
|
|
{
|
2023-05-07 18:51:32 +02:00
|
|
|
_error = PCA963X_ERR_I2C;
|
|
|
|
return PCA963X_ERROR;
|
2020-11-27 11:28:57 +01:00
|
|
|
}
|
2023-05-07 18:51:32 +02:00
|
|
|
_error = PCA963X_OK;
|
2023-03-07 16:18:49 +01:00
|
|
|
return _error;
|
2016-04-24 08:26:22 +02:00
|
|
|
}
|
|
|
|
|
2021-01-29 12:31:58 +01:00
|
|
|
|
2023-05-07 18:51:32 +02:00
|
|
|
uint8_t PCA9635::writeN_noStop(uint8_t channel, uint8_t* arr, uint8_t count)
|
2016-04-24 08:26:22 +02:00
|
|
|
{
|
2023-05-07 18:51:32 +02:00
|
|
|
if (channel + count > _channelCount)
|
2020-11-27 11:28:57 +01:00
|
|
|
{
|
2023-05-07 18:51:32 +02:00
|
|
|
_error = PCA963X_ERR_WRITE;
|
|
|
|
return PCA963X_ERROR;
|
2020-11-27 11:28:57 +01:00
|
|
|
}
|
2023-05-07 18:51:32 +02:00
|
|
|
uint8_t base = PCA963X_PWM(channel);
|
|
|
|
_wire->beginTransmission(_address);
|
|
|
|
_wire->write(base);
|
|
|
|
for(uint8_t i = 0; i < count; i++)
|
2020-11-27 11:28:57 +01:00
|
|
|
{
|
2023-05-07 18:51:32 +02:00
|
|
|
_wire->write(arr[i]);
|
2020-11-27 11:28:57 +01:00
|
|
|
}
|
2023-05-07 18:51:32 +02:00
|
|
|
// OK so far
|
|
|
|
return PCA963X_OK;
|
2016-04-24 08:26:22 +02:00
|
|
|
}
|
|
|
|
|
2021-01-29 12:31:58 +01:00
|
|
|
|
2023-05-07 18:51:32 +02:00
|
|
|
uint8_t PCA9635::writeStop()
|
2016-04-24 08:26:22 +02:00
|
|
|
{
|
2023-05-07 18:51:32 +02:00
|
|
|
_error = _wire->endTransmission();
|
|
|
|
if (_error != 0)
|
2020-11-27 11:28:57 +01:00
|
|
|
{
|
2023-05-07 18:51:32 +02:00
|
|
|
_error = PCA963X_ERR_I2C;
|
|
|
|
return PCA963X_ERROR;
|
2020-11-27 11:28:57 +01:00
|
|
|
}
|
2023-05-07 18:51:32 +02:00
|
|
|
return PCA963X_OK;
|
2016-04-24 08:26:22 +02:00
|
|
|
}
|
|
|
|
|
2021-01-29 12:31:58 +01:00
|
|
|
|
2023-03-07 16:18:49 +01:00
|
|
|
/////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// ERROR
|
|
|
|
//
|
2016-04-24 08:26:22 +02:00
|
|
|
int PCA9635::lastError()
|
|
|
|
{
|
2020-11-27 11:28:57 +01:00
|
|
|
int e = _error;
|
2023-05-07 18:51:32 +02:00
|
|
|
_error = PCA963X_OK;
|
2020-11-27 11:28:57 +01:00
|
|
|
return e;
|
2016-04-24 08:26:22 +02:00
|
|
|
}
|
|
|
|
|
2020-11-27 11:28:57 +01:00
|
|
|
|
2022-06-02 12:11:57 +02:00
|
|
|
/////////////////////////////////////////////////////
|
|
|
|
//
|
2022-11-19 16:54:49 +01:00
|
|
|
// SUB CALL - ALL CALL
|
2022-06-02 12:11:57 +02:00
|
|
|
//
|
|
|
|
bool PCA9635::enableSubCall(uint8_t nr)
|
|
|
|
{
|
|
|
|
if ((nr == 0) || (nr > 3)) return false;
|
|
|
|
uint8_t prev = getMode1();
|
2023-03-07 16:18:49 +01:00
|
|
|
uint8_t mask = prev;
|
2023-05-26 16:22:43 +02:00
|
|
|
if (nr == 1) mask |= PCA963X_MODE1_SUB1;
|
|
|
|
else if (nr == 2) mask |= PCA963X_MODE1_SUB2;
|
|
|
|
else mask |= PCA963X_MODE1_SUB3;
|
2022-06-02 12:11:57 +02:00
|
|
|
// only update if changed.
|
2023-03-07 16:18:49 +01:00
|
|
|
if (mask != prev)
|
|
|
|
{
|
|
|
|
setMode1(mask);
|
|
|
|
// TODO error handling ...
|
|
|
|
}
|
2022-06-02 12:11:57 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool PCA9635::disableSubCall(uint8_t nr)
|
|
|
|
{
|
|
|
|
if ((nr == 0) || (nr > 3)) return false;
|
|
|
|
uint8_t prev = getMode1();
|
2023-03-07 16:18:49 +01:00
|
|
|
uint8_t mask = prev;
|
2023-05-26 16:22:43 +02:00
|
|
|
if (nr == 1) mask &= ~PCA963X_MODE1_SUB1;
|
|
|
|
else if (nr == 2) mask &= ~PCA963X_MODE1_SUB2;
|
|
|
|
else mask &= ~PCA963X_MODE1_SUB3;
|
2022-06-02 12:11:57 +02:00
|
|
|
// only update if changed.
|
2023-03-07 16:18:49 +01:00
|
|
|
if (mask != prev)
|
|
|
|
{
|
|
|
|
setMode1(mask);
|
|
|
|
// TODO error handling ...
|
|
|
|
}
|
2022-06-02 12:11:57 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool PCA9635::isEnabledSubCall(uint8_t nr)
|
|
|
|
{
|
|
|
|
if ((nr == 0) || (nr > 3)) return false;
|
2023-03-07 16:18:49 +01:00
|
|
|
uint8_t mask = getMode1();
|
2023-05-26 16:22:43 +02:00
|
|
|
if (nr == 1) return (mask & PCA963X_MODE1_SUB1) > 0;
|
|
|
|
if (nr == 2) return (mask & PCA963X_MODE1_SUB2) > 0;
|
|
|
|
return (mask & PCA963X_MODE1_SUB3) > 0;
|
2022-06-02 12:11:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool PCA9635::setSubCallAddress(uint8_t nr, uint8_t address)
|
|
|
|
{
|
2023-03-07 16:18:49 +01:00
|
|
|
if ((nr == 0) || (nr > 3))
|
|
|
|
{
|
|
|
|
// _error = ?? TODO
|
|
|
|
return false;
|
|
|
|
}
|
2023-05-26 16:22:43 +02:00
|
|
|
writeReg(PCA963X_SUBADR(nr), address);
|
2022-06-02 12:11:57 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint8_t PCA9635::getSubCallAddress(uint8_t nr)
|
|
|
|
{
|
2023-03-07 16:18:49 +01:00
|
|
|
if ((nr == 0) || (nr > 3))
|
|
|
|
{
|
|
|
|
// _error = ?? TODO
|
|
|
|
return 0;
|
|
|
|
}
|
2023-05-26 16:22:43 +02:00
|
|
|
uint8_t address = readReg(PCA963X_SUBADR(nr));
|
2022-06-02 12:11:57 +02:00
|
|
|
return address;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool PCA9635::enableAllCall()
|
|
|
|
{
|
|
|
|
uint8_t prev = getMode1();
|
2023-05-26 16:22:43 +02:00
|
|
|
uint8_t mask = prev | PCA963X_MODE1_ALLCALL;
|
2022-06-02 12:11:57 +02:00
|
|
|
// only update if changed.
|
2023-03-07 16:18:49 +01:00
|
|
|
if (mask != prev)
|
|
|
|
{
|
|
|
|
setMode1(mask);
|
|
|
|
// error handling TODO
|
|
|
|
}
|
2022-06-02 12:11:57 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool PCA9635::disableAllCall()
|
|
|
|
{
|
|
|
|
uint8_t prev = getMode1();
|
2023-05-26 16:22:43 +02:00
|
|
|
uint8_t mask = prev & ~PCA963X_MODE1_ALLCALL;
|
2022-06-02 12:11:57 +02:00
|
|
|
// only update if changed.
|
2023-03-07 16:18:49 +01:00
|
|
|
if (mask != prev)
|
|
|
|
{
|
|
|
|
setMode1(mask);
|
|
|
|
// error handling TODO
|
|
|
|
}
|
2022-06-02 12:11:57 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool PCA9635::isEnabledAllCall()
|
|
|
|
{
|
2023-03-07 16:18:49 +01:00
|
|
|
uint8_t mask = getMode1();
|
2023-05-26 16:22:43 +02:00
|
|
|
return mask & PCA963X_MODE1_ALLCALL;
|
2022-06-02 12:11:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool PCA9635::setAllCallAddress(uint8_t address)
|
|
|
|
{
|
2023-05-26 16:22:43 +02:00
|
|
|
writeReg(PCA963X_ALLCALLADR, address);
|
2022-06-02 12:11:57 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint8_t PCA9635::getAllCallAddress()
|
|
|
|
{
|
2023-05-26 16:22:43 +02:00
|
|
|
uint8_t address = readReg(PCA963X_ALLCALLADR);
|
2022-06-02 12:11:57 +02:00
|
|
|
return address;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-03-07 16:18:49 +01:00
|
|
|
/////////////////////////////////////////////////////
|
|
|
|
//
|
2023-05-07 18:51:32 +02:00
|
|
|
// OUTPUT ENABLE (OE) control
|
2023-03-07 16:18:49 +01:00
|
|
|
//
|
|
|
|
// active LOW see page 5 par 6.2 datasheet
|
|
|
|
//
|
|
|
|
bool PCA9635::setOutputEnablePin(uint8_t pin)
|
|
|
|
{
|
|
|
|
_OutputEnablePin = pin;
|
|
|
|
if (_OutputEnablePin != 255)
|
|
|
|
{
|
|
|
|
pinMode(_OutputEnablePin, OUTPUT);
|
|
|
|
digitalWrite(_OutputEnablePin, HIGH);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
// must it be set to HIGH now?
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool PCA9635::setOutputEnable(bool on)
|
|
|
|
{
|
|
|
|
if (_OutputEnablePin != 255)
|
|
|
|
{
|
|
|
|
digitalWrite(_OutputEnablePin, on ? LOW : HIGH);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint8_t PCA9635::getOutputEnable()
|
|
|
|
{
|
|
|
|
if (_OutputEnablePin != 255)
|
|
|
|
{
|
|
|
|
return digitalRead(_OutputEnablePin);
|
|
|
|
}
|
|
|
|
return HIGH;
|
|
|
|
}
|
|
|
|
|
2022-06-02 12:11:57 +02:00
|
|
|
|
2023-03-17 10:31:25 +01:00
|
|
|
//////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// EXPERIMENTAL
|
|
|
|
//
|
|
|
|
int PCA9635::I2C_SoftwareReset(uint8_t method)
|
|
|
|
{
|
|
|
|
// only support 0 and 1
|
|
|
|
if (method > 1) return -999;
|
|
|
|
if (method == 1)
|
|
|
|
{
|
|
|
|
// from https://github.com/RobTillaart/PCA9634/issues/10#issuecomment-1206326417
|
|
|
|
const uint8_t SW_RESET = 0x03;
|
|
|
|
_wire->beginTransmission(SW_RESET);
|
|
|
|
_wire->write(0xA5);
|
|
|
|
_wire->write(0x5A);
|
|
|
|
return _wire->endTransmission(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
// default - based upon NXP specification - UM10204.pdf - page 16
|
|
|
|
_wire->beginTransmission(0x00);
|
|
|
|
_wire->write(0x06);
|
|
|
|
return _wire->endTransmission(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-05-07 18:51:32 +02:00
|
|
|
///////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// EXPERIMENTAL LEDOUT
|
|
|
|
//
|
|
|
|
uint8_t PCA9635::writeLedOut(uint8_t reg, uint8_t mask)
|
|
|
|
{
|
|
|
|
if (reg > 3) return PCA963X_ERROR;
|
|
|
|
writeReg(PCA963X_LEDOUT_BASE + reg, mask);
|
|
|
|
return PCA963X_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint8_t PCA9635::readLedOut(uint8_t reg)
|
|
|
|
{
|
|
|
|
if (reg > 3) return 0x00;
|
|
|
|
return readReg(PCA963X_LEDOUT_BASE + reg);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-09-24 14:21:39 +02:00
|
|
|
// TODO move to right section after testing.
|
2023-05-07 18:51:32 +02:00
|
|
|
uint8_t PCA9635::setLedDriverMode(uint8_t mode)
|
|
|
|
{
|
|
|
|
if (mode > 3) return PCA963X_ERR_MODE;
|
|
|
|
uint8_t mask = 0b00000000;
|
|
|
|
switch(mode)
|
|
|
|
{
|
|
|
|
case PCA963X_LEDGRPPWM:
|
|
|
|
mask = 0b11111111;
|
|
|
|
break;
|
|
|
|
case PCA963X_LEDPWM:
|
|
|
|
mask = 0b10101010;
|
|
|
|
break;
|
|
|
|
case PCA963X_LEDON:
|
|
|
|
mask = 0b01010101;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
mask = 0b00000000;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
for (int reg = 0; reg < 3; reg++)
|
|
|
|
{
|
|
|
|
writeLedOut(reg, mask);
|
|
|
|
}
|
|
|
|
return PCA963X_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-11-27 11:28:57 +01:00
|
|
|
/////////////////////////////////////////////////////
|
|
|
|
//
|
2022-11-19 16:54:49 +01:00
|
|
|
// PRIVATE
|
2020-11-27 11:28:57 +01:00
|
|
|
//
|
2021-01-29 12:31:58 +01:00
|
|
|
uint8_t PCA9635::writeReg(uint8_t reg, uint8_t value)
|
2016-04-24 08:26:22 +02:00
|
|
|
{
|
2021-01-29 12:31:58 +01:00
|
|
|
_wire->beginTransmission(_address);
|
|
|
|
_wire->write(reg);
|
|
|
|
_wire->write(value);
|
|
|
|
_error = _wire->endTransmission();
|
2023-03-07 16:18:49 +01:00
|
|
|
|
2023-05-07 18:51:32 +02:00
|
|
|
if (_error == 0) _error = PCA963X_OK;
|
|
|
|
else _error = PCA963X_ERR_I2C;
|
2021-01-29 12:31:58 +01:00
|
|
|
return _error;
|
2016-04-24 08:26:22 +02:00
|
|
|
}
|
|
|
|
|
2020-11-27 11:28:57 +01:00
|
|
|
|
2016-04-24 08:26:22 +02:00
|
|
|
uint8_t PCA9635::readReg(uint8_t reg)
|
|
|
|
{
|
2021-01-29 12:31:58 +01:00
|
|
|
_wire->beginTransmission(_address);
|
|
|
|
_wire->write(reg);
|
|
|
|
_error = _wire->endTransmission();
|
2023-03-07 16:18:49 +01:00
|
|
|
|
2021-01-29 12:31:58 +01:00
|
|
|
if (_wire->requestFrom(_address, (uint8_t)1) != 1)
|
2020-11-27 11:28:57 +01:00
|
|
|
{
|
2023-05-07 18:51:32 +02:00
|
|
|
_error = PCA963X_ERROR;
|
2020-11-27 11:28:57 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2023-05-07 18:51:32 +02:00
|
|
|
_error = PCA963X_OK;
|
|
|
|
return _wire->read();
|
2016-04-24 08:26:22 +02:00
|
|
|
}
|
|
|
|
|
2021-12-23 10:41:42 +01:00
|
|
|
|
2023-03-07 16:18:49 +01:00
|
|
|
// -- END OF FILE --
|
2021-12-23 10:41:42 +01:00
|
|
|
|