ArduinoLibs
SoftI2C.cpp
00001 /*
00002  * Copyright (C) 2012 Southern Storm Software, Pty Ltd.
00003  *
00004  * Permission is hereby granted, free of charge, to any person obtaining a
00005  * copy of this software and associated documentation files (the "Software"),
00006  * to deal in the Software without restriction, including without limitation
00007  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
00008  * and/or sell copies of the Software, and to permit persons to whom the
00009  * Software is furnished to do so, subject to the following conditions:
00010  *
00011  * The above copyright notice and this permission notice shall be included
00012  * in all copies or substantial portions of the Software.
00013  *
00014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
00015  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00016  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00017  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00018  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
00019  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
00020  * DEALINGS IN THE SOFTWARE.
00021  */
00022 
00023 #include "SoftI2C.h"
00024 #if defined(ARDUINO) && ARDUINO >= 100
00025 #include <Arduino.h>
00026 #else
00027 #include <WProgram.h>
00028 #endif
00029 
00045 #define i2cDelay()  delayMicroseconds(5)
00046 
00050 SoftI2C::SoftI2C(uint8_t dataPin, uint8_t clockPin)
00051     : _dataPin(dataPin)
00052     , _clockPin(clockPin)
00053     , started(false)
00054     , acked(true)
00055     , inWrite(false)
00056     , readCount(0)
00057 {
00058     // Initially set the CLOCK and DATA lines to be outputs in the high state.
00059     pinMode(_clockPin, OUTPUT);
00060     pinMode(_dataPin, OUTPUT);
00061     digitalWrite(_clockPin, HIGH);
00062     digitalWrite(_dataPin, HIGH);
00063 }
00064 
00065 unsigned int SoftI2C::maxTransferSize() const
00066 {
00067     return 0xFFFF;
00068 }
00069 
00070 void SoftI2C::start()
00071 {
00072     pinMode(_dataPin, OUTPUT);
00073     if (started) {
00074         // Already started, so send a restart condition.
00075         digitalWrite(_dataPin, HIGH);
00076         digitalWrite(_clockPin, HIGH);
00077         i2cDelay();
00078     }
00079     digitalWrite(_dataPin, LOW);
00080     i2cDelay();
00081     digitalWrite(_clockPin, LOW);
00082     i2cDelay();
00083     started = true;
00084     acked = true;
00085 }
00086 
00087 void SoftI2C::stop()
00088 {
00089     pinMode(_dataPin, OUTPUT);
00090     digitalWrite(_dataPin, LOW);
00091     digitalWrite(_clockPin, HIGH);
00092     i2cDelay();
00093     digitalWrite(_dataPin, HIGH);
00094     i2cDelay();
00095     started = false;
00096     inWrite = false;
00097 }
00098 
00099 #define I2C_WRITE   0x00
00100 #define I2C_WRITE10 0xF0
00101 #define I2C_READ    0x01
00102 #define I2C_READ10  0xF1
00103 
00104 void SoftI2C::startWrite(unsigned int address)
00105 {
00106     start();
00107     inWrite = true;
00108     if (address < 0x80) {
00109         // 7-bit address.
00110         write((uint8_t)((address << 1) | I2C_WRITE));
00111     } else {
00112         // 10-bit address.
00113         write((uint8_t)(((address >> 7) & 0x06)) | I2C_WRITE10);
00114         write((uint8_t)address);
00115     }
00116 }
00117 
00118 void SoftI2C::write(uint8_t value)
00119 {
00120     uint8_t mask = 0x80;
00121     while (mask != 0) {
00122         writeBit((value & mask) != 0);
00123         mask >>= 1;
00124     }
00125     if (readBit())  // 0: ACK, 1: NACK
00126         acked = false;
00127 }
00128 
00129 bool SoftI2C::endWrite()
00130 {
00131     stop();
00132     return acked;
00133 }
00134 
00135 bool SoftI2C::startRead(unsigned int address, unsigned int count)
00136 {
00137     start();
00138     inWrite = false;
00139     if (address < 0x80) {
00140         // 7-bit address.
00141         write((uint8_t)((address << 1) | I2C_READ));
00142     } else {
00143         // 10-bit address.
00144         write((uint8_t)(((address >> 7) & 0x06)) | I2C_READ10);
00145         write((uint8_t)address);
00146     }
00147     if (!acked) {
00148         readCount = 0;
00149         return false;
00150     }
00151     readCount = count;
00152     return true;
00153 }
00154 
00155 unsigned int SoftI2C::available()
00156 {
00157     return readCount;
00158 }
00159 
00160 uint8_t SoftI2C::read()
00161 {
00162     uint8_t value = 0;
00163     for (uint8_t bit = 0; bit < 8; ++bit)
00164         value = (value << 1) | readBit();
00165     if (readCount > 1) {
00166         // More bytes left to read - send an ACK.
00167         writeBit(false);
00168         --readCount;
00169     } else {
00170         // Last byte - send the NACK and a stop condition.
00171         writeBit(true);
00172         stop();
00173         readCount = 0;
00174     }
00175     return value;
00176 }
00177 
00178 void SoftI2C::writeBit(bool bit)
00179 {
00180     pinMode(_dataPin, OUTPUT);
00181     if (bit)
00182         digitalWrite(_dataPin, HIGH);
00183     else
00184         digitalWrite(_dataPin, LOW);
00185     i2cDelay();
00186     digitalWrite(_clockPin, HIGH);
00187     i2cDelay();
00188     digitalWrite(_clockPin, LOW);
00189     i2cDelay();
00190 }
00191 
00192 bool SoftI2C::readBit()
00193 {
00194     pinMode(_dataPin, INPUT);
00195     digitalWrite(_dataPin, HIGH);
00196     digitalWrite(_clockPin, HIGH);
00197     bool bit = digitalRead(_dataPin);
00198     i2cDelay();
00199     digitalWrite(_clockPin, LOW);
00200     i2cDelay();
00201     return bit;
00202 }
 All Classes Files Functions Variables Enumerations Enumerator