AceSegment  0.11.0
A library for rendering seven segment LED displays using the TM1637, TM1638, MAX7219, HT16K33, or 74HC595 controller chips
Tm1638Module.h
1 /*
2 MIT License
3 
4 Copyright (c) 2022 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_TM1638_MODULE_H
26 #define ACE_SEGMENT_TM1638_MODULE_H
27 
28 #include <Arduino.h>
29 #include <AceCommon.h> // incrementMod()
30 #include "../LedModule.h"
31 
32 class Tm1638ModuleTest_flushIncremental;
33 class Tm1638ModuleTest_flush;
34 
35 namespace ace_segment {
36 
41 static const uint16_t kDefaultTm1638DelayMicros = 1;
42 
52 extern const uint8_t kDigitRemapArray8Tm1638[8];
53 
63 template <typename T_TMII, uint8_t T_DIGITS>
64 class Tm1638Module : public LedModule {
65  public:
66 
74  explicit Tm1638Module(
75  const T_TMII& tmiInterface,
76  const uint8_t* remapArray = nullptr
77  ) :
78  LedModule(mPatterns, T_DIGITS),
79  mTmiInterface(tmiInterface),
80  mRemapArray(remapArray)
81  {}
82 
83  //-----------------------------------------------------------------------
84  // Initialization and termination.
85  //-----------------------------------------------------------------------
86 
91  void begin() {
93 
94  memset(mPatterns, 0, T_DIGITS);
95  setDisplayOn(true);
96  setBrightness(0x7);
97  }
98 
100  void end() {
101  LedModule::end();
102  }
103 
104  //-----------------------------------------------------------------------
105  // Additional brightness control supported by the TM1638 chip.
106  //-----------------------------------------------------------------------
107 
112  void setDisplayOn(bool on = true) {
113  mDisplayOn = on;
114  setBrightness(getBrightness()); // mark the brightness dirty
115  }
116 
117  //-----------------------------------------------------------------------
118  // Methods related to rendering.
119  //-----------------------------------------------------------------------
120 
122  bool isFlushRequired() const {
123  return isAnyDigitDirty() || isBrightnessDirty();
124  }
125 
142  void flush() {
143  // Command1: Update the digits using auto incrementing mode.
144  mTmiInterface.beginTransaction();
145  mTmiInterface.write(kDataCmdAutoAddress);
146  mTmiInterface.endTransaction();
147 
148  // Command2: Send the LED patterns.
149  mTmiInterface.beginTransaction();
150  mTmiInterface.write(kAddressCmd);
151  for (uint8_t chipPos = 0; chipPos < T_DIGITS; ++chipPos) {
152  // Remap the logical position used by the controller to the actual
153  // position. For example, if the controller digit 0 appears at physical
154  // digit 2, we need to display the segment pattern given by logical
155  // position 2 when sending the byte to controller digit 0.
156  uint8_t physicalPos = remapLogicalToPhysical(chipPos);
157  uint8_t effectivePattern = mPatterns[physicalPos];
158  mTmiInterface.write(effectivePattern);
159  mTmiInterface.write(0x00); // SEG8 and SEG9 not supported in this class
160  }
161  mTmiInterface.endTransaction();
162 
163  // Command3: Update the brightness last. This matches the recommendation
164  // given in the Titan Micro TM1638 datasheet. But experimentation shows
165  // that things seems to work even if brightness is sent first, before the
166  // digit patterns.
167  mTmiInterface.beginTransaction();
168  mTmiInterface.write(kBrightnessCmd
169  | (mDisplayOn ? kBrightnessLevelOn : 0x0)
170  | (getBrightness() & 0xF));
171  mTmiInterface.endTransaction();
172 
175  }
176 
177  private:
179  uint8_t remapLogicalToPhysical(uint8_t pos) const {
180  return mRemapArray ? mRemapArray[pos] : pos;
181  }
182 
183  private:
184  // Give access to mIsDirty.
185  friend class ::Tm1638ModuleTest_flush;
186 
187  // These come from the TM1638 controller chip datasheet.
188  static uint8_t const kDataCmdWriteDisplay = 0b01000000;
189  static uint8_t const kDataCmdReadKeys = 0b01000010;
190  static uint8_t const kDataCmdAutoAddress = 0b01000000;
191  static uint8_t const kDataCmdFixedAddress = 0b01000100;
192  static uint8_t const kAddressCmd = 0b11000000;
193  static uint8_t const kBrightnessCmd = 0b10000000;
194  static uint8_t const kBrightnessLevelOn = 0b00001000;
195 
196  // The ordering of these fields is partially determined to save memory on
197  // 32-bit processors.
198 
199  // TM1638 interface object. Copied by value instead of reference to avoid an
200  // extra level of indirection.
201  const T_TMII mTmiInterface;
202 
203  const uint8_t* const mRemapArray;
204  uint8_t mPatterns[T_DIGITS];
205  bool mDisplayOn;
206 };
207 
208 } // ace_segment
209 
210 #endif
ace_segment::LedModule::clearDigitsDirty
void clearDigitsDirty()
Clear dirty bits of all digits.
Definition: LedModule.h:126
ace_segment::Tm1638Module::begin
void begin()
Initialize the module.
Definition: Tm1638Module.h:91
ace_segment::LedModule
General interface that represents a generic seven-segment LED module with multiple digits.
Definition: LedModule.h:44
ace_segment::LedModule::isAnyDigitDirty
bool isAnyDigitDirty() const
Return true if any digits are dirty.
Definition: LedModule.h:131
ace_segment::Tm1638Module
An implementation of LedModule using the TM1638 chip.
Definition: Tm1638Module.h:64
ace_segment::LedModule::begin
void begin()
Subclasses should call this from its own begin().
Definition: LedModule.h:93
ace_segment::LedModule::clearBrightnessDirty
void clearBrightnessDirty()
Clear the dirty bit for brightness.
Definition: LedModule.h:146
ace_segment::LedModule::setBrightness
void setBrightness(uint8_t brightness)
Set global brightness of all digits.
Definition: LedModule.h:81
ace_segment::Tm1638Module::Tm1638Module
Tm1638Module(const T_TMII &tmiInterface, const uint8_t *remapArray=nullptr)
Constructor.
Definition: Tm1638Module.h:74
ace_segment::Tm1638Module::isFlushRequired
bool isFlushRequired() const
Return true if flushing required.
Definition: Tm1638Module.h:122
ace_segment::Tm1638Module::flush
void flush()
Send segment patterns of all digits plus the brightness to the display.
Definition: Tm1638Module.h:142
ace_segment::LedModule::end
void end()
Subclasses should call this from its own end().
Definition: LedModule.h:108
ace_segment::LedModule::getBrightness
uint8_t getBrightness() const
Get the current brightness.
Definition: LedModule.h:87
ace_segment::LedModule::isBrightnessDirty
bool isBrightnessDirty() const
Check if the brightness level is dirty.
Definition: LedModule.h:136
ace_segment::Tm1638Module::setDisplayOn
void setDisplayOn(bool on=true)
Turn off the entire display.
Definition: Tm1638Module.h:112
ace_segment::Tm1638Module::end
void end()
Signal end of usage.
Definition: Tm1638Module.h:100