Digital IO
SoftI2cMaster.h
Go to the documentation of this file.
1 /* Arduino DigitalIO Library
2  * Copyright (C) 2013 by William Greiman
3  *
4  * This file is part of the Arduino DigitalIO Library
5  *
6  * This Library is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This Library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with the Arduino DigitalIO Library. If not, see
18  * <http://www.gnu.org/licenses/>.
19  */
20 #ifndef SOFT_I2C_MASTER_H
21 #define SOFT_I2C_MASTER_H
22 
30 #if defined(__AVR__) || defined(DOXYGEN) // AVR only
31 #include <Arduino.h>
32 #include <util/delay_basic.h>
33 #include "DigitalPin.h"
34 #include "I2cConstants.h"
35 //------------------------------------------------------------------------------
36 // State codes.
37 
39 const uint8_t STATE_STOP = 0;
40 
42 const uint8_t STATE_REP_START = 1;
43 
45 const uint8_t STATE_RX_DATA = 2;
46 
48 const uint8_t STATE_TX_DATA = 3;
49 
51 const uint8_t STATE_RX_ADDR_NACK = 4;
52 
54 const uint8_t STATE_TX_ADDR_NACK = 5;
56 const uint8_t STATE_TX_DATA_NACK = 6;
57 //==============================================================================
63  public:
64  I2cMasterBase() : _state(STATE_STOP) {}
75  virtual uint8_t read(uint8_t last) = 0;
76 
82  virtual void start() = 0;
88  virtual void stop() = 0;
89 
90  bool transfer(uint8_t addressRW, void *buf,
91  size_t nbyte, uint8_t option = I2C_STOP);
92 
93  bool transferContinue(void *buf, size_t nbyte, uint8_t option = I2C_STOP);
101  virtual bool write(uint8_t data) = 0;
102 
103  private:
104  uint8_t _state;
105 };
106 //==============================================================================
111 class SoftI2cMaster : public I2cMasterBase {
112  public:
113  SoftI2cMaster() {}
114  SoftI2cMaster(uint8_t sclPin, uint8_t sdaPin);
115  void begin(uint8_t sclPin, uint8_t sdaPin);
116  uint8_t read(uint8_t last);
117  void start();
118  void stop(void);
119  bool write(uint8_t b);
120 
121  private:
122  uint8_t _sclBit;
123  uint8_t _sdaBit;
124  volatile uint8_t* _sclDDR;
125  volatile uint8_t* _sdaDDR;
126  volatile uint8_t* _sdaInReg;
127  //----------------------------------------------------------------------------
128  bool readSda() {return *_sdaInReg & _sdaBit;}
129  //----------------------------------------------------------------------------
130  void sclDelay(uint8_t n) {_delay_loop_1(n);}
131  //----------------------------------------------------------------------------
132  void writeScl(bool value) {
133  uint8_t s = SREG;
134  noInterrupts();
135  if (value == LOW) {
136  // Pull scl low.
137  *_sclDDR |= _sclBit;
138  } else {
139  // Put scl in high Z input mode.
140  *_sclDDR &= ~_sclBit;
141  }
142  SREG = s;
143  }
144  //----------------------------------------------------------------------------
145  void writeSda(bool value) {
146  uint8_t s = SREG;
147  noInterrupts();
148  if (value == LOW) {
149  // Pull sda low.
150  *_sdaDDR |= _sdaBit;
151  } else {
152  // Put sda in high Z input mode.
153  *_sdaDDR &= ~_sdaBit;
154  }
155  SREG = s;
156  }
157 };
158 //==============================================================================
159 // Template based fast software I2C
160 //------------------------------------------------------------------------------
165 template<uint8_t sclPin, uint8_t sdaPin>
166 class FastI2cMaster : public I2cMasterBase {
167  public:
168  //----------------------------------------------------------------------------
169  FastI2cMaster() {
170  begin();
171  }
172  //----------------------------------------------------------------------------
174  void begin() {
175  fastDigitalWrite(sclPin, LOW);
176  fastDigitalWrite(sdaPin, LOW);
177 
178  sclWrite(HIGH);
179  sdaWrite(HIGH);
180  }
181  //----------------------------------------------------------------------------
182  uint8_t read(uint8_t last) {
183  uint8_t data = 0;
184  sdaWrite(HIGH);
185 
186  readBit(7, &data);
187  readBit(6, &data);
188  readBit(5, &data);
189  readBit(4, &data);
190  readBit(3, &data);
191  readBit(2, &data);
192  readBit(1, &data);
193  readBit(0, &data);
194 
195  // send ACK or NACK
196  sdaWrite(last);
197  sclDelay(4);
198  sclWrite(HIGH);
199  sclDelay(6);
200  sclWrite(LOW);
201  sdaWrite(LOW);
202  return data;
203  }
204  //----------------------------------------------------------------------------
205  void start() {
206  if (!fastDigitalRead(sdaPin)) {
207  // It's a repeat start.
208  sdaWrite(HIGH);
209  sclDelay(8);
210  sclWrite(HIGH);
211  sclDelay(8);
212  }
213  sdaWrite(LOW);
214  sclDelay(8);
215  sclWrite(LOW);
216  sclDelay(8);
217  }
218  //----------------------------------------------------------------------------
219  void stop(void) {
220  sdaWrite(LOW);
221  sclDelay(8);
222  sclWrite(HIGH);
223  sclDelay(8);
224  sdaWrite(HIGH);
225  sclDelay(8);
226  }
227  //----------------------------------------------------------------------------
228  bool write(uint8_t data) {
229  // write byte
230  writeBit(7, data);
231  writeBit(6, data);
232  writeBit(5, data);
233  writeBit(4, data);
234  writeBit(3, data);
235  writeBit(2, data);
236  writeBit(1, data);
237  writeBit(0, data);
238 
239  // get ACK or NACK
240  sdaWrite(HIGH);
241 
242  sclWrite(HIGH);
243  sclDelay(5);
244  bool rtn = fastDigitalRead(sdaPin);
245  sclWrite(LOW);
246  sdaWrite(LOW);
247  return rtn == 0;
248  }
249 
250  private:
251  //----------------------------------------------------------------------------
252  inline __attribute__((always_inline))
253  void sclWrite(bool value) {fastDdrWrite(sclPin, !value);}
254  //----------------------------------------------------------------------------
255  inline __attribute__((always_inline))
256  void sdaWrite(bool value) {fastDdrWrite(sdaPin, !value);}
257  //----------------------------------------------------------------------------
258  inline __attribute__((always_inline))
259  void readBit(uint8_t bit, uint8_t* data) {
260  sclWrite(HIGH);
261  sclDelay(5);
262  if (fastDigitalRead(sdaPin)) *data |= 1 << bit;
263  sclWrite(LOW);
264  if (bit) sclDelay(6);
265  }
266  //----------------------------------------------------------------------------
267  void sclDelay(uint8_t n) {_delay_loop_1(n);}
268  //----------------------------------------------------------------------------
269  inline __attribute__((always_inline))
270  void writeBit(uint8_t bit, uint8_t data) {
271  uint8_t mask = 1 << bit;
272  sdaWrite(data & mask);
273  sclWrite(HIGH);
274  sclDelay(5);
275  sclWrite(LOW);
276  sclDelay(5);
277  }
278 };
279 #endif // __AVR__
280 #endif // SOFT_I2C_MASTER_H
281 
AVR Software I2C master class.
AVR Fast software I2C master class.
virtual uint8_t read(uint8_t last)=0
bool transfer(uint8_t addressRW, void *buf, size_t nbyte, uint8_t option=I2C_STOP)
const uint8_t STATE_TX_DATA_NACK
Definition: SoftI2cMaster.h:56
uint8_t read(uint8_t last)
uint8_t read(uint8_t last)
Base class for FastI2cMaster, SoftI2cMaster.
Definition: SoftI2cMaster.h:62
void stop(void)
const uint8_t STATE_TX_ADDR_NACK
Definition: SoftI2cMaster.h:54
const uint8_t I2C_STOP
Definition: I2cConstants.h:38
virtual void stop()=0
const uint8_t STATE_RX_DATA
Definition: SoftI2cMaster.h:45
static void fastDigitalWrite(uint8_t pin, bool level)
Definition: DigitalPin.h:153
static bool fastDigitalRead(uint8_t pin)
Definition: DigitalPin.h:127
const uint8_t STATE_REP_START
Definition: SoftI2cMaster.h:42
Fast Digital Pin functions.
bool write(uint8_t b)
virtual void start()=0
bool write(uint8_t data)
static void fastDdrWrite(uint8_t pin, bool level)
Definition: DigitalPin.h:162
void stop(void)
const uint8_t STATE_STOP
Definition: SoftI2cMaster.h:39
bool transferContinue(void *buf, size_t nbyte, uint8_t option=I2C_STOP)
const uint8_t STATE_TX_DATA
Definition: SoftI2cMaster.h:48
void begin(uint8_t sclPin, uint8_t sdaPin)
Two Wire Interface constants.
virtual bool write(uint8_t data)=0
const uint8_t STATE_RX_ADDR_NACK
Definition: SoftI2cMaster.h:51