ClearCore Library
ShiftRegister.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2020 Teknic, Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20  * SOFTWARE.
21  */
22 
31 #ifndef __SHIFTREGISTER_H__
32 #define __SHIFTREGISTER_H__
33 
34 #include <stdint.h>
35 #include "atomic_utils.h"
36 #include "BlinkCodeDriver.h"
37 
38 namespace ClearCore {
39 
40 #ifndef HIDE_FROM_DOXYGEN
41 
48 class ShiftRegister {
49  friend class AdcManager;
50  friend class DigitalInAnalogIn;
51  friend class DigitalInOutAnalogOut;
52  friend class DigitalIn;
53  friend class DigitalInOut;
54  friend class DigitalInOutHBridge;
55  friend class CcioBoardManager;
56  friend class LedDriver;
57  friend class MotorDriver;
58  friend class MotorManager;
59  friend class SerialDriver;
60  friend class StatusManager;
61  friend class SysManager;
62  friend class TestIO;
63 
64 public:
65 
73  union ShiftChain {
77  uint32_t reg;
78 
82  struct _bit {
83  uint32_t A_CTRL_3 : 1; // 0
84  uint32_t A_CTRL_2 : 1; // 1
85  uint32_t LED_IO_5 : 1; // 2
86  uint32_t LED_IO_4 : 1; // 3
87  uint32_t LED_IO_3 : 1; // 4
88  uint32_t LED_IO_2 : 1; // 5
89  uint32_t LED_IO_1 : 1; // 6
90  uint32_t LED_IO_0 : 1; // 7
91  uint32_t EN_OUT_3 : 1; // 8
92  uint32_t EN_OUT_2 : 1; // 9
93  uint32_t EN_OUT_1 : 1; // 10
94  uint32_t EN_OUT_0 : 1; // 11
95  uint32_t UART_TTL_1 : 1; // 12
96  uint32_t UART_TTL_0 : 1; // 13
97  uint32_t UNDERGLOW : 1; // 14
98  uint32_t LED_USB : 1; // 15
99  uint32_t UART_SPI_SEL_1 : 1; // 16
100  uint32_t UART_SPI_SEL_0 : 1; // 17
101  uint32_t LED_COM_0 : 1; // 18
102  uint32_t LED_COM_1 : 1; // 19
103  uint32_t CFG00_AOUT : 1; // 20
104  uint32_t LED_DI_6 : 1; // 21
105  uint32_t LED_DI_7 : 1; // 22
106  uint32_t LED_DI_8 : 1; // 23
107  uint32_t LED_ADI_12 : 1; // 24
108  uint32_t LED_ADI_11 : 1; // 25
109  uint32_t LED_ADI_10 : 1; // 26
110  uint32_t LED_ADI_09 : 1; // 27
111  uint32_t ANAIN_DIGITAL_12 : 1; // 28
112  uint32_t ANAIN_DIGITAL_11 : 1; // 29
113  uint32_t ANAIN_DIGITAL_10 : 1; // 30
114  uint32_t ANAIN_DIGITAL_09 : 1; // 31
115  } bit;
116 
117  // Construct
118  ShiftChain() {
119  reg = 0;
120  }
121 
122  // Construct
123  ShiftChain(uint32_t val) {
124  reg = val;
125  }
126  }; // ShiftChain
127 
133  enum Masks {
134  SR_NO_FEEDBACK_MASK = 0,
135  SR_A_CTRL_3_MASK = 1U << 0,
136  SR_A_CTRL_2_MASK = 1U << 1,
137  SR_LED_IO_5_MASK = 1U << 2,
138  SR_LED_IO_4_MASK = 1U << 3,
139  SR_LED_IO_3_MASK = 1U << 4,
140  SR_LED_IO_2_MASK = 1U << 5,
141  SR_LED_IO_1_MASK = 1U << 6,
142  SR_LED_IO_0_MASK = 1U << 7,
143  SR_EN_OUT_3_MASK = 1U << 8,
144  SR_EN_OUT_2_MASK = 1U << 9,
145  SR_EN_OUT_1_MASK = 1U << 10,
146  SR_EN_OUT_0_MASK = 1U << 11,
147  SR_UART_TTL_1_MASK = 1U << 12,
148  SR_UART_TTL_0_MASK = 1U << 13,
149  SR_UNDERGLOW_MASK = 1U << 14,
150  SR_LED_USB_MASK = 1U << 15,
151  SR_UART_SPI_SEL_1_MASK = 1U << 16,
152  SR_UART_SPI_SEL_0_MASK = 1U << 17,
153  SR_LED_COM_0_MASK = 1U << 18,
154  SR_LED_COM_1_MASK = 1U << 19,
155  SR_CFG00_AOUT_MASK = 1U << 20,
156  SR_LED_DI_6_MASK = 1U << 21,
157  SR_LED_DI_7_MASK = 1U << 22,
158  SR_LED_DI_8_MASK = 1U << 23,
159  SR_LED_ADI_12_MASK = 1U << 24,
160  SR_LED_ADI_11_MASK = 1U << 25,
161  SR_LED_ADI_10_MASK = 1U << 26,
162  SR_LED_ADI_09_MASK = 1U << 27,
163  SR_ANAIN_DIGITAL_12_MASK = 1U << 28,
164  SR_ANAIN_DIGITAL_11_MASK = 1U << 29,
165  SR_ANAIN_DIGITAL_10_MASK = 1U << 30,
166  SR_ANAIN_DIGITAL_09_MASK = 1U << 31
167  };
168 
175  enum LED_BLINK_CODE {
176  // LED Patterns
177  LED_BLINK_IO_SET = 0, // lowest priority
178  LED_BLINK_FADE,
179  LED_BLINK_BREATHING,
180  LED_BLINK_FAST_STROBE, // highest priority
181  // Max value for bounds checking
182  LED_BLINK_CODE_MAX,
183  LED_BLINK_PWM = LED_BLINK_FADE,
184  // Mapped Error Codes to Patterns
185  LED_BLINK_OVERLOAD = LED_BLINK_FAST_STROBE,
186  LED_BLINK_CCIO_COMM_ERR = LED_BLINK_FADE,
187  LED_BLINK_CCIO_ONLINE = LED_BLINK_BREATHING
188  };
189 
193  ShiftRegister();
194 
195 private:
199  void Initialize();
200 
204  volatile const uint32_t &OverloadActive() {
205  return m_patternMasks[LED_BLINK_OVERLOAD];
206  }
207 
211  volatile const bool &Ready() {
212  return m_initialized;
213  }
214 
220  ShiftChain ShifterState() {
221  return atomic_load_n(&m_patternOutputs[LED_BLINK_IO_SET]);
222  }
223 
229  bool ShifterState(Masks bitToGet) {
230  return atomic_load_n(&m_patternOutputs[LED_BLINK_IO_SET]) & bitToGet;
231  }
232 
238  volatile const uint32_t &LastOutput() {
239  return m_lastOutput;
240  }
241 
249  void ShifterState(bool setFlds, const ShiftChain &fldsToChange) {
250  setFlds ? ShifterStateSet(fldsToChange)
251  : ShifterStateClear(fldsToChange);
252  }
253 
261  void ShifterState(bool setFlds, Masks bitsToChange) {
262  setFlds ? ShifterStateSet(bitsToChange)
263  : ShifterStateClear(bitsToChange);
264  }
265 
272  void ShifterStateToggle(ShiftChain fldsToToggle) {
273  atomic_xor_fetch(&m_patternOutputs[LED_BLINK_IO_SET], fldsToToggle.reg);
274  }
275 
281  void ShifterStateReplace(uint32_t value) {
282  atomic_exchange_n(&m_patternOutputs[LED_BLINK_IO_SET], value);
283  }
292  void LedInFault(uint32_t ledMask, bool state) {
293  if (state) {
294  m_patternMasks[LED_BLINK_OVERLOAD] |= ledMask;
295  }
296  else {
297  m_patternMasks[LED_BLINK_OVERLOAD] &= ~ledMask;
298  }
299  }
300 
310  void LedInPwm(Masks ledMask, bool state, uint8_t index) {
311  index &= 0xf; // guard against index out of bounds
312  m_fadeCounter.m_analogMasks[index] = ledMask;
313  state ? m_fadeCounter.m_activeMask |= 1 << index
314  : m_fadeCounter.m_activeMask &= ~(1 << index);
315  LedPattern(ledMask, LED_BLINK_FADE, state);
316  }
317 
324  void LedPwmValue(uint8_t index, uint32_t value) {
325  index &= 0xf; // guard against index out of bounds
326  m_fadeCounter.m_valuesBuf[index] = value;
327  }
328 
329 
337  void LedPattern(uint32_t ledMask, LED_BLINK_CODE pattern,
338  bool state) {
339  state ? m_patternMasks[pattern] |= ledMask
340  : m_patternMasks[pattern] &= ~ledMask;
341  }
342 
352  struct TickCounter {
353  uint32_t period;
354  uint32_t cc;
355 
356  private:
357  uint32_t count;
358 
359  public:
360  TickCounter()
361  : period(5000),
362  cc(2500),
363  count(0) {}
364 
365  TickCounter(uint32_t period, uint32_t cc)
366  : period(period),
367  cc(cc),
368  count(0) {}
369 
370  const uint32_t returnTable[2] = {0x00000000, 0xffffffff};
371 
372  uint32_t Update() {
373  if (!count--) {
374  count = period;
375  }
376  return returnTable[count < cc];
377  }
378  };
379 
386  class AnalogLedDriver {
387  public:
388  uint16_t m_activeMask;
389  uint32_t m_lastOutput;
390  uint8_t m_count;
391  uint8_t m_values[16];
392  uint8_t m_valuesBuf[16];
393  Masks m_analogMasks[16];
394 
395  AnalogLedDriver()
396  : m_activeMask(0),
397  m_lastOutput(0),
398  m_count(UINT8_MAX - 1),
399  m_values{0},
400  m_valuesBuf{0},
401  m_analogMasks{SR_NO_FEEDBACK_MASK} {}
402 
403  uint32_t Update() {
404  uint32_t retVal = m_lastOutput;
405  if (!m_activeMask) {
406  m_count = UINT8_MAX - 1;
407  return 0;
408  }
409 
410  if (++m_count > UINT8_MAX >> 2) {
411  retVal = 0;
412  m_count = 0;
413  for (uint8_t i = 0; i < 16; i++) {
414  if (m_activeMask & (1 << i) && m_valuesBuf[i]) {
415  m_values[i] = m_valuesBuf[i];
416  retVal |= m_analogMasks[i];
417  }
418  }
419  }
420  else {
421  uint8_t compare = m_count << 2;
422  for (uint8_t i = 0; i < 16; i++) {
423  if ((retVal & m_analogMasks[i]) &&
424  (m_values[i] < compare)) {
425  retVal &= ~m_analogMasks[i];
426  }
427  }
428  }
429  return m_lastOutput = retVal;
430  }
431  };
432 
440  struct FadeInOutCounter {
441  uint8_t m_maxValue;
442  uint8_t m_minValue;
443 
444  private:
445  uint8_t m_count;
446  uint8_t m_compare;
447  bool fadingIn;
448  const uint32_t returnTable[2] = {0x00000000, 0xffffffff};
449 
450  public:
451  FadeInOutCounter(uint8_t maxValue = UINT8_MAX >> 1,
452  uint8_t minValue = 0x08)
453  : m_maxValue(maxValue),
454  m_minValue(minValue),
455  m_count(0),
456  m_compare(0),
457  fadingIn(true) {}
458 
459  uint32_t Update() {
460  if (++m_count >= UINT8_MAX >> 2) {
461  m_count = 0;
462  if (fadingIn) {
463  if (++m_compare >= m_maxValue) {
464  fadingIn = false;
465  }
466  }
467  else {
468  if (--m_compare <= m_minValue) {
469  fadingIn = true;
470  }
471  }
472  }
473  return returnTable[m_count << 2 < m_compare];
474  }
475  };
476 
477  // the "close" LEDs
478  static const uint8_t LED_BANK_0_LEN = 6;
479  const Masks LED_BANK_0[LED_BANK_0_LEN] = {SR_LED_IO_0_MASK,
480  SR_LED_IO_1_MASK, SR_LED_IO_2_MASK, SR_LED_IO_3_MASK, SR_LED_IO_4_MASK,
481  SR_LED_IO_5_MASK
482  };
483 
484  // the "far" LEDs
485  static const uint8_t LED_BANK_1_LEN = 7;
486  const Masks LED_BANK_1[LED_BANK_1_LEN] = {SR_LED_ADI_12_MASK,
487  SR_LED_ADI_11_MASK, SR_LED_ADI_10_MASK, SR_LED_ADI_09_MASK,
488  SR_LED_DI_8_MASK, SR_LED_DI_7_MASK, SR_LED_DI_6_MASK
489  };
490 
491  // the "misc" LEDs
492  static const uint8_t LED_BANK_2_LEN = 4;
493  const Masks LED_BANK_2[LED_BANK_2_LEN] = {SR_UNDERGLOW_MASK,
494  SR_LED_USB_MASK, SR_LED_COM_0_MASK, SR_LED_COM_1_MASK
495  };
496 
497  static const uint16_t DELAY_TIME = 25; // milliseconds
498 
499  // A mask that prevents sketches from changing Shift Register values that
500  // aren't LEDs.
501  const uint32_t SAFE_LED_MASK = SR_LED_IO_0_MASK | SR_LED_IO_1_MASK |
502  SR_LED_IO_2_MASK | SR_LED_IO_3_MASK | SR_LED_IO_4_MASK |
503  SR_LED_IO_5_MASK | SR_LED_DI_6_MASK | SR_LED_DI_7_MASK |
504  SR_LED_DI_8_MASK | SR_LED_ADI_09_MASK | SR_LED_ADI_10_MASK |
505  SR_LED_ADI_11_MASK | SR_LED_ADI_12_MASK | SR_LED_USB_MASK;
506 
512  const uint32_t FAST_COUNTER_PERIOD = 500;
513  const uint32_t FAST_COUNTER_CC = 200;
514  TickCounter m_fastCounter;
515  FadeInOutCounter m_breathingCounter;
516  AnalogLedDriver m_fadeCounter;
519  // Inversion mask of actual shift register state
520  ShiftChain m_shiftInversions;
521 
522  uint32_t m_patternMasks[LED_BLINK_CODE_MAX];
523  uint32_t m_patternOutputs[LED_BLINK_CODE_MAX];
524  uint32_t m_altOutput;
525 
526  // Set after initialization
527  bool m_initialized;
528  bool m_blinkCodeActive;
529  bool m_blinkCodeState;
530  bool m_useAltOutput;
531 
532  // The values about to be written to the SPI data register.
533  uint32_t m_pendingOutput;
534  // The last values written to the SPI data register.
535  uint32_t m_lastOutput;
536  // The last values read from the SPI data register.
537  uint32_t m_latchedOutput;
538 
542  void Send();
543 
547  void Update();
548 
554  void ShifterStateSet(ShiftChain fldsToSet) {
555  atomic_or_fetch(&m_patternOutputs[LED_BLINK_IO_SET], fldsToSet.reg);
556  }
557 
563  void ShifterStateSet(Masks bitsToSet) {
564  atomic_or_fetch(&m_patternOutputs[LED_BLINK_IO_SET], bitsToSet);
565  }
566 
573  void ShifterStateClear(ShiftChain fldsToClr) {
574  atomic_and_fetch(&m_patternOutputs[LED_BLINK_IO_SET], ~fldsToClr.reg);
575  }
576 
582  void ShifterStateClear(Masks bitsToClr) {
583  atomic_and_fetch(&m_patternOutputs[LED_BLINK_IO_SET], ~bitsToClr);
584  }
585 
594  void DiagnosticLedSweep();
595 
596  void BlinkCode(bool blinkCodeActive, bool blinkCodeState) {
597  m_blinkCodeActive = blinkCodeActive;
598  m_blinkCodeState = blinkCodeState;
599  }
600 
601 }; // ShiftRegister
602 #endif
603 
604 } // ClearCore namespace
605 
606 #endif // __SHIFTREGISTER_H__
Namespace to encompass the ClearCore board API.
Definition: AdcManager.h:36