FastLED 3.9.15
Loading...
Searching...
No Matches
fastled_delay.h
Go to the documentation of this file.
1#pragma once
2
3#ifndef __INC_FL_DELAY_H
4#define __INC_FL_DELAY_H
5
6#include "FastLED.h"
7#include "fl/types.h"
8#include "fl/force_inline.h"
9#include "fl/int.h"
10
13
15
16
17#if (!defined(NO_MINIMUM_WAIT) || (NO_MINIMUM_WAIT==0))
18
21template<int WAIT> class CMinWait {
23 fl::u16 mLastMicros;
24
25public:
28
30 void wait() {
31 fl::u16 diff;
32 do {
33 diff = (micros() & 0xFFFF) - mLastMicros;
34 } while(diff < WAIT);
35 }
36
38 void mark() { mLastMicros = micros() & 0xFFFF; }
39};
40
41#else
42
43// 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.
44template<int WAIT> class CMinWait {
45public:
46 CMinWait() { }
47 void wait() { }
48 void mark() {}
49};
50
51#endif
52
53
59
60// Default is now just 'nop', with special case for AVR
61
62// ESP32 core has it's own definition of NOP, so undef it first
63#ifdef ESP32
64#undef NOP
65#undef NOP2
66#endif
67
68#if defined(__AVR__)
69# define FL_NOP __asm__ __volatile__ ("cp r0,r0\n");
70# define FL_NOP2 __asm__ __volatile__ ("rjmp .+0");
71#else
73# define FL_NOP __asm__ __volatile__ ("nop\n");
75# define FL_NOP2 __asm__ __volatile__ ("nop\n\t nop\n");
76#endif
77
78// predeclaration to not upset the compiler
79
80
84template<fl::cycle_t CYCLES> inline void delaycycles();
85
88template<fl::cycle_t CYCLES> inline void delaycycles_min1() {
90 delaycycles<CYCLES-1>();
91}
92
93
94// TODO: ARM version of _delaycycles_
95
96// usable definition
97#if defined(FASTLED_AVR)
98// worker template - this will nop for LOOP * 3 + PAD cycles total
99template<int LOOP, fl::cycle_t PAD> inline void _delaycycles_AVR() {
101 // the loop below is 3 cycles * LOOP. the LDI is one cycle,
102 // the DEC is 1 cycle, the BRNE is 2 cycles if looping back and
103 // 1 if not (the LDI balances out the BRNE being 1 cycle on exit)
104 __asm__ __volatile__ (
105 " LDI R16, %0\n"
106 "L_%=: DEC R16\n"
107 " BRNE L_%=\n"
108 : /* no outputs */
109 : "M" (LOOP)
110 : "r16"
111 );
112}
113
114template<fl::cycle_t CYCLES> FASTLED_FORCE_INLINE void delaycycles() {
115 _delaycycles_AVR<CYCLES / 3, CYCLES % 3>();
116}
117
118
119
120#else
121// template<int LOOP, fl::cycle_t PAD> inline void _delaycycles_ARM() {
122// delaycycles<PAD>();
123// // the loop below is 3 cycles * LOOP. the LDI is one cycle,
124// // the DEC is 1 cycle, the BRNE is 2 cycles if looping back and
125// // 1 if not (the LDI balances out the BRNE being 1 cycle on exit)
126// __asm__ __volatile__ (
127// " mov.w r9, %0\n"
128// "L_%=: subs.w r9, r9, #1\n"
129// " bne.n L_%=\n"
130// : /* no outputs */
131// : "M" (LOOP)
132// : "r9"
133// );
134// }
135
136
137template<fl::cycle_t CYCLES> FASTLED_FORCE_INLINE void delaycycles() {
138 // _delaycycles_ARM<CYCLES / 3, CYCLES % 3>();
139 FL_NOP; delaycycles<CYCLES-1>();
140}
141
142
143
144
145#endif
146
147// pre-instantiations for values small enough to not need the loop, as well as sanity holders
148// for some negative values.
149
150// These are hidden from Doxygen because they match the expected behavior of the class.
152template<> FASTLED_FORCE_INLINE void delaycycles<-10>() {}
153template<> FASTLED_FORCE_INLINE void delaycycles<-9>() {}
154template<> FASTLED_FORCE_INLINE void delaycycles<-8>() {}
155template<> FASTLED_FORCE_INLINE void delaycycles<-7>() {}
156template<> FASTLED_FORCE_INLINE void delaycycles<-6>() {}
157template<> FASTLED_FORCE_INLINE void delaycycles<-5>() {}
158template<> FASTLED_FORCE_INLINE void delaycycles<-4>() {}
159template<> FASTLED_FORCE_INLINE void delaycycles<-3>() {}
160template<> FASTLED_FORCE_INLINE void delaycycles<-2>() {}
161template<> FASTLED_FORCE_INLINE void delaycycles<-1>() {}
162template<> FASTLED_FORCE_INLINE void delaycycles<0>() {}
163template<> FASTLED_FORCE_INLINE void delaycycles<1>() {FL_NOP;}
168#if defined(ESP32)
170 // specialization for a gigantic amount of cycles, apparently this is needed
171 // or esp32 will blow the stack with cycles = 4294966398.
172 const fl::u32 termination = 4294966398 / 10;
173 const fl::u32 remainder = 4294966398 % 10;
174 for (fl::u32 i = 0; i < termination; i++) {
177 }
178
179 // remainder
180 switch (remainder) {
181 case 9: FL_NOP;
182 case 8: FL_NOP;
183 case 7: FL_NOP;
184 case 6: FL_NOP;
185 case 5: FL_NOP;
186 case 4: FL_NOP;
187 case 3: FL_NOP;
188 case 2: FL_NOP;
189 case 1: FL_NOP;
190 }
191}
192#endif
194
196
197
200
201// Macro to convert from nano-seconds to clocks and clocks to nano-seconds
202// #define NS(_NS) (_NS / (1000 / (F_CPU / 1000000L)))
203
205#define F_CPU_MHZ (F_CPU / 1000000L)
206
207// #define NS(_NS) ( (_NS * (F_CPU / 1000000L))) / 1000
208
210#define NS(_NS) (((_NS * F_CPU_MHZ) + 999) / 1000)
212#define CLKS_TO_MICROS(_CLKS) ((long)(_CLKS)) / (F_CPU / 1000000L)
213
215#define NO_TIME(A, B, C) (NS(A) < 3 || NS(B) < 3 || NS(C) < 6)
216
218
220
221#endif
central include file for FastLED, defines the CFastLED class/object
fl::u16 mLastMicros
Timestamp of the last time this was run, in microseconds.
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.
Class to ensure that a minimum amount of time has kicked since the last time run - and delay if not e...
#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.
#define FASTLED_FORCE_INLINE
Definition force_inline.h:6
#define FASTLED_NAMESPACE_END
Definition namespace.h:23
#define FASTLED_NAMESPACE_BEGIN
Definition namespace.h:22