36constexpr uint8_t kHardwareRows = 12;
37constexpr uint8_t kHardwareCols = 16;
38constexpr uint8_t kLedCount = kHardwareRows * kHardwareCols;
40constexpr uint8_t kLogicalRows = 4;
50enum CommonRegister : uint8_t {
62enum PagedRegister : uint16_t {
87enum PswlOptions : uint8_t {
96enum ImrOptions : uint8_t {
107enum IsrOptions : uint8_t {
119enum CrOptions : uint8_t {
120 CR_SYNC_MASTER = 0x40,
121 CR_SYNC_SLAVE = 0x80,
131inline uint8_t CR_PFS(uint8_t page) {
132 return (page & 0x03) << 5;
143enum class ColorOrder : uint8_t {
156enum class ABMMode : uint8_t {
167enum AbmT1 : uint8_t {
181enum AbmT2 : uint8_t {
196enum AbmT3 : uint8_t {
210enum AbmT4 : uint8_t {
227enum AbmLoopBegin : uint8_t {
228 LOOP_BEGIN_T1 = 0x00,
229 LOOP_BEGIN_T2 = 0x10,
230 LOOP_BEGIN_T3 = 0x20,
231 LOOP_BEGIN_T4 = 0x30,
237enum AbmLoopEnd : uint8_t {
243constexpr int kAbmLoopTimesMax = 0x0FFF;
245constexpr int kAbmLoopForever = 0x0000;
283 IS31FL3733(TwoWire *wire, uint8_t addr = 0x50, uint8_t sdbPin = 0xFF, uint8_t irqPin = 0xFF);
302 bool begin(uint8_t pfs = 0, uint8_t pur = 0b111, uint8_t pdr = 0b111);
329 void SetGCC(uint8_t gcc);
333 void SetSWPUR(uint8_t pur);
337 void SetCSPDR(uint8_t pdr);
342 void SetPFS(uint8_t pfs);
346 void SetIMR(uint8_t imrMask);
354 _maskShortFaults = enable;
359 return _maskShortFaults;
364 return _pwmTxn.txPtr !=
nullptr || _pwmEnqueued != 0u || _pwmLocked || _pwmBatchActive;
377 void SetPixelPWM(uint8_t row, uint8_t col, uint8_t pwm);
382 void SetRowPWM(uint8_t row,
const uint8_t *pwmValues);
388 void BeginPwmBatch();
392 void EndPwmBatch(
bool flush =
true);
398 void SetPixelMode(uint8_t row, uint8_t col, ABMMode mode);
403 void SetRowMode(uint8_t row, ABMMode mode);
409 ABMMode GetPixelMode(uint8_t row, uint8_t col)
const;
423 void SetPixelColor(uint8_t row, uint8_t col, uint8_t r, uint8_t g, uint8_t b);
429 void SetPixelColorMode(uint8_t row, uint8_t col, ABMMode mode);
451 void Fill(uint8_t pwm = 0);
455 void SetMatrixMode(ABMMode mode);
460 void SetABMCallback(uint8_t abmNum, std::function<
void()> callback);
471 void ConfigureABM(uint8_t abmNumber,
const ABMConfig &config);
474 void ConfigureABM1(
const ABMConfig &config);
477 void ConfigureABM2(
const ABMConfig &config);
480 void ConfigureABM3(
const ABMConfig &config);
484 void EnableABM(
bool enable =
true);
536 uint8_t _pwm_matrix[kHardwareRows]
539 uint8_t _pwmTxPtr[kHardwareCols + 1];
553 uint8_t _abm_matrix[kHardwareRows]
556 uint8_t _abmTxPtr[kHardwareCols + 1];
563 std::function<void()> _abmCallbacks[3];
571 SercomTxn _cmdTxn[4];
577 void (*userCallback)(
void *, int);
604 uint8_t _ledOpen[24];
605 uint8_t _ledShort[24];
626 inline void _sendRowPWM();
629 inline void _sendRowMode();
634 void _ensurePage(uint8_t page);
637 void _resumeDataTransfers();
640 inline void _asyncWrite(uint16_t pagereg,
const uint8_t *data, uint8_t len,
641 void (*callback)(
void *,
int) =
nullptr,
void *user =
nullptr);
644 inline void _asyncRead(uint16_t pagereg, uint8_t *dest, uint8_t len,
645 void (*callback)(
void *,
int) =
nullptr,
void *user =
nullptr);
648 bool _syncWrite(uint16_t pagereg,
const uint8_t *data, uint8_t len);
651 bool _syncRead(uint16_t pagereg, uint8_t *dest, uint8_t len);
662 static inline void _txnCallback(
void *user,
int status);
667 static inline void _txnModeCallback(
void *user,
int status);
670 static inline void _irqCallback();
675 static inline void _onServiceCallback(
void *user,
int status);
680 static void _cmdCallback(
void *user,
int status);
683 static void _osbCallback(
void *user,
int status);
687 static void _abm1CallbackWrapper();
689 static void _abm2CallbackWrapper();
691 static void _abm3CallbackWrapper();
701 if (_pwmLocked || _pwmBatchActive || _pwmTxn.txPtr)
705 int row = _pwmPendingRows.read_char();
708 for (uint8_t candidate = 0; candidate < kHardwareRows; candidate++) {
709 if (_pwmEnqueued & (1u << candidate)) {
720 _pwmEnqueued &= ~(1 << row);
723 memcpy(_pwmTxPtr, _pwm_matrix[row], 17);
726 _pwmTxn.txPtr = _pwmTxPtr;
727 _pwmTxn.chainNext =
false;
732 _hw->enqueueWIRE(&_pwmTxn);
737 if (_abmLocked || _abmTxn.txPtr)
741 int row = _abmPendingRows.read_char();
744 for (uint8_t candidate = 0; candidate < kHardwareRows; candidate++) {
745 if (_abmEnqueued & (1u << candidate)) {
756 _abmEnqueued &= ~(1 << row);
760 memcpy(_abmTxPtr, _abm_matrix[row], 17);
763 _abmTxn.txPtr = _abmTxPtr;
764 _abmTxn.chainNext =
false;
769 _hw->enqueueWIRE(&_abmTxn);
773 void (*callback)(
void *,
int),
void *user) {
774 uint8_t page = pagereg >> 8;
779 _cmdTx[0] = pagereg & 0xFF;
780 }
else if (page >= IMR)
786 memcpy(_cmdTx + 1, data, len);
789 _cmdTxn[2].length = 1 + len;
791 _cmdCtx[2].
user = user;
794 _cmdTxn[2].onComplete = _cmdCallback;
795 _cmdTxn[2].user = &_cmdCtx[2];
796 _cmdTxn[2].chainNext =
false;
797 _hw->enqueueWIRE(&_cmdTxn[2]);
801 void (*callback)(
void *,
int),
void *user) {
802 uint8_t page = pagereg >> 8;
807 _cmdTx[0] = pagereg & 0xFF;
808 }
else if (page >= IMR)
814 _cmdTxn[2].length = 1;
816 _cmdCtx[2].
user =
nullptr;
819 _cmdTxn[2].onComplete = _cmdCallback;
820 _cmdTxn[2].user = &_cmdCtx[2];
821 _cmdTxn[2].chainNext =
false;
824 _cmdTxn[3].rxPtr = dest;
825 _cmdTxn[3].length = len;
827 _cmdCtx[3].
user = user;
830 _cmdTxn[3].onComplete = _cmdCallback;
831 _cmdTxn[3].user = &_cmdCtx[3];
832 _cmdTxn[3].chainNext =
false;
835 _hw->enqueueWIRE(&_cmdTxn[2]);
836 _hw->enqueueWIRE(&_cmdTxn[3]);
848 self->_pwmTxn.txPtr =
nullptr;
859 self->_abmTxn.txPtr =
nullptr;
862 self->_sendRowMode();
869 _instance->_asyncRead((uint16_t)ISR << 8, &_instance->_lastISR, 1, _onServiceCallback,
879 self->_pwmLocked =
true;
880 self->_abmLocked =
true;
882 uint8_t isr = self->_lastISR;
887 _abm1CallbackWrapper();
889 _abm2CallbackWrapper();
891 _abm3CallbackWrapper();
894 const bool hasOpenFault = (isr & ISR_OB) != 0;
895 const bool hasShortFault = ((isr & ISR_SB) != 0) && self->_maskShortFaults;
898 if (hasOpenFault || hasShortFault) {
900 uint16_t pagereg = hasOpenFault ? LEDOPEN : LEDSHORT;
901 uint8_t *dest = hasOpenFault ? self->_ledOpen : self->_ledShort;
904 self->_asyncRead(pagereg, dest, 24, _osbCallback, self);
910 self->_resumeDataTransfers();
Asynchronous DMA-driven IS31FL3733 LED driver for SAMD SERCOM I2C.
static void _irqCallback()
GPIO IRQ callback (triggered by IRQ pin edge).
bool _begun
True after successful begin(); used for destructor auto-end safety.
void _asyncRead(uint16_t pagereg, uint8_t *dest, uint8_t len, void(*callback)(void *, int)=nullptr, void *user=nullptr)
Generic async read helper (inline for performance).
uint8_t _currentPage
Tracks current page (0-3, 0xFF=unknown) to minimize page selects.
RingBufferN< kHardwareRows+1 > _abmPendingRows
Effective capacity: kHardwareRows.
const uint8_t * GetLEDShort() const
Get the cached LED short status (from last fault detection).
uint16_t _pwmEnqueued
Bitfield tracking enqueued rows (0x0001..0x0FFF)
volatile uint8_t _cmdReturn
Bitfield of completed command transactions (bits 0..3)
uint8_t _sdbPin
SDB (shutdown) pin (0xFF = not used)
static IS31FL3733 * _instance
Static instance pointer for ISR access.
RingBufferN< kHardwareRows+1 > _pwmPendingRows
Effective capacity: kHardwareRows.
void SetShortFaultMaskEnabled(bool enable)
Control whether LEDSHORT bits are applied when computing LEDONOFF mask.
volatile bool _syncComplete
Blocking command completion flag.
bool _pwmLocked
True when command chain has preempted PWM.
static void _txnCallback(void *user, int status)
PWM row transaction callback, enqueues the next pending row if any.
void _sendRowPWM()
Dequeue and transmit next pending PWM row.
SERCOM * _hw
SERCOM I2C hardware interface.
void _asyncWrite(uint16_t pagereg, const uint8_t *data, uint8_t len, void(*callback)(void *, int)=nullptr, void *user=nullptr)
Generic async write helper (inline for performance).
void _sendRowMode()
Dequeue and transmit next pending ABM row.
SercomTxn _pwmTxn
Single in-flight PWM transaction descriptor.
uint8_t _irqPin
IRQ pin (0xFF = not used)
uint8_t _lastISR
Cached ISR value from last fault detection.
volatile uint8_t _cmdError
Bitfield of command transactions with nonzero status.
bool IsPwmUpdatePending() const
Returns true while PWM row writes are in flight or queued.
uint16_t _abmEnqueued
Bitfield tracking enqueued rows (0x0001..0x0FFF)
SercomTxn _abmTxn
Single in-flight ABM transaction descriptor.
static void _onServiceCallback(void *user, int status)
ISR completion callback (processes _lastISR after F1h read).
const uint8_t * GetLEDOn() const
Get the cached LED on/off mask (last value written to LEDONOFF).
bool _maskShortFaults
Include LEDSHORT bits in computed LEDONOFF mask.
uint8_t _addr
7-bit I2C address
ColorOrder _colorOrder
RGB pixel color order.
ColorOrder GetColorOrder() const
Get the current color order.
volatile int8_t _syncTargetCmd
Index of command awaited by blocking API.
const uint8_t * GetLEDOpen() const
Get the cached LED open status (from last fault detection).
bool _pwmBatchActive
True while staged PWM updates are being batched.
static void _txnModeCallback(void *user, int status)
ABM row transaction callback, enqueues the next pending mode row if any.
volatile int _syncStatus
Blocking command final status.
bool _abmLocked
True when command chain has preempted ABM.
uint8_t _crValue
Shadow of CR register state for runtime updates.
void SetColorOrder(ColorOrder order)
Set the color order for RGB pixel mapping.
bool GetShortFaultMaskEnabled() const
Returns true when LEDSHORT contributes to LEDONOFF masking.
High-level ABM configuration values before register packing.
AbmLoopBegin Tbegin
Loop begin segment selector.
AbmT1 T1
Fade-in segment duration selector.
AbmT4 T4
Off-time segment duration selector.
AbmT2 T2
Hold-high segment duration selector.
AbmLoopEnd Tend
Loop end segment selector.
AbmT3 T3
Fade-out segment duration selector.
uint16_t Times
Loop count (0 = kAbmLoopForever, max = kAbmLoopTimesMax)
Context passed to SERCOM ISR callback for command-chain transactions.
int initialStatus
First error status observed in the chain.
bool isFinal
If true, invoke userCallback on this transaction.
uint8_t index
Index of this transaction in the chain.
IS31FL3733 * self
Driver instance owning the transaction chain.
void * user
User pointer passed to callback.
void(* userCallback)(void *, int)
Optional user callback for final status.