FastLED 3.9.3
Loading...
Searching...
No Matches
fastled_delay.h
Go to the documentation of this file.
1#ifndef __INC_FL_DELAY_H
2#define __INC_FL_DELAY_H
3
4#include "FastLED.h"
5#include "types.h"
6#include "force_inline.h"
7
10
11FASTLED_NAMESPACE_BEGIN
12
13
14#if (!defined(NO_MINIMUM_WAIT) || (NO_MINIMUM_WAIT==0))
15
18template<int WAIT> class CMinWait {
20 uint16_t mLastMicros;
21
22public:
24 CMinWait() { mLastMicros = 0; }
25
27 void wait() {
28 uint16_t diff;
29 do {
30 diff = (micros() & 0xFFFF) - mLastMicros;
31 } while(diff < WAIT);
32 }
33
35 void mark() { mLastMicros = micros() & 0xFFFF; }
36};
37
38#else
39
40// if you keep your own FPS (and therefore don't call show() too quickly for pixels to latch), you may not want a minimum wait.
41template<int WAIT> class CMinWait {
42public:
43 CMinWait() { }
44 void wait() { }
45 void mark() {}
46};
47
48#endif
49
50
56
57// Default is now just 'nop', with special case for AVR
58
59// ESP32 core has it's own definition of NOP, so undef it first
60#ifdef ESP32
61#undef NOP
62#undef NOP2
63#endif
64
65#if defined(__AVR__)
66# define FL_NOP __asm__ __volatile__ ("cp r0,r0\n");
67# define FL_NOP2 __asm__ __volatile__ ("rjmp .+0");
68#else
70# define FL_NOP __asm__ __volatile__ ("nop\n");
72# define FL_NOP2 __asm__ __volatile__ ("nop\n\t nop\n");
73#endif
74
75// predeclaration to not upset the compiler
76
77
81template<cycle_t CYCLES> inline void delaycycles();
82
85template<cycle_t CYCLES> inline void delaycycles_min1() {
87 delaycycles<CYCLES-1>();
88}
89
90
91// TODO: ARM version of _delaycycles_
92
93// usable definition
94#if defined(FASTLED_AVR)
95// worker template - this will nop for LOOP * 3 + PAD cycles total
96template<int LOOP, cycle_t PAD> inline void _delaycycles_AVR() {
98 // the loop below is 3 cycles * LOOP. the LDI is one cycle,
99 // the DEC is 1 cycle, the BRNE is 2 cycles if looping back and
100 // 1 if not (the LDI balances out the BRNE being 1 cycle on exit)
101 __asm__ __volatile__ (
102 " LDI R16, %0\n"
103 "L_%=: DEC R16\n"
104 " BRNE L_%=\n"
105 : /* no outputs */
106 : "M" (LOOP)
107 : "r16"
108 );
109}
110
111template<cycle_t CYCLES> FASTLED_FORCE_INLINE void delaycycles() {
112 _delaycycles_AVR<CYCLES / 3, CYCLES % 3>();
113}
114
115
116
117#else
118// template<int LOOP, cycle_t PAD> inline void _delaycycles_ARM() {
119// delaycycles<PAD>();
120// // the loop below is 3 cycles * LOOP. the LDI is one cycle,
121// // the DEC is 1 cycle, the BRNE is 2 cycles if looping back and
122// // 1 if not (the LDI balances out the BRNE being 1 cycle on exit)
123// __asm__ __volatile__ (
124// " mov.w r9, %0\n"
125// "L_%=: subs.w r9, r9, #1\n"
126// " bne.n L_%=\n"
127// : /* no outputs */
128// : "M" (LOOP)
129// : "r9"
130// );
131// }
132
133
134template<cycle_t CYCLES> FASTLED_FORCE_INLINE void delaycycles() {
135 // _delaycycles_ARM<CYCLES / 3, CYCLES % 3>();
136 FL_NOP; delaycycles<CYCLES-1>();
137}
138
139
140
141
142#endif
143
144// pre-instantiations for values small enough to not need the loop, as well as sanity holders
145// for some negative values.
146
147// These are hidden from Doxygen because they match the expected behavior of the class.
149template<> FASTLED_FORCE_INLINE void delaycycles<-10>() {}
150template<> FASTLED_FORCE_INLINE void delaycycles<-9>() {}
151template<> FASTLED_FORCE_INLINE void delaycycles<-8>() {}
152template<> FASTLED_FORCE_INLINE void delaycycles<-7>() {}
153template<> FASTLED_FORCE_INLINE void delaycycles<-6>() {}
154template<> FASTLED_FORCE_INLINE void delaycycles<-5>() {}
155template<> FASTLED_FORCE_INLINE void delaycycles<-4>() {}
156template<> FASTLED_FORCE_INLINE void delaycycles<-3>() {}
157template<> FASTLED_FORCE_INLINE void delaycycles<-2>() {}
158template<> FASTLED_FORCE_INLINE void delaycycles<-1>() {}
159template<> FASTLED_FORCE_INLINE void delaycycles<0>() {}
160template<> FASTLED_FORCE_INLINE void delaycycles<1>() {FL_NOP;}
161template<> FASTLED_FORCE_INLINE void delaycycles<2>() {FL_NOP2;}
162template<> FASTLED_FORCE_INLINE void delaycycles<3>() {FL_NOP;FL_NOP2;}
163template<> FASTLED_FORCE_INLINE void delaycycles<4>() {FL_NOP2;FL_NOP2;}
164template<> FASTLED_FORCE_INLINE void delaycycles<5>() {FL_NOP2;FL_NOP2;FL_NOP;}
165#if defined(ESP32)
166template<> FASTLED_FORCE_INLINE void delaycycles<4294966398>() {
167 // specialization for a gigantic amount of cycles, apparently this is needed
168 // or esp32 will blow the stack with cycles = 4294966398.
169 const uint32_t termination = 4294966398 / 10;
170 const uint32_t remainder = 4294966398 % 10;
171 for (uint32_t i = 0; i < termination; i++) {
174 }
175
176 // remainder
177 switch (remainder) {
178 case 9: FL_NOP;
179 case 8: FL_NOP;
180 case 7: FL_NOP;
181 case 6: FL_NOP;
182 case 5: FL_NOP;
183 case 4: FL_NOP;
184 case 3: FL_NOP;
185 case 2: FL_NOP;
186 case 1: FL_NOP;
187 }
188}
189#endif
191
193
194
197
198// Macro to convert from nano-seconds to clocks and clocks to nano-seconds
199// #define NS(_NS) (_NS / (1000 / (F_CPU / 1000000L)))
200
202#define F_CPU_MHZ (F_CPU / 1000000L)
203
204// #define NS(_NS) ( (_NS * (F_CPU / 1000000L))) / 1000
205
207#define NS(_NS) (((_NS * F_CPU_MHZ) + 999) / 1000)
209#define CLKS_TO_MICROS(_CLKS) ((long)(_CLKS)) / (F_CPU / 1000000L)
210
212#define NO_TIME(A, B, C) (NS(A) < 3 || NS(B) < 3 || NS(C) < 6)
213
215
216FASTLED_NAMESPACE_END
217
218#endif
central include file for FastLED, defines the CFastLED class/object
Class to ensure that a minimum amount of time has kicked since the last time run - and delay if not e...
CMinWait()
Constructor.
void mark()
Reset the timestamp that marks the start of the wait period.
void wait()
Blocking delay until WAIT time since mark() has passed.
#define FL_NOP2
Double no operation ("no-op") instruction for delay.
void delaycycles_min1()
A variant of delaycycles that will always delay at least one cycle.
void delaycycles()
Delay N clock cycles.
#define FL_NOP
Single no operation ("no-op") instruction for delay.