FastLED 3.10.8
Loading...
Searching...
No Matches
ObjectFLEDDmaManager.cpp.hpp
Go to the documentation of this file.
1#include "platforms/arm/teensy/is_teensy.h"
2
3#if defined(FL_IS_TEENSY_4X) // Teensy 4.0/4.1 only
4
6#include "fl/system/delay.h"
8#include "fl/stl/malloc.h"
9#include "platforms/arm/teensy/teensy4_common/dmamem.h"
10
11namespace fl {
12
13// Define static members
14FL_DMAMEM uint32_t ObjectFLEDDmaManager::bitmask[4] __attribute__((aligned(32)));
15
16// #3416 OF-HIGH-1 / CodeRabbit-flagged: save/restore PRIMASK rather than
17// unconditionally re-enabling interrupts, so we don't clobber the
18// caller's IRQ-disabled state if we're invoked from inside another
19// critical section. Inline asm avoids needing the CMSIS header.
20static inline uint32_t fl_save_primask_disable() {
21 uint32_t pm;
22 __asm volatile ("mrs %0, primask\n\tcpsid i" : "=r"(pm) :: "memory");
23 return pm;
24}
25static inline void fl_restore_primask(uint32_t pm) {
26 __asm volatile ("msr primask, %0" :: "r"(pm) : "memory");
27}
28
29void ObjectFLEDDmaManager::acquire(void* owner) {
30 // Wait for any current transmission to complete
31 waitForCompletion();
32
33 const uint32_t pm = fl_save_primask_disable();
34 mCurrentOwner = owner;
35 fl_restore_primask(pm);
36}
37
38void ObjectFLEDDmaManager::release(void* owner) {
39 const uint32_t pm = fl_save_primask_disable();
40 if (mCurrentOwner != owner) {
41 fl_restore_primask(pm);
42 return;
43 }
44 mCurrentOwner = nullptr;
45 fl_restore_primask(pm);
46}
47
48void ObjectFLEDDmaManager::waitForCompletion() {
49 // Spin-wait for DMA completion with periodic delays.
50 while (!dma3.complete()) {
52 }
53 // #3416 OF-MED-6: dma3.complete() reflects DMA major-loop done but
54 // does NOT include the WS2812 reset latch period. If the caller is
55 // about to destroy the LED buffer or hand the line off to another
56 // peripheral, returning here can corrupt the final frame's tail
57 // bits. The destructor wait path adds its own latch margin (see
58 // ObjectFLED::~ObjectFLED) but defensive callers should also gate
59 // on busy()==0 which factors in LATCH_DELAY. Documented here so
60 // the next reader doesn't mistake "DMA done" for "frame done".
61}
62
63bool ObjectFLEDDmaManager::ensureBitdata(uint32_t numbytes) {
64 const uint32_t words =
65 objectfled::grownBitdataWords(bitdataWords, numbytes, BYTES_PER_DMA);
66 if (words == bitdataWords && bitdata != nullptr) {
67 return true;
68 }
69 // Over-allocate and align the start to a 32-byte cache line. The size
70 // is a multiple of 128 B, so arm_dcache_flush_delete() never touches a
71 // line shared with other heap data.
72 // Free the old (too small) buffer first: it can't serve this frame, and
73 // freeing it lets the allocator reuse that space for the larger block.
74 fl::free(mBitdataAlloc);
75 mBitdataAlloc = nullptr;
76 bitdata = nullptr;
77 bitdataWords = 0;
78 void* block = fl::malloc(words * sizeof(uint32_t) + 31);
79 if (block == nullptr) {
80 return false; // caller drops the frame
81 }
82 mBitdataAlloc = block;
83 bitdata = reinterpret_cast<uint32_t*>(
84 (reinterpret_cast<uintptr_t>(block) + 31) & ~uintptr_t(31));
85 bitdataWords = words;
86 return true;
87}
88
89bool ObjectFLEDDmaManager::isBusy() {
90 return !dma3.complete();
91}
92
93} // namespace fl
94
95#endif // FL_IS_TEENSY_4X
Delay utilities for FastLED Includes nanosecond-precision delays, cycle counting, and microsecond del...
fl::u32 uint32_t
Definition s16x16x4.h:219
FASTLED_FORCE_INLINE void free(void *ptr) FL_NO_EXCEPT
Definition malloc.h:23
FASTLED_FORCE_INLINE void * malloc(size_t size) FL_NO_EXCEPT
Definition malloc.h:21
fl::uptr uintptr_t
Definition s16x16x4.h:224
void delayMicroseconds(u32 us) FL_NO_EXCEPT
Delay for a given number of microseconds.
Base definition for an LED controller.
constexpr uint32_t grownBitdataWords(uint32_t currentWords, uint32_t numbytes, uint32_t bytesPerDma)
New capacity after seeing a frame of numbytes: grows, never shrinks.