AceTMI  0.6
Interfaces for communicating with the TM1637 and TM1638 LED controllers on Arduino platforms
SimpleTmi1637Interface.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_INTERFACE_H
26 #define ACE_TMI_SIMPLE_TMI_1637_INTERFACE_H
27 
28 #include <Arduino.h>
29 
30 namespace ace_tmi {
31 
64  public:
78  uint8_t dioPin,
79  uint8_t clkPin,
80  uint8_t delayMicros
81  ) :
82  mDioPin(dioPin),
83  mClkPin(clkPin),
84  mDelayMicros(delayMicros)
85  {}
86 
96  void begin() const {
97  digitalWrite(mClkPin, LOW);
98  digitalWrite(mDioPin, LOW);
99 
100  // Begin with both lines at HIGH.
101  clockHigh();
102  dataHigh();
103  }
104 
106  void end() const {
107  clockHigh();
108  dataHigh();
109  }
110 
112  void startCondition() const {
113  clockHigh();
114  dataHigh();
115 
116  dataLow();
117  clockLow();
118  }
119 
121  void stopCondition() const {
122  // clock will always be LOW when this is called
123  dataLow();
124  clockHigh();
125  dataHigh();
126  }
127 
141  uint8_t write(uint8_t data) const {
142  for (uint8_t i = 0; i < 8; ++i) {
143  if (data & 0x1) {
144  dataHigh();
145  } else {
146  dataLow();
147  }
148 
149  // Device reads DIO on the rising edge of CLK.
150  clockHigh();
151 
152  // An extra bitDelay() here would make the HIGH and LOW states symmetric
153  // in duration (if digitalWrite() is assumed to be infinitely fast,
154  // which it is definitely not). But actual devices that I have tested
155  // seem to support the absence of that extra delay. So let's ignore it
156  // to make the transfer speed faster.
157  clockLow();
158  data >>= 1;
159  }
160 
161  uint8_t ack = readAck();
162  return ack ^ 0x1; // invert the 0 and 1
163  }
164 
176  uint8_t read() const {
177  // Make sure mDioPin is in INPUT mode because the previous write() may
178  // have put mDioPin into open-drain OUTPUT mode.
179  dataHigh();
180 
181  uint8_t data = 0x0;
182  for (uint8_t i = 0; i < 8; ++i) {
183  // Device sets the DIO pin on the falling edge of CLK.
184  clockLow();
185  uint8_t bit = dataRead();
186  clockHigh();
187  data >>= 1;
188  data |= (bit & 0x1) ? 0x80 : 0x00;
189  }
190 
191  // Read the ACK from device
192  uint8_t ack = readAck();
193  (void) ack;
194 
195  return data;
196  }
197 
198  // Use default copy constructor and assignment operator.
200  SimpleTmi1637Interface& operator=(const SimpleTmi1637Interface&) = default;
201 
202  private:
209  uint8_t readAck() const {
210  // Go into INPUT mode, reusing dataHigh(), saving 10 flash bytes on AVR.
211  dataHigh();
212 
213  // DIO is supposed to remain stable after CLK is set HIGH.
214  clockHigh();
215 
216  uint8_t ack = digitalRead(mDioPin);
217 
218  // Device releases DIO upon falling edge of the 9th CLK.
219  clockLow();
220  return ack;
221  }
222 
223  void bitDelay() const { delayMicroseconds(mDelayMicros); }
224 
225  void clockHigh() const { pinMode(mClkPin, INPUT); bitDelay(); }
226 
227  void clockLow() const { pinMode(mClkPin, OUTPUT); bitDelay(); }
228 
229  void dataHigh() const { pinMode(mDioPin, INPUT); bitDelay(); }
230 
231  void dataLow() const { pinMode(mDioPin, OUTPUT); bitDelay(); }
232 
233  uint8_t dataRead() const {
234  uint8_t data = digitalRead(mDioPin);
235  bitDelay();
236  return data;
237  }
238 
239  private:
240  uint8_t const mDioPin;
241  uint8_t const mClkPin;
242  uint8_t const mDelayMicros;
243 };
244 
245 } // ace_tmi
246 
247 #endif
ace_tmi::SimpleTmi1637Interface::SimpleTmi1637Interface
SimpleTmi1637Interface(uint8_t dioPin, uint8_t clkPin, uint8_t delayMicros)
Constructor.
Definition: SimpleTmi1637Interface.h:77
ace_tmi::SimpleTmi1637Interface::begin
void begin() const
Initialize the DIO and CLK pins.
Definition: SimpleTmi1637Interface.h:96
ace_tmi::SimpleTmi1637Interface::stopCondition
void stopCondition() const
Generate the I2C-like stop condition.
Definition: SimpleTmi1637Interface.h:121
ace_tmi::SimpleTmi1637Interface
Class that knows how to communicate with a TM1637 chip.
Definition: SimpleTmi1637Interface.h:63
ace_tmi::SimpleTmi1637Interface::end
void end() const
Set dio and clk pins to INPUT mode.
Definition: SimpleTmi1637Interface.h:106
ace_tmi::SimpleTmi1637Interface::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: SimpleTmi1637Interface.h:141
ace_tmi::SimpleTmi1637Interface::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: SimpleTmi1637Interface.h:176
ace_tmi::SimpleTmi1637Interface::startCondition
void startCondition() const
Generate the I2C-like start condition.
Definition: SimpleTmi1637Interface.h:112