AceSegment  0.8.0
A framework for rendering seven segment LED displays using the TM1637, MAX7219, HT16K33, or 74HC595 controller chips
LedMatrixDirectFast4.h
1 /*
2 MIT License
3 
4 Copyright (c) 2021 Brian T. Park
5 
6 Permission is hereby granted, free of charge, to any person obtaining a copy
7 of this software and associated documentation files (the "Software"), to deal
8 in the Software without restriction, including without limitation the rights
9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 copies of the Software, and to permit persons to whom the Software is
11 furnished to do so, subject to the following conditions:
12 
13 The above copyright notice and this permission notice shall be included in all
14 copies or substantial portions of the Software.
15 
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 SOFTWARE.
23 */
24 
25 #ifndef ACE_SEGMENT_LED_MATRIX_DIRECT_FAST_H
26 #define ACE_SEGMENT_LED_MATRIX_DIRECT_FAST_H
27 
28 // This header file requires the digitalWriteFast library on AVR, or the
29 // EpoxyMockDigitalWriteFast library on EpoxyDuino.
30 #if defined(ARDUINO_ARCH_AVR) || defined(EPOXY_DUINO)
31 
32 #include <stdint.h>
33 #include <Arduino.h> // OUTPUT, INPUT
34 #include "LedMatrixBase.h"
35 
36 // Select OPTION_ARRAY to use an array of function pointers. Using an array
37 // of function takes 27 microseconds for displayCurentField(), but 8 extra bytes
38 // of flash, and 48 extra bytes of static RAM, compared to the SWITCH option.
39 //
40 // Select OPTION_SWITCH to use a switch statement. This is 30% slower for
41 // displayCurentField(), 35 microseconds, but has smaller memory footprint).
42 #define ACE_SEGMENT_LMDF_OPTION_ARRAY 0
43 #define ACE_SEGMENT_LMDF_OPTION_SWITCH 1
44 #if ! defined(ACE_SEGMENT_LMDF_OPTION)
45 #define ACE_SEGMENT_LMDF_OPTION ACE_SEGMENT_LMDF_OPTION_ARRAY
46 #endif
47 
48 namespace ace_segment {
49 
50 #if ACE_SEGMENT_LMDF_OPTION == ACE_SEGMENT_LMDF_OPTION_ARRAY
51 typedef void (*DigitalWriter)(void);
52 #endif
53 
68 template <
69  uint8_t e0, uint8_t e1, uint8_t e2, uint8_t e3,
70  uint8_t e4, uint8_t e5, uint8_t e6, uint8_t e7,
71  uint8_t g0, uint8_t g1, uint8_t g2, uint8_t g3
72 >
73 class LedMatrixDirectFast4 : public LedMatrixBase {
74  public:
75  static const uint8_t kNumElements = 8;
76  static const uint8_t kNumGroups = 4;
77 
78  LedMatrixDirectFast4(
79  uint8_t elementOnPattern,
80  uint8_t groupOnPattern
81  ) :
82  LedMatrixBase(elementOnPattern, groupOnPattern)
83  {}
84 
85  void begin() const {
86  // Set LEDs to off.
87  clear();
88 
89  // Set pins to OUTPUT mode.
90  pinModeFast(e0, OUTPUT);
91  pinModeFast(e1, OUTPUT);
92  pinModeFast(e2, OUTPUT);
93  pinModeFast(e3, OUTPUT);
94  pinModeFast(e4, OUTPUT);
95  pinModeFast(e5, OUTPUT);
96  pinModeFast(e6, OUTPUT);
97  pinModeFast(e7, OUTPUT);
98 
99  // Set pins to OUTPUT mode.
100  pinModeFast(g0, OUTPUT);
101  pinModeFast(g1, OUTPUT);
102  pinModeFast(g2, OUTPUT);
103  pinModeFast(g3, OUTPUT);
104  }
105 
106  void end() const {
107  // Set pins to INPUT mode.
108  pinModeFast(g0, INPUT);
109  pinModeFast(g1, INPUT);
110  pinModeFast(g2, INPUT);
111  pinModeFast(g3, INPUT);
112 
113  // Set pins to INPUT mode.
114  pinModeFast(e0, INPUT);
115  pinModeFast(e1, INPUT);
116  pinModeFast(e2, INPUT);
117  pinModeFast(e3, INPUT);
118  pinModeFast(e4, INPUT);
119  pinModeFast(e5, INPUT);
120  pinModeFast(e6, INPUT);
121  pinModeFast(e7, INPUT);
122  }
123 
124  void draw(uint8_t group, uint8_t elementPattern) const {
125  if (group != mPrevGroup) {
126  disableGroup(mPrevGroup);
127  }
128 
129  drawElements(elementPattern);
130  enableGroup(group);
131  mPrevGroup = group;
132  }
133 
134  void enableGroup(uint8_t group) const {
135  writeGroupPin(group, 0x1);
136  mPrevGroup = group;
137  }
138 
139  void disableGroup(uint8_t group) const {
140  writeGroupPin(group, 0x0);
141  mPrevGroup = group;
142  }
143 
144  void clear() const {
145  for (uint8_t group = 0; group < kNumGroups; group++) {
146  writeGroupPin(group, 0x0);
147  }
148  drawElements(0x00);
149  }
150 
151  private:
153  void drawElements(uint8_t pattern) const {
154  for (uint8_t element = 0; element < kNumElements; element++) {
155  writeElementPin(element, pattern);
156  pattern >>= 1;
157  }
158  }
159 
161  void writeElementPin(uint8_t element, uint8_t output) const {
162  uint8_t actualOutput = (output ^ mElementXorMask) & 0x1;
163  uint8_t index = element * 2 + actualOutput;
164 
165  #if ACE_SEGMENT_LMDF_OPTION == ACE_SEGMENT_LMDF_OPTION_ARRAY
166  DigitalWriter writer = kElementWriters[index];
167  writer();
168 
169  #else
170  switch (index) {
171  case 0: digitalWriteFast(e0, LOW); break;
172  case 1: digitalWriteFast(e0, HIGH); break;
173  case 2: digitalWriteFast(e1, LOW); break;
174  case 3: digitalWriteFast(e1, HIGH); break;
175  case 4: digitalWriteFast(e2, LOW); break;
176  case 5: digitalWriteFast(e2, HIGH); break;
177  case 6: digitalWriteFast(e3, LOW); break;
178  case 7: digitalWriteFast(e3, HIGH); break;
179  case 8: digitalWriteFast(e4, LOW); break;
180  case 9: digitalWriteFast(e4, HIGH); break;
181  case 10: digitalWriteFast(e5, LOW); break;
182  case 11: digitalWriteFast(e5, HIGH); break;
183  case 12: digitalWriteFast(e6, LOW); break;
184  case 13: digitalWriteFast(e6, HIGH); break;
185  case 14: digitalWriteFast(e7, LOW); break;
186  case 15: digitalWriteFast(e7, HIGH); break;
187  default: break;
188  }
189  #endif
190  }
191 
193  void writeGroupPin(uint8_t group, uint8_t output) const {
194  uint8_t actualOutput = (output ^ mGroupXorMask) & 0x1;
195  uint8_t index = group * 2 + actualOutput;
196 
197  #if ACE_SEGMENT_LMDF_OPTION == ACE_SEGMENT_LMDF_OPTION_ARRAY
198  DigitalWriter writer = kGroupWriters[index];
199  writer();
200 
201  #else
202  switch (index) {
203  case 0: digitalWriteFast(g0, LOW); break;
204  case 1: digitalWriteFast(g0, HIGH); break;
205  case 2: digitalWriteFast(g1, LOW); break;
206  case 3: digitalWriteFast(g1, HIGH); break;
207  case 4: digitalWriteFast(g2, LOW); break;
208  case 5: digitalWriteFast(g2, HIGH); break;
209  case 6: digitalWriteFast(g3, LOW); break;
210  case 7: digitalWriteFast(g3, HIGH); break;
211  default: break;
212  }
213  #endif
214  }
215 
216  #if ACE_SEGMENT_LMDF_OPTION == ACE_SEGMENT_LMDF_OPTION_ARRAY
217  // DigitalWriter functions for writing element pins.
218  static void digitalWriteFastElement0L() { digitalWriteFast(e0, LOW); }
219  static void digitalWriteFastElement0H() { digitalWriteFast(e0, HIGH); }
220  static void digitalWriteFastElement1L() { digitalWriteFast(e1, LOW); }
221  static void digitalWriteFastElement1H() { digitalWriteFast(e1, HIGH); }
222  static void digitalWriteFastElement2L() { digitalWriteFast(e2, LOW); }
223  static void digitalWriteFastElement2H() { digitalWriteFast(e2, HIGH); }
224  static void digitalWriteFastElement3L() { digitalWriteFast(e3, LOW); }
225  static void digitalWriteFastElement3H() { digitalWriteFast(e3, HIGH); }
226  static void digitalWriteFastElement4L() { digitalWriteFast(e4, LOW); }
227  static void digitalWriteFastElement4H() { digitalWriteFast(e4, HIGH); }
228  static void digitalWriteFastElement5L() { digitalWriteFast(e5, LOW); }
229  static void digitalWriteFastElement5H() { digitalWriteFast(e5, HIGH); }
230  static void digitalWriteFastElement6L() { digitalWriteFast(e6, LOW); }
231  static void digitalWriteFastElement6H() { digitalWriteFast(e6, HIGH); }
232  static void digitalWriteFastElement7L() { digitalWriteFast(e7, LOW); }
233  static void digitalWriteFastElement7H() { digitalWriteFast(e7, HIGH); }
234 
235  // DigitalWriter functions for writing group pins.
236  static void digitalWriteFastGroup0L() { digitalWriteFast(g0, LOW); }
237  static void digitalWriteFastGroup0H() { digitalWriteFast(g0, HIGH); }
238  static void digitalWriteFastGroup1L() { digitalWriteFast(g1, LOW); }
239  static void digitalWriteFastGroup1H() { digitalWriteFast(g1, HIGH); }
240  static void digitalWriteFastGroup2L() { digitalWriteFast(g2, LOW); }
241  static void digitalWriteFastGroup2H() { digitalWriteFast(g2, HIGH); }
242  static void digitalWriteFastGroup3L() { digitalWriteFast(g3, LOW); }
243  static void digitalWriteFastGroup3H() { digitalWriteFast(g3, HIGH); }
244  #endif
245 
246  private:
247  #if ACE_SEGMENT_LMDF_OPTION == ACE_SEGMENT_LMDF_OPTION_ARRAY
248  static const DigitalWriter kGroupWriters[2 * kNumGroups];
249  static const DigitalWriter kElementWriters[2 * kNumElements];
250  #endif
251 
253  mutable uint8_t mPrevGroup = 0;
254 };
255 
256 #if ACE_SEGMENT_LMDF_OPTION == ACE_SEGMENT_LMDF_OPTION_ARRAY
257 
258 template <
259  uint8_t e0, uint8_t e1, uint8_t e2, uint8_t e3,
260  uint8_t e4, uint8_t e5, uint8_t e6, uint8_t e7,
261  uint8_t g0, uint8_t g1, uint8_t g2, uint8_t g3
262 >
263 const DigitalWriter
264 LedMatrixDirectFast4<e0, e1, e2, e3, e4, e5, e6, e7, g0, g1, g2, g3>
265 ::kElementWriters[2 * kNumElements] = {
266  digitalWriteFastElement0L,
267  digitalWriteFastElement0H,
268  digitalWriteFastElement1L,
269  digitalWriteFastElement1H,
270  digitalWriteFastElement2L,
271  digitalWriteFastElement2H,
272  digitalWriteFastElement3L,
273  digitalWriteFastElement3H,
274  digitalWriteFastElement4L,
275  digitalWriteFastElement4H,
276  digitalWriteFastElement5L,
277  digitalWriteFastElement5H,
278  digitalWriteFastElement6L,
279  digitalWriteFastElement6H,
280  digitalWriteFastElement7L,
281  digitalWriteFastElement7H,
282 };
283 
284 template <
285  uint8_t e0, uint8_t e1, uint8_t e2, uint8_t e3,
286  uint8_t e4, uint8_t e5, uint8_t e6, uint8_t e7,
287  uint8_t g0, uint8_t g1, uint8_t g2, uint8_t g3
288 >
289 const DigitalWriter
290 LedMatrixDirectFast4<e0, e1, e2, e3, e4, e5, e6, e7, g0, g1, g2, g3>
291 ::kGroupWriters[2 * kNumGroups] = {
292  digitalWriteFastGroup0L,
293  digitalWriteFastGroup0H,
294  digitalWriteFastGroup1L,
295  digitalWriteFastGroup1H,
296  digitalWriteFastGroup2L,
297  digitalWriteFastGroup2H,
298  digitalWriteFastGroup3L,
299  digitalWriteFastGroup3H,
300 };
301 
302 #endif
303 
304 } // ace_segment
305 
306 #endif // defined(ARDUINO_ARCH_AVR)
307 
308 #endif
309