forked from FastLED/FastLED
-
Notifications
You must be signed in to change notification settings - Fork 0
/
fastled_delay.h
121 lines (100 loc) · 4.05 KB
/
fastled_delay.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#ifndef __INC_FL_DELAY_H
#define __INC_FL_DELAY_H
///@file fastled_delay.h
///Utility functions and classes for managing delaycycles
FASTLED_NAMESPACE_BEGIN
/// Class to ensure that a minimum amount of time has kicked since the last time run - and delay if not enough time has passed yet
/// this should make sure that chipsets that have
template<int WAIT> class CMinWait {
uint16_t mLastMicros;
public:
CMinWait() { mLastMicros = 0; }
void wait() {
uint16_t diff;
do {
diff = (micros() & 0xFFFF) - mLastMicros;
} while(diff < WAIT);
}
void mark() { mLastMicros = micros() & 0xFFFF; }
};
////////////////////////////////////////////////////////////////////////////////////////////
//
// Clock cycle counted delay loop
//
////////////////////////////////////////////////////////////////////////////////////////////
// Default is now just 'nop', with special case for AVR
#if defined(__AVR__)
# define NOP __asm__ __volatile__ ("cp r0,r0\n");
# define NOP2 __asm__ __volatile__ ("rjmp .+0");
#else
# define NOP __asm__ __volatile__ ("nop\n");
# define NOP2 __asm__ __volatile__ ("nop\n\t nop\n");
#endif
// predeclaration to not upset the compiler
template<int CYCLES> inline void delaycycles();
// TODO: ARM version of _delaycycles_
// usable definition
#if defined(FASTLED_AVR)
// worker template - this will nop for LOOP * 3 + PAD cycles total
template<int LOOP, int PAD> inline void _delaycycles_AVR() {
delaycycles<PAD>();
// the loop below is 3 cycles * LOOP. the LDI is one cycle,
// the DEC is 1 cycle, the BRNE is 2 cycles if looping back and
// 1 if not (the LDI balances out the BRNE being 1 cycle on exit)
__asm__ __volatile__ (
" LDI R16, %0\n"
"L_%=: DEC R16\n"
" BRNE L_%=\n"
: /* no outputs */
: "M" (LOOP)
: "r16"
);
}
template<int CYCLES> __attribute__((always_inline)) inline void delaycycles() {
_delaycycles_AVR<CYCLES / 3, CYCLES % 3>();
}
#else
// template<int LOOP, int PAD> inline void _delaycycles_ARM() {
// delaycycles<PAD>();
// // the loop below is 3 cycles * LOOP. the LDI is one cycle,
// // the DEC is 1 cycle, the BRNE is 2 cycles if looping back and
// // 1 if not (the LDI balances out the BRNE being 1 cycle on exit)
// __asm__ __volatile__ (
// " mov.w r9, %0\n"
// "L_%=: subs.w r9, r9, #1\n"
// " bne.n L_%=\n"
// : /* no outputs */
// : "M" (LOOP)
// : "r9"
// );
// }
template<int CYCLES> __attribute__((always_inline)) inline void delaycycles() {
// _delaycycles_ARM<CYCLES / 3, CYCLES % 3>();
NOP; delaycycles<CYCLES-1>();
}
#endif
// pre-instantiations for values small enough to not need the loop, as well as sanity holders
// for some negative values.
template<> __attribute__((always_inline)) inline void delaycycles<-6>() {}
template<> __attribute__((always_inline)) inline void delaycycles<-5>() {}
template<> __attribute__((always_inline)) inline void delaycycles<-4>() {}
template<> __attribute__((always_inline)) inline void delaycycles<-3>() {}
template<> __attribute__((always_inline)) inline void delaycycles<-2>() {}
template<> __attribute__((always_inline)) inline void delaycycles<-1>() {}
template<> __attribute__((always_inline)) inline void delaycycles<0>() {}
template<> __attribute__((always_inline)) inline void delaycycles<1>() {NOP;}
template<> __attribute__((always_inline)) inline void delaycycles<2>() {NOP2;}
template<> __attribute__((always_inline)) inline void delaycycles<3>() {NOP;NOP2;}
template<> __attribute__((always_inline)) inline void delaycycles<4>() {NOP2;NOP2;}
template<> __attribute__((always_inline)) inline void delaycycles<5>() {NOP2;NOP2;NOP;}
// Some timing related macros/definitions
// Macro to convert from nano-seconds to clocks and clocks to nano-seconds
// #define NS(_NS) (_NS / (1000 / (F_CPU / 1000000L)))
#define F_CPU_MHZ (F_CPU / 1000000L)
// #define NS(_NS) ( (_NS * (F_CPU / 1000000L))) / 1000
#define NS(_NS) (((_NS * F_CPU_MHZ) + 999) / 1000)
#define CLKS_TO_MICROS(_CLKS) ((long)(_CLKS)) / (F_CPU / 1000000L)
// Macro for making sure there's enough time available
#define NO_TIME(A, B, C) (NS(A) < 3 || NS(B) < 3 || NS(C) < 6)
FASTLED_NAMESPACE_END
#endif