ClearCore Library
Loading...
Searching...
No Matches
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
38namespace ClearCore {
39
40#ifndef HIDE_FROM_DOXYGEN
48class 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
64public:
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
195private:
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