PCA9685 Driver
API reference
Loading...
Searching...
No Matches
pca9685.hpp
Go to the documentation of this file.
1
6#pragma once
7#include <algorithm>
8#include <array>
9#include <cmath>
10#include <cstddef>
11#include <cstdint>
12
14#include "pca9685_version.h"
15
16namespace pca9685 {
17
34template <typename I2cType>
35class PCA9685 {
36public:
44 enum class Error : uint16_t {
45 None = 0,
46 I2cWrite = 1 << 0,
47 I2cRead = 1 << 1,
48 InvalidParam = 1 << 2,
49 DeviceNotFound = 1 << 3,
50 NotInitialized = 1 << 4,
51 OutOfRange = 1 << 5
52 };
53
57 enum class Register : uint8_t {
58 MODE1 = 0x00,
59 MODE2 = 0x01,
60 SUBADR1 = 0x02,
61 SUBADR2 = 0x03,
62 SUBADR3 = 0x04,
63 ALLCALLADR = 0x05,
64 LED0_ON_L = 0x06,
65 LED0_ON_H = 0x07,
66 LED0_OFF_L = 0x08,
68 0x09,
69 /* LED1–LED15: registers 0x0A–0x45 (four bytes per channel, same layout as LED0) */
70 ALL_LED_ON_L = 0xFA,
71 ALL_LED_ON_H = 0xFB,
72 ALL_LED_OFF_L = 0xFC,
73 ALL_LED_OFF_H = 0xFD,
74 PRE_SCALE = 0xFE,
75 TESTMODE = 0xFF
76 };
77
78 static constexpr uint8_t MAX_CHANNELS_ = 16;
79 static constexpr uint16_t MAX_PWM_ = 4095;
80 static constexpr uint32_t OSC_FREQ_ = 25000000;
83 static constexpr uint32_t OSC_STARTUP_US_ = 500;
84
91 PCA9685(I2cType* bus, uint8_t address);
92
106 bool EnsureInitialized() noexcept;
107
112 bool IsInitialized() const noexcept {
113 return initialized_;
114 }
115
127 bool Reset() noexcept;
128
139 bool SetPwmFreq(float freq_hz) noexcept;
140
152 bool SetPwm(uint8_t channel, uint16_t on_time, uint16_t off_time) noexcept;
153
166 bool SetDuty(uint8_t channel, float duty) noexcept;
167
177 bool SetAllPwm(uint16_t on_time, uint16_t off_time) noexcept;
178
183 [[nodiscard]] uint16_t GetErrorFlags() const noexcept {
184 return error_flags_;
185 }
186
197 [[nodiscard]] bool HasError(Error e) const noexcept {
198 return (error_flags_ & static_cast<uint16_t>(e)) != 0;
199 }
200
205 [[nodiscard]] bool HasAnyError() const noexcept {
206 return error_flags_ != 0;
207 }
208
213 void ClearError(Error e) noexcept {
214 error_flags_ &= ~static_cast<uint16_t>(e);
215 }
216
221 void ClearErrorFlags(uint16_t mask = 0xFFFF) noexcept {
222 error_flags_ &= ~mask;
223 }
224
229 [[nodiscard]] Error GetLastError() const noexcept {
230 return last_error_;
231 }
232
238 [[nodiscard]] bool GetPrescale(uint8_t& prescale) noexcept;
239
244 void SetRetries(int retries) noexcept {
245 retries_ = retries;
246 }
247
254 using RetryDelayFn = void (*)();
255
265 void SetRetryDelay(RetryDelayFn fn) noexcept {
266 retry_delay_ = fn;
267 }
268
269 // ---- Power Management ----
270
279 bool Sleep() noexcept;
280
292 bool Wake() noexcept;
293
294 // ---- Output Configuration ----
295
305 bool SetOutputInvert(bool invert) noexcept;
306
316 bool SetOutputDriverMode(bool totem_pole) noexcept;
317
333 bool SetOutputEnable(bool enable) noexcept;
334
335 // ---- Channel On/Off ----
336
345 bool SetChannelFullOn(uint8_t channel) noexcept;
346
355 bool SetChannelFullOff(uint8_t channel) noexcept;
356
357 // ===========================================================================
358 // Driver Version
359 // ===========================================================================
360
374 static constexpr const char* GetDriverVersion() noexcept {
375 return HF_PCA9685_VERSION_STRING;
376 }
377
382 static constexpr uint8_t GetDriverVersionMajor() noexcept {
383 return HF_PCA9685_VERSION_MAJOR;
384 }
385
390 static constexpr uint8_t GetDriverVersionMinor() noexcept {
391 return HF_PCA9685_VERSION_MINOR;
392 }
393
398 static constexpr uint8_t GetDriverVersionPatch() noexcept {
399 return HF_PCA9685_VERSION_PATCH;
400 }
401
402private:
403 static constexpr uint8_t MODE1_RESTART_ = 0x80;
404 static constexpr uint8_t MODE1_AI_ = 0x20;
405 static constexpr uint8_t MODE1_SLEEP_ = 0x10;
407 static constexpr uint32_t OSC_STARTUP_FALLBACK_READS_ = 13;
408
409 I2cType* i2c_;
410 uint8_t addr_;
412 uint16_t error_flags_{0};
413 int retries_{3};
415 bool initialized_{false};
416
418 void setError(Error e) noexcept {
419 last_error_ = e;
420 error_flags_ |= static_cast<uint16_t>(e);
421 }
422
425 bool writeReg(uint8_t reg, uint8_t value) noexcept;
428 bool readReg(uint8_t reg, uint8_t& value) noexcept;
431 bool writeRegBlock(uint8_t reg, const uint8_t* data, size_t len) noexcept;
434 bool readRegBlock(uint8_t reg, uint8_t* data, size_t len) noexcept;
437 [[nodiscard]] uint8_t calcPrescale(float freq_hz) const noexcept;
438
444 bool writeMode1(uint8_t value) noexcept;
445
452 bool restartAfterSleep(uint8_t mode1, bool restart) noexcept;
453
458 void waitOscillatorStartup() noexcept;
459
466 [[nodiscard]] static ::std::array<uint8_t, 4> pwmFrame(uint16_t on_time,
467 uint16_t off_time) noexcept;
468
476 bool modifyReg(uint8_t reg, uint8_t mask, uint8_t value) noexcept;
477};
478
479// Include template implementation
480#define PCA9685_HEADER_INCLUDED
481// NOLINTNEXTLINE(bugprone-suspicious-include) - Intentional: template
482// implementation file
483#include "../src/pca9685.ipp"
484#undef PCA9685_HEADER_INCLUDED
485
486// Public API: Get driver version string
487inline const char* GetDriverVersion() noexcept {
488 return HF_PCA9685_VERSION_STRING;
489}
490
491} // namespace pca9685
Driver for the PCA9685 16-channel 12-bit PWM controller.
Definition pca9685.hpp:35
void(*)() RetryDelayFn
Type of optional callback invoked between I2C retry attempts.
Definition pca9685.hpp:254
void SetRetries(int retries) noexcept
Set the I2C retry count for register read/write operations.
Definition pca9685.hpp:244
bool IsInitialized() const noexcept
Check if the driver has been initialized.
Definition pca9685.hpp:112
bool SetPwmFreq(float freq_hz) noexcept
Set the PWM frequency for all channels.
Definition pca9685.ipp:57
static constexpr uint8_t MODE1_RESTART_
MODE1 bit 7: RESTART (Table 5)
Definition pca9685.hpp:403
bool SetPwm(uint8_t channel, uint16_t on_time, uint16_t off_time) noexcept
Set the PWM on/off time for a channel.
Definition pca9685.ipp:91
static constexpr uint8_t GetDriverVersionPatch() noexcept
Get the compiled driver patch version number.
Definition pca9685.hpp:398
bool SetAllPwm(uint16_t on_time, uint16_t off_time) noexcept
Set all channels to the same PWM value.
Definition pca9685.ipp:127
bool initialized_
Definition pca9685.hpp:415
static constexpr uint32_t OSC_STARTUP_US_
Definition pca9685.hpp:83
uint8_t calcPrescale(float freq_hz) const noexcept
Compute prescale value for given frequency.
Definition pca9685.ipp:410
uint8_t addr_
Definition pca9685.hpp:410
static constexpr uint8_t GetDriverVersionMajor() noexcept
Get the compiled driver major version number.
Definition pca9685.hpp:382
void setError(Error e) noexcept
Set last error and add to error flags.
Definition pca9685.hpp:418
bool Wake() noexcept
Wake the PCA9685 from sleep mode.
Definition pca9685.ipp:177
void ClearErrorFlags(uint16_t mask=0xFFFF) noexcept
Clear specific error flags by raw bitmask.
Definition pca9685.hpp:221
Error
Error codes for PCA9685 operations (bitmask flags).
Definition pca9685.hpp:44
@ OutOfRange
Value out of hardware range.
@ I2cRead
An I2C read operation failed.
@ NotInitialized
Driver not initialized.
@ DeviceNotFound
Device did not respond.
@ InvalidParam
Invalid parameter (channel, value, etc.)
@ I2cWrite
An I2C write operation failed.
static constexpr uint32_t OSC_STARTUP_FALLBACK_READS_
MODE1 reads that cover OSC_STARTUP_US_ at 1 MHz SCL when the port has no DelayUs().
Definition pca9685.hpp:407
bool SetOutputInvert(bool invert) noexcept
Set output polarity inversion.
Definition pca9685.ipp:202
static ::std::array< uint8_t, 4 > pwmFrame(uint16_t on_time, uint16_t off_time) noexcept
Build the four LEDn / ALL_LED bytes for ON and OFF ticks; equal ticks give full OFF.
Definition pca9685.ipp:384
bool EnsureInitialized() noexcept
Ensure the driver and I2C bus are initialized (lazy initialization).
Definition pca9685.ipp:28
static constexpr uint16_t MAX_PWM_
Maximum tick value (12-bit)
Definition pca9685.hpp:79
Error last_error_
Definition pca9685.hpp:411
bool Reset() noexcept
Reset the device to its power-on default state.
Definition pca9685.ipp:36
void ClearError(Error e) noexcept
Clear a single error flag.
Definition pca9685.hpp:213
int retries_
Definition pca9685.hpp:413
uint16_t error_flags_
Definition pca9685.hpp:412
RetryDelayFn retry_delay_
Definition pca9685.hpp:414
static constexpr uint8_t GetDriverVersionMinor() noexcept
Get the compiled driver minor version number.
Definition pca9685.hpp:390
void waitOscillatorStartup() noexcept
Wait OSC_STARTUP_US_ through I2cType::DelayUs(), or with MODE1 reads if the port has none.
Definition pca9685.ipp:368
bool readReg(uint8_t reg, uint8_t &value) noexcept
Read one byte from a register.
Definition pca9685.ipp:294
bool SetDuty(uint8_t channel, float duty) noexcept
Set the duty cycle for a channel (0.0-1.0).
Definition pca9685.ipp:113
I2cType * i2c_
Definition pca9685.hpp:409
bool SetOutputEnable(bool enable) noexcept
Enable or blank all 16 outputs with the OE pin.
Definition pca9685.ipp:222
static constexpr uint32_t OSC_FREQ_
Definition pca9685.hpp:80
void SetRetryDelay(RetryDelayFn fn) noexcept
Set optional callback invoked between I2C retry attempts (after a failure, before next try).
Definition pca9685.hpp:265
bool readRegBlock(uint8_t reg, uint8_t *data, size_t len) noexcept
Read a block of bytes from a register.
Definition pca9685.ipp:329
bool SetChannelFullOn(uint8_t channel) noexcept
Set a channel to fully ON (100% duty, no PWM).
Definition pca9685.ipp:235
bool modifyReg(uint8_t reg, uint8_t mask, uint8_t value) noexcept
Read-modify-write a single register.
Definition pca9685.ipp:396
bool Sleep() noexcept
Put the PCA9685 into low-power sleep mode.
Definition pca9685.ipp:160
static constexpr uint8_t MODE1_SLEEP_
Definition pca9685.hpp:405
Register
PCA9685 register map (I2C register addresses).
Definition pca9685.hpp:57
@ LED0_OFF_H
LED0 output and brightness control byte 3 (off time, high bits + full-off)
@ ALL_LED_ON_L
All LED on time, low byte.
@ SUBADR1
I2C subaddress 1.
@ PRE_SCALE
Prescaler for PWM frequency (oscillator / (4096 * freq))
@ LED0_ON_L
LED0 output and brightness control byte 0 (on time, low byte)
@ LED0_ON_H
LED0 output and brightness control byte 1 (on time, high bits + full-on)
@ LED0_OFF_L
LED0 output and brightness control byte 2 (off time, low byte)
@ MODE2
Mode register 2 (output drive, invert, output change behaviour)
@ TESTMODE
Test mode register.
@ ALL_LED_OFF_L
All LED off time, low byte.
@ ALL_LED_OFF_H
All LED off time, high bits.
@ ALLCALLADR
All-call I2C address.
@ MODE1
Mode register 1 (reset, sleep, auto-increment, etc.)
@ SUBADR3
I2C subaddress 3.
@ ALL_LED_ON_H
All LED on time, high bits.
@ SUBADR2
I2C subaddress 2.
bool SetChannelFullOff(uint8_t channel) noexcept
Set a channel to fully OFF (0% duty, no PWM).
Definition pca9685.ipp:255
bool writeMode1(uint8_t value) noexcept
Write MODE1 with AI forced to 1 and RESTART forced to 0.
Definition pca9685.ipp:346
bool restartAfterSleep(uint8_t mode1, bool restart) noexcept
Clear SLEEP, wait for the oscillator, then optionally write RESTART (datasheet 7.3....
Definition pca9685.ipp:354
Error GetLastError() const noexcept
Get the last error code (single-error convenience accessor).
Definition pca9685.hpp:229
bool HasAnyError() const noexcept
Check if any error flag is set.
Definition pca9685.hpp:205
uint16_t GetErrorFlags() const noexcept
Get the accumulated error flags (bitmask).
Definition pca9685.hpp:183
static constexpr const char * GetDriverVersion() noexcept
Get the compiled driver version string.
Definition pca9685.hpp:374
static constexpr uint8_t MODE1_AI_
MODE1 bit 5: register auto-increment.
Definition pca9685.hpp:404
bool GetPrescale(uint8_t &prescale) noexcept
Get the current prescale value (frequency divider).
Definition pca9685.ipp:145
static constexpr uint8_t MAX_CHANNELS_
Number of PWM channels (0-15)
Definition pca9685.hpp:78
bool HasError(Error e) const noexcept
Check if a specific error flag is set.
Definition pca9685.hpp:197
bool writeReg(uint8_t reg, uint8_t value) noexcept
Write one byte to a register.
Definition pca9685.ipp:277
bool writeRegBlock(uint8_t reg, const uint8_t *data, size_t len) noexcept
Write a block of bytes to a register.
Definition pca9685.ipp:311
bool SetOutputDriverMode(bool totem_pole) noexcept
Set the output driver mode.
Definition pca9685.ipp:212
Definition pca9685.hpp:16
CRTP-based I2C interface for PCA9685 driver.