diff --git a/CHANGELOG.md b/CHANGELOG.md index b83b151..60839e4 100644 --- a/CHANGELOG.md +++ b/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.6.1] - 2025-05-08 +- fix #34, Sync PCA9634 / 32 +- rename setLedDriverMode() => setLedDriverModeAll() +- add **writeAll(arr)** +- add **allOff()** +- remove old defines, all are now PCA963X_xxxx +- update readme.md +- update examples +- minor edits + ## [0.6.0] - 2024-01-18 - fix #32, setLedDriverMode(uint8_t mode) - minor edits (examples) diff --git a/LICENSE b/LICENSE index cef01c5..cb368db 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2016-2024 Rob Tillaart +Copyright (c) 2016-2025 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/PCA9635.cpp b/PCA9635.cpp index a6cdc57..ce63624 100644 --- a/PCA9635.cpp +++ b/PCA9635.cpp @@ -2,7 +2,7 @@ // FILE: PCA9635.cpp // AUTHOR: Rob Tillaart // DATE: 23-apr-2016 -// VERSION: 0.6.0 +// VERSION: 0.6.1 // PURPOSE: Arduino library for PCA9635 I2C LED driver, 16 channel PWM, 8 bit // URL: https://github.com/RobTillaart/PCA9635 @@ -75,6 +75,33 @@ uint8_t PCA9635::channelCount() // // LED DRIVER MODE // +uint8_t PCA9635::setLedDriverModeAll(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 < 4; reg++) + { + writeLedOut(reg, mask); + } + return PCA963X_OK; +} + + uint8_t PCA9635::setLedDriverMode(uint8_t channel, uint8_t mode) { if (channel >= _channelCount) @@ -93,8 +120,8 @@ uint8_t PCA9635::setLedDriverMode(uint8_t channel, uint8_t mode) 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); + uint8_t value = (readRegister(reg) & clrmask) | setmask; + writeRegister(reg, value); _error = PCA963X_OK; return _error; } @@ -111,7 +138,7 @@ uint8_t PCA9635::getLedDriverMode(uint8_t channel) 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; + uint8_t value = (readRegister(reg) >> shift ) & 0x03; _error = PCA963X_OK; return value; } @@ -125,7 +152,7 @@ uint8_t PCA9635::writeMode(uint8_t reg, uint8_t value) { if ((reg == PCA963X_MODE1) || (reg == PCA963X_MODE2)) { - writeReg(reg, value); + writeRegister(reg, value); return PCA963X_OK; } _error = PCA963X_ERR_REG; @@ -139,7 +166,7 @@ uint8_t PCA9635::readMode(uint8_t reg) if ((reg == PCA963X_MODE1) || (reg == PCA963X_MODE2)) { _error = PCA963X_OK; - uint8_t value = readReg(reg); + uint8_t value = readRegister(reg); return value; } _error = PCA963X_ERR_REG; @@ -149,53 +176,55 @@ uint8_t PCA9635::readMode(uint8_t reg) uint8_t PCA9635::setMode1(uint8_t value) { - return writeMode(PCA963X_MODE1, value); + writeRegister(PCA963X_MODE1, value); + return PCA963X_OK; } uint8_t PCA9635::setMode2(uint8_t value) { - return writeMode(PCA963X_MODE2, value); + writeRegister(PCA963X_MODE2, value); + return PCA963X_OK; } uint8_t PCA9635::getMode1() { - return readMode(PCA963X_MODE1); + return readRegister(PCA963X_MODE1); } uint8_t PCA9635::getMode2() { - return readMode(PCA963X_MODE2); + return readRegister(PCA963X_MODE2); } ///////////////////////////////////////////////////// // -// GROUP PWM +// GROUP REGISTERS // -void PCA9635::setGroupPWM(uint8_t value) +uint8_t PCA9635::setGroupPWM(uint8_t value) { - writeReg(PCA963X_GRPPWM, value); + return writeRegister(PCA963X_GRPPWM, value); } uint8_t PCA9635::getGroupPWM() { - return readReg(PCA963X_GRPPWM); + return readRegister(PCA963X_GRPPWM); } -void PCA9635::setGroupFREQ(uint8_t value) +uint8_t PCA9635::setGroupFREQ(uint8_t value) { - writeReg(PCA963X_GRPFREQ, value); + return writeRegister(PCA963X_GRPFREQ, value); } uint8_t PCA9635::getGroupFREQ() { - return readReg(PCA963X_GRPFREQ); + return readRegister(PCA963X_GRPFREQ); } @@ -246,6 +275,19 @@ uint8_t PCA9635::writeN(uint8_t channel, uint8_t* arr, uint8_t count) } +uint8_t PCA9635::writeAll(uint8_t * arr) +{ + return writeN(0, arr, 16); +} + + +uint8_t PCA9635::allOff() +{ + uint8_t arr[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + return writeN(0, arr, 16); +} + + uint8_t PCA9635::writeN_noStop(uint8_t channel, uint8_t* arr, uint8_t count) { if (channel + count > _channelCount) @@ -291,7 +333,7 @@ int PCA9635::lastError() ///////////////////////////////////////////////////// // -// SUB CALL - ALL CALL +// SUB CALL // bool PCA9635::enableSubCall(uint8_t nr) { @@ -346,7 +388,7 @@ bool PCA9635::setSubCallAddress(uint8_t nr, uint8_t address) // _error = ?? TODO return false; } - writeReg(PCA963X_SUBADR(nr), address); + writeRegister(PCA963X_SUBADR(nr), address); return true; } @@ -358,11 +400,15 @@ uint8_t PCA9635::getSubCallAddress(uint8_t nr) // _error = ?? TODO return 0; } - uint8_t address = readReg(PCA963X_SUBADR(nr)); + uint8_t address = readRegister(PCA963X_SUBADR(nr)); return address; } +///////////////////////////////////////////////////// +// +// ALL CALL +// bool PCA9635::enableAllCall() { uint8_t prev = getMode1(); @@ -394,20 +440,20 @@ bool PCA9635::disableAllCall() bool PCA9635::isEnabledAllCall() { uint8_t mask = getMode1(); - return mask & PCA963X_MODE1_ALLCALL; + return (mask & PCA963X_MODE1_ALLCALL) > 0; } bool PCA9635::setAllCallAddress(uint8_t address) { - writeReg(PCA963X_ALLCALLADR, address); + writeRegister(PCA963X_ALLCALLADR, address); return true; } uint8_t PCA9635::getAllCallAddress() { - uint8_t address = readReg(PCA963X_ALLCALLADR); + uint8_t address = readRegister(PCA963X_ALLCALLADR); return address; } @@ -485,7 +531,7 @@ int PCA9635::I2C_SoftwareReset(uint8_t method) uint8_t PCA9635::writeLedOut(uint8_t reg, uint8_t mask) { if (reg > 3) return PCA963X_ERROR; - writeReg(PCA963X_LEDOUT_BASE + reg, mask); + writeRegister(PCA963X_LEDOUT_BASE + reg, mask); return PCA963X_OK; } @@ -493,35 +539,17 @@ uint8_t PCA9635::writeLedOut(uint8_t reg, uint8_t mask) uint8_t PCA9635::readLedOut(uint8_t reg) { if (reg > 3) return 0x00; - return readReg(PCA963X_LEDOUT_BASE + reg); + return readRegister(PCA963X_LEDOUT_BASE + reg); } -// TODO move to right section after testing. +///////////////////////////////////////////////////// +// +// OBSOLETE +// 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 < 4; reg++) - { - writeLedOut(reg, mask); - } - return PCA963X_OK; + return setLedDriverModeAll(mode); } @@ -529,7 +557,7 @@ uint8_t PCA9635::setLedDriverMode(uint8_t mode) // // PRIVATE // -uint8_t PCA9635::writeReg(uint8_t reg, uint8_t value) +uint8_t PCA9635::writeRegister(uint8_t reg, uint8_t value) { _wire->beginTransmission(_address); _wire->write(reg); @@ -542,7 +570,7 @@ uint8_t PCA9635::writeReg(uint8_t reg, uint8_t value) } -uint8_t PCA9635::readReg(uint8_t reg) +uint8_t PCA9635::readRegister(uint8_t reg) { _wire->beginTransmission(_address); _wire->write(reg); diff --git a/PCA9635.h b/PCA9635.h index ca2c503..c6eab2e 100644 --- a/PCA9635.h +++ b/PCA9635.h @@ -3,7 +3,7 @@ // FILE: PCA9635.h // AUTHOR: Rob Tillaart // DATE: 23-apr-2016 -// VERSION: 0.6.0 +// VERSION: 0.6.1 // PURPOSE: Arduino library for PCA9635 I2C LED driver, 16 channel PWM, 8 bit // URL: https://github.com/RobTillaart/PCA9635 @@ -12,46 +12,30 @@ #include "Wire.h" -#define PCA9635_LIB_VERSION (F("0.6.0")) +#define PCA9635_LIB_VERSION (F("0.6.1")) // mode codes -// NEW #define PCA963X_MODE1 0x00 #define PCA963X_MODE2 0x01 -// OLD -#define PCA9635_MODE1 0x00 -#define PCA9635_MODE2 0x01 // 0x80 bit ==> Auto-Increment for all registers. // used in writeN() - see issue #9 PCA9634 -// NEW #define PCA963X_PWM(x) (0x82+(x)) #define PCA963X_GRPPWM 0x12 #define PCA963X_GRPFREQ 0x13 -// OLD -#define PCA9635_PWM(x) (0x82+(x)) -#define PCA9635_GRPPWM 0x12 -#define PCA9635_GRPFREQ 0x13 // check datasheet for details -// NEW -#define PCA963X_LEDOUT_BASE 0x14 // 0x14..0x17 -#define PCA963X_LEDOFF 0x00 // default @ startup +#define PCA963X_LEDOUT_BASE 0x14 // 0x14..0x17 +#define PCA963X_LEDOFF 0x00 // default @ startup #define PCA963X_LEDON 0x01 #define PCA963X_LEDPWM 0x02 #define PCA963X_LEDGRPPWM 0x03 -// OLD -#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 + // Error codes -// NEW #define PCA963X_OK 0x00 #define PCA963X_ERROR 0xFF #define PCA963X_ERR_WRITE 0xFE @@ -59,18 +43,9 @@ #define PCA963X_ERR_MODE 0xFC #define PCA963X_ERR_REG 0xFB #define PCA963X_ERR_I2C 0xFA -// OLD -#define PCA9635_OK 0x00 -#define PCA9635_ERROR 0xFF -#define PCA9635_ERR_WRITE 0xFE -#define PCA9635_ERR_CHAN 0xFD -#define PCA9635_ERR_MODE 0xFC -#define PCA9635_ERR_REG 0xFB -#define PCA9635_ERR_I2C 0xFA // Configuration bits MODE1 register -// NEW #define PCA963X_MODE1_AUTOINCR2 0x80 // ReadOnly, 0 = disable 1 = enable #define PCA963X_MODE1_AUTOINCR1 0x40 // ReadOnly, bit1 #define PCA963X_MODE1_AUTOINCR0 0x20 // ReadOnly, bit0 @@ -80,59 +55,31 @@ #define PCA963X_MODE1_SUB3 0x02 // 0 = disable 1 = enable #define PCA963X_MODE1_ALLCALL 0x01 // 0 = disable 1 = enable #define PCA963X_MODE1_NONE 0x00 -// OLD -#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 -// NEW #define PCA963X_MODE2_BLINK 0x20 // 0 = dim 1 = blink #define PCA963X_MODE2_INVERT 0x10 // 0 = normal 1 = inverted #define PCA963X_MODE2_ACK 0x08 // 0 = on STOP 1 = on ACK #define PCA963X_MODE2_TOTEMPOLE 0x04 // 0 = open drain 1 = totem-pole #define PCA963X_MODE2_NONE 0x00 -// OLD -#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 // Registers in which the ALLCALL and sub-addresses are stored -// NEW #define PCA963X_SUBADR(x) (0x17 +(x)) // x = 1..3 #define PCA963X_ALLCALLADR 0x1B -// OLD -#define PCA9635_SUBADR(x) (0x17+(x)) // x = 1..3 -#define PCA9635_ALLCALLADR 0x1B // Standard ALLCALL and sub-addresses --> only work for write commands and NOT for read commands -// TODO -//#define PCA963X_ALLCALL 0x70 // TDS of chip says 0xE0, however, - // in this library the LSB is added during the write command - // (0xE0 --> 0b11100000, 0x70 --> 0b1110000) -//#define PCA963X_SUB1 0x71 // see line above (0xE2 --> 0x71) -//#define PCA963X_SUB2 0x72 // see line above (0xE4 --> 0x72) -//#define PCA963X_SUB3 0x74 // see line above (0xE8 --> 0x74) - +#define PCA963X_ALLCALL 0x70 // TDS of chip says 0xE0, however, + // in this library the LSB is added during the write command + // (0xE0 --> 0b11100000, 0x70 --> 0b1110000) +#define PCA963X_SUB1 0x71 // see line above (0xE2 --> 0x71) +#define PCA963X_SUB2 0x72 // see line above (0xE4 --> 0x72) +#define PCA963X_SUB3 0x74 // see line above (0xE8 --> 0x74) - -///////////////////////////////////////////////////// -// -// CLASS -// class PCA9635 { public: @@ -151,22 +98,35 @@ class PCA9635 uint8_t configure(uint8_t mode1_mask, uint8_t mode2_mask); uint8_t channelCount(); + + ///////////////////////////////////////////////////// + // + // LED DRIVER MODE + // + uint8_t setLedDriverModeAll(uint8_t mode); uint8_t setLedDriverMode(uint8_t channel, uint8_t mode); uint8_t getLedDriverMode(uint8_t channel); - // reg = 1, 2 check datasheet for values - uint8_t writeMode(uint8_t reg, uint8_t value); - uint8_t readMode(uint8_t reg); - // convenience wrappers + + ///////////////////////////////////////////////////// + // + // WRITE MODE REGISTERS + // + // values == masks see defines above + // check datasheet for detailed meaning uint8_t setMode1(uint8_t value); uint8_t setMode2(uint8_t value); uint8_t getMode1(); uint8_t getMode2(); - void setGroupPWM(uint8_t value); - uint8_t getGroupPWM(); - void setGroupFREQ(uint8_t value); + ///////////////////////////////////////////////////// + // + // GROUP REGISTERS + // + uint8_t setGroupPWM(uint8_t value); + uint8_t getGroupPWM(); + uint8_t setGroupFREQ(uint8_t value); uint8_t getGroupFREQ(); @@ -174,17 +134,21 @@ class PCA9635 // // WRITE // - // single PWM setting + // write single PWM registers uint8_t write1(uint8_t channel, uint8_t value); - // RGB setting, write three consecutive PWM registers + // write three consecutive PWM registers, RGB setting 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); + uint8_t writeN(uint8_t channel, uint8_t * arr, uint8_t count); + + // array at least 16 elements + uint8_t writeAll(uint8_t * arr); + uint8_t allOff(); // generic worker, write N consecutive PWM registers without Stop command - uint8_t writeN_noStop(uint8_t channel, uint8_t* arr, uint8_t count); + uint8_t writeN_noStop(uint8_t channel, uint8_t * arr, uint8_t count); // write stop command to end transmission uint8_t writeStop(); @@ -192,15 +156,7 @@ class PCA9635 ///////////////////////////////////////////////////// // - // ERROR - // - // note error flag is reset after read! - int lastError(); - - - ///////////////////////////////////////////////////// - // - // SUB CALL - ALL CALL (since 0.2.0) + // SUB CALL // // nr = { 1, 2, 3 } bool enableSubCall(uint8_t nr); @@ -208,7 +164,9 @@ class PCA9635 bool isEnabledSubCall(uint8_t nr); bool setSubCallAddress(uint8_t nr, uint8_t address); uint8_t getSubCallAddress(uint8_t nr); - + // + // ALL CALL + // bool enableAllCall(); bool disableAllCall(); bool isEnabledAllCall(); @@ -230,6 +188,7 @@ class PCA9635 // EXPERIMENTAL // // 0.4.4 + // method = 0 or 1 See implementation int I2C_SoftwareReset(uint8_t method); // 0.4.5 // writing reg 14-17 LEDOUT @@ -240,20 +199,38 @@ class PCA9635 // 3 12..15 uint8_t writeLedOut(uint8_t reg, uint8_t mask); uint8_t readLedOut(uint8_t reg); + + + ///////////////////////////////////////////////////// + // + // ERROR + // + // note error flag is reset after read! + int lastError(); + + + ///////////////////////////////////////////////////// + // + // OBSOLETE future + // + [[deprecated("Use setLedDriverModeAll(mode) instead")]] uint8_t setLedDriverMode(uint8_t mode); + [[deprecated("use setMode1(value) or setMode2(value) instead")]] + uint8_t writeMode(uint8_t reg, uint8_t value); + uint8_t readMode(uint8_t reg); + private: // DIRECT CONTROL - uint8_t writeReg(uint8_t reg, uint8_t value); // returns error status. - uint8_t readReg(uint8_t reg); + uint8_t writeRegister(uint8_t reg, uint8_t value); // returns error status. + uint8_t readRegister(uint8_t reg); uint8_t _address; - int _error; + TwoWire * _wire; + int _error = PCA963X_OK; uint8_t _channelCount = 16; uint8_t _OutputEnablePin; - - TwoWire* _wire; }; diff --git a/README.md b/README.md index 36784a0..ba4907e 100644 --- a/README.md +++ b/README.md @@ -21,8 +21,15 @@ The 16 channels are independently configurable in steps of 1/256. This allows for better than 1% fine tuning of the duty-cycle of the PWM signal. +Feedback is welcome, please open an issue with your questions and remarks. -#### 0.5.0 Breaking change + +### 0.6.1 change + +Some functions are deprecated, replacements available. + + +### 0.5.0 Breaking change Version 0.5.0 introduced a breaking change. You cannot set the pins in **begin()** any more. @@ -31,11 +38,13 @@ The user has to call **Wire.begin()** and can optionally set the Wire pins before calling **begin()**. -#### Related +### Related +- https://github.com/RobTillaart/PCA9632 (4 channel) - https://github.com/RobTillaart/PCA9634 (8 channel) - https://github.com/RobTillaart/PCA9635 (16 channel) - https://github.com/RobTillaart/PCA9685_RT (16 channel) +- https://github.com/RobTillaart/map2colour ## Interface @@ -45,27 +54,27 @@ before calling **begin()**. ``` -#### Constructor +### Constructor - **PCA9635(uint8_t deviceAddress, TwoWire \*wire = &Wire)** Constructor with I2C device address, and optional the Wire interface as parameter. - **bool begin(uint8_t mode1_mask = PCA963X_MODE1_ALLCALL, uint8_t mode2_mask = PCA963X_MODE2_NONE)** initializes the library after startup. Optionally setting the MODE1 and MODE2 configuration registers. -See PCA9635.h and datasheet for settings possible. +See .h and datasheet for settings possible. - **void configure(uint8_t mode1_mask, uint8_t mode2_mask)** To configure the library after startup one can set the MODE1 and MODE2 configuration registers. -See PCA9635.h and datasheet for settings possible. +See .h and datasheet for settings possible. - **bool isConnected()** checks if address is available on I2C bus. -- **uint8_t channelCount()** returns the number of channels = 16. +- **uint8_t channelCount()** returns the number of channels (16). -#### LedDriverMode +### LedDriverMode -Configure LED behaviour. +Configure LED behaviour. Channel = 0..7. Check datasheet for details. -- **uint8_t setLedDriverMode(uint8_t channel, uint8_t mode)** mode is 0..3 See datasheet for full details. +- **uint8_t setLedDriverMode(uint8_t channel, uint8_t mode)** set mode for one channel. - returns error code, see below. -- **uint8_t setLedDriverMode(uint8_t mode)** set same mode for ALL channels. +- **uint8_t setLedDriverModeAll(uint8_t mode)** set same mode for ALL channels. - **uint8_t getLedDriverMode(uint8_t channel)** returns the current mode of the channel. | LED mode | Value | Description | @@ -80,7 +89,7 @@ Configure LED behaviour. 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. @@ -94,24 +103,37 @@ write count consecutive PWM registers. May return **PCA963X_ERR_CHAN** if array has too many elements (including channel as offset). +Write all channels at once -#### Mode registers +- **uint8_t writeAll(uint8_t \* arr)** array of at least 8 elements. +- **uint8_t allOff()** idem. -Used to configure the PCA963x general behaviour. -- **uint8_t writeMode(uint8_t reg, uint8_t value)** configuration of one of the two configuration registers. -Check datasheet for details. -- **uint8_t readMode(uint8_t reg)** reads back the configured mode, -useful to add or remove a single flag (bit masking). -- **uint8_t setMode1(uint8_t value)** convenience wrapper. -- **uint8_t setMode2(uint8_t value)** convenience wrapper. -- **uint8_t getMode1()** convenience wrapper. -- **uint8_t getMode2()** convenience wrapper. +### Multi call writes. + +- **uint8_t writeN_noStop(uint8_t channel, uint8_t \* array, uint8_t count)** +See **Synchronous multi-chip multi-LED operation** below. +- **writeStop()** + + +### Mode registers +Used to configure the PCA963x general behaviour. Check datasheet for details. -#### Constants for mode registers +- **uint8_t setMode1(uint8_t value)** see table below +- **uint8_t setMode2(uint8_t value)** see table below +- **uint8_t getMode1()** +- **uint8_t getMode2()** +Obsolete in near future, use functions above as those are less error prone. + +- **uint8_t writeMode(uint8_t reg, uint8_t value)** configuration of one of the two configuration registers. +- **uint8_t readMode(uint8_t reg)** reads the configured mode + + +### Constants for mode registers + | Name | Value | Description | |:--------------------------|:-------:|:-------------------------------------| | PCA963X_MODE1_AUTOINCR2 | 0x80 | Read Only, 0 = disable 1 = enable | @@ -135,32 +157,32 @@ 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: ```cpp -ledArray.writeMode(PCA963X_MODE2, 0b00110100); +ledArray.setMode2(0b00110100); // would become uint8_t mode2_mask = PCA963X_MODE2_BLINK | PCA963X_MODE2_INVERT | PCA963X_MODE2_TOTEMPOLE; -ledArray.writeMode(PCA963X_MODE2, mode2_mask); +ledArray.setMode2(mode2_mask); -// or even +// or ledArray.setMode2(PCA963X_MODE2_BLINK | PCA963X_MODE2_INVERT | PCA963X_MODE2_TOTEMPOLE); ``` -#### Group PWM and frequency +### Group PWM and frequency Check datasheet for the details. -- **void setGroupPWM(uint8_t value)** sets all channels that are part of the PWM group to value. +- **uint8_t setGroupPWM(uint8_t value)** sets all channels that are part of the PWM group to value. - **uint8_t getGroupPWM()** get the current PWM setting of the group. -- **void setGroupFREQ(uint8_t value)** is used for blinking the group of configured LED. +- **uint8_t setGroupFREQ(uint8_t value)** is used for blinking the group of configured LED. Value goes from 0 to 255 with each step representing an increase of approx. 41 ms. 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 +### Error - **int lastError()** returns **PCA963X_OK** if all is OK, and other error codes otherwise. @@ -179,18 +201,18 @@ So 0x00 results in 41 ms blinking period (on AND off) and 0xFF in approx. 10.5 s Please read the datasheet to understand the working of **SUB CALL** and **ALL CALL**. -Since version 0.4.0 there is (experimental) support for the **SUB CALL** and **ALL CALL** functions. +There is (experimental) support for the **SUB CALL** and **ALL CALL** functions. It needs more testing and if there are issues, please report. AllCall is automatically activated for each device on startup. -#### Description +### Description **SUB CALL** allows one to make groups of PCA9635 devices and control them on group level. The number of groups one can make depends on free I2C addresses on one I2C bus. Using multiple I2C buses or multiplexers will even increase the possible number. -Every PCA9635 device can be member of up to three of these groups. +Every PCA9635 device can be member of up to three of these groups. To become member one needs to set the **setSubCallAddress(nr, address)** and enable it with **enableSubCall(nr)**. @@ -198,7 +220,7 @@ In the same way one can become member of an **ALL CALL** group. Typically there is only one such group but one can configure more of them by applying different addresses. -#### Interface +### Interface The functions to enable all/sub-addresses are straightforward: @@ -215,9 +237,9 @@ The functions to enable all/sub-addresses are straightforward: - **uint8_t getAllCallAddress()** -#### OutputEnable +### OutputEnable -Since 0.4.3 (experimental) support to control the OE (Output Enable) pin of the PCA9635. +There is (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 devices by connecting the OE pins. Think of simultaneous switching ON/OFF or get dimming with a high frequency PWM. @@ -239,7 +261,7 @@ Note: the OE is LOW active. The user has to set the power on value by means of a PULL UP / DOWN resistor. -#### I2C Software reset +### I2C Software reset The goal of this function is to reset ALL devices on the bus. When using the software reset, ALL devices attached to the bus are set to their hardware startup conditions. @@ -266,7 +288,7 @@ please give feedback, so the documentation can be improved. For further details of the development, see - #10 (PCA9634 repo) -#### LEDOUT +### LEDOUT Experimental, needs testing, read datasheet 7.3.6 @@ -276,7 +298,7 @@ The typical use case is to use PWM per channel but one can also set a channel / LED fully ON or OFF. These functions are a fast way to switch multiple LEDs ON/OFF. -The 4 registers LEDOUT0 .. LEDOUT3 each control 4 channels +The four registers LEDOUT0 .. LEDOUT3 each control 4 channels | register | channels | mask layout | notes | |:----------:|:----------:|:-------------:|:-------:| @@ -309,18 +331,17 @@ PCA.writeLedOut(1, mask); - improve documentation - restructure readme.md - #### Should +- keep in sync with PCA9632/34/35/85 developments - improve error handling - return values etc. - documentation. -- keep in sync with PCA9634/5 developments -- remove OLD #defines PCA9635_... => PCA963X - - const int? +- #defines ==> const int? #### Could +- default values for functions. - unit tests - SUB CALL if possible? - ALL CALL if possible? @@ -333,7 +354,7 @@ PCA.writeLedOut(1, mask); - readme.md - **setGroupFreq()** - set time in milliseconds and round to nearest value? - +- read back (cache?) #### Wont diff --git a/examples/PCA9635_shift_rotate/PCA9635_shift_rotate.ino b/examples/PCA9635_shift_rotate/PCA9635_shift_rotate.ino index d50cb15..6811e3a 100644 --- a/examples/PCA9635_shift_rotate/PCA9635_shift_rotate.ino +++ b/examples/PCA9635_shift_rotate/PCA9635_shift_rotate.ino @@ -36,7 +36,7 @@ void setup() ledArray.setLedDriverMode(channel, PCA963X_LEDOFF); } // set all to PWM - ledArray.setLedDriverMode(PCA963X_LEDPWM); + ledArray.setLedDriverModeAll(PCA963X_LEDPWM); initArray(); diff --git a/examples/PCA9635_test01/PCA9635_test01.ino b/examples/PCA9635_test01/PCA9635_test01.ino index 2f2bf35..caa52a4 100644 --- a/examples/PCA9635_test01/PCA9635_test01.ino +++ b/examples/PCA9635_test01/PCA9635_test01.ino @@ -181,14 +181,16 @@ void testSetAndReadMode() Serial.print(millis()); Serial.print("\t"); Serial.println("Test - readMode"); - uint8_t regval = ledArray.readMode(PCA963X_MODE1); - ledArray.writeMode(PCA963X_MODE1, regval); // non destructive + + uint8_t regval = ledArray.getMode1(); + ledArray.setMode1(regval); // non destructive Serial.print(millis()); Serial.print("\t"); Serial.print("PCA963X_MODE1: "); Serial.println(regval); - regval = ledArray.readMode(PCA963X_MODE2); - ledArray.writeMode(PCA963X_MODE2, regval); + + regval = ledArray.getMode2(); + ledArray.setMode2(regval); Serial.print(millis()); Serial.print("\t"); Serial.print("PCA963X_MODE2: "); diff --git a/keywords.txt b/keywords.txt index f7f7ee9..eb95e87 100644 --- a/keywords.txt +++ b/keywords.txt @@ -7,18 +7,16 @@ PCA9635 KEYWORD1 # Methods and Functions (KEYWORD2) begin KEYWORD2 +isConnected KEYWORD2 +getAddress KEYWORD2 + configure KEYWORD2 +channelCount KEYWORD2 -isConnected KEYWORD2 +setLedDriverModeAll KEYWORD2 setLedDriverMode KEYWORD2 getLedDriverMode KEYWORD2 -write1 KEYWORD2 -write3 KEYWORD2 -writeN KEYWORD2 - -writeMode KEYWORD2 -readMode KEYWORD2 setMode1 KEYWORD2 setMode2 KEYWORD2 getMode1 KEYWORD2 @@ -29,7 +27,14 @@ getGroupPWM KEYWORD2 setGroupFREQ KEYWORD2 getGroupFREQ KEYWORD2 -lastError KEYWORD2 +write1 KEYWORD2 +write3 KEYWORD2 +writeN KEYWORD2 +writeAll KEYWORD2 +allOff KEYWORD2 + +writeN_noStop KEYWORD2 +writeStop KEYWORD2 enableSubCall KEYWORD2 disableSubCall KEYWORD2 @@ -48,6 +53,9 @@ writeLedOut KEYWORD2 readLedOut KEYWORD2 +lastError KEYWORD2 + + # # Constants ( LITERAL1) # diff --git a/library.json b/library.json index 3326378..e564413 100644 --- a/library.json +++ b/library.json @@ -15,7 +15,7 @@ "type": "git", "url": "https://github.com/RobTillaart/PCA9635.git" }, - "version": "0.6.0", + "version": "0.6.1", "license": "MIT", "frameworks": "*", "platforms": "*", diff --git a/library.properties b/library.properties index 78e6a44..9d7758b 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=PCA9635 -version=0.6.0 +version=0.6.1 author=Rob Tillaart maintainer=Rob Tillaart sentence=Arduino library for PCA9635 I2C LED driver, 16 channel PWM, 8 bit. diff --git a/test/unit_test_001.cpp b/test/unit_test_001.cpp index a098bc8..da9828b 100644 --- a/test/unit_test_001.cpp +++ b/test/unit_test_001.cpp @@ -94,7 +94,7 @@ unittest(test_LedDriverMode) assertTrue(ledArray.begin()); - // TODO + // TODO }