AceWire  0.2.0
Unified interface for selecting different I2C implementations on Arduino platforms
SimpleWireInterface.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_WIRE_SIMPLE_WIRE_INTERFACE_H
26 #define ACE_WIRE_SIMPLE_WIRE_INTERFACE_H
27 
28 #include <stdint.h>
29 #include <Arduino.h> // pinMode(), digitalWrite()
30 
31 namespace ace_wire {
32 
57  public:
72  uint8_t dataPin, uint8_t clockPin, uint8_t delayMicros
73  ) :
74  mDataPin(dataPin),
75  mClockPin(clockPin),
76  mDelayMicros(delayMicros)
77  {}
78 
87  void begin() const {
88  digitalWrite(mClockPin, LOW);
89  digitalWrite(mDataPin, LOW);
90 
91  // Begin with both lines in INPUT mode to passively go HIGH.
92  clockHigh();
93  dataHigh();
94  }
95 
97  void end() const {
98  clockHigh();
99  dataHigh();
100  }
101 
106  void beginTransmission(uint8_t addr) const {
107  clockHigh();
108  dataHigh();
109 
110  dataLow();
111  clockLow();
112 
113  // Send I2C addr (7 bits) and the R/W bit set to "write" (0x00).
114  uint8_t effectiveAddr = (addr << 1) | 0x00;
115  write(effectiveAddr);
116  }
117 
128  uint8_t write(uint8_t data) const {
129  for (uint8_t i = 0; i < 8; ++i) {
130  if (data & 0x80) {
131  dataHigh();
132  } else {
133  dataLow();
134  }
135  clockHigh();
136  clockLow();
137  data <<= 1;
138  }
139 
140  return readAck();
141  }
142 
144  void endTransmission() const {
145  // clock will always be LOW when this is called
146  dataLow();
147  clockHigh();
148  dataHigh();
149  }
150 
152  uint8_t requestFrom(uint8_t addr, uint8_t quantity, bool stop = true) {
153  mQuantity = quantity;
154  mStop = stop;
155 
156  clockHigh();
157  dataHigh();
158 
159  dataLow();
160  clockLow();
161 
162  // Send I2C addr (7 bits) and the R/W bit set to "read" (0x01).
163  uint8_t effectiveAddr = (addr << 1) | 0x01;
164  write(effectiveAddr);
165 
166  return quantity;
167  }
168 
175  uint8_t read() {
176  // Read one byte
177  dataHigh();
178  uint8_t data = 0;
179  for (uint8_t i = 0; i < 8; ++i) {
180  clockHigh();
181  data <<= 1;
182  uint8_t bit = digitalRead(mDataPin);
183  data |= (bit & 0x1);
184  clockLow();
185  }
186 
187  // Decrement quantity to determine if NACK or ACK should be sent.
188  mQuantity--;
189  if (mQuantity) {
190  sendAck();
191  } else {
192  sendNack();
193  }
194 
195  return data;
196  }
197 
199  void endRequest() {
200  if (mStop) {
201  endTransmission();
202  }
203  }
204 
205  // Use default copy constructor and assignment operator.
206  SimpleWireInterface(const SimpleWireInterface&) = default;
207  SimpleWireInterface& operator=(const SimpleWireInterface&) = default;
208 
209  private:
214  uint8_t readAck() const {
215  // Go into INPUT mode, reusing dataHigh(), saving 10 flash bytes on AVR.
216  dataHigh();
217  uint8_t ack = digitalRead(mDataPin);
218 
219  // Device releases SDA upon falling edge of the 9th CLK.
220  clockHigh();
221  clockLow();
222  return ack;
223  }
224 
226  void sendAck() const {
227  dataLow();
228  clockHigh();
229  clockLow();
230  }
231 
233  void sendNack() const {
234  dataHigh();
235  clockHigh();
236  clockLow();
237  }
238 
239  void bitDelay() const { delayMicroseconds(mDelayMicros); }
240 
241  void clockHigh() const { pinMode(mClockPin, INPUT); bitDelay(); }
242 
243  void clockLow() const { pinMode(mClockPin, OUTPUT); bitDelay(); }
244 
245  void dataHigh() const { pinMode(mDataPin, INPUT); bitDelay(); }
246 
247  void dataLow() const { pinMode(mDataPin, OUTPUT); bitDelay(); }
248 
249  private:
250  uint8_t const mDataPin;
251  uint8_t const mClockPin;
252  uint8_t const mDelayMicros;
253  uint8_t mQuantity;
254  bool mStop;
255 };
256 
257 }
258 
259 #endif
ace_wire::SimpleWireInterface::endRequest
void endRequest()
End requestFrom() by sending I2C STOP condition if 'stop' is 'true'.
Definition: SimpleWireInterface.h:199
ace_wire::SimpleWireInterface::end
void end() const
Set clock and data pins to INPUT mode.
Definition: SimpleWireInterface.h:97
ace_wire::SimpleWireInterface::read
uint8_t read()
Read byte.
Definition: SimpleWireInterface.h:175
ace_wire::SimpleWireInterface::write
uint8_t write(uint8_t data) const
Send the data byte on the data bus, with MSB first as specified by I2C.
Definition: SimpleWireInterface.h:128
ace_wire::SimpleWireInterface::requestFrom
uint8_t requestFrom(uint8_t addr, uint8_t quantity, bool stop=true)
Prepare to read bytes by sending I2C START condition.
Definition: SimpleWireInterface.h:152
ace_wire::SimpleWireInterface::beginTransmission
void beginTransmission(uint8_t addr) const
Send the I2C START condition.
Definition: SimpleWireInterface.h:106
ace_wire::SimpleWireInterface
A software I2C implementation for sending LED segment patterns over I2C.
Definition: SimpleWireInterface.h:56
ace_wire::SimpleWireInterface::endTransmission
void endTransmission() const
Send the I2C STOP condition.
Definition: SimpleWireInterface.h:144
ace_wire::SimpleWireInterface::SimpleWireInterface
SimpleWireInterface(uint8_t dataPin, uint8_t clockPin, uint8_t delayMicros)
Constructor.
Definition: SimpleWireInterface.h:71
ace_wire::SimpleWireInterface::begin
void begin() const
Initialize the clock and data pins.
Definition: SimpleWireInterface.h:87