AceSegment  0.4.0
An adjustable, configurable, and extensible framework for rendering seven segment LED displays.
LedMatrixDirectFast.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 #if defined(ARDUINO_ARCH_AVR)
29 
30 #include <stdint.h>
31 #include <Arduino.h> // OUTPUT, INPUT
32 #include <digitalWriteFast.h>
33 #include "../LedMatrixBase.h"
34 
35 // Select OPTION_ARRAY to use an array of function pointers. Using an array
36 // of function takes 27 microseconds for displayCurentField(), but 8 extra bytes
37 // of flash, and 48 extra bytes of static RAM, compared to the SWITCH option.
38 //
39 // Select OPTION_SWITCH to use a switch statement. This is 30% slower for
40 // displayCurentField(), 35 microseconds, but has smaller memory footprint).
41 #define ACE_SEGMENT_LMDF_OPTION_ARRAY 0
42 #define ACE_SEGMENT_LMDF_OPTION_SWITCH 1
43 #if ! defined(ACE_SEGMENT_LMDF_OPTION)
44 #define ACE_SEGMENT_LMDF_OPTION ACE_SEGMENT_LMDF_OPTION_ARRAY
45 #endif
46 
47 namespace ace_segment {
48 
49 #if ACE_SEGMENT_LMDF_OPTION == ACE_SEGMENT_LMDF_OPTION_ARRAY
50 typedef void (*DigitalWriter)(void);
51 #endif
52 
61 template<
62  uint8_t g0, uint8_t g1, uint8_t g2, uint8_t g3,
63  uint8_t e0, uint8_t e1, uint8_t e2, uint8_t e3,
64  uint8_t e4, uint8_t e5, uint8_t e6, uint8_t e7
65 >
66 class LedMatrixDirectFast : public LedMatrixBase {
67  public:
68  constexpr static uint8_t kNumGroups = 4;
69  constexpr static uint8_t kNumElements = 8;
70 
71  LedMatrixDirectFast(uint8_t groupOnPattern, uint8_t elementOnPattern) :
72  LedMatrixBase(groupOnPattern, elementOnPattern)
73  {}
74 
75  void begin() const {
76  // Set pins to OUTPUT mode but set LEDs to OFF.
77  pinModeFast(g0, OUTPUT);
78  pinModeFast(g1, OUTPUT);
79  pinModeFast(g2, OUTPUT);
80  pinModeFast(g3, OUTPUT);
81 
82  pinModeFast(e0, OUTPUT);
83  pinModeFast(e1, OUTPUT);
84  pinModeFast(e2, OUTPUT);
85  pinModeFast(e3, OUTPUT);
86  pinModeFast(e4, OUTPUT);
87  pinModeFast(e5, OUTPUT);
88  pinModeFast(e6, OUTPUT);
89  pinModeFast(e7, OUTPUT);
90 
91  // Set LEDs to off.
92  clear();
93  }
94 
95  void end() const {
96  // Set pins to INPUT mode.
97  pinModeFast(g0, INPUT);
98  pinModeFast(g1, INPUT);
99  pinModeFast(g2, INPUT);
100  pinModeFast(g3, INPUT);
101 
102  // Set pins to INPUT mode.
103  pinModeFast(e0, INPUT);
104  pinModeFast(e1, INPUT);
105  pinModeFast(e2, INPUT);
106  pinModeFast(e3, INPUT);
107  pinModeFast(e4, INPUT);
108  pinModeFast(e5, INPUT);
109  pinModeFast(e6, INPUT);
110  pinModeFast(e7, INPUT);
111  }
112 
113  void draw(uint8_t group, uint8_t elementPattern) const {
114  if (group != mPrevGroup) {
115  disableGroup(mPrevGroup);
116  }
117 
118  drawElements(elementPattern);
119  enableGroup(group);
120  mPrevGroup = group;
121  }
122 
123  void enableGroup(uint8_t group) const {
124  writeGroupPin(group, 0x1);
125  mPrevGroup = group;
126  }
127 
128  void disableGroup(uint8_t group) const {
129  writeGroupPin(group, 0x0);
130  mPrevGroup = group;
131  }
132 
133  void clear() const {
134  for (uint8_t group = 0; group < kNumGroups; group++) {
135  writeGroupPin(group, 0x0);
136  }
137  drawElements(0x00);
138  }
139 
140  private:
142  void drawElements(uint8_t pattern) const {
143  for (uint8_t element = 0; element < kNumElements; element++) {
144  writeElementPin(element, pattern);
145  pattern >>= 1;
146  }
147  }
148 
150  void writeElementPin(uint8_t element, uint8_t output) const {
151  uint8_t actualOutput = (output ^ mElementXorMask) & 0x1;
152  uint8_t index = element * 2 + actualOutput;
153 
154  #if ACE_SEGMENT_LMDF_OPTION == ACE_SEGMENT_LMDF_OPTION_ARRAY
155  DigitalWriter writer = kElementWriters[index];
156  writer();
157 
158  #else
159  switch (index) {
160  case 0: digitalWriteFast(e0, LOW); break;
161  case 1: digitalWriteFast(e0, HIGH); break;
162  case 2: digitalWriteFast(e1, LOW); break;
163  case 3: digitalWriteFast(e1, HIGH); break;
164  case 4: digitalWriteFast(e2, LOW); break;
165  case 5: digitalWriteFast(e2, HIGH); break;
166  case 6: digitalWriteFast(e3, LOW); break;
167  case 7: digitalWriteFast(e3, HIGH); break;
168  case 8: digitalWriteFast(e4, LOW); break;
169  case 9: digitalWriteFast(e4, HIGH); break;
170  case 10: digitalWriteFast(e5, LOW); break;
171  case 11: digitalWriteFast(e5, HIGH); break;
172  case 12: digitalWriteFast(e6, LOW); break;
173  case 13: digitalWriteFast(e6, HIGH); break;
174  case 14: digitalWriteFast(e7, LOW); break;
175  case 15: digitalWriteFast(e7, HIGH); break;
176  default: break;
177  }
178  #endif
179  }
180 
182  void writeGroupPin(uint8_t group, uint8_t output) const {
183  uint8_t actualOutput = (output ^ mGroupXorMask) & 0x1;
184  uint8_t index = group * 2 + actualOutput;
185 
186  #if ACE_SEGMENT_LMDF_OPTION == ACE_SEGMENT_LMDF_OPTION_ARRAY
187  DigitalWriter writer = kGroupWriters[index];
188  writer();
189 
190  #else
191  switch (index) {
192  case 0: digitalWriteFast(g0, LOW); break;
193  case 1: digitalWriteFast(g0, HIGH); break;
194  case 2: digitalWriteFast(g1, LOW); break;
195  case 3: digitalWriteFast(g1, HIGH); break;
196  case 4: digitalWriteFast(g2, LOW); break;
197  case 5: digitalWriteFast(g2, HIGH); break;
198  case 6: digitalWriteFast(g3, LOW); break;
199  case 7: digitalWriteFast(g3, HIGH); break;
200  default: break;
201  }
202  #endif
203  }
204 
205  #if ACE_SEGMENT_LMDF_OPTION == ACE_SEGMENT_LMDF_OPTION_ARRAY
206  // DigitalWriter functions for writing element pins.
207  static void digitalWriteFastElement0L() { digitalWriteFast(e0, LOW); }
208  static void digitalWriteFastElement0H() { digitalWriteFast(e0, HIGH); }
209  static void digitalWriteFastElement1L() { digitalWriteFast(e1, LOW); }
210  static void digitalWriteFastElement1H() { digitalWriteFast(e1, HIGH); }
211  static void digitalWriteFastElement2L() { digitalWriteFast(e2, LOW); }
212  static void digitalWriteFastElement2H() { digitalWriteFast(e2, HIGH); }
213  static void digitalWriteFastElement3L() { digitalWriteFast(e3, LOW); }
214  static void digitalWriteFastElement3H() { digitalWriteFast(e3, HIGH); }
215  static void digitalWriteFastElement4L() { digitalWriteFast(e4, LOW); }
216  static void digitalWriteFastElement4H() { digitalWriteFast(e4, HIGH); }
217  static void digitalWriteFastElement5L() { digitalWriteFast(e5, LOW); }
218  static void digitalWriteFastElement5H() { digitalWriteFast(e5, HIGH); }
219  static void digitalWriteFastElement6L() { digitalWriteFast(e6, LOW); }
220  static void digitalWriteFastElement6H() { digitalWriteFast(e6, HIGH); }
221  static void digitalWriteFastElement7L() { digitalWriteFast(e7, LOW); }
222  static void digitalWriteFastElement7H() { digitalWriteFast(e7, HIGH); }
223 
224  // DigitalWriter functions for writing group pins.
225  static void digitalWriteFastGroup0L() { digitalWriteFast(g0, LOW); }
226  static void digitalWriteFastGroup0H() { digitalWriteFast(g0, HIGH); }
227  static void digitalWriteFastGroup1L() { digitalWriteFast(g1, LOW); }
228  static void digitalWriteFastGroup1H() { digitalWriteFast(g1, HIGH); }
229  static void digitalWriteFastGroup2L() { digitalWriteFast(g2, LOW); }
230  static void digitalWriteFastGroup2H() { digitalWriteFast(g2, HIGH); }
231  static void digitalWriteFastGroup3L() { digitalWriteFast(g3, LOW); }
232  static void digitalWriteFastGroup3H() { digitalWriteFast(g3, HIGH); }
233  #endif
234 
235  private:
236  #if ACE_SEGMENT_LMDF_OPTION == ACE_SEGMENT_LMDF_OPTION_ARRAY
237  static const DigitalWriter kGroupWriters[2 * kNumGroups];
238  static const DigitalWriter kElementWriters[2 * kNumElements];
239  #endif
240 
242  mutable uint8_t mPrevGroup = 0;
243 };
244 
245 #if ACE_SEGMENT_LMDF_OPTION == ACE_SEGMENT_LMDF_OPTION_ARRAY
246 
247 template<
248  uint8_t g0, uint8_t g1, uint8_t g2, uint8_t g3,
249  uint8_t e0, uint8_t e1, uint8_t e2, uint8_t e3,
250  uint8_t e4, uint8_t e5, uint8_t e6, uint8_t e7
251 >
252 const DigitalWriter
253 LedMatrixDirectFast<g0, g1, g2, g3, e0, e1, e2, e3, e4, e5, e6, e7>
254 ::kElementWriters[2 * kNumElements] = {
255  digitalWriteFastElement0L,
256  digitalWriteFastElement0H,
257  digitalWriteFastElement1L,
258  digitalWriteFastElement1H,
259  digitalWriteFastElement2L,
260  digitalWriteFastElement2H,
261  digitalWriteFastElement3L,
262  digitalWriteFastElement3H,
263  digitalWriteFastElement4L,
264  digitalWriteFastElement4H,
265  digitalWriteFastElement5L,
266  digitalWriteFastElement5H,
267  digitalWriteFastElement6L,
268  digitalWriteFastElement6H,
269  digitalWriteFastElement7L,
270  digitalWriteFastElement7H,
271 };
272 
273 template<
274  uint8_t g0, uint8_t g1, uint8_t g2, uint8_t g3,
275  uint8_t e0, uint8_t e1, uint8_t e2, uint8_t e3,
276  uint8_t e4, uint8_t e5, uint8_t e6, uint8_t e7
277 >
278 const DigitalWriter
279 LedMatrixDirectFast<g0, g1, g2, g3, e0, e1, e2, e3, e4, e5, e6, e7>
280 ::kGroupWriters[2 * kNumGroups] = {
281  digitalWriteFastGroup0L,
282  digitalWriteFastGroup0H,
283  digitalWriteFastGroup1L,
284  digitalWriteFastGroup1H,
285  digitalWriteFastGroup2L,
286  digitalWriteFastGroup2H,
287  digitalWriteFastGroup3L,
288  digitalWriteFastGroup3H,
289 };
290 
291 #endif
292 
293 } // ace_segment
294 
295 #endif // defined(ARDUINO_ARCH_AVR)
296 
297 #endif
298