IS31FL3733 Async Driver 1.0.0
Asynchronous DMA-driven IS31FL3733 LED driver for Arduino SAMD
Loading...
Searching...
No Matches
is31fl3733.hpp
1/*---------------------------------------------------------------------------------------------
2 * Copyright (c) Cal Abel. All rights reserved.
3 * Author: Cal Abel (async rewrite and ongoing maintenance)
4 * Author: Neil Enns (original C++ library)
5 * Licensed under the MIT License. See LICENSE in the project root for license information.
6 *
7 * Based on the original IS31FL3733 C++ library by Neil Enns
8 * (https://github.com/neilenns/is31fl3733).
9 * This is a nearly complete rewrite for asynchronous DMA-driven operation on
10 * Arduino SAMD.
11 *
12 * Asynchronous DMA-driven IS31FL3733 driver for Arduino SAMD (SimIO framework).
13 *
14 * Architecture:
15 * - Non-blocking I2C via SERCOM transaction descriptors with DMA
16 * - Lock-free ring buffer for PWM row updates (12 rows, bitfield-tracked)
17 * - Single in-flight PWM transaction (_pwmTxn) with shadow buffer (_pwmTxPtr[17])
18 * - Separate command transaction chain (_cmdTxn[4]) for page select / fault handling
19 * - Default Page 1 (PWM) - no page switching for normal writes
20 * - IRQ-driven fault detection (open/short) with async transaction chain
21 * - Color order support (RGB, GRB, BRG, RBG, GBR, BGR)
22 *
23 * See /docs/ASYNC_DMA_ARCHITECTURE.md for full design details.
24 *--------------------------------------------------------------------------------------------*/
25#pragma once
26
27#include <Arduino.h>
28#include <Wire.h> // TwoWire I2C interface
29#include <functional>
30
31namespace IS31FL3733 {
32// -----------------------------------------------------------------------------------------
33// Constants
34// -----------------------------------------------------------------------------------------
35
36constexpr uint8_t kHardwareRows = 12;
37constexpr uint8_t kHardwareCols = 16;
38constexpr uint8_t kLedCount = kHardwareRows * kHardwareCols;
39
40constexpr uint8_t kLogicalRows = 4;
41
42// -----------------------------------------------------------------------------------------
43// Register Addresses (Common + Paged)
44// -----------------------------------------------------------------------------------------
45
50enum CommonRegister : uint8_t {
51 PSR = 0xFD,
52 PSWL = 0xFE,
53 IMR = 0xF0,
54 ISR = 0xF1,
55};
56
62enum PagedRegister : uint16_t {
63 LEDONOFF = 0x0000,
64 LEDOPEN = 0x0018,
65 LEDSHORT = 0x0030,
66 LEDPWM = 0x0100,
67 LEDABM = 0x0200,
68 CR = 0x0300,
69 GCC = 0x0301,
70 ABM1CR = 0x0302,
71 ABM2CR = 0x0306,
72 ABM3CR = 0x030A,
73 TUR = 0x030E,
74 SWPUR = 0x030F,
75 CSPDR = 0x0310,
76 RESET = 0x0311,
77};
78
79// -----------------------------------------------------------------------------------------
80// Register Configuration Options
81// -----------------------------------------------------------------------------------------
82
87enum PswlOptions : uint8_t {
88 PSWL_DISABLE = 0x00,
89 PSWL_ENABLE = 0xC5,
90};
91
96enum ImrOptions : uint8_t {
97 IMR_IAC = 0x08,
98 IMR_IAB = 0x04,
99 IMR_IS = 0x02,
100 IMR_IO = 0x01,
101};
102
107enum IsrOptions : uint8_t {
108 ISR_ABM3 = 0x10,
109 ISR_ABM2 = 0x08,
110 ISR_ABM1 = 0x04,
111 ISR_SB = 0x02,
112 ISR_OB = 0x01,
113};
114
119enum CrOptions : uint8_t {
120 CR_SYNC_MASTER = 0x40,
121 CR_SYNC_SLAVE = 0x80,
122 CR_OSD = 0x04,
123 CR_BEN = 0x02,
124 CR_SSD = 0x01,
125};
126
131inline uint8_t CR_PFS(uint8_t page) {
132 return (page & 0x03) << 5;
133} // PSR bits are [6:5] for page select
134
135// -----------------------------------------------------------------------------------------
136// Color Order Enum
137// -----------------------------------------------------------------------------------------
138
143enum class ColorOrder : uint8_t {
144 RGB = 0,
145 GRB = 1,
146 BRG = 2,
147 RBG = 3,
148 GBR = 4,
149 BGR = 5,
150};
151
156enum class ABMMode : uint8_t {
157 PWM_MODE = 0x00, // Renamed from PWM to avoid Arduino Due macro conflict
158 ABM1 = 0x01,
159 ABM2 = 0x02,
160 ABM3 = 0x03,
161};
162
167enum AbmT1 : uint8_t {
168 T1_210MS = 0x00,
169 T1_420MS = 0x20,
170 T1_840MS = 0x40,
171 T1_1680MS = 0x60,
172 T1_3360MS = 0x80,
173 T1_6720MS = 0xA0,
174 T1_13440MS = 0xC0,
175 T1_26880MS = 0xE0,
176};
177
181enum AbmT2 : uint8_t {
182 T2_0MS = 0x00,
183 T2_210MS = 0x02,
184 T2_420MS = 0x04,
185 T2_840MS = 0x06,
186 T2_1680MS = 0x08,
187 T2_3360MS = 0x0A,
188 T2_6720MS = 0x0C,
189 T2_13440MS = 0x0E,
190 T2_26880MS = 0x10,
191};
192
196enum AbmT3 : uint8_t {
197 T3_210MS = 0x00,
198 T3_420MS = 0x20,
199 T3_840MS = 0x40,
200 T3_1680MS = 0x60,
201 T3_3360MS = 0x80,
202 T3_6720MS = 0xA0,
203 T3_13440MS = 0xC0,
204 T3_26880MS = 0xE0,
205};
206
210enum AbmT4 : uint8_t {
211 T4_0MS = 0x00,
212 T4_210MS = 0x02,
213 T4_420MS = 0x04,
214 T4_840MS = 0x06,
215 T4_1680MS = 0x08,
216 T4_3360MS = 0x0A,
217 T4_6720MS = 0x0C,
218 T4_13440MS = 0x0E,
219 T4_26880MS = 0x10,
220 T4_53760MS = 0x12,
221 T4_107520MS = 0x14,
222};
223
227enum AbmLoopBegin : uint8_t {
228 LOOP_BEGIN_T1 = 0x00,
229 LOOP_BEGIN_T2 = 0x10,
230 LOOP_BEGIN_T3 = 0x20,
231 LOOP_BEGIN_T4 = 0x30,
232};
233
237enum AbmLoopEnd : uint8_t {
238 LOOP_END_T3 = 0x00,
239 LOOP_END_T1 = 0x40,
240};
241
243constexpr int kAbmLoopTimesMax = 0x0FFF;
245constexpr int kAbmLoopForever = 0x0000;
246
254struct ABMConfig {
255 AbmT1 T1;
256 AbmT2 T2;
257 AbmT3 T3;
258 AbmT4 T4;
259 AbmLoopBegin Tbegin;
260 AbmLoopEnd Tend;
261 uint16_t Times;
262};
263
264// -----------------------------------------------------------------------------------------
265// IS31FL3733 Async Driver Class
266// -----------------------------------------------------------------------------------------
267
272 public:
273 // ---------------------------------------------------------------------------------------
274 // Constructor / Destructor
275 // ---------------------------------------------------------------------------------------
278
283 IS31FL3733(TwoWire *wire, uint8_t addr = 0x50, uint8_t sdbPin = 0xFF, uint8_t irqPin = 0xFF);
284
286 ~IS31FL3733();
289 // ---------------------------------------------------------------------------------------
290 // Initialization
291 // ---------------------------------------------------------------------------------------
294
302 bool begin(uint8_t pfs = 0, uint8_t pur = 0b111, uint8_t pdr = 0b111);
303
307 void end();
310 // ---------------------------------------------------------------------------------------
311 // Device Control
312 // ---------------------------------------------------------------------------------------
315
316 void DeviceOn();
317
319 void DeviceOff();
322 // ---------------------------------------------------------------------------------------
323 // Runtime Configuration (Page 3/Common)
324 // ---------------------------------------------------------------------------------------
327
329 void SetGCC(uint8_t gcc);
330
333 void SetSWPUR(uint8_t pur);
334
337 void SetCSPDR(uint8_t pdr);
338
342 void SetPFS(uint8_t pfs);
343
346 void SetIMR(uint8_t imrMask);
347
353 void SetShortFaultMaskEnabled(bool enable) {
354 _maskShortFaults = enable;
355 }
356
359 return _maskShortFaults;
360 }
361
363 bool IsPwmUpdatePending() const {
364 return _pwmTxn.txPtr != nullptr || _pwmEnqueued != 0u || _pwmLocked || _pwmBatchActive;
365 }
368 // ---------------------------------------------------------------------------------------
369 // PWM & ABM Control (Raw Hardware Interface)
370 // ---------------------------------------------------------------------------------------
373
377 void SetPixelPWM(uint8_t row, uint8_t col, uint8_t pwm);
378
382 void SetRowPWM(uint8_t row, const uint8_t *pwmValues);
383
388 void BeginPwmBatch();
389
392 void EndPwmBatch(bool flush = true);
393
398 void SetPixelMode(uint8_t row, uint8_t col, ABMMode mode);
399
403 void SetRowMode(uint8_t row, ABMMode mode);
404
409 ABMMode GetPixelMode(uint8_t row, uint8_t col) const;
412 // ---------------------------------------------------------------------------------------
413 // RGB Pixel Control (Logical Coordinates with Color Order)
414 // ---------------------------------------------------------------------------------------
417
423 void SetPixelColor(uint8_t row, uint8_t col, uint8_t r, uint8_t g, uint8_t b);
424
429 void SetPixelColorMode(uint8_t row, uint8_t col, ABMMode mode);
430
433 void SetColorOrder(ColorOrder order) {
434 _colorOrder = order;
435 }
436
439 ColorOrder GetColorOrder() const {
440 return _colorOrder;
441 }
444 // ---------------------------------------------------------------------------------------
445 // Bulk Operations
446 // ---------------------------------------------------------------------------------------
449
451 void Fill(uint8_t pwm = 0);
452
455 void SetMatrixMode(ABMMode mode);
456
460 void SetABMCallback(uint8_t abmNum, std::function<void()> callback);
463 // ---------------------------------------------------------------------------------------
464 // ABM Page 3 Control
465 // ---------------------------------------------------------------------------------------
468
471 void ConfigureABM(uint8_t abmNumber, const ABMConfig &config);
472
474 void ConfigureABM1(const ABMConfig &config);
475
477 void ConfigureABM2(const ABMConfig &config);
478
480 void ConfigureABM3(const ABMConfig &config);
481
484 void EnableABM(bool enable = true);
485
487 void TriggerABM();
490 // ---------------------------------------------------------------------------------------
491 // Fault Detection (Read-Only)
492 // ---------------------------------------------------------------------------------------
495
497 const uint8_t *GetLEDOpen() const {
498 return _ledOpen;
499 }
500
503 const uint8_t *GetLEDShort() const {
504 return _ledShort;
505 }
506
509 const uint8_t *GetLEDOn() const {
510 return _ledOn;
511 }
514#ifndef TEST_NATIVE
515 private:
516#endif // TEST_NATIVE
517 // ---------------------------------------------------------------------------------------
518 // Hardware Handles
519 // ---------------------------------------------------------------------------------------
522 SERCOM *_hw;
523 uint8_t _addr;
524 uint8_t _sdbPin;
525 uint8_t _irqPin;
526 uint8_t _currentPage;
527
531 // ---------------------------------------------------------------------------------------
532 // PWM Matrix and Transaction State (Page 1)
533 // ---------------------------------------------------------------------------------------
536 uint8_t _pwm_matrix[kHardwareRows]
537 [kHardwareCols + 1];
538 SercomTxn _pwmTxn;
539 uint8_t _pwmTxPtr[kHardwareCols + 1];
540
541 RingBufferN<kHardwareRows + 1> _pwmPendingRows;
542 uint16_t _pwmEnqueued;
543
548 // ---------------------------------------------------------------------------------------
549 // Mode Matrix and Transaction State (Page 2)
550 // ---------------------------------------------------------------------------------------
553 uint8_t _abm_matrix[kHardwareRows]
554 [kHardwareCols + 1];
555 SercomTxn _abmTxn;
556 uint8_t _abmTxPtr[kHardwareCols + 1];
557
558 RingBufferN<kHardwareRows + 1> _abmPendingRows;
559 uint16_t _abmEnqueued;
560
562
563 std::function<void()> _abmCallbacks[3];
566 // ---------------------------------------------------------------------------------------
567 // Command Transaction Chain (Non-PWM Operations)
568 // ---------------------------------------------------------------------------------------
571 SercomTxn _cmdTxn[4];
572
576 uint8_t index;
577 void (*userCallback)(void *, int);
578 void *user;
579 bool isFinal;
581 };
582
583 CmdTxnContext _cmdCtx[4];
584 uint8_t _crwlTx[2];
585 uint8_t _pgSelTx[2];
586 uint8_t _cmdTx[25];
587 uint8_t _cmdRx[24];
588
589 volatile uint8_t _cmdReturn;
590 volatile uint8_t _cmdError;
591
592 volatile bool _syncComplete;
593 volatile int _syncStatus;
594 volatile int8_t _syncTargetCmd;
597 bool _begun;
598
599 // ---------------------------------------------------------------------------------------
600 // Fault Detection and ISR Cache
601 // ---------------------------------------------------------------------------------------
604 uint8_t _ledOpen[24];
605 uint8_t _ledShort[24];
606 uint8_t _ledOn[24];
607 uint8_t _lastISR;
610 // ---------------------------------------------------------------------------------------
611 // Configuration
612 // ---------------------------------------------------------------------------------------
615 uint8_t _crValue;
616 ColorOrder _colorOrder;
620 // ---------------------------------------------------------------------------------------
621 // Private Methods (Transaction Management)
622 // ---------------------------------------------------------------------------------------
625
626 inline void _sendRowPWM();
627
629 inline void _sendRowMode();
630
634 void _ensurePage(uint8_t page);
635
637 void _resumeDataTransfers();
638
640 inline void _asyncWrite(uint16_t pagereg, const uint8_t *data, uint8_t len,
641 void (*callback)(void *, int) = nullptr, void *user = nullptr);
642
644 inline void _asyncRead(uint16_t pagereg, uint8_t *dest, uint8_t len,
645 void (*callback)(void *, int) = nullptr, void *user = nullptr);
646
648 bool _syncWrite(uint16_t pagereg, const uint8_t *data, uint8_t len);
649
651 bool _syncRead(uint16_t pagereg, uint8_t *dest, uint8_t len);
654 // ---------------------------------------------------------------------------------------
655 // Static Callbacks
656 // ---------------------------------------------------------------------------------------
659
662 static inline void _txnCallback(void *user, int status);
663
667 static inline void _txnModeCallback(void *user, int status);
668
670 static inline void _irqCallback();
671
675 static inline void _onServiceCallback(void *user, int status);
676
680 static void _cmdCallback(void *user, int status);
681
683 static void _osbCallback(void *user, int status);
684
687 static void _abm1CallbackWrapper();
689 static void _abm2CallbackWrapper();
691 static void _abm3CallbackWrapper();
693};
694
695// =========================================================================================
696// Inline Method Implementations
697// =========================================================================================
698
700 // Don't send if PWM is locked, batch staging is active, or if transaction is in-flight
701 if (_pwmLocked || _pwmBatchActive || _pwmTxn.txPtr)
702 return;
703
704 // Dequeue next row
705 int row = _pwmPendingRows.read_char();
706 if (row < 0) {
707 // Queue can be full with one row represented only in _pwmEnqueued.
708 for (uint8_t candidate = 0; candidate < kHardwareRows; candidate++) {
709 if (_pwmEnqueued & (1u << candidate)) {
710 row = candidate;
711 break;
712 }
713 }
714 }
715
716 if (row < 0)
717 return; // Nothing pending
718
719 // Clear enqueued bit
720 _pwmEnqueued &= ~(1 << row);
721
722 // Copy row data to transmit buffer
723 memcpy(_pwmTxPtr, _pwm_matrix[row], 17);
724
725 // Point transaction at prepared PWM row buffer
726 _pwmTxn.txPtr = _pwmTxPtr;
727 _pwmTxn.chainNext = false;
728
729 _ensurePage(1);
730
731 // Enqueue transaction
732 _hw->enqueueWIRE(&_pwmTxn);
733}
734
736 // Don't send if ABM is locked by command chain or if transaction already in-flight
737 if (_abmLocked || _abmTxn.txPtr)
738 return;
739
740 // Dequeue next row
741 int row = _abmPendingRows.read_char();
742 if (row < 0) {
743 // Queue can be full with one row represented only in _abmEnqueued.
744 for (uint8_t candidate = 0; candidate < kHardwareRows; candidate++) {
745 if (_abmEnqueued & (1u << candidate)) {
746 row = candidate;
747 break;
748 }
749 }
750 }
751
752 if (row < 0)
753 return; // Nothing pending
754
755 // Clear enqueued bit
756 _abmEnqueued &= ~(1 << row);
757
758 // Copy row data to transmit buffer
759 // [row][0] is the page 2 row address (0x00..0x0B)
760 memcpy(_abmTxPtr, _abm_matrix[row], 17);
761
762 // Point transaction at prepared ABM row buffer
763 _abmTxn.txPtr = _abmTxPtr;
764 _abmTxn.chainNext = false;
765
766 _ensurePage(2);
767
768 // Enqueue transaction
769 _hw->enqueueWIRE(&_abmTxn);
770}
771
772inline void IS31FL3733::_asyncWrite(uint16_t pagereg, const uint8_t *data, uint8_t len,
773 void (*callback)(void *, int), void *user) {
774 uint8_t page = pagereg >> 8;
775
776 // Ensure page if needed (pages 0-3)
777 if (page < 4) {
778 _ensurePage(page);
779 _cmdTx[0] = pagereg & 0xFF;
780 } else if (page >= IMR)
781 _cmdTx[0] = page;
782 else
783 return;
784
785 // Copy data to TX buffer
786 memcpy(_cmdTx + 1, data, len);
787
788 // Configure and enqueue write transaction
789 _cmdTxn[2].length = 1 + len;
790 _cmdCtx[2].userCallback = callback;
791 _cmdCtx[2].user = user;
792 _cmdCtx[2].isFinal = true; // This is the only transaction
793 _cmdCtx[2].initialStatus = 0;
794 _cmdTxn[2].onComplete = _cmdCallback;
795 _cmdTxn[2].user = &_cmdCtx[2];
796 _cmdTxn[2].chainNext = false;
797 _hw->enqueueWIRE(&_cmdTxn[2]);
798}
799
800inline void IS31FL3733::_asyncRead(uint16_t pagereg, uint8_t *dest, uint8_t len,
801 void (*callback)(void *, int), void *user) {
802 uint8_t page = pagereg >> 8;
803
804 // Ensure page if needed
805 if (page < 4) {
806 _ensurePage(page);
807 _cmdTx[0] = pagereg & 0xFF;
808 } else if (page >= IMR)
809 _cmdTx[0] = page;
810 else
811 return;
812
813 // Configure write transaction (send register address) - NOT final
814 _cmdTxn[2].length = 1;
815 _cmdCtx[2].userCallback = nullptr;
816 _cmdCtx[2].user = nullptr;
817 _cmdCtx[2].isFinal = false; // Address phase doesn't trigger callback
818 _cmdCtx[2].initialStatus = 0;
819 _cmdTxn[2].onComplete = _cmdCallback;
820 _cmdTxn[2].user = &_cmdCtx[2];
821 _cmdTxn[2].chainNext = false;
822
823 // Configure read transaction - IS final (will invoke user callback)
824 _cmdTxn[3].rxPtr = dest;
825 _cmdTxn[3].length = len;
826 _cmdCtx[3].userCallback = callback;
827 _cmdCtx[3].user = user;
828 _cmdCtx[3].isFinal = true; // Data phase is final, triggers callback
829 _cmdCtx[3].initialStatus = 0; // Can be populated by write phase if needed
830 _cmdTxn[3].onComplete = _cmdCallback;
831 _cmdTxn[3].user = &_cmdCtx[3];
832 _cmdTxn[3].chainNext = false;
833
834 // Enqueue both transactions
835 _hw->enqueueWIRE(&_cmdTxn[2]);
836 _hw->enqueueWIRE(&_cmdTxn[3]);
837}
838
839// ---------------------------------------------------------------------------------------
840// Inline Callbacks
841// ---------------------------------------------------------------------------------------
842
843inline void IS31FL3733::_txnCallback(void *user, int status) {
844 IS31FL3733 *self = (IS31FL3733 *)user;
845 (void)status;
846
847 // Clear PWM transaction in-progress flag
848 self->_pwmTxn.txPtr = nullptr;
849
850 // Transaction complete - send next PWM row if available
851 self->_sendRowPWM();
852}
853
854inline void IS31FL3733::_txnModeCallback(void *user, int status) {
855 IS31FL3733 *self = (IS31FL3733 *)user;
856 (void)status;
857
858 // Clear ABM transaction in-progress flag
859 self->_abmTxn.txPtr = nullptr;
860
861 // Transaction complete - send next ABM row if available
862 self->_sendRowMode();
863}
864
866 // Hardware ISR: Read F1h (ISR register) into _lastISR, with _onServiceCallback as completion
867 // No page select needed for common register F1h
868 if (_instance)
869 _instance->_asyncRead((uint16_t)ISR << 8, &_instance->_lastISR, 1, _onServiceCallback,
870 _instance);
871}
872
873inline void IS31FL3733::_onServiceCallback(void *user, int status) {
874 // Static callback after ISR read completes - dispatch to instance method
875 IS31FL3733 *self = (IS31FL3733 *)user;
876 (void)status;
877 // Process _lastISR value (already read by _irqCallback)
878 // Lock PWM writes during fault handling
879 self->_pwmLocked = true;
880 self->_abmLocked = true;
881
882 uint8_t isr = self->_lastISR;
883
884 if (isr & 0x1C) { // ABM1 (0x04), ABM2 (0x08), ABM3 (0x10)
885 // Dispatch ABM completion to registered callback(s)
886 if (isr & ISR_ABM1)
887 _abm1CallbackWrapper();
888 if (isr & ISR_ABM2)
889 _abm2CallbackWrapper();
890 if (isr & ISR_ABM3)
891 _abm3CallbackWrapper();
892 }
893
894 const bool hasOpenFault = (isr & ISR_OB) != 0;
895 const bool hasShortFault = ((isr & ISR_SB) != 0) && self->_maskShortFaults;
896
897 // Service open faults always; service short faults only when short masking is enabled.
898 if (hasOpenFault || hasShortFault) {
899 // Determine which fault register to read
900 uint16_t pagereg = hasOpenFault ? LEDOPEN : LEDSHORT;
901 uint8_t *dest = hasOpenFault ? self->_ledOpen : self->_ledShort;
902
903 // Read fault register asynchronously
904 self->_asyncRead(pagereg, dest, 24, _osbCallback, self);
905
906 return;
907 }
908
909 // No recognized interrupts - just unlock PWM/ABM
910 self->_resumeDataTransfers();
911}
912
913} // namespace IS31FL3733
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.