FastLED 3.6.0
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
8
9FASTLED_NAMESPACE_BEGIN
10
11
12#if (!defined(NO_MINIMUM_WAIT) || (NO_MINIMUM_WAIT==0))
13
16template<int WAIT> class CMinWait {
18 uint16_t mLastMicros;
19
20public:
22 CMinWait() { mLastMicros = 0; }
23
25 void wait() {
26 uint16_t diff;
27 do {
28 diff = (micros() & 0xFFFF) - mLastMicros;
29 } while(diff < WAIT);
30 }
31
33 void mark() { mLastMicros = micros() & 0xFFFF; }
34};
35
36#else
37
38// 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.
39template<int WAIT> class CMinWait {
40public:
41 CMinWait() { }
42 void wait() { }
43 void mark() {}
44};
45
46#endif
47
48
54
55// Default is now just 'nop', with special case for AVR
56
57// ESP32 core has it's own definition of NOP, so undef it first
58#ifdef ESP32
59#undef NOP
60#undef NOP2
61#endif
62
63#if defined(__AVR__)
64# define FL_NOP __asm__ __volatile__ ("cp r0,r0\n");
65# define FL_NOP2 __asm__ __volatile__ ("rjmp .+0");
66#else
68# define FL_NOP __asm__ __volatile__ ("nop\n");
70# define FL_NOP2 __asm__ __volatile__ ("nop\n\t nop\n");
71#endif
72
73// predeclaration to not upset the compiler
74
75
79template<int CYCLES> inline void delaycycles();
80
83template<int CYCLES> inline void delaycycles_min1() {
84 delaycycles<1>();
85 delaycycles<CYCLES-1>();
86}
87
88
89// TODO: ARM version of _delaycycles_
90
91// usable definition
92#if defined(FASTLED_AVR)
93// worker template - this will nop for LOOP * 3 + PAD cycles total
94template<int LOOP, int PAD> inline void _delaycycles_AVR() {
95 delaycycles<PAD>();
96 // the loop below is 3 cycles * LOOP. the LDI is one cycle,
97 // the DEC is 1 cycle, the BRNE is 2 cycles if looping back and
98 // 1 if not (the LDI balances out the BRNE being 1 cycle on exit)
99 __asm__ __volatile__ (
100 " LDI R16, %0\n"
101 "L_%=: DEC R16\n"
102 " BRNE L_%=\n"
103 : /* no outputs */
104 : "M" (LOOP)
105 : "r16"
106 );
107}
108
109template<int CYCLES> __attribute__((always_inline)) inline void delaycycles() {
110 _delaycycles_AVR<CYCLES / 3, CYCLES % 3>();
111}
112#else
113// template<int LOOP, int PAD> inline void _delaycycles_ARM() {
114// delaycycles<PAD>();
115// // the loop below is 3 cycles * LOOP. the LDI is one cycle,
116// // the DEC is 1 cycle, the BRNE is 2 cycles if looping back and
117// // 1 if not (the LDI balances out the BRNE being 1 cycle on exit)
118// __asm__ __volatile__ (
119// " mov.w r9, %0\n"
120// "L_%=: subs.w r9, r9, #1\n"
121// " bne.n L_%=\n"
122// : /* no outputs */
123// : "M" (LOOP)
124// : "r9"
125// );
126// }
127
128
129template<int CYCLES> __attribute__((always_inline)) inline void delaycycles() {
130 // _delaycycles_ARM<CYCLES / 3, CYCLES % 3>();
131 FL_NOP; delaycycles<CYCLES-1>();
132}
133#endif
134
135// pre-instantiations for values small enough to not need the loop, as well as sanity holders
136// for some negative values.
137
138// These are hidden from Doxygen because they match the expected behavior of the class.
140template<> __attribute__((always_inline)) inline void delaycycles<-10>() {}
141template<> __attribute__((always_inline)) inline void delaycycles<-9>() {}
142template<> __attribute__((always_inline)) inline void delaycycles<-8>() {}
143template<> __attribute__((always_inline)) inline void delaycycles<-7>() {}
144template<> __attribute__((always_inline)) inline void delaycycles<-6>() {}
145template<> __attribute__((always_inline)) inline void delaycycles<-5>() {}
146template<> __attribute__((always_inline)) inline void delaycycles<-4>() {}
147template<> __attribute__((always_inline)) inline void delaycycles<-3>() {}
148template<> __attribute__((always_inline)) inline void delaycycles<-2>() {}
149template<> __attribute__((always_inline)) inline void delaycycles<-1>() {}
150template<> __attribute__((always_inline)) inline void delaycycles<0>() {}
151template<> __attribute__((always_inline)) inline void delaycycles<1>() {FL_NOP;}
152template<> __attribute__((always_inline)) inline void delaycycles<2>() {FL_NOP2;}
153template<> __attribute__((always_inline)) inline void delaycycles<3>() {FL_NOP;FL_NOP2;}
154template<> __attribute__((always_inline)) inline void delaycycles<4>() {FL_NOP2;FL_NOP2;}
155template<> __attribute__((always_inline)) inline void delaycycles<5>() {FL_NOP2;FL_NOP2;FL_NOP;}
157
159
160
163
164// Macro to convert from nano-seconds to clocks and clocks to nano-seconds
165// #define NS(_NS) (_NS / (1000 / (F_CPU / 1000000L)))
166
168#define F_CPU_MHZ (F_CPU / 1000000L)
169
170// #define NS(_NS) ( (_NS * (F_CPU / 1000000L))) / 1000
171
173#define NS(_NS) (((_NS * F_CPU_MHZ) + 999) / 1000)
175#define CLKS_TO_MICROS(_CLKS) ((long)(_CLKS)) / (F_CPU / 1000000L)
176
178#define NO_TIME(A, B, C) (NS(A) < 3 || NS(B) < 3 || NS(C) < 6)
179
181
182FASTLED_NAMESPACE_END
183
184#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.