ArduinoLibs
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
SoftI2C.cpp
1 /*
2  * Copyright (C) 2012 Southern Storm Software, Pty Ltd.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included
12  * in all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20  * DEALINGS IN THE SOFTWARE.
21  */
22 
23 #include "SoftI2C.h"
24 #if defined(ARDUINO) && ARDUINO >= 100
25 #include <Arduino.h>
26 #else
27 #include <WProgram.h>
28 #endif
29 
45 #define i2cDelay() delayMicroseconds(5)
46 
50 SoftI2C::SoftI2C(uint8_t dataPin, uint8_t clockPin)
51  : _dataPin(dataPin)
52  , _clockPin(clockPin)
53  , started(false)
54  , acked(true)
55  , inWrite(false)
56  , readCount(0)
57 {
58  // Initially set the CLOCK and DATA lines to be outputs in the high state.
59  pinMode(_clockPin, OUTPUT);
60  pinMode(_dataPin, OUTPUT);
61  digitalWrite(_clockPin, HIGH);
62  digitalWrite(_dataPin, HIGH);
63 }
64 
65 unsigned int SoftI2C::maxTransferSize() const
66 {
67  return 0xFFFF;
68 }
69 
70 void SoftI2C::start()
71 {
72  pinMode(_dataPin, OUTPUT);
73  if (started) {
74  // Already started, so send a restart condition.
75  digitalWrite(_dataPin, HIGH);
76  digitalWrite(_clockPin, HIGH);
77  i2cDelay();
78  }
79  digitalWrite(_dataPin, LOW);
80  i2cDelay();
81  digitalWrite(_clockPin, LOW);
82  i2cDelay();
83  started = true;
84  acked = true;
85 }
86 
87 void SoftI2C::stop()
88 {
89  pinMode(_dataPin, OUTPUT);
90  digitalWrite(_dataPin, LOW);
91  digitalWrite(_clockPin, HIGH);
92  i2cDelay();
93  digitalWrite(_dataPin, HIGH);
94  i2cDelay();
95  started = false;
96  inWrite = false;
97 }
98 
99 #define I2C_WRITE 0x00
100 #define I2C_WRITE10 0xF0
101 #define I2C_READ 0x01
102 #define I2C_READ10 0xF1
103 
104 void SoftI2C::startWrite(unsigned int address)
105 {
106  start();
107  inWrite = true;
108  if (address < 0x80) {
109  // 7-bit address.
110  write((uint8_t)((address << 1) | I2C_WRITE));
111  } else {
112  // 10-bit address.
113  write((uint8_t)(((address >> 7) & 0x06)) | I2C_WRITE10);
114  write((uint8_t)address);
115  }
116 }
117 
118 void SoftI2C::write(uint8_t value)
119 {
120  uint8_t mask = 0x80;
121  while (mask != 0) {
122  writeBit((value & mask) != 0);
123  mask >>= 1;
124  }
125  if (readBit()) // 0: ACK, 1: NACK
126  acked = false;
127 }
128 
130 {
131  stop();
132  return acked;
133 }
134 
135 bool SoftI2C::startRead(unsigned int address, unsigned int count)
136 {
137  start();
138  inWrite = false;
139  if (address < 0x80) {
140  // 7-bit address.
141  write((uint8_t)((address << 1) | I2C_READ));
142  } else {
143  // 10-bit address.
144  write((uint8_t)(((address >> 7) & 0x06)) | I2C_READ10);
145  write((uint8_t)address);
146  }
147  if (!acked) {
148  readCount = 0;
149  return false;
150  }
151  readCount = count;
152  return true;
153 }
154 
155 unsigned int SoftI2C::available()
156 {
157  return readCount;
158 }
159 
160 uint8_t SoftI2C::read()
161 {
162  uint8_t value = 0;
163  for (uint8_t bit = 0; bit < 8; ++bit)
164  value = (value << 1) | readBit();
165  if (readCount > 1) {
166  // More bytes left to read - send an ACK.
167  writeBit(false);
168  --readCount;
169  } else {
170  // Last byte - send the NACK and a stop condition.
171  writeBit(true);
172  stop();
173  readCount = 0;
174  }
175  return value;
176 }
177 
178 void SoftI2C::writeBit(bool bit)
179 {
180  pinMode(_dataPin, OUTPUT);
181  if (bit)
182  digitalWrite(_dataPin, HIGH);
183  else
184  digitalWrite(_dataPin, LOW);
185  i2cDelay();
186  digitalWrite(_clockPin, HIGH);
187  i2cDelay();
188  digitalWrite(_clockPin, LOW);
189  i2cDelay();
190 }
191 
192 bool SoftI2C::readBit()
193 {
194  pinMode(_dataPin, INPUT);
195  digitalWrite(_dataPin, HIGH);
196  digitalWrite(_clockPin, HIGH);
197  bool bit = digitalRead(_dataPin);
198  i2cDelay();
199  digitalWrite(_clockPin, LOW);
200  i2cDelay();
201  return bit;
202 }
bool startRead(unsigned int address, unsigned int count)
Starts a read operation for count bytes by sending the start condition and the I2C control byte...
Definition: SoftI2C.cpp:135
bool endWrite()
Ends the current write operation.
Definition: SoftI2C.cpp:129
SoftI2C(uint8_t dataPin, uint8_t clockPin)
Constructs a new software I2C master on dataPin and clockPin.
Definition: SoftI2C.cpp:50
unsigned int available()
Returns the number of bytes that are still available for reading.
Definition: SoftI2C.cpp:155
uint8_t read()
Reads a single byte from the I2C bus.
Definition: SoftI2C.cpp:160
void write(uint8_t value)
Writes a single byte value on the I2C bus.
Definition: SoftI2C.cpp:118
unsigned int maxTransferSize() const
Returns the maximum number of bytes that can be read or written in a single request by this bus maste...
Definition: SoftI2C.cpp:65
void startWrite(unsigned int address)
Starts a write operation by sending a start condition and the I2C control byte.
Definition: SoftI2C.cpp:104