From 6b5a5cc63830beac0a84aabef55a0678c116025d Mon Sep 17 00:00:00 2001 From: rob tillaart Date: Tue, 7 Mar 2023 16:18:49 +0100 Subject: [PATCH] 0.4.3 PCA9635 --- .../.github/workflows/arduino-lint.yml | 2 +- .../.github/workflows/arduino_test_runner.yml | 2 +- .../PCA9635/.github/workflows/jsoncheck.yml | 2 +- libraries/PCA9635/CHANGELOG.md | 10 ++ libraries/PCA9635/LICENSE | 2 +- libraries/PCA9635/PCA9635.cpp | 167 +++++++++++++----- libraries/PCA9635/PCA9635.h | 101 +++++++---- libraries/PCA9635/README.md | 123 ++++++++----- .../PCA9635_OE_control/PCA9635_OE_control.ino | 45 +++++ libraries/PCA9635/keywords.txt | 6 + libraries/PCA9635/library.json | 2 +- libraries/PCA9635/library.properties | 2 +- libraries/PCA9635/test/unit_test_001.cpp | 29 ++- 13 files changed, 363 insertions(+), 130 deletions(-) create mode 100644 libraries/PCA9635/examples/PCA9635_OE_control/PCA9635_OE_control.ino diff --git a/libraries/PCA9635/.github/workflows/arduino-lint.yml b/libraries/PCA9635/.github/workflows/arduino-lint.yml index b2ca058c..8a26f14a 100644 --- a/libraries/PCA9635/.github/workflows/arduino-lint.yml +++ b/libraries/PCA9635/.github/workflows/arduino-lint.yml @@ -6,7 +6,7 @@ jobs: lint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: arduino/arduino-lint-action@v1 with: library-manager: update diff --git a/libraries/PCA9635/.github/workflows/arduino_test_runner.yml b/libraries/PCA9635/.github/workflows/arduino_test_runner.yml index 096b975b..fadfa904 100644 --- a/libraries/PCA9635/.github/workflows/arduino_test_runner.yml +++ b/libraries/PCA9635/.github/workflows/arduino_test_runner.yml @@ -8,7 +8,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: ruby/setup-ruby@v1 with: ruby-version: 2.6 diff --git a/libraries/PCA9635/.github/workflows/jsoncheck.yml b/libraries/PCA9635/.github/workflows/jsoncheck.yml index 04603d08..37a11298 100644 --- a/libraries/PCA9635/.github/workflows/jsoncheck.yml +++ b/libraries/PCA9635/.github/workflows/jsoncheck.yml @@ -10,7 +10,7 @@ jobs: test: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: json-syntax-check uses: limitusus/json-syntax-check@v1 with: diff --git a/libraries/PCA9635/CHANGELOG.md b/libraries/PCA9635/CHANGELOG.md index 48865a6d..ec3d985b 100644 --- a/libraries/PCA9635/CHANGELOG.md +++ b/libraries/PCA9635/CHANGELOG.md @@ -6,6 +6,16 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## [0.4.3] - 2023-01-23 +- update GitHub actions +- update license 2023 +- add OutputEnable control functions. +- add example **PCA9635_OE_control.ino** +- update unit test. +- **configure()** now returns error state +- update readme.md +- minor edits + ## [0.4.2] - 2022-11-19 - add RP2040 in build-CI diff --git a/libraries/PCA9635/LICENSE b/libraries/PCA9635/LICENSE index ce6d6f88..eae2a1a7 100644 --- a/libraries/PCA9635/LICENSE +++ b/libraries/PCA9635/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2016-2022 Rob Tillaart +Copyright (c) 2016-2023 Rob Tillaart Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/libraries/PCA9635/PCA9635.cpp b/libraries/PCA9635/PCA9635.cpp index 058c6899..1d9b1185 100644 --- a/libraries/PCA9635/PCA9635.cpp +++ b/libraries/PCA9635/PCA9635.cpp @@ -2,7 +2,7 @@ // FILE: PCA9635.cpp // AUTHOR: Rob Tillaart // DATE: 23-apr-2016 -// VERSION: 0.4.2 +// VERSION: 0.4.3 // PURPOSE: Arduino library for PCA9635 I2C LED driver // URL: https://github.com/RobTillaart/PCA9635 @@ -16,9 +16,12 @@ // PCA9635::PCA9635(const uint8_t deviceAddress, TwoWire *wire) { - _address = deviceAddress; - _wire = wire; - _channelCount = 16; + _address = deviceAddress; + _wire = wire; + _channelCount = 16; + _data = 0; + _error = PCA9635_OK; + _OutputEnablePin = 255; } @@ -48,6 +51,22 @@ bool PCA9635::begin(uint8_t mode1_mask, uint8_t mode2_mask) } +uint8_t PCA9635::configure(uint8_t mode1_mask, uint8_t mode2_mask) +{ + _data = 0; + _error = PCA9635_OK; + + uint8_t r1 = setMode1(mode1_mask); + uint8_t r2 = setMode2(mode2_mask); + + if ((r1 != PCA9635_OK) || (r2 != PCA9635_OK)) + { + return PCA9635_ERROR; + } + return _error; +} + + bool PCA9635::isConnected() { _wire->beginTransmission(_address); @@ -56,13 +75,9 @@ bool PCA9635::isConnected() } -void PCA9635::configure(uint8_t mode1_mask, uint8_t mode2_mask) +uint8_t PCA9635::channelCount() { - _data = 0; - _error = 0; - - setMode1(mode1_mask); - setMode2(mode2_mask); + return _channelCount; } @@ -88,7 +103,7 @@ uint8_t PCA9635::writeN(uint8_t channel, uint8_t* arr, uint8_t count) { if (channel + count > _channelCount) { - _error = PCA9635_ERR_WRITE; + _error = PCA9635_ERR_CHAN; return PCA9635_ERROR; } uint8_t base = PCA9635_PWM(channel); @@ -104,7 +119,8 @@ uint8_t PCA9635::writeN(uint8_t channel, uint8_t* arr, uint8_t count) _error = PCA9635_ERR_I2C; return PCA9635_ERROR; } - return PCA9635_OK; + _error = PCA9635_OK; + return _error; } @@ -116,7 +132,7 @@ uint8_t PCA9635::writeMode(uint8_t reg, uint8_t value) return PCA9635_OK; } _error = PCA9635_ERR_REG; - return PCA9635_ERROR; + return _error; } @@ -130,7 +146,7 @@ uint8_t PCA9635::readMode(uint8_t reg) return value; } _error = PCA9635_ERR_REG; - return PCA9635_ERROR; + return _error; } @@ -154,7 +170,8 @@ uint8_t PCA9635::setLedDriverMode(uint8_t channel, uint8_t mode) uint8_t clrmask = ~(0x03 << shift); uint8_t value = (readReg(reg) & clrmask) | setmask; writeReg(reg, value); - return PCA9635_OK; + _error = PCA9635_OK; + return _error; } @@ -168,13 +185,16 @@ uint8_t PCA9635::getLedDriverMode(uint8_t channel) } uint8_t reg = PCA9635_LEDOUT_BASE + (channel >> 2); - uint8_t shift = (channel & 0x03) * 2; // 0,2,4,6 places + uint8_t shift = (channel & 0x03) * 2; // 0, 2, 4, 6 places uint8_t value = (readReg(reg) >> shift ) & 0x03; return value; } -// note error flag is reset after read! +///////////////////////////////////////////////////// +// +// ERROR +// int PCA9635::lastError() { int e = _error; @@ -183,7 +203,6 @@ int PCA9635::lastError() } - ///////////////////////////////////////////////////// // // SUB CALL - ALL CALL @@ -192,12 +211,16 @@ bool PCA9635::enableSubCall(uint8_t nr) { if ((nr == 0) || (nr > 3)) return false; uint8_t prev = getMode1(); - uint8_t reg = prev; - if (nr == 1) reg |= PCA9635_MODE1_SUB1; - else if (nr == 2) reg |= PCA9635_MODE1_SUB2; - else reg |= PCA9635_MODE1_SUB3; + uint8_t mask = prev; + if (nr == 1) mask |= PCA9635_MODE1_SUB1; + else if (nr == 2) mask |= PCA9635_MODE1_SUB2; + else mask |= PCA9635_MODE1_SUB3; // only update if changed. - if (reg != prev) setMode1(reg); + if (mask != prev) + { + setMode1(mask); + // TODO error handling ... + } return true; } @@ -206,12 +229,16 @@ bool PCA9635::disableSubCall(uint8_t nr) { if ((nr == 0) || (nr > 3)) return false; uint8_t prev = getMode1(); - uint8_t reg = prev; - if (nr == 1) reg &= ~PCA9635_MODE1_SUB1; - else if (nr == 2) reg &= ~PCA9635_MODE1_SUB2; - else reg &= ~PCA9635_MODE1_SUB3; + uint8_t mask = prev; + if (nr == 1) mask &= ~PCA9635_MODE1_SUB1; + else if (nr == 2) mask &= ~PCA9635_MODE1_SUB2; + else mask &= ~PCA9635_MODE1_SUB3; // only update if changed. - if (reg != prev) setMode1(reg); + if (mask != prev) + { + setMode1(mask); + // TODO error handling ... + } return true; } @@ -219,16 +246,20 @@ bool PCA9635::disableSubCall(uint8_t nr) bool PCA9635::isEnabledSubCall(uint8_t nr) { if ((nr == 0) || (nr > 3)) return false; - uint8_t reg = getMode1(); - if (nr == 1) return (reg & PCA9635_MODE1_SUB1) > 0; - if (nr == 2) return (reg & PCA9635_MODE1_SUB2) > 0; - return (reg & PCA9635_MODE1_SUB3) > 0; + uint8_t mask = getMode1(); + if (nr == 1) return (mask & PCA9635_MODE1_SUB1) > 0; + if (nr == 2) return (mask & PCA9635_MODE1_SUB2) > 0; + return (mask & PCA9635_MODE1_SUB3) > 0; } bool PCA9635::setSubCallAddress(uint8_t nr, uint8_t address) { - if ((nr == 0) || (nr > 3)) return false; + if ((nr == 0) || (nr > 3)) + { + // _error = ?? TODO + return false; + } writeReg(PCA9635_SUBADR(nr), address); return true; } @@ -236,7 +267,11 @@ bool PCA9635::setSubCallAddress(uint8_t nr, uint8_t address) uint8_t PCA9635::getSubCallAddress(uint8_t nr) { - if ((nr == 0) || (nr > 3)) return 0; + if ((nr == 0) || (nr > 3)) + { + // _error = ?? TODO + return 0; + } uint8_t address = readReg(PCA9635_SUBADR(nr)); return address; } @@ -245,9 +280,13 @@ uint8_t PCA9635::getSubCallAddress(uint8_t nr) bool PCA9635::enableAllCall() { uint8_t prev = getMode1(); - uint8_t reg = prev | PCA9635_MODE1_ALLCALL; + uint8_t mask = prev | PCA9635_MODE1_ALLCALL; // only update if changed. - if (reg != prev) setMode1(reg); + if (mask != prev) + { + setMode1(mask); + // error handling TODO + } return true; } @@ -255,17 +294,21 @@ bool PCA9635::enableAllCall() bool PCA9635::disableAllCall() { uint8_t prev = getMode1(); - uint8_t reg = prev & ~PCA9635_MODE1_ALLCALL; + uint8_t mask = prev & ~PCA9635_MODE1_ALLCALL; // only update if changed. - if (reg != prev) setMode1(reg); + if (mask != prev) + { + setMode1(mask); + // error handling TODO + } return true; } bool PCA9635::isEnabledAllCall() { - uint8_t reg = getMode1(); - return reg & PCA9635_MODE1_ALLCALL; + uint8_t mask = getMode1(); + return mask & PCA9635_MODE1_ALLCALL; } @@ -283,6 +326,46 @@ uint8_t PCA9635::getAllCallAddress() } +///////////////////////////////////////////////////// +// +// OE - Output Enable control +// +// 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; +} + ///////////////////////////////////////////////////// // @@ -294,6 +377,7 @@ uint8_t PCA9635::writeReg(uint8_t reg, uint8_t value) _wire->write(reg); _wire->write(value); _error = _wire->endTransmission(); + if (_error == 0) _error = PCA9635_OK; else _error = PCA9635_ERR_I2C; return _error; @@ -305,6 +389,7 @@ uint8_t PCA9635::readReg(uint8_t reg) _wire->beginTransmission(_address); _wire->write(reg); _error = _wire->endTransmission(); + if (_wire->requestFrom(_address, (uint8_t)1) != 1) { _error = PCA9635_ERROR; @@ -316,5 +401,5 @@ uint8_t PCA9635::readReg(uint8_t reg) } -// -- END OF FILE -- +// -- END OF FILE -- diff --git a/libraries/PCA9635/PCA9635.h b/libraries/PCA9635/PCA9635.h index 77fed1ab..61fd44aa 100644 --- a/libraries/PCA9635/PCA9635.h +++ b/libraries/PCA9635/PCA9635.h @@ -3,7 +3,7 @@ // FILE: PCA9635.h // AUTHOR: Rob Tillaart // DATE: 23-apr-2016 -// VERSION: 0.4.2 +// VERSION: 0.4.3 // PURPOSE: Arduino library for PCA9635 I2C LED driver, 16 channel // URL: https://github.com/RobTillaart/PCA9635 @@ -12,7 +12,7 @@ #include "Wire.h" -#define PCA9635_LIB_VERSION (F("0.4.2")) +#define PCA9635_LIB_VERSION (F("0.4.3")) #define PCA9635_MODE1 0x00 #define PCA9635_MODE2 0x01 @@ -25,8 +25,8 @@ #define PCA9635_GRPFREQ 0x13 // check datasheet for details -#define PCA9635_LEDOUT_BASE 0x14 // 0x14..0x17 -#define PCA9635_LEDOFF 0x00 // default @ startup +#define PCA9635_LEDOUT_BASE 0x14 // 0x14..0x17 +#define PCA9635_LEDOFF 0x00 // default @ startup #define PCA9635_LEDON 0x01 #define PCA9635_LEDPWM 0x02 #define PCA9635_LEDGRPPWM 0x03 @@ -41,26 +41,26 @@ #define PCA9635_ERR_I2C 0xFA -// Configuration bits MODE1 register -#define PCA9635_MODE1_AUTOINCR2 0x80 // ReadOnly, 0 = disable 1 = enable -#define PCA9635_MODE1_AUTOINCR1 0x40 // ReadOnly, bit1 -#define PCA9635_MODE1_AUTOINCR0 0x20 // ReadOnly, bit0 -#define PCA9635_MODE1_SLEEP 0x10 // 0 = normal 1 = sleep -#define PCA9635_MODE1_SUB1 0x08 // 0 = disable 1 = enable -#define PCA9635_MODE1_SUB2 0x04 // 0 = disable 1 = enable -#define PCA9635_MODE1_SUB3 0x02 // 0 = disable 1 = enable -#define PCA9635_MODE1_ALLCALL 0x01 // 0 = disable 1 = enable +// Configuration bits MODE1 register +#define PCA9635_MODE1_AUTOINCR2 0x80 // ReadOnly, 0 = disable 1 = enable +#define PCA9635_MODE1_AUTOINCR1 0x40 // ReadOnly, bit1 +#define PCA9635_MODE1_AUTOINCR0 0x20 // ReadOnly, bit0 +#define PCA9635_MODE1_SLEEP 0x10 // 0 = normal 1 = sleep +#define PCA9635_MODE1_SUB1 0x08 // 0 = disable 1 = enable +#define PCA9635_MODE1_SUB2 0x04 // 0 = disable 1 = enable +#define PCA9635_MODE1_SUB3 0x02 // 0 = disable 1 = enable +#define PCA9635_MODE1_ALLCALL 0x01 // 0 = disable 1 = enable #define PCA9635_MODE1_NONE 0x00 -// Configuration bits MODE2 register -#define PCA9635_MODE2_BLINK 0x20 // 0 = dim 1 = blink -#define PCA9635_MODE2_INVERT 0x10 // 0 = normal 1 = inverted -#define PCA9635_MODE2_ACK 0x08 // 0 = on STOP 1 = on ACK -#define PCA9635_MODE2_TOTEMPOLE 0x04 // 0 = open drain 1 = totem-pole +// Configuration bits MODE2 register +#define PCA9635_MODE2_BLINK 0x20 // 0 = dim 1 = blink +#define PCA9635_MODE2_INVERT 0x10 // 0 = normal 1 = inverted +#define PCA9635_MODE2_ACK 0x08 // 0 = on STOP 1 = on ACK +#define PCA9635_MODE2_TOTEMPOLE 0x04 // 0 = open drain 1 = totem-pole #define PCA9635_MODE2_NONE 0x00 -// NOT IMPLEMENTED YET -#define PCA9635_SUBADR(x) (0x17+(x)) // x = 1..3 +// NOT IMPLEMENTED YET +#define PCA9635_SUBADR(x) (0x17+(x)) // x = 1..3 #define PCA9635_ALLCALLADR 0x1B @@ -76,23 +76,19 @@ public: #endif bool begin(uint8_t mode1_mask = PCA9635_MODE1_ALLCALL, uint8_t mode2_mask = PCA9635_MODE2_NONE); - void configure(uint8_t mode1_mask, uint8_t mode2_mask); bool isConnected(); - uint8_t channelCount() { return _channelCount; }; + + ///////////////////////////////////////////////////// + // + // CONFIGURATION + // + uint8_t configure(uint8_t mode1_mask, uint8_t mode2_mask); + uint8_t channelCount(); uint8_t setLedDriverMode(uint8_t channel, uint8_t mode); uint8_t getLedDriverMode(uint8_t channel); - // single PWM setting - uint8_t write1(uint8_t channel, uint8_t value); - - // RGB setting, write three consecutive PWM registers - uint8_t write3(uint8_t channel, uint8_t R, uint8_t G, uint8_t B); - - // generic worker, write N consecutive PWM registers - uint8_t writeN(uint8_t channel, uint8_t* arr, uint8_t count); - // reg = 1, 2 check datasheet for values uint8_t writeMode(uint8_t reg, uint8_t value); uint8_t readMode(uint8_t reg); @@ -102,7 +98,6 @@ public: uint8_t getMode1() { return readMode(PCA9635_MODE1); }; uint8_t getMode2() { return readMode(PCA9635_MODE2); }; - // TODO PWM also in %% ? void setGroupPWM(uint8_t value) { writeReg(PCA9635_GRPPWM, value); }; uint8_t getGroupPWM() { return readReg(PCA9635_GRPPWM); }; @@ -111,11 +106,32 @@ public: void setGroupFREQ(uint8_t value) { writeReg(PCA9635_GRPFREQ, value); }; uint8_t getGroupFREQ() { return readReg(PCA9635_GRPFREQ); }; - int lastError(); ///////////////////////////////////////////////////// // - // SUB CALL - ALL CALL (since 0.2.0) + // WRITE + // + // single PWM setting + uint8_t write1(uint8_t channel, uint8_t value); + + // RGB setting, write three consecutive PWM registers + uint8_t write3(uint8_t channel, uint8_t R, uint8_t G, uint8_t B); + + // generic worker, write N consecutive PWM registers + uint8_t writeN(uint8_t channel, uint8_t* arr, uint8_t count); + + + ///////////////////////////////////////////////////// + // + // ERROR + // + // note error flag is reset after read! + int lastError(); + + + ///////////////////////////////////////////////////// + // + // SUB CALL - ALL CALL (since 0.2.0) // // nr = { 1, 2, 3 } bool enableSubCall(uint8_t nr); @@ -131,20 +147,29 @@ public: uint8_t getAllCallAddress(); + ///////////////////////////////////////////////////// + // + // OE - Output Enable control + // + bool setOutputEnablePin(uint8_t pin); + bool setOutputEnable(bool on); + uint8_t getOutputEnable(); + + private: - // DIRECT CONTROL - uint8_t writeReg(uint8_t reg, uint8_t value); // returns error status. + // DIRECT CONTROL + uint8_t writeReg(uint8_t reg, uint8_t value); // returns error status. uint8_t readReg(uint8_t reg); uint8_t _address; - uint8_t _register; uint8_t _data; int _error; uint8_t _channelCount = 16; + uint8_t _OutputEnablePin; TwoWire* _wire; }; -// -- END OF FILE -- +// -- END OF FILE -- diff --git a/libraries/PCA9635/README.md b/libraries/PCA9635/README.md index 79daca20..ae8d6769 100644 --- a/libraries/PCA9635/README.md +++ b/libraries/PCA9635/README.md @@ -15,17 +15,20 @@ Arduino library for PCA9635 I2C 8 bit PWM LED driver, 16 channel. This library is to control the I2C PCA9635 PWM extender. The 16 channels are independently configurable in steps of 1/256. -this allows for better than 1% fine tuning of the duty-cycle +This allows for better than 1% fine tuning of the duty-cycle of the PWM signal. -library is related to the 8 channel PCA9634 class. +library is related to the 8 channel https://github.com/RobTillaart/PCA9634 class. (these might merge in the future) ## Interface +```cpp +#include "PCA9635.h" +``` -### Constructor +#### Constructor - **PCA9635(uint8_t deviceAddress, TwoWire \*wire = &Wire)** Constructor with I2C device address, and optional the Wire interface as parameter. @@ -41,25 +44,25 @@ See PCA9635.h and datasheet for settings possible. - **uint8_t channelCount()** returns the number of channels = 16. -### LedDriverMode +#### LedDriverMode Configure LED behaviour. - **uint8_t setLedDriverMode(uint8_t channel, uint8_t mode)** mode is 0..3 See datasheet for full details. - **uint8_t getLedDriverMode(uint8_t channel)** returns the current mode of the channel. -| LED mode | Value | Description | -|:-------------------|:-----:|:----------------------------------| -| PCA9635_LEDOFF | 0x00 | led is 100% off, default @startup | -| PCA9635_LEDON | 0x01 | led is 100% on. | -| PCA9635_LEDPWM | 0x02 | set LED in PWM mode, 0..255 | -| PCA9635_LEDGRPPWM | 0x03 | add LED to the GRPPWM* | +| LED mode | Value | Description | +|:--------------------|:-------:|:------------------------------------| +| PCA9635_LEDOFF | 0x00 | led is 100% off, default @startup | +| PCA9635_LEDON | 0x01 | led is 100% on. | +| PCA9635_LEDPWM | 0x02 | set LED in PWM mode, 0..255 | +| PCA9635_LEDGRPPWM | 0x03 | add LED to the GRPPWM* | \* all LEDs in the group GRPPWM can be set to the same PWM value in one set. This is ideal to trigger e.g. multiple LEDs (servo's) at same time. -### Read and write +#### Read and write Read and write individual values to LED channels. Requires LEDs' DriverMode of the specific channels to be in PWM mode. @@ -74,7 +77,7 @@ May return **PCA9635_ERR_WRITE** if array has too many elements (including channel as offset). -### Mode registers +#### Mode registers Used to configure the PCA963x general behaviour. @@ -92,21 +95,21 @@ useful to add or remove a single flag (bit masking). (added 0.3.4) -| Name | Value | Description | -|:------------------------|:-----:|:-----------------------------------| -| PCA9635_MODE1_AUTOINCR2 | 0x80 | Read Only, 0 = disable 1 = enable | -| PCA9635_MODE1_AUTOINCR1 | 0x40 | Read Only, bit1 | -| PCA9635_MODE1_AUTOINCR0 | 0x20 | Read Only, bit0 | -| PCA9635_MODE1_SLEEP | 0x10 | 0 = normal 1 = sleep | -| PCA9635_MODE1_SUB1 | 0x08 | 0 = disable 1 = enable | -| PCA9635_MODE1_SUB2 | 0x04 | 0 = disable 1 = enable | -| PCA9635_MODE1_SUB3 | 0x02 | 0 = disable 1 = enable | -| PCA9635_MODE1_ALLCALL | 0x01 | 0 = disable 1 = enable | -| | | | -| PCA9635_MODE2_BLINK | 0x20 | 0 = dim 1 = blink | -| PCA9635_MODE2_INVERT | 0x10 | 0 = normal 1 = inverted | -| PCA9635_MODE2_STOP | 0x08 | 0 = on STOP 1 = on ACK | -| PCA9635_MODE2_TOTEMPOLE | 0x04 | 0 = open drain 1 = totem-pole | +| Name | Value | Description | +|:--------------------------|:-------:|:-------------------------------------| +| PCA9635_MODE1_AUTOINCR2 | 0x80 | Read Only, 0 = disable 1 = enable | +| PCA9635_MODE1_AUTOINCR1 | 0x40 | Read Only, bit1 | +| PCA9635_MODE1_AUTOINCR0 | 0x20 | Read Only, bit0 | +| PCA9635_MODE1_SLEEP | 0x10 | 0 = normal 1 = sleep | +| PCA9635_MODE1_SUB1 | 0x08 | 0 = disable 1 = enable | +| PCA9635_MODE1_SUB2 | 0x04 | 0 = disable 1 = enable | +| PCA9635_MODE1_SUB3 | 0x02 | 0 = disable 1 = enable | +| PCA9635_MODE1_ALLCALL | 0x01 | 0 = disable 1 = enable | +| ---- | | | +| PCA9635_MODE2_BLINK | 0x20 | 0 = dim 1 = blink | +| PCA9635_MODE2_INVERT | 0x10 | 0 = normal 1 = inverted | +| PCA9635_MODE2_STOP | 0x08 | 0 = on STOP 1 = on ACK | +| PCA9635_MODE2_TOTEMPOLE | 0x04 | 0 = open drain 1 = totem-pole | These constants makes it easier to set modes without using a non descriptive bit mask. The constants can be merged by OR-ing them together, see snippet: @@ -125,7 +128,7 @@ ledArray.setMode2(PCA9635_MODE2_BLINK | PCA9635_MODE2_INVERT | PCA9635_MODE2_TOT ``` -### Group PWM and frequency +#### Group PWM and frequency Check datasheet for the details. @@ -137,22 +140,22 @@ So 0x00 results in 41 ms blinking period (on AND off) and 0xFF in approx. 10.5 s - **uint8_t getGroupFREQ()** returns the set frequency of the PWM group. -### Miscellaneous +#### Miscellaneous - **int lastError()** returns **PCA9635_OK** if all is OK, and other error codes otherwise. -| Error code | Value | Description | -|:------------------|:-----:|:---------------------| -| PCA9635_OK | 0x00 | Everything went well -| PCA9635_ERROR | 0xFF | Generic error -| PCA9635_ERR_WRITE | 0xFE | Tries to write more elements than PWM channels -| PCA9635_ERR_CHAN | 0xFD | Channel out of range -| PCA9635_ERR_MODE | 0xFC | Invalid mode -| PCA9635_ERR_REG | 0xFB | Invalid register -| PCA9635_ERR_I2C | 0xFA | I2C communication error +| Error code | Value | Description | +|:--------------------|:-------:|:----------------------| +| PCA9635_OK | 0x00 | Everything went well +| PCA9635_ERROR | 0xFF | Generic error +| PCA9635_ERR_WRITE | 0xFE | Tries to write more elements than PWM channels +| PCA9635_ERR_CHAN | 0xFD | Channel out of range +| PCA9635_ERR_MODE | 0xFC | Invalid mode +| PCA9635_ERR_REG | 0xFB | Invalid register +| PCA9635_ERR_I2C | 0xFA | I2C communication error -### SUB CALL and ALL CALL +## SUB CALL and ALL CALL Please read the datasheet to understand the working of **SUB CALL** and **ALL CALL**. @@ -192,24 +195,56 @@ The functions to enable all/sub-addresses are straightforward: - **uint8_t getAllCallAddress()** -## Operation +#### OutputEnable -See examples +Since 0.4.3 (experimental) support to control the OE (Output Enable) pin of the PCA9635. +This OE pin can control all LEDs simultaneously. It also allows to +control multiple PCA9635. +Think of simultaneous switching ON/OFF of get dimming with a high frequency PWM. + +See datasheet for the details + +- **bool setOutputEnablePin(uint8_t pin = 255)** sets the IO pin to connect to the OE pin of the PCA9635. +A value of 255 indicates no pin set/selected. +Sets the OE pin to LOW. +Returns true on success. +- **bool setOutputEnable(uint8_t value)** Sets the OE pin HIGH or LOW. +All non zero values are HIGH. +Returns true on success. +- **uint8_t getOutputEnable()** get the current value of the OE pin. +If pin is not set/selected it will return LOW. + +Note: the OE is LOW active. The user has to set the power on value +by means of a PULL UP / DOWN resistor. ## Future -#### must +#### Must + - improve documentation -#### should +#### Should + - move code from .h to .cpp - unit tests - SUB CALL if possible? - ALL CALL if possible? - add examples +- improve error handling (0.5.0) + - return values etc. + - documentation. + + +#### Could -#### could - sync with PCA9634 developments - merge with PCA9634 and a PCA963X base class if possible +- restructure function groups + - in .cpp to match .h + - readme.md + + +#### Wont + diff --git a/libraries/PCA9635/examples/PCA9635_OE_control/PCA9635_OE_control.ino b/libraries/PCA9635/examples/PCA9635_OE_control/PCA9635_OE_control.ino new file mode 100644 index 00000000..1d92c06e --- /dev/null +++ b/libraries/PCA9635/examples/PCA9635_OE_control/PCA9635_OE_control.ino @@ -0,0 +1,45 @@ +// +// FILE: PCA9635_OE_control.ino +// AUTHOR: Rob Tillaart +// PURPOSE: test PCA9635 library + + +#include "Arduino.h" +#include "Wire.h" +#include "PCA9635.h" + + +PCA9635 ledArray(0x20); + + +void setup() +{ + Serial.begin(115200); + Serial.print("PCA9635 LIB version: "); + Serial.println(PCA9635_LIB_VERSION); + Serial.println(); + + ledArray.begin(); + + // just one channel + ledArray.write1(1, 100); + + ledArray.setOutputEnablePin(12); + ledArray.setOutputEnable(true); + delay(1000); + ledArray.setOutputEnable(false); + delay(1000); + ledArray.setOutputEnable(true); + + // TODO elaborate + + Serial.println("done..."); +} + +void loop() +{ +} + + +// -- END OF FILE -- + diff --git a/libraries/PCA9635/keywords.txt b/libraries/PCA9635/keywords.txt index e005413c..389154e5 100644 --- a/libraries/PCA9635/keywords.txt +++ b/libraries/PCA9635/keywords.txt @@ -38,9 +38,15 @@ enableAllCall KEYWORD2 disableAllCall KEYWORD2 isEnabledAllCall KEYWORD2 +setOutputEnablePin KEYWORD2 +setOutputEnable KEYWORD2 +getOutputEnable KEYWORD2 +# # Constants ( LITERAL1) +# PCA9635_LIB_VERSION LITERAL1 + PCA9635_OK LITERAL1 PCA9635_ERROR LITERAL1 PCA9635_ERR_WRITE LITERAL1 diff --git a/libraries/PCA9635/library.json b/libraries/PCA9635/library.json index 1b73de5f..3ef7f7cf 100644 --- a/libraries/PCA9635/library.json +++ b/libraries/PCA9635/library.json @@ -15,7 +15,7 @@ "type": "git", "url": "https://github.com/RobTillaart/PCA9635.git" }, - "version": "0.4.2", + "version": "0.4.3", "license": "MIT", "frameworks": "arduino", "platforms": "*", diff --git a/libraries/PCA9635/library.properties b/libraries/PCA9635/library.properties index a33e8bda..465d6a13 100644 --- a/libraries/PCA9635/library.properties +++ b/libraries/PCA9635/library.properties @@ -1,5 +1,5 @@ name=PCA9635 -version=0.4.2 +version=0.4.3 author=Rob Tillaart maintainer=Rob Tillaart sentence=Arduino library for PCA9635 I2C LED driver 16 channel diff --git a/libraries/PCA9635/test/unit_test_001.cpp b/libraries/PCA9635/test/unit_test_001.cpp index c9e41925..8bedffee 100644 --- a/libraries/PCA9635/test/unit_test_001.cpp +++ b/libraries/PCA9635/test/unit_test_001.cpp @@ -89,6 +89,33 @@ unittest(test_LedDriverMode) } +unittest(test_OutputEnable) +{ + PCA9635 ledArray(0x20); + + assertTrue(ledArray.begin()); + + assertEqual(HIGH, ledArray.getOutputEnable()); + + assertTrue(ledArray.setOutputEnablePin(12)); + assertEqual(HIGH, ledArray.getOutputEnable()); + + assertTrue(ledArray.setOutputEnable(true)); + assertEqual(LOW, ledArray.getOutputEnable()); + + assertTrue(ledArray.setOutputEnable(false)); + assertEqual(HIGH, ledArray.getOutputEnable()); + + assertTrue(ledArray.setOutputEnable(true)); + assertEqual(LOW, ledArray.getOutputEnable()); + + assertFalse(ledArray.setOutputEnablePin(255)); + assertEqual(HIGH, ledArray.getOutputEnable()); +} + + unittest_main() -// -------- + +// -- END OF FILE -- +