Lumitronix_Iflex_Pro_Workshop
Library to interact with the iFlexPro
NeoArmMethod.h
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2 LumitronixIFlex library helper functions for ARM MCUs.
3 Teensy 3.0, 3.1, LC, Arduino Due
4 
5 Written by Michael C. Miller.
6 Some work taken from the Adafruit LumitronixIFlex library.
7 
8 I invest time and resources providing this open source code,
9 please support me by dontating (see https://github.com/Makuna)
10 
11 -------------------------------------------------------------------------
12 This file is part of the LUMITRONIX_iFlex_Workshop library.
13 The contents of this file were taken from the Adafruit LumitronixIFlex library
14 and modified only to fit within individual calling functions.
15 
16 LumitronixIFlexBus is free software: you can redistribute it and/or modify
17 it under the terms of the GNU Lesser General Public License as
18 published by the Free Software Foundation, either version 3 of
19 the License, or (at your option) any later version.
20 
21 LumitronixIFlexBus is distributed in the hope that it will be useful,
22 but WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 GNU Lesser General Public License for more details.
25 
26 You should have received a copy of the GNU Lesser General Public
27 License along with LumitronixIFlex. If not, see
28 <http://www.gnu.org/licenses/>.
29 -------------------------------------------------------------------------*/
30 
31 #pragma once
32 
33 #if defined(__arm__) && !defined(ARDUINO_ARCH_NRF52840)
34 
35 template<typename T_SPEED> class NeoArmMethodBase
36 {
37 public:
38  typedef NeoNoSettings SettingsObject;
39 
40  NeoArmMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize) :
41  _sizeData(pixelCount * elementSize + settingsSize),
42  _pin(pin)
43  {
44  pinMode(pin, OUTPUT);
45 
46  _data = static_cast<uint8_t*>(malloc(_sizeData));
47  // data cleared later in Begin()
48  }
49 
50  ~NeoArmMethodBase()
51  {
52  pinMode(_pin, INPUT);
53 
54  free(_data);
55  }
56 
57  bool IsReadyToUpdate() const
58  {
59  uint32_t delta = micros() - _endTime;
60 
61  return (delta >= T_SPEED::ResetTimeUs);
62  }
63 
64  void Initialize()
65  {
66  digitalWrite(_pin, LOW);
67 
68  _endTime = micros();
69  }
70 
71  void Update(bool)
72  {
73  // Data latch = 50+ microsecond pause in the output stream. Rather than
74  // put a delay at the end of the function, the ending time is noted and
75  // the function will simply hold off (if needed) on issuing the
76  // subsequent round of data until the latch time has elapsed. This
77  // allows the mainline code to start generating the next frame of data
78  // rather than stalling for the latch.
79  while (!IsReadyToUpdate())
80  {
81  yield(); // allows for system yield if needed
82  }
83 
84  noInterrupts(); // Need 100% focus on instruction timing
85 
86  T_SPEED::send_pixels(_data, _sizeData, _pin);
87 
88  interrupts();
89 
90  // save EOD time for latch on next call
91  _endTime = micros();
92  }
93 
94  bool AlwaysUpdate()
95  {
96  // this method requires update to be called only if changes to buffer
97  return false;
98  }
99 
100  uint8_t* getData() const
101  {
102  return _data;
103  };
104 
105  size_t getDataSize() const
106  {
107  return _sizeData;
108  };
109 
110  void applySettings([[maybe_unused]] const SettingsObject& settings)
111  {
112  }
113 
114 private:
115  const size_t _sizeData; // Size of '_data' buffer below
116 
117  uint32_t _endTime; // Latch timing reference
118  uint8_t* _data; // Holds LED color values
119  uint8_t _pin; // output pin number
120 };
121 
122 // Teensy 3.0 or 3.1 (3.2) or 3.5 or 3.6
123 #if defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__)
124 
125 class NeoArmMk20dxSpeedProps800KbpsBase
126 {
127 public:
128  static const uint32_t CyclesT0h = (F_CPU / 4000000);
129  static const uint32_t CyclesT1h = (F_CPU / 1250000);
130  static const uint32_t Cycles = (F_CPU / 800000);
131 };
132 
133 class NeoArmMk20dxSpeedPropsWs2812x : public NeoArmMk20dxSpeedProps800KbpsBase
134 {
135 public:
136  static const uint32_t ResetTimeUs = 300;
137 };
138 
139 class NeoArmMk20dxSpeedPropsSk6812 : public NeoArmMk20dxSpeedProps800KbpsBase
140 {
141 public:
142  static const uint32_t ResetTimeUs = 80;
143 };
144 
145 class NeoArmMk20dxSpeedPropsTm1814 : public NeoArmMk20dxSpeedProps800KbpsBase
146 {
147 public:
148  static const uint32_t ResetTimeUs = 200;
149 };
150 
151 class NeoArmMk20dxSpeedPropsTm1829 : public NeoArmMk20dxSpeedProps800KbpsBase
152 {
153 public:
154  static const uint32_t ResetTimeUs = 200;
155 };
156 
157 class NeoArmMk20dxSpeedProps800Kbps : public NeoArmMk20dxSpeedProps800KbpsBase
158 {
159 public:
160  static const uint32_t ResetTimeUs = 50;
161 };
162 
163 class NeoArmMk20dxSpeedProps400Kbps
164 {
165 public:
166  static const uint32_t CyclesT0h = (F_CPU / 2000000);
167  static const uint32_t CyclesT1h = (F_CPU / 833333);
168  static const uint32_t Cycles = (F_CPU / 400000);
169  static const uint32_t ResetTimeUs = 50;
170 };
171 
172 class NeoArmMk20dxSpeedPropsApa106
173 {
174 public:
175  static const uint32_t CyclesT0h = (F_CPU / 4000000);
176  static const uint32_t CyclesT1h = (F_CPU / 913750);
177  static const uint32_t Cycles = (F_CPU / 584800);
178  static const uint32_t ResetTimeUs = 50;
179 };
180 
181 template<typename T_SPEEDPROPS> class NeoArmMk20dxSpeedBase
182 {
183 public:
184  static const uint32_t ResetTimeUs = T_SPEEDPROPS::ResetTimeUs;
185 
186  static void send_pixels(uint8_t* pixels, size_t sizePixels, uint8_t pin)
187  {
188  uint8_t* p = pixels;
189  uint8_t* end = p + sizePixels;
190  uint8_t pix;
191  uint8_t mask;
192 
193  volatile uint8_t* set = portSetRegister(pin);
194  volatile uint8_t* clr = portClearRegister(pin);
195 
196  uint32_t cyc;
197 
198  ARM_DEMCR |= ARM_DEMCR_TRCENA;
199  ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA;
200 
201  cyc = ARM_DWT_CYCCNT + T_SPEEDPROPS::Cycles;
202  while (p < end)
203  {
204  pix = *p++;
205  for (mask = 0x80; mask; mask >>= 1)
206  {
207  while (ARM_DWT_CYCCNT - cyc < T_SPEEDPROPS::Cycles);
208 
209  cyc = ARM_DWT_CYCCNT;
210  *set = 1;
211  if (pix & mask)
212  {
213  while (ARM_DWT_CYCCNT - cyc < T_SPEEDPROPS::CyclesT1h);
214  }
215  else
216  {
217  while (ARM_DWT_CYCCNT - cyc < T_SPEEDPROPS::CyclesT0h);
218  }
219  *clr = 1;
220  }
221  }
222  }
223 };
224 
225 typedef NeoArmMethodBase<NeoArmMk20dxSpeedBase<NeoArmMk20dxSpeedPropsWs2812x>> NeoArmWs2812xMethod;
226 typedef NeoArmMethodBase<NeoArmMk20dxSpeedBase<NeoArmMk20dxSpeedPropsSk6812>> NeoArmSk6812Method;
227 typedef NeoArmMethodBase<NeoArmMk20dxSpeedBase<NeoArmMk20dxSpeedPropsTm1814>> NeoArmTm1814InvertedMethod;
228 typedef NeoArmMethodBase<NeoArmMk20dxSpeedBase<NeoArmMk20dxSpeedPropsTm1829>> NeoArmTm1829InvertedMethod;
229 typedef NeoArmMethodBase<NeoArmMk20dxSpeedBase<NeoArmMk20dxSpeedPropsApa106>> NeoArmApa106Method;
230 typedef NeoArmMethodBase<NeoArmMk20dxSpeedBase<NeoArmMk20dxSpeedProps800Kbps>> NeoArm800KbpsMethod;
231 typedef NeoArmMethodBase<NeoArmMk20dxSpeedBase<NeoArmMk20dxSpeedProps400Kbps>> NeoArm400KbpsMethod;
232 
233 typedef NeoArmTm1814InvertedMethod NeoArmTm1914InvertedMethod;
234 
235 #elif defined(__MKL26Z64__) // Teensy-LC
236 
237 #if F_CPU == 48000000
238 
239 class NeoArmMk26z64Speed800KbpsBase
240 {
241 public:
242  static void send_pixels(uint8_t* pixels, size_t sizePixels, uint8_t pin)
243  {
244  uint8_t* p = pixels;
245  uint8_t pix;
246  uint8_t count;
247  uint8_t dly;
248  uint8_t bitmask = digitalPinToBitMask(pin);
249  volatile uint8_t* reg = portSetRegister(pin);
250  uint32_t num = sizePixels;
251 
252  asm volatile(
253  "L%=_begin:" "\n\t"
254  "ldrb %[pix], [%[p], #0]" "\n\t"
255  "lsl %[pix], #24" "\n\t"
256  "movs %[count], #7" "\n\t"
257  "L%=_loop:" "\n\t"
258  "lsl %[pix], #1" "\n\t"
259  "bcs L%=_loop_one" "\n\t"
260  "L%=_loop_zero:"
261  "strb %[bitmask], [%[reg], #0]" "\n\t"
262  "movs %[dly], #4" "\n\t"
263  "L%=_loop_delay_T0H:" "\n\t"
264  "sub %[dly], #1" "\n\t"
265  "bne L%=_loop_delay_T0H" "\n\t"
266  "strb %[bitmask], [%[reg], #4]" "\n\t"
267  "movs %[dly], #13" "\n\t"
268  "L%=_loop_delay_T0L:" "\n\t"
269  "sub %[dly], #1" "\n\t"
270  "bne L%=_loop_delay_T0L" "\n\t"
271  "b L%=_next" "\n\t"
272  "L%=_loop_one:"
273  "strb %[bitmask], [%[reg], #0]" "\n\t"
274  "movs %[dly], #13" "\n\t"
275  "L%=_loop_delay_T1H:" "\n\t"
276  "sub %[dly], #1" "\n\t"
277  "bne L%=_loop_delay_T1H" "\n\t"
278  "strb %[bitmask], [%[reg], #4]" "\n\t"
279  "movs %[dly], #4" "\n\t"
280  "L%=_loop_delay_T1L:" "\n\t"
281  "sub %[dly], #1" "\n\t"
282  "bne L%=_loop_delay_T1L" "\n\t"
283  "nop" "\n\t"
284  "L%=_next:" "\n\t"
285  "sub %[count], #1" "\n\t"
286  "bne L%=_loop" "\n\t"
287  "lsl %[pix], #1" "\n\t"
288  "bcs L%=_last_one" "\n\t"
289  "L%=_last_zero:"
290  "strb %[bitmask], [%[reg], #0]" "\n\t"
291  "movs %[dly], #4" "\n\t"
292  "L%=_last_delay_T0H:" "\n\t"
293  "sub %[dly], #1" "\n\t"
294  "bne L%=_last_delay_T0H" "\n\t"
295  "strb %[bitmask], [%[reg], #4]" "\n\t"
296  "movs %[dly], #10" "\n\t"
297  "L%=_last_delay_T0L:" "\n\t"
298  "sub %[dly], #1" "\n\t"
299  "bne L%=_last_delay_T0L" "\n\t"
300  "b L%=_repeat" "\n\t"
301  "L%=_last_one:"
302  "strb %[bitmask], [%[reg], #0]" "\n\t"
303  "movs %[dly], #13" "\n\t"
304  "L%=_last_delay_T1H:" "\n\t"
305  "sub %[dly], #1" "\n\t"
306  "bne L%=_last_delay_T1H" "\n\t"
307  "strb %[bitmask], [%[reg], #4]" "\n\t"
308  "movs %[dly], #1" "\n\t"
309  "L%=_last_delay_T1L:" "\n\t"
310  "sub %[dly], #1" "\n\t"
311  "bne L%=_last_delay_T1L" "\n\t"
312  "nop" "\n\t"
313  "L%=_repeat:" "\n\t"
314  "add %[p], #1" "\n\t"
315  "sub %[num], #1" "\n\t"
316  "bne L%=_begin" "\n\t"
317  "L%=_done:" "\n\t"
318  : [p] "+r" (p),
319  [pix] "=&r" (pix),
320  [count] "=&r" (count),
321  [dly] "=&r" (dly),
322  [num] "+r" (num)
323  : [bitmask] "r" (bitmask),
324  [reg] "r" (reg)
325  );
326  }
327 };
328 
329 class NeoArmMk26z64SpeedWs2812x : public NeoArmMk26z64Speed800KbpsBase
330 {
331 public:
332  const static uint32_t ResetTimeUs = 300;
333 };
334 
335 class NeoArmMk26z64SpeedSk6812 : public NeoArmMk26z64Speed800KbpsBase
336 {
337 public:
338  const static uint32_t ResetTimeUs = 80;
339 };
340 
341 class NeoArmMk26z64SpeedTm1814 : public NeoArmMk26z64Speed800KbpsBase
342 {
343 public:
344  const static uint32_t ResetTimeUs = 200;
345 };
346 
347 class NeoArmMk26z64SpeedTm1829 : public NeoArmMk26z64Speed800KbpsBase
348 {
349 public:
350  const static uint32_t ResetTimeUs = 200;
351 };
352 
353 class NeoArmMk26z64Speed800Kbps : public NeoArmMk26z64Speed800KbpsBase
354 {
355 public:
356  const static uint32_t ResetTimeUs = 50;
357 };
358 
359 typedef NeoArmMethodBase<NeoArmMk26z64SpeedWs2812x> NeoArmWs2812xMethod;
360 typedef NeoArmMethodBase<NeoArmMk26z64SpeedSk6812> NeoArmSk6812Method;
361 typedef NeoArmMethodBase<NeoArmMk26z64SpeedTm1814> NeoArmTm1814InvertedMethod;
362 typedef NeoArmMethodBase<NeoArmMk26z64SpeedTm1829> NeoArmTm1829InvertedMethod;
363 typedef NeoArmMethodBase<NeoArmMk26z64Speed800Kbps> NeoArm800KbpsMethod;
364 typedef NeoArm800KbpsMethod NeoArmApa106Method;
365 typedef NeoArmTm1814InvertedMethod NeoArmTm1914InvertedMethod;
366 
367 #else
368 #error "Teensy-LC: Sorry, only 48 MHz is supported, please set Tools > CPU Speed to 48 MHz"
369 #endif // F_CPU == 48000000
370 
371 #elif defined(__SAMD21G18A__) // Arduino Zero
372 
373 
374 class NeoArmSamd21g18aSpeedProps800KbpsBase
375 {
376 public:
377  static void BitPreWait()
378  {
379  asm("nop; nop; nop; nop; nop; nop; nop; nop;");
380  }
381  static void BitT1hWait()
382  {
383  asm("nop; nop; nop; nop; nop; nop; nop; nop;"
384  "nop; nop; nop; nop; nop; nop; nop; nop;"
385  "nop; nop; nop; nop;");
386  }
387  static void BitT0lWait()
388  {
389  asm("nop; nop; nop; nop; nop; nop; nop; nop;"
390  "nop; nop; nop; nop; nop; nop; nop; nop;"
391  "nop; nop; nop; nop;");
392  }
393  static void BitPostWait()
394  {
395  asm("nop; nop; nop; nop; nop; nop; nop; nop; nop;");
396  }
397 };
398 
399 class NeoArmSamd21g18aSpeedPropsWs2812x : public NeoArmSamd21g18aSpeedProps800KbpsBase
400 {
401 public:
402  static const uint32_t ResetTimeUs = 300;
403 };
404 
405 class NeoArmSamd21g18aSpeedPropsSk6812 : public NeoArmSamd21g18aSpeedProps800KbpsBase
406 {
407 public:
408  static const uint32_t ResetTimeUs = 80;
409 };
410 
411 class NeoArmSamd21g18aSpeedPropsTm1814 : public NeoArmSamd21g18aSpeedProps800KbpsBase
412 {
413 public:
414  static const uint32_t ResetTimeUs = 200;
415 };
416 
417 class NeoArmSamd21g18aSpeedPropsTm1829 : public NeoArmSamd21g18aSpeedProps800KbpsBase
418 {
419 public:
420  static const uint32_t ResetTimeUs = 200;
421 };
422 
423 class NeoArmSamd21g18aSpeedProps800Kbps : public NeoArmSamd21g18aSpeedProps800KbpsBase
424 {
425 public:
426  static const uint32_t ResetTimeUs = 50;
427 };
428 
429 
430 class NeoArmSamd21g18aSpeedProps400Kbps
431 {
432 public:
433  static void BitPreWait()
434  {
435  asm("nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop;");
436  }
437  static void BitT1hWait()
438  {
439  asm("nop; nop; nop; nop; nop; nop; nop; nop;"
440  "nop; nop; nop; nop; nop; nop; nop; nop;"
441  "nop; nop; nop; nop; nop; nop; nop; nop;"
442  "nop; nop; nop;");
443  }
444  static void BitT0lWait()
445  {
446  asm("nop; nop; nop; nop; nop; nop; nop; nop;"
447  "nop; nop; nop; nop; nop; nop; nop; nop;"
448  "nop; nop; nop; nop; nop; nop; nop; nop;"
449  "nop; nop; nop;");
450  }
451  static void BitPostWait()
452  {
453  asm("nop; nop; nop; nop; nop; nop; nop;");
454  }
455  static const uint32_t ResetTimeUs = 50;
456 };
457 
458 template<typename T_SPEEDPROPS> class NeoArmSamd21g18aSpeedBase
459 {
460 public:
461  static const uint32_t ResetTimeUs = T_SPEEDPROPS::ResetTimeUs;
462 
463  static void send_pixels(uint8_t* pixels, size_t sizePixels, uint8_t pin)
464  {
465  // Tried this with a timer/counter, couldn't quite get adequate
466  // resolution. So yay, you get a load of goofball NOPs...
467  uint8_t* ptr = pixels;
468  uint8_t* end = ptr + sizePixels;;
469  uint8_t p = *ptr++;
470  uint8_t bitMask = 0x80;
471  uint8_t portNum = g_APinDescription[pin].ulPort;
472  uint32_t pinMask = 1ul << g_APinDescription[pin].ulPin;
473 
474  volatile uint32_t* set = &(PORT->Group[portNum].OUTSET.reg);
475  volatile uint32_t* clr = &(PORT->Group[portNum].OUTCLR.reg);
476 
477  for (;;)
478  {
479  *set = pinMask;
480  T_SPEEDPROPS::BitPreWait();
481 
482  if (p & bitMask)
483  {
484  T_SPEEDPROPS::BitT1hWait();
485  *clr = pinMask;
486  }
487  else
488  {
489  *clr = pinMask;
490  T_SPEEDPROPS::BitT0lWait();
491  }
492  if (bitMask >>= 1)
493  {
494  T_SPEEDPROPS::BitPostWait();
495  }
496  else
497  {
498  if (ptr >= end)
499  {
500  break;
501  }
502  p = *ptr++;
503  bitMask = 0x80;
504  }
505  }
506  }
507 };
508 
509 typedef NeoArmMethodBase<NeoArmSamd21g18aSpeedBase<NeoArmSamd21g18aSpeedPropsWs2812x>> NeoArmWs2812xMethod;
510 typedef NeoArmMethodBase<NeoArmSamd21g18aSpeedBase<NeoArmSamd21g18aSpeedPropsSk6812>> NeoArmSk6812Method;
511 typedef NeoArmMethodBase<NeoArmSamd21g18aSpeedBase<NeoArmSamd21g18aSpeedPropsTm1814>> NeoArmTm1814InvertedMethod;
512 typedef NeoArmMethodBase<NeoArmSamd21g18aSpeedBase<NeoArmSamd21g18aSpeedPropsTm1829>> NeoArmTm1829InvertedMethod;
513 typedef NeoArmMethodBase<NeoArmSamd21g18aSpeedBase<NeoArmSamd21g18aSpeedProps800Kbps>> NeoArm800KbpsMethod;
514 typedef NeoArmMethodBase<NeoArmSamd21g18aSpeedBase<NeoArmSamd21g18aSpeedProps400Kbps>> NeoArm400KbpsMethod;
515 typedef NeoArm400KbpsMethod NeoArmApa106Method;
516 typedef NeoArmTm1814InvertedMethod NeoArmTm1914InvertedMethod;
517 
518 #elif defined(ARDUINO_STM32_FEATHER) || defined(ARDUINO_ARCH_STM32L4) || defined(ARDUINO_ARCH_STM32F4) || defined(ARDUINO_ARCH_STM32F1)// FEATHER WICED (120MHz)
519 
520 class NeoArmStm32SpeedProps800KbpsBase
521 {
522 public:
523  static void BitT1hWait()
524  {
525  asm("nop; nop; nop; nop; nop; nop; nop; nop;"
526  "nop; nop; nop; nop; nop; nop; nop; nop;"
527  "nop; nop; nop; nop; nop; nop; nop; nop;"
528  "nop; nop; nop; nop; nop; nop; nop; nop;"
529  "nop; nop; nop; nop; nop; nop; nop; nop;"
530  "nop; nop; nop; nop; nop; nop; nop; nop;"
531  "nop; nop; nop; nop; nop; nop; nop; nop;"
532  "nop; nop; nop; nop; nop; nop; nop; nop;"
533  "nop; nop; nop; nop; nop; nop; nop; nop;"
534  "nop; nop; nop; nop; nop; nop; nop; nop;"
535  "nop; nop; nop; nop; nop; nop; nop; nop;"
536  "nop; nop; nop; nop; nop; nop;");
537  }
538  static void BitT1lWait()
539  {
540  asm("nop; nop; nop; nop; nop; nop; nop; nop;"
541  "nop; nop; nop; nop; nop; nop; nop; nop;"
542  "nop; nop; nop; nop; nop; nop; nop; nop;"
543  "nop; nop; nop; nop; nop; nop; nop; nop;"
544  "nop; nop; nop; nop; nop; nop;");
545  }
546  static void BitT0hWait()
547  {
548  asm("nop; nop; nop; nop; nop; nop; nop; nop;"
549  "nop; nop; nop; nop; nop; nop; nop; nop;"
550  "nop; nop; nop; nop; nop; nop; nop; nop;"
551  "nop; nop; nop; nop; nop; nop; nop; nop;"
552  "nop; nop; nop; nop; nop; nop; nop; nop;"
553  "nop;");
554  }
555  static void BitT0lWait()
556  {
557  asm("nop; nop; nop; nop; nop; nop; nop; nop;"
558  "nop; nop; nop; nop; nop; nop; nop; nop;"
559  "nop; nop; nop; nop; nop; nop; nop; nop;"
560  "nop; nop; nop; nop; nop; nop; nop; nop;"
561  "nop; nop; nop; nop; nop; nop; nop; nop;"
562  "nop; nop; nop; nop; nop; nop; nop; nop;"
563  "nop; nop; nop; nop; nop; nop; nop; nop;"
564  "nop; nop; nop; nop; nop; nop; nop; nop;"
565  "nop; nop; nop; nop; nop; nop; nop; nop;"
566  "nop; nop; nop; nop; nop; nop; nop; nop;"
567  "nop; nop; nop; nop; nop; nop; nop; nop;"
568  "nop; nop; nop; nop;");
569  }
570 };
571 
572 class NeoArmStm32SpeedPropsWs2812x : public NeoArmStm32SpeedProps800KbpsBase
573 {
574 public:
575  static const uint32_t ResetTimeUs = 300;
576 };
577 
578 class NeoArmStm32SpeedPropsSk6812 : public NeoArmStm32SpeedProps800KbpsBase
579 {
580 public:
581  static const uint32_t ResetTimeUs = 80;
582 };
583 
584 class NeoArmStm32SpeedPropsTm1814 : public NeoArmStm32SpeedProps800KbpsBase
585 {
586 public:
587  static const uint32_t ResetTimeUs = 200;
588 };
589 
590 class NeoArmStm32SpeedPropsTm1829 : public NeoArmStm32SpeedProps800KbpsBase
591 {
592 public:
593  static const uint32_t ResetTimeUs = 200;
594 };
595 
596 class NeoArmStm32SpeedProps800Kbps : public NeoArmStm32SpeedProps800KbpsBase
597 {
598 public:
599  static const uint32_t ResetTimeUs = 50;
600 };
601 
602 /* TODO - not found in Adafruit library
603 class NeoArmStm32SpeedProps400Kbps
604 {
605 static void BitT1hWait()
606 {
607 }
608 static void BitT1lWait()
609 {
610 }
611 static void BitT0hWait()
612 {
613 }
614 static void BitT0lWait()
615 {
616 }
617 };
618 */
619 
620 template<typename T_SPEEDPROPS> class NeoArmStm32SpeedBase
621 {
622 public:
623  static const uint32_t ResetTimeUs = T_SPEEDPROPS::ResetTimeUs;
624 
625  static void send_pixels(uint8_t* pixels, size_t sizePixels, uint8_t pin)
626  {
627  // Tried this with a timer/counter, couldn't quite get adequate
628  // resolution. So yay, you get a load of goofball NOPs...
629 
630  uint8_t* ptr = pixels;
631  uint8_t* end = ptr + sizePixels;
632  uint8_t p = *ptr++;
633  uint8_t bitMask = 0x80;
634 
635 #if defined(ARDUINO_STM32_FEATHER)
636  uint32_t pinMask = BIT(PIN_MAP[pin].gpio_bit);
637 
638  volatile uint16_t* set = &(PIN_MAP[pin].gpio_device->regs->BSRRL);
639  volatile uint16_t* clr = &(PIN_MAP[pin].gpio_device->regs->BSRRH);
640 
641 #elif defined(ARDUINO_ARCH_STM32F4)
642  uint32_t pinMask = BIT(pin & 0x0f);
643 
644  volatile uint16_t* set = &(PIN_MAP[pin].gpio_device->regs->BSRRL);
645  volatile uint16_t* clr = &(PIN_MAP[pin].gpio_device->regs->BSRRH);
646 
647 #elif defined(ARDUINO_ARCH_STM32F1)
648 
649  uint32_t pinMask = BIT(PIN_MAP[pin].gpio_bit);
650 
651  volatile uint32_t* set = &(PIN_MAP[pin].gpio_device->regs->BRR);
652  volatile uint32_t* clr = &(PIN_MAP[pin].gpio_device->regs->BSRR);
653 
654 #elif defined(ARDUINO_ARCH_STM32L4)
655 
656  uint32_t pinMask = g_APinDescription[pin].bit;
657 
658  GPIO_TypeDef* GPIO = static_cast<GPIO_TypeDef*>(g_APinDescription[pin].GPIO);
659 
660  volatile uint32_t* set = &(GPIO->BRR);
661  volatile uint32_t* clr = &(GPIO->BSRR);
662 
663 #endif
664  for (;;)
665  {
666  if (p & bitMask)
667  {
668  // ONE
669  // High 800ns
670  *set = pinMask;
671  T_SPEEDPROPS::BitT1hWait();
672  // Low 450ns
673  *clr = pinMask;
674  T_SPEEDPROPS::BitT1lWait();
675  }
676  else
677  {
678  // ZERO
679  // High 400ns
680  *set = pinMask;
681  T_SPEEDPROPS::BitT0hWait();
682  // Low 850ns
683  *clr = pinMask;
684  T_SPEEDPROPS::BitT0lWait();
685  }
686  if (bitMask >>= 1)
687  {
688  // Move on to the next pixel
689  asm("nop;");
690  }
691  else
692  {
693  if (ptr >= end)
694  {
695  break;
696  }
697 
698  p = *ptr++;
699  bitMask = 0x80;
700  }
701  }
702  }
703 };
704 
705 typedef NeoArmMethodBase<NeoArmStm32SpeedBase<NeoArmStm32SpeedPropsWs2812x>> NeoArmWs2812xMethod;
706 typedef NeoArmMethodBase<NeoArmStm32SpeedBase<NeoArmStm32SpeedPropsSk6812>> NeoArmSk6812Method;
707 typedef NeoArmMethodBase<NeoArmStm32SpeedBase<NeoArmStm32SpeedPropsTm1814>> NeoArmTm1814InvertedMethod;
708 typedef NeoArmMethodBase<NeoArmStm32SpeedBase<NeoArmStm32SpeedPropsTm1829>> NeoArmTm1829InvertedMethod;
709 typedef NeoArmMethodBase<NeoArmStm32SpeedBase<NeoArmStm32SpeedProps800Kbps>> NeoArm800KbpsMethod;
710 typedef NeoArm800KbpsMethod NeoArmApa106Method;
711 typedef NeoArmTm1814InvertedMethod NeoArmTm1914InvertedMethod;
712 
713 #else // Other ARM architecture -- Presumed Arduino Due
714 
715 
716 #define ARM_OTHER_SCALE VARIANT_MCK / 2UL / 1000000UL
717 #define ARM_OTHER_INST (2UL * F_CPU / VARIANT_MCK)
718 
719 class NeoArmOtherSpeedProps800KbpsBase
720 {
721 public:
722  static const uint32_t CyclesT0h = static_cast<uint32_t>((0.40 * ARM_OTHER_SCALE + 0.5) - (5 * ARM_OTHER_INST));
723  static const uint32_t CyclesT1h = static_cast<uint32_t>((0.80 * ARM_OTHER_SCALE + 0.5) - (5 * ARM_OTHER_INST));
724  static const uint32_t Cycles = static_cast<uint32_t>((1.25 * ARM_OTHER_SCALE + 0.5) - (5 * ARM_OTHER_INST));
725 };
726 
727 class NeoArmOtherSpeedPropsWs2812x : public NeoArmOtherSpeedProps800KbpsBase
728 {
729 public:
730  static const uint32_t ResetTimeUs = 300;
731 };
732 
733 class NeoArmOtherSpeedPropsSk6812 : public NeoArmOtherSpeedProps800KbpsBase
734 {
735 public:
736  static const uint32_t ResetTimeUs = 80;
737 };
738 
739 class NeoArmOtherSpeedPropsTm1814 : public NeoArmOtherSpeedProps800KbpsBase
740 {
741 public:
742  static const uint32_t ResetTimeUs = 200;
743 };
744 
745 class NeoArmOtherSpeedPropsTm1829 : public NeoArmOtherSpeedProps800KbpsBase
746 {
747 public:
748  static const uint32_t ResetTimeUs = 200;
749 };
750 
751 class NeoArmOtherSpeedProps800Kbps : public NeoArmOtherSpeedProps800KbpsBase
752 {
753 public:
754  static const uint32_t ResetTimeUs = 50;
755 };
756 
757 class NeoArmOtherSpeedProps400Kbps
758 {
759 public:
760  static const uint32_t CyclesT0h = static_cast<uint32_t>((0.50 * ARM_OTHER_SCALE + 0.5) - (5 * ARM_OTHER_INST));
761  static const uint32_t CyclesT1h = static_cast<uint32_t>((1.20 * ARM_OTHER_SCALE + 0.5) - (5 * ARM_OTHER_INST));
762  static const uint32_t Cycles = static_cast<uint32_t>((2.50 * ARM_OTHER_SCALE + 0.5) - (5 * ARM_OTHER_INST));
763  static const uint32_t ResetTimeUs = 50;
764 };
765 
766 template<typename T_SPEEDPROPS> class NeoArmOtherSpeedBase
767 {
768 public:
769  static const uint32_t ResetTimeUs = T_SPEEDPROPS::ResetTimeUs;
770 
771  static void send_pixels(uint8_t* pixels, size_t sizePixels, uint8_t pin)
772  {
773  uint32_t pinMask;
774  uint32_t t;
775  Pio* port;
776  volatile WoReg* portSet;
777  volatile WoReg* portClear;
778  volatile WoReg* timeValue;
779  volatile WoReg* timeReset;
780  uint8_t* p;
781  uint8_t* end;
782  uint8_t pix;
783  uint8_t mask;
784 
785  pmc_set_writeprotect(false);
786  pmc_enable_periph_clk(static_cast<uint32_t>(TC3_IRQn));
787 
788  TC_Configure(TC1, 0,
789  TC_CMR_WAVE | TC_CMR_WAVSEL_UP | TC_CMR_TCCLKS_TIMER_CLOCK1);
790  TC_Start(TC1, 0);
791 
792  pinMask = g_APinDescription[pin].ulPin; // Don't 'optimize' these into
793  port = g_APinDescription[pin].pPort; // declarations above. Want to
794  portSet = &(port->PIO_SODR); // burn a few cycles after
795  portClear = &(port->PIO_CODR); // starting timer to minimize
796  timeValue = &(TC1->TC_CHANNEL[0].TC_CV); // the initial 'while'.
797  timeReset = &(TC1->TC_CHANNEL[0].TC_CCR);
798  p = pixels;
799  end = p + sizePixels;
800  pix = *p++;
801  mask = 0x80;
802 
803  for (;;)
804  {
805  if (pix & mask)
806  {
807  t = T_SPEEDPROPS::CyclesT1h;
808  }
809  else
810  {
811  t = T_SPEEDPROPS::CyclesT0h;
812  }
813 
814  // wait for the end of the previous cycle
815  while (*timeValue < T_SPEEDPROPS::Cycles);
816 
817  *portSet = pinMask;
818  *timeReset = TC_CCR_CLKEN | TC_CCR_SWTRG;
819 
820  while (*timeValue < t);
821 
822  *portClear = pinMask;
823  if (!(mask >>= 1))
824  {
825  // This 'inside-out' loop logic utilizes
826  if (p >= end)
827  {
828  break; // idle time to minimize inter-byte delays.
829  }
830  pix = *p++;
831  mask = 0x80;
832  }
833  }
834 
835  // not really needed as the wait for latch does this and
836  // while (*timeValue < T_SPEEDPROPS::Cycles); // Wait for last bit
837 
838  TC_Stop(TC1, 0);
839  }
840 };
841 
842 typedef NeoArmMethodBase<NeoArmOtherSpeedBase<NeoArmOtherSpeedPropsWs2812x>> NeoArmWs2812xMethod;
843 typedef NeoArmMethodBase<NeoArmOtherSpeedBase<NeoArmOtherSpeedPropsSk6812>> NeoArmSk6812Method;
844 typedef NeoArmMethodBase<NeoArmOtherSpeedBase<NeoArmOtherSpeedPropsTm1814>> NeoArmTm1814InvertedMethod;
845 typedef NeoArmMethodBase<NeoArmOtherSpeedBase<NeoArmOtherSpeedPropsTm1829>> NeoArmTm1829InvertedMethod;
846 typedef NeoArmMethodBase<NeoArmOtherSpeedBase<NeoArmOtherSpeedProps800Kbps>> NeoArm800KbpsMethod;
847 typedef NeoArmMethodBase<NeoArmOtherSpeedBase<NeoArmOtherSpeedProps400Kbps>> NeoArm400KbpsMethod;
848 typedef NeoArm400KbpsMethod NeoArmApa106Method;
849 typedef NeoArmTm1814InvertedMethod NeoArmTm1914InvertedMethod;
850 
851 #endif
852 
853 
854 // Arm doesn't have alternatives methods yet, so only one to make the default
855 typedef NeoArmWs2812xMethod NeoWs2813Method;
856 typedef NeoArmWs2812xMethod NeoWs2812xMethod;
857 typedef NeoArmWs2812xMethod NeoWs2811Method;
858 typedef NeoArmWs2812xMethod NeoWs2816Method;
859 typedef NeoArmSk6812Method NeoSk6812Method;
860 typedef NeoArmSk6812Method NeoLc8812Method;
861 typedef NeoArm800KbpsMethod NeoWs2812Method;
862 typedef NeoArmApa106Method NeoApa106Method;
863 typedef NeoArmWs2812xMethod Neo800KbpsMethod;
864 #ifdef NeoArm400KbpsMethod // this is needed due to missing 400Kbps for some platforms
865 typedef NeoArm400KbpsMethod Neo400KbpsMethod;
866 #endif
867 // there is no non-invert methods for arm, but the norm for TM1814 is inverted, so
868 typedef NeoArmTm1814InvertedMethod NeoTm1814InvertedMethod;
869 typedef NeoArmTm1914InvertedMethod NeoTm1914InvertedMethod;
870 typedef NeoArmTm1829InvertedMethod NeoTm1829InvertedMethod;
871 
872 #endif // defined(__arm__)
873 
Definition: NeoSettings.h:29