Lumitronix_Iflex_Pro_Workshop
Library to interact with the iFlexPro
NeoEspBitBangMethod.h
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2 LumitronixIFlex library helper functions for Esp8266 and Esp32
3 
4 Written by Michael C. Miller.
5 
6 I invest time and resources providing this open source code,
7 please support me by dontating (see https://github.com/Makuna)
8 
9 -------------------------------------------------------------------------
10 This file is part of the LUMITRONIX_iFlex_Workshop library.
11 
12 LumitronixIFlexBus is free software: you can redistribute it and/or modify
13 it under the terms of the GNU Lesser General Public License as
14 published by the Free Software Foundation, either version 3 of
15 the License, or (at your option) any later version.
16 
17 LumitronixIFlexBus is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU Lesser General Public License for more details.
21 
22 You should have received a copy of the GNU Lesser General Public
23 License along with LumitronixIFlex. If not, see
24 <http://www.gnu.org/licenses/>.
25 -------------------------------------------------------------------------*/
26 
27 #pragma once
28 
29 #if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
30 
31 #if defined(ARDUINO_ARCH_ESP8266)
32 #include <eagle_soc.h>
33 #endif
34 #if defined(CONFIG_IDF_TARGET_ESP32C3)
35 #define CYCLES_LOOPTEST (1) // adjustment due to loop exit test instruction cycles
36 #elif defined(CONFIG_IDF_TARGET_ESP32S3)
37 #define CYCLES_LOOPTEST (2) // adjustment due to loop exit test instruction cycles
38 #else
39 #define CYCLES_LOOPTEST (4) // adjustment due to loop exit test instruction cycles
40 #endif
41 
42 extern void neoEspBitBangWriteSpacingPixels(const uint8_t* pixels,
43  const uint8_t* end,
44  uint8_t pin,
45  uint32_t t0h,
46  uint32_t t1h,
47  uint32_t period,
48  size_t sizePixel,
49  uint32_t tSpacing,
50  bool invert);
51 
52 
53 class NeoEspNotInverted
54 {
55 public:
56  const static uint8_t IdleLevel = LOW;
57 };
58 
59 class NeoEspInverted
60 {
61 public:
62  const static uint8_t IdleLevel = HIGH;
63 };
64 
65 class NeoEspBitBangSpeedWs2811
66 {
67 public:
68  const static uint32_t T0H = (F_CPU / 3333333 - CYCLES_LOOPTEST); // 0.3us
69  const static uint32_t T1H = (F_CPU / 1052632 - CYCLES_LOOPTEST); // 0.95us
70  const static uint32_t Period = (F_CPU / 800000 - CYCLES_LOOPTEST); // 1.25us per bit
71 
72  static const uint32_t ResetTimeUs = 300;
73  const static uint32_t TInterPixel = 0;
74 };
75 
76 class NeoEspBitBangSpeedWs2812x
77 {
78 public:
79  const static uint32_t T0H = (F_CPU / 2500000 - CYCLES_LOOPTEST); // 0.4us
80  const static uint32_t T1H = (F_CPU / 1250000 - CYCLES_LOOPTEST); // 0.8us
81  const static uint32_t Period = (F_CPU / 800000 - CYCLES_LOOPTEST); // 1.25us per bit
82 
83  static const uint32_t ResetTimeUs = 300;
84  const static uint32_t TInterPixel = 0;
85 };
86 
87 class NeoEspBitBangSpeedSk6812
88 {
89 public:
90  const static uint32_t T0H = (F_CPU / 2500000 - CYCLES_LOOPTEST); // 0.4us
91  const static uint32_t T1H = (F_CPU / 1250000 - CYCLES_LOOPTEST); // 0.8us
92  const static uint32_t Period = (F_CPU / 800000 - CYCLES_LOOPTEST); // 1.25us per bit
93 
94  static const uint32_t ResetTimeUs = 80;
95  const static uint32_t TInterPixel = 0;
96 };
97 
98 // Tm1814 normal is inverted signal
99 class NeoEspBitBangSpeedTm1814
100 {
101 public:
102  const static uint32_t T0H = (F_CPU / 2916666 - CYCLES_LOOPTEST); // 0.35us
103  const static uint32_t T1H = (F_CPU / 1666666 - CYCLES_LOOPTEST); // 0.75us
104  const static uint32_t Period = (F_CPU / 800000 - CYCLES_LOOPTEST); // 1.25us per bit
105 
106  static const uint32_t ResetTimeUs = 200;
107  const static uint32_t TInterPixel = 0;
108 };
109 
110 // Tm1829 normal is inverted signal
111 class NeoEspBitBangSpeedTm1829
112 {
113 public:
114  const static uint32_t T0H = (F_CPU / 3333333 - CYCLES_LOOPTEST); // 0.3us
115  const static uint32_t T1H = (F_CPU / 1250000 - CYCLES_LOOPTEST); // 0.8us
116  const static uint32_t Period = (F_CPU / 800000 - CYCLES_LOOPTEST); // 1.25us per bit
117 
118  static const uint32_t ResetTimeUs = 200;
119  const static uint32_t TInterPixel = 0;
120 };
121 
122 class NeoEspBitBangSpeed800Kbps
123 {
124 public:
125  const static uint32_t T0H = (F_CPU / 2500000 - CYCLES_LOOPTEST); // 0.4us
126  const static uint32_t T1H = (F_CPU / 1250000 - CYCLES_LOOPTEST); // 0.8us
127  const static uint32_t Period = (F_CPU / 800000 - CYCLES_LOOPTEST); // 1.25us per bit
128 
129  static const uint32_t ResetTimeUs = 50;
130  const static uint32_t TInterPixel = 0;
131 };
132 
133 class NeoEspBitBangSpeed400Kbps
134 {
135 public:
136  const static uint32_t T0H = (F_CPU / 2000000 - CYCLES_LOOPTEST);
137  const static uint32_t T1H = (F_CPU / 833333 - CYCLES_LOOPTEST);
138  const static uint32_t Period = (F_CPU / 400000 - CYCLES_LOOPTEST);
139 
140  static const uint32_t ResetTimeUs = 50;
141  const static uint32_t TInterPixel = 0;
142 };
143 
144 class NeoEspBitBangSpeedApa106
145 {
146 public:
147  const static uint32_t T0H = (F_CPU / 2857143 - CYCLES_LOOPTEST); // 0.35us
148  const static uint32_t T1H = (F_CPU / 740741 - CYCLES_LOOPTEST); // 1.35
149  const static uint32_t Period = (F_CPU / 606061 - CYCLES_LOOPTEST); // 1.65us
150 
151  static const uint32_t ResetTimeUs = 50;
152  const static uint32_t TInterPixel = 0;
153 };
154 
155 class NeoEspBitBangSpeedIntertek
156 {
157 public:
158  const static uint32_t T0H = (F_CPU / 2500000 - CYCLES_LOOPTEST); // 0.4us
159  const static uint32_t T1H = (F_CPU / 1250000 - CYCLES_LOOPTEST); // 0.8us
160  const static uint32_t Period = (F_CPU / 800000 - CYCLES_LOOPTEST); // 1.25us per bit
161 
162  const static uint32_t ResetTimeUs = 12470;
163  const static uint32_t TInterPixel = (F_CPU / 50000); // 20us
164 };
165 
166 
167 template<typename T_SPEED, typename T_INVERTED> class NeoEspBitBangEncode : public T_SPEED, public T_INVERTED
168 {
169 public:
170  static void WritePixels(uint8_t pin,
171  const uint8_t* data,
172  size_t sizeData,
173  size_t sizePixel)
174  {
175  neoEspBitBangWriteSpacingPixels(data,
176  data + sizeData,
177  pin,
178  T_SPEED::T0H,
179  T_SPEED::T1H,
180  T_SPEED::Period,
181  sizePixel,
182  T_SPEED::TInterPixel,
183  T_INVERTED::IdleLevel);
184  }
185 };
186 
187 template<typename T_ENCODER> class NeoEspBitBangMethodBase
188 {
189 public:
190  typedef NeoNoSettings SettingsObject;
191 
192  NeoEspBitBangMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize) :
193  _sizePixel(elementSize),
194  _sizeData(pixelCount * elementSize + settingsSize),
195  _pin(pin)
196  {
197  pinMode(pin, OUTPUT);
198 
199  _data = static_cast<uint8_t*>(malloc(_sizeData));
200  // data cleared later in Begin()
201  }
202 
203  ~NeoEspBitBangMethodBase()
204  {
205  pinMode(_pin, INPUT);
206 
207  free(_data);
208  }
209 
210  bool IsReadyToUpdate() const
211  {
212  uint32_t delta = micros() - _endTime;
213 
214  return (delta >= T_ENCODER::ResetTimeUs);
215  }
216 
217  void Initialize()
218  {
219  digitalWrite(_pin, T_ENCODER::IdleLevel);
220 
221  _endTime = micros();
222  }
223 
224  void Update(bool)
225  {
226  // Data latch = 50+ microsecond pause in the output stream. Rather than
227  // put a delay at the end of the function, the ending time is noted and
228  // the function will simply hold off (if needed) on issuing the
229  // subsequent round of data until the latch time has elapsed. This
230  // allows the mainline code to start generating the next frame of data
231  // rather than stalling for the latch.
232  while (!IsReadyToUpdate())
233  {
234  yield(); // allows for system yield if needed
235  }
236 
237  // Need 100% focus on instruction timing
238 #if defined(ARDUINO_ARCH_ESP32)
239  // delay(1); // required ?
240  portMUX_TYPE updateMux = portMUX_INITIALIZER_UNLOCKED;
241 
242  portENTER_CRITICAL(&updateMux);
243 #else
244  noInterrupts();
245 #endif
246 
247  T_ENCODER::WritePixels(_pin,
248  _data,
249  _sizeData,
250  _sizePixel);
251 
252 #if defined(ARDUINO_ARCH_ESP32)
253  portEXIT_CRITICAL(&updateMux);
254 #else
255  interrupts();
256 #endif
257 
258  // save EOD time for latch on next call
259  _endTime = micros();
260  }
261 
262  bool AlwaysUpdate()
263  {
264  // this method requires update to be called only if changes to buffer
265  return false;
266  }
267 
268  uint8_t* getData() const
269  {
270  return _data;
271  };
272 
273  size_t getDataSize() const
274  {
275  return _sizeData;
276  };
277 
278  void applySettings([[maybe_unused]] const SettingsObject& settings)
279  {
280  }
281 
282 private:
283  const size_t _sizePixel; // size of a pixel in _data
284  const size_t _sizeData; // Size of '_data' buffer below
285  const uint8_t _pin; // output pin number
286 
287  uint32_t _endTime; // Latch timing reference
288  uint8_t* _data; // Holds LED color values
289 };
290 
291 
292 #if defined(ARDUINO_ARCH_ESP32)
293 
294 typedef NeoEspBitBangMethodBase<NeoEspBitBangEncode<NeoEspBitBangSpeedWs2811, NeoEspNotInverted>> NeoEsp32BitBangWs2811Method;
295 typedef NeoEspBitBangMethodBase<NeoEspBitBangEncode<NeoEspBitBangSpeedWs2812x, NeoEspNotInverted>> NeoEsp32BitBangWs2812xMethod;
296 typedef NeoEspBitBangMethodBase<NeoEspBitBangEncode<NeoEspBitBangSpeedSk6812, NeoEspNotInverted>> NeoEsp32BitBangSk6812Method;
297 typedef NeoEspBitBangMethodBase<NeoEspBitBangEncode<NeoEspBitBangSpeedTm1814, NeoEspInverted>> NeoEsp32BitBangTm1814Method;
298 typedef NeoEspBitBangMethodBase<NeoEspBitBangEncode<NeoEspBitBangSpeedTm1829, NeoEspInverted>> NeoEsp32BitBangTm1829Method;
299 typedef NeoEspBitBangMethodBase<NeoEspBitBangEncode<NeoEspBitBangSpeed800Kbps, NeoEspNotInverted>> NeoEsp32BitBang800KbpsMethod;
300 typedef NeoEspBitBangMethodBase<NeoEspBitBangEncode<NeoEspBitBangSpeed400Kbps, NeoEspNotInverted>> NeoEsp32BitBang400KbpsMethod;
301 typedef NeoEspBitBangMethodBase<NeoEspBitBangEncode<NeoEspBitBangSpeedApa106, NeoEspNotInverted>> NeoEsp32BitBangApa106Method;
302 typedef NeoEspBitBangMethodBase<NeoEspBitBangEncode<NeoEspBitBangSpeedIntertek, NeoEspNotInverted>> NeoEsp32BitBangIntertekMethod;
303 
304 typedef NeoEsp32BitBangWs2812xMethod NeoEsp32BitBangWs2813Method;
305 typedef NeoEsp32BitBang800KbpsMethod NeoEsp32BitBangWs2812Method;
306 typedef NeoEsp32BitBangWs2812xMethod NeoEsp32BitBangWs2816Method;
307 typedef NeoEsp32BitBangTm1814Method NeoEsp32BitBangTm1914Method;
308 typedef NeoEsp32BitBangSk6812Method NeoEsp32BitBangLc8812Method;
309 
310 typedef NeoEspBitBangMethodBase<NeoEspBitBangEncode<NeoEspBitBangSpeedWs2811, NeoEspInverted>> NeoEsp32BitBangWs2811InvertedMethod;
311 typedef NeoEspBitBangMethodBase<NeoEspBitBangEncode<NeoEspBitBangSpeedWs2812x, NeoEspInverted>> NeoEsp32BitBangWs2812xInvertedMethod;
312 typedef NeoEspBitBangMethodBase<NeoEspBitBangEncode<NeoEspBitBangSpeedSk6812, NeoEspInverted>> NeoEsp32BitBangSk6812InvertedMethod;
313 typedef NeoEspBitBangMethodBase<NeoEspBitBangEncode<NeoEspBitBangSpeedTm1814, NeoEspNotInverted>> NeoEsp32BitBangTm1814InvertedMethod;
314 typedef NeoEspBitBangMethodBase<NeoEspBitBangEncode<NeoEspBitBangSpeedTm1829, NeoEspNotInverted>> NeoEsp32BitBangTm1829InvertedMethod;
315 typedef NeoEspBitBangMethodBase<NeoEspBitBangEncode<NeoEspBitBangSpeed800Kbps, NeoEspInverted>> NeoEsp32BitBang800KbpsInvertedMethod;
316 typedef NeoEspBitBangMethodBase<NeoEspBitBangEncode<NeoEspBitBangSpeed400Kbps, NeoEspInverted>> NeoEsp32BitBang400KbpsInvertedMethod;
317 typedef NeoEspBitBangMethodBase<NeoEspBitBangEncode<NeoEspBitBangSpeedApa106, NeoEspInverted>> NeoEsp32BitBangApa106InvertedMethod;
318 typedef NeoEspBitBangMethodBase<NeoEspBitBangEncode<NeoEspBitBangSpeedIntertek, NeoEspInverted>> NeoEsp32BitBangIntertekInvertedMethod;
319 
320 typedef NeoEsp32BitBangWs2812xInvertedMethod NeoEsp32BitBangWs2813InvertedMethod;
321 typedef NeoEsp32BitBang800KbpsInvertedMethod NeoEsp32BitBangWs2812InvertedMethod;
322 typedef NeoEsp32BitBangWs2812xInvertedMethod NeoEsp32BitBangWs2816InvertedMethod;
323 typedef NeoEsp32BitBangTm1814InvertedMethod NeoEsp32BitBangTm1914InvertedMethod;
324 typedef NeoEsp32BitBangSk6812InvertedMethod NeoEsp32BitBangLc8812InvertedMethod;
325 
326 #else // defined(ARDUINO_ARCH_ESP8266)
327 
328 typedef NeoEspBitBangMethodBase<NeoEspBitBangEncode<NeoEspBitBangSpeedWs2811, NeoEspNotInverted>> NeoEsp8266BitBangWs2811Method;
329 typedef NeoEspBitBangMethodBase<NeoEspBitBangEncode<NeoEspBitBangSpeedWs2812x, NeoEspNotInverted>> NeoEsp8266BitBangWs2812xMethod;
330 typedef NeoEspBitBangMethodBase<NeoEspBitBangEncode<NeoEspBitBangSpeedSk6812, NeoEspNotInverted>> NeoEsp8266BitBangSk6812Method;
331 typedef NeoEspBitBangMethodBase<NeoEspBitBangEncode<NeoEspBitBangSpeedTm1814, NeoEspInverted>> NeoEsp8266BitBangTm1814Method;
332 typedef NeoEspBitBangMethodBase<NeoEspBitBangEncode<NeoEspBitBangSpeedTm1829, NeoEspInverted>> NeoEsp8266BitBangTm1829Method;
333 typedef NeoEspBitBangMethodBase<NeoEspBitBangEncode<NeoEspBitBangSpeed800Kbps, NeoEspNotInverted>> NeoEsp8266BitBang800KbpsMethod;
334 typedef NeoEspBitBangMethodBase<NeoEspBitBangEncode<NeoEspBitBangSpeed400Kbps, NeoEspNotInverted>> NeoEsp8266BitBang400KbpsMethod;
335 typedef NeoEspBitBangMethodBase<NeoEspBitBangEncode<NeoEspBitBangSpeedApa106, NeoEspNotInverted>> NeoEsp8266BitBangApa106Method;
336 typedef NeoEspBitBangMethodBase<NeoEspBitBangEncode<NeoEspBitBangSpeedIntertek, NeoEspNotInverted>> NeoEsp8266BitBangIntertekMethod;
337 
338 typedef NeoEsp8266BitBangWs2812xMethod NeoEsp8266BitBangWs2813Method;
339 typedef NeoEsp8266BitBang800KbpsMethod NeoEsp8266BitBangWs2812Method;
340 typedef NeoEsp8266BitBangWs2812xMethod NeoEsp8266BitBangWs2816Method;
341 typedef NeoEsp8266BitBangTm1814Method NeoEsp8266BitBangTm1914Method;
342 typedef NeoEsp8266BitBangSk6812Method NeoEsp8266BitBangLc8812Method;
343 
344 typedef NeoEspBitBangMethodBase<NeoEspBitBangEncode<NeoEspBitBangSpeedWs2811, NeoEspInverted>> NeoEsp8266BitBangWs2811InvertedMethod;
345 typedef NeoEspBitBangMethodBase<NeoEspBitBangEncode<NeoEspBitBangSpeedWs2812x, NeoEspInverted>> NeoEsp8266BitBangWs2812xInvertedMethod;
346 typedef NeoEspBitBangMethodBase<NeoEspBitBangEncode<NeoEspBitBangSpeedSk6812, NeoEspInverted>> NeoEsp8266BitBangSk6812InvertedMethod;
347 typedef NeoEspBitBangMethodBase<NeoEspBitBangEncode<NeoEspBitBangSpeedTm1814, NeoEspNotInverted>> NeoEsp8266BitBangTm1814InvertedMethod;
348 typedef NeoEspBitBangMethodBase<NeoEspBitBangEncode<NeoEspBitBangSpeedTm1829, NeoEspNotInverted>> NeoEsp8266BitBangTm1829InvertedMethod;
349 typedef NeoEspBitBangMethodBase<NeoEspBitBangEncode<NeoEspBitBangSpeed800Kbps, NeoEspInverted>> NeoEsp8266BitBang800KbpsInvertedMethod;
350 typedef NeoEspBitBangMethodBase<NeoEspBitBangEncode<NeoEspBitBangSpeed400Kbps, NeoEspInverted>> NeoEsp8266BitBang400KbpsInvertedMethod;
351 typedef NeoEspBitBangMethodBase<NeoEspBitBangEncode<NeoEspBitBangSpeedApa106, NeoEspInverted>> NeoEsp8266BitBangApa106InvertedMethod;
352 typedef NeoEspBitBangMethodBase<NeoEspBitBangEncode<NeoEspBitBangSpeedIntertek, NeoEspInverted>> NeoEsp8266BitBangIntertekInvertedMethod;
353 
354 typedef NeoEsp8266BitBangWs2812xInvertedMethod NeoEsp8266BitBangWs2813InvertedMethod;
355 typedef NeoEsp8266BitBang800KbpsInvertedMethod NeoEsp8266BitBangWs2812InvertedMethod;
356 typedef NeoEsp8266BitBangWs2812xInvertedMethod NeoEsp8266BitBangWs2816InvertedMethod;
357 typedef NeoEsp8266BitBangTm1814InvertedMethod NeoEsp8266BitBangTm1914InvertedMethod;
358 typedef NeoEsp8266BitBangSk6812InvertedMethod NeoEsp8266BitBangLc8812InvertedMethod;
359 
360 #endif // defined(ARDUINO_ARCH_ESP32)
361 
362 // ESP bitbang doesn't have defaults and should avoided except for testing
363 
364 #endif // defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
Definition: NeoSettings.h:29