AceTMI  0.6
Interfaces for communicating with the TM1637 and TM1638 LED controllers on Arduino platforms
SimpleTmi1638FastInterface.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_TMI_SIMPLE_TMI_1638_FAST_INTERFACE_H
26 #define ACE_TMI_SIMPLE_TMI_1638_FAST_INTERFACE_H
27 
28 #include <stdint.h>
29 #include <Arduino.h> // delayMicroseconds()
30 
31 namespace ace_tmi {
32 
68 template <
69  uint8_t T_DIO_PIN,
70  uint8_t T_CLK_PIN,
71  uint8_t T_STB_PIN,
72  uint8_t T_DELAY_MICROS
73 >
75  public:
77  explicit SimpleTmi1638FastInterface() = default;
78 
88  void begin() const {
89  clockHigh();
90  strobeHigh();
91  pinModeFast(T_CLK_PIN, OUTPUT);
92  pinModeFast(T_STB_PIN, OUTPUT);
93  dataHigh(); // open-drain HIGH
94  }
95 
97  void end() const {
98  pinModeFast(T_CLK_PIN, INPUT);
99  pinModeFast(T_STB_PIN, INPUT);
100  dataHigh(); // open-drain HIGH
101  }
102 
104  void beginTransaction() const {
105  clockHigh();
106  strobeLow();
107  dataHigh(); // open-drain HIGH
108  }
109 
111  void endTransaction() const {
112  clockHigh();
113  strobeHigh();
114  dataHigh(); // open-drain HIGH
115  }
116 
126  void write(uint8_t data) const {
127  for (uint8_t i = 0; i < 8; ++i) {
128  clockLow();
129  if (data & 0x1) {
130  dataHigh();
131  } else {
132  dataLow();
133  }
134 
135  // Device reads DIO on the rising edge of CLK.
136  clockHigh();
137  // The CLK LOW is twice as long as HIGH. An extra bitDelay() right after
138  // the clockHigh() would make the HIGH and LOW states symmetric in
139  // duration (if digitalWriteFast() is assumed to be infinitely fast,
140  // which it is definitely not). But actual devices that I have tested
141  // seem to support the absence of that extra delay. So let's ignore it
142  // to make the transfer speed faster.
143 
144  data >>= 1;
145  }
146  }
147 
159  uint8_t read() const {
160  // Make sure mDioPin is in INPUT mode because the previous write() may
161  // have put mDioPin into open-drain OUTPUT mode.
162  dataHigh();
163 
164  uint8_t data = 0x0;
165  for (uint8_t i = 0; i < 8; ++i) {
166  // Device sets the DIO pin on the falling edge of CLK.
167  clockLow();
168  uint8_t bit = dataRead();
169  clockHigh();
170  data >>= 1;
171  data |= (bit & 0x1) ? 0x80 : 0x00;
172  }
173  return data;
174  }
175 
176  // Use default copy constructor and assignment operator.
179  default;
180 
181  private:
182 
183  static void bitDelay() { delayMicroseconds(T_DELAY_MICROS); }
184 
185  static void clockHigh() { digitalWriteFast(T_CLK_PIN, HIGH); bitDelay(); }
186 
187  static void clockLow() { digitalWriteFast(T_CLK_PIN, LOW); bitDelay(); }
188 
189  static void dataHigh() { pinModeFast(T_DIO_PIN, INPUT); bitDelay(); }
190 
191  static void dataLow() { pinModeFast(T_DIO_PIN, OUTPUT); bitDelay(); }
192 
193  static void strobeHigh() { digitalWriteFast(T_STB_PIN, HIGH); bitDelay(); }
194 
195  static void strobeLow() { digitalWriteFast(T_STB_PIN, LOW); bitDelay(); }
196 
197  static uint8_t dataRead() {
198  // Use digitalRead() because digitalReadFast() seems to be buggy for a
199  // SparkFun Pro Micro (__AVR_ATmega32U4__).
200  uint8_t data = digitalRead(T_DIO_PIN);
201  bitDelay();
202  return data;
203  }
204 
205 };
206 
207 } // ace_tmi
208 
209 #endif
ace_tmi::SimpleTmi1638FastInterface::end
void end() const
Set pins to INPUT mode.
Definition: SimpleTmi1638FastInterface.h:97
ace_tmi::SimpleTmi1638FastInterface::begin
void begin() const
Initialize the DIO, CLK, and STB pins.
Definition: SimpleTmi1638FastInterface.h:88
ace_tmi::SimpleTmi1638FastInterface
Exactly the same as SimpleTmi1638Interface except that this uses the digitalWriteFast library on AVR ...
Definition: SimpleTmi1638FastInterface.h:74
ace_tmi::SimpleTmi1638FastInterface::read
uint8_t read() const
Read the data byte on the data bus, with LSB first instead of the usual MSB first for SPI.
Definition: SimpleTmi1638FastInterface.h:159
ace_tmi::SimpleTmi1638FastInterface::endTransaction
void endTransaction() const
Generate the SPI-like stop condition.
Definition: SimpleTmi1638FastInterface.h:111
ace_tmi::SimpleTmi1638FastInterface::write
void write(uint8_t data) const
Send the data byte on the data bus, with LSB first instead of the usual MSB first for SPI.
Definition: SimpleTmi1638FastInterface.h:126
ace_tmi::SimpleTmi1638FastInterface::beginTransaction
void beginTransaction() const
Generate the SPI-like start condition.
Definition: SimpleTmi1638FastInterface.h:104
ace_tmi::SimpleTmi1638FastInterface::SimpleTmi1638FastInterface
SimpleTmi1638FastInterface()=default
Constructor.