AceTMI  0.6
Interfaces for communicating with the TM1637 and TM1638 LED controllers on Arduino platforms
SimpleTmi1637FastInterface.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_TMI_SIMPLE_TMI_1637_FAST_INTERFACE_H
26 #define ACE_TMI_SIMPLE_TMI_1637_FAST_INTERFACE_H
27 
28 #include <stdint.h>
29 #include <Arduino.h> // delayMicroseconds()
30 
31 namespace ace_tmi {
32 
70 template <
71  uint8_t T_DIO_PIN,
72  uint8_t T_CLK_PIN,
73  uint8_t T_DELAY_MICROS
74 >
76  public:
78  explicit SimpleTmi1637FastInterface() = default;
79 
89  void begin() const {
90  digitalWriteFast(T_CLK_PIN, LOW);
91  digitalWriteFast(T_DIO_PIN, LOW);
92 
93  // Begin with both lines at HIGH.
94  clockHigh();
95  dataHigh();
96  }
97 
99  void end() const {
100  clockHigh();
101  dataHigh();
102  }
103 
105  void startCondition() const {
106  clockHigh();
107  dataHigh();
108 
109  dataLow();
110  clockLow();
111  }
112 
114  void stopCondition() const {
115  // clock will always be LOW when this is called
116  dataLow();
117  clockHigh();
118  dataHigh();
119  }
120 
134  uint8_t write(uint8_t data) const {
135  for (uint8_t i = 0; i < 8; ++i) {
136  if (data & 0x1) {
137  dataHigh();
138  } else {
139  dataLow();
140  }
141 
142  // Device reads DIO on the rising edge of CLK.
143  clockHigh();
144 
145  // An extra bitDelay() here would make the HIGH and LOW states symmetric
146  // in duration (if digitalWriteFast() is assumed to be infinitely fast,
147  // which it is definitely not). But actual devices that I have tested
148  // seem to support the absence of that extra delay. So let's ignore it
149  // to make the transfer speed faster.
150  clockLow();
151  data >>= 1;
152  }
153 
154  uint8_t ack = readAck();
155  return ack ^ 0x1; // invert the 0 and 1
156  }
157 
169  uint8_t read() const {
170  // Make sure mDioPin is in INPUT mode because the previous write() may
171  // have put mDioPin into open-drain OUTPUT mode.
172  dataHigh();
173 
174  uint8_t data = 0x0;
175  for (uint8_t i = 0; i < 8; ++i) {
176  // Device sets the DIO pin on the falling edge of CLK.
177  clockLow();
178  uint8_t bit = dataRead();
179  clockHigh();
180  data >>= 1;
181  data |= (bit & 0x1) ? 0x80 : 0x00;
182  }
183 
184  // Read the ACK from device
185  uint8_t ack = readAck();
186  (void) ack;
187 
188  return data;
189  }
190 
191  // Use default copy constructor and assignment operator.
194  default;
195 
196  private:
203  uint8_t readAck() const {
204  // Go into INPUT mode, reusing dataHigh(), saving 6 flash bytes on AVR.
205  dataHigh();
206 
207  // DIO is supposed to remain stable after CLK is set HIGH.
208  clockHigh();
209 
210  uint8_t ack = digitalReadFast(T_DIO_PIN);
211 
212  // Device releases DIO upon falling edge of the 9th CLK.
213  clockLow();
214  return ack;
215  }
216 
217  static void bitDelay() { delayMicroseconds(T_DELAY_MICROS); }
218 
219  static void clockHigh() { pinModeFast(T_CLK_PIN, INPUT); bitDelay(); }
220 
221  static void clockLow() { pinModeFast(T_CLK_PIN, OUTPUT); bitDelay(); }
222 
223  static void dataHigh() { pinModeFast(T_DIO_PIN, INPUT); bitDelay(); }
224 
225  static void dataLow() { pinModeFast(T_DIO_PIN, OUTPUT); bitDelay(); }
226 
227  static uint8_t dataRead() {
228  // Use digitalRead() because digitalReadFast() seems to be buggy for a
229  // SparkFun Pro Micro (__AVR_ATmega32U4__).
230  uint8_t data = digitalRead(T_DIO_PIN);
231  bitDelay();
232  return data;
233  }
234 };
235 
236 } // ace_tmi
237 
238 #endif
ace_tmi::SimpleTmi1637FastInterface::startCondition
void startCondition() const
Generate the I2C-like start condition.
Definition: SimpleTmi1637FastInterface.h:105
ace_tmi::SimpleTmi1637FastInterface::write
uint8_t write(uint8_t data) const
Send the data byte on the data bus, with LSB first instead of the usual MSB first for I2C.
Definition: SimpleTmi1637FastInterface.h:134
ace_tmi::SimpleTmi1637FastInterface::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: SimpleTmi1637FastInterface.h:169
ace_tmi::SimpleTmi1637FastInterface::end
void end() const
Set dio and clk pins to INPUT mode.
Definition: SimpleTmi1637FastInterface.h:99
ace_tmi::SimpleTmi1637FastInterface
Exactly the same as SimpleTmi1637Interface except that this uses the digitalWriteFast library on AVR ...
Definition: SimpleTmi1637FastInterface.h:75
ace_tmi::SimpleTmi1637FastInterface::begin
void begin() const
Initialize the DIO and CLK pins.
Definition: SimpleTmi1637FastInterface.h:89
ace_tmi::SimpleTmi1637FastInterface::stopCondition
void stopCondition() const
Generate the I2C-like stop condition.
Definition: SimpleTmi1637FastInterface.h:114
ace_tmi::SimpleTmi1637FastInterface::SimpleTmi1637FastInterface
SimpleTmi1637FastInterface()=default
Constructor.