You are on page 1of 7

Search the Arduino Playground

Manuals and Curriculum


(http://playground.arduino.cc/Main/ManualsAndCurriculum)
Arduino StackExchange
(http://arduino.stackexchange.com)
Board Setup and Conguration
(http://playground.arduino.cc/Main/ArduinoCoreHardware)
Development Tools
(http://playground.arduino.cc/Main/DevelopmentTools)
Arduino on other Chips
(http://playground.arduino.cc/Main/ArduinoOnOtherAtmelChips)
Interfacing With Hardware
(http://playground.arduino.cc/Main/InterfacingWithHardware)
-

Output
(http://playground.arduino.cc/Main/InterfacingWithHardware#Output)

Input
(http://playground.arduino.cc/Main/InterfacingWithHardware#InputTOC)

User Interface
(http://playground.arduino.cc/Main/InterfacingWithHardware#ui)

Storage
(http://playground.arduino.cc/Main/InterfacingWithHardware#Storage)

Communication
(http://playground.arduino.cc/Main/InterfacingWithHardware#Communication)

Power supplies
(http://playground.arduino.cc/Main/IntWithHWPwrSup)

General
(http://playground.arduino.cc/Main/InterfacingWithHardware#General)

Interfacing with Software


(http://playground.arduino.cc/Main/InterfacingWithSoftware)
User Code Library
(http://playground.arduino.cc/Main/GeneralCodeLibrary)
-

Snippets and Sketches


(http://playground.arduino.cc/Main/SketchList)

Libraries
(http://playground.arduino.cc/Main/LibraryList)

Tutorials
(http://playground.arduino.cc/Main/TutorialList)

Suggestions & Bugs


(https://github.com/arduino/arduino/issues)
Electronics Technique
(http://playground.arduino.cc/Main/ElectroInfoResources)
Sources for Electronic Parts
(http://playground.arduino.cc/Main/Resources)

Related Hardware and Initiatives


(http://playground.arduino.cc/Main/SimilarBoards)
Arduino People/Groups & Sites
(http://playground.arduino.cc/Main/People)
Exhibition
(http://playground.arduino.cc/Projects/ArduinoUsers)
Project Ideas
(http://playground.arduino.cc/Projects/Ideas)
Languages
(http://playground.arduino.cc/Main/Languages)
Participate
(http://playground.arduino.cc/Main/Participate)
-

Formatting guidelines
(http://playground.arduino.cc/Main/Participate#contribrules)

All recent changes


(http://playground.arduino.cc/Site/AllRecentChanges)

PmWiki
(http://playground.arduino.cc/PmWiki/PmWiki)

WikiSandBox training
(http://playground.arduino.cc/Main/WikiSandbox)

Basic Editing
(http://playground.arduino.cc/PmWiki/BasicEditing)

Documentation index
(http://www.pmwiki.org/wiki/PmWiki/DocumentationIndex)

Software I2C library


The library can be downloaded from Github: https://github.com/felias-fogg/SoftI2CMaster
(https://github.com/felias-fogg/SoftI2CMaster).

Why another I2C library?


The standard I2C library for the Arduino is the Wire library (http://arduino.cc/en/Reference/Wire).
While this library is sucient most of the time, there are situations when it cannot be used:
-

the I2C pins A4/A5 are in use already for other purposes,

the code shall run on both an ATmega processor with 16 MHz and an ATtiny processor with 1 MHz,

you need to use the repeated start condition, for instance when interfacing to the infrared
thermometer MLX90614 (http://bildr.org/2011/02/mlx90614-arduino/).

In order to deal with these cases, one could use the I2cMaster library by landis
(https://github.com/landis/arduino/tree/master/libraries/I2cMaster). However, it is very slow. For
example, on a 8Mhz processor, the I2C bus frequency is 20kHz. So you cannot use it to interface to
SMbus devices on processors with a clock less than 8MHz.
I adapted Peter Fleury's I2C software library (http://homepage.hispeed.ch/petereury/avrsoftware.html) that is written in assembler, extremely light weight and very fast. Even on an ATtiny
running with 1MHz, one can still operate the bus with 33 kHz, which implies that you can drive slave
devices that use the SMBus protocol (which timeout if the the bus frequency is below 10 kHz).

Installation
Just download the Zip-File from github (https://github.com/felias-fogg/SoftI2CMaster), uncompress,
rename the directory to SoftI2CMaster and move it into the libraries folder. In case you have not
installed a library before, consult the the respective help page (http://arduino.cc/en/Guide/Libraries).

Importing the library


In order to use the library, you have to import it using the include statement:
#include<SoftI2CMaster.h>

In the program text before the include statement, some compile-time parameters have to be specied,
such as which pins are used for the data (SDA) and clock (SCL) lines. These pins have to be specied in
a way so that port manipulation commands (http://www.arduino.cc/en/Reference/PortManipulation)
can be used. So instead of specifying the number of the digital pin (0-19) the port (PORTB, PORTC,
PORTD) and the port pin has to be specied. The mapping is explained here
(http://www.arduino.cc/en/Reference/PortManipulation). For example, if you want to use digital pin 2
for SCL and digital pin 14 (= analog pin 0) for SDA, you have to specify port pin 2 of PORTD for SCL and
port pin 0 of PORTC for SDA:
#defineSCL_PIN2
#defineSCL_PORTPORTD
#defineSDA_PIN0
#defineSDA_PORTPORTC
#include<SoftI2CMaster.h>

Conguration
There are a few other constants that you can dene in order to control the behavior of the library.
#defineI2C_TIMEOUT...

Since slave devices can stretch the low period of the clock indenitely, they can lock up the MCU. In
order to avoid this, one can dene I2C_TIMEOUT. Specify the number of milliseconds after which the
I2C functions will time out. Possible values are 0 (no time out) to 10000 (i.e., 10 seconds).
#defineI2C_NOINTERRUPT1

With this denition you disable interrupts between issuing a start condition and terminating the
transfer with a stop condition. Usually, this is not necessary. However, if you have an SMbus device
that can timeout, one may want to use this feature. Note however, that in this case interrupts become
unconditionally enabled after calling i2c_stop() .
#defineI2C_CPUFREQ...

If you are changing the CPU frequency dynamically using the clock prescale register CLKPR and intend
to call the I2C functions with a frequency different from F_CPU, then dene this constant with the
correct frequency. For instance, if you used a prescale factor of 8, then the following denition would
be adequate:
#defineI2C_CPUFREQ(F_CPU/8)
#defineI2C_FASTMODE1

The standard I2C bus frequency is 100kHz. Often, however, devices permit for faster transfers up to
400kHz. If you want to allow for the higher frequency, then the above denition should be used.
#defineI2C_SLOWMODE1

In case you want to slow down the transfer to 25kHz, you can use this denition (in this case, do not
dene I2C_FASTMODE ).
I have measured the maximum bus frequency with different processor frequencies. The results are
displayed in the following table.


I2C slow mode kHz
I2C standard mode kHz
I2C fast mode kHz

1MHz
25
40
40

2MHz
25
80
80

4MHz
25
100
150

8MHz
25
100
300

16MHz
25
100
400

20MHz
25
100
400

Interface
The following functions are provided by the library:
i2c_init()

Initialize the I2C system. Must be called once in setup() . Will return false if SDA or SCL is on a
low level, which means that the bus is locked.
i2c_start( addr | R/W-bit )

Initiates a transfer to the slave device with the (8-bit) I2C address addr. Note that this library uses the
8-bit addressing scheme different from the 7-bit scheme in the Wire library. In addition the R/W-bit
must be specied as I2C_WRITE (=0) or I2C_READ (=1).
i2c_start_wait( addr | R/W-bit )

Similar to the i2c_start function. However, it tries repeatedly to start the transfer until the device
sends an acknowledge.
i2c_rep_start( addr | R/W-bit )

Sends a repeated start condition, i.e., it starts a new transfer without sending rst a stop condition.
i2c_stop()

Sends a stop condition and thereby releases the bus.


i2c_write( byte )

Sends a byte to the previously addressed device. Returns true if the device replies with an ACK.
i2c_read( last )

Requests to receive a byte from the slave device. If last is true , then a NAK is sent after receiving
the byte nishing the read transfer sequence.

Example
As a small example, let us consider reading the values from the BMA020 acceleration sensor.
// Simple sketch to read out BMA020 using SoftI2C
#dene SDA_PORT PORTD
#dene SDA_PIN 3
#dene SCL_PORT PORTD
#dene SCL_PIN 5
#include <SoftI2CMaster.h>

#dene BMAADDR 0x70


int xval, yval, zval;
boolean setControlBits(uint8_t cntr)
{
Serial.println(F("Soft reset"));
if (!i2c_start(BMAADDR | I2C_WRITE)) {
return false;
}
if (!i2c_write(0x0A)) {
return false;
}
if (!i2c_write(cntr)) {
return false;
}
i2c_stop();
return true;
}
boolean initBma(void)
{
if (!setControlBits(B00000010)) return false;;
delay(100);
return true;
}
int readOneVal(boolean last)
{
uint8_t msb, lsb;
lsb = i2c_read(false);
msb = i2c_read(last);
return (int)((msb<<8)|lsb)/64;
}
boolean readBma(void)
{
xval = 0xFFFF;
yval = 0xFFFF;
zval = 0xFFFF;
if (!i2c_start(BMAADDR | I2C_WRITE)) return false;
if (!i2c_write(0x02)) return false;
if (!i2c_rep_start(BMAADDR | I2C_READ)) return false;
xval = readOneVal(false);
yval = readOneVal(false);
zval = readOneVal(true);
i2c_stop();
return true;
}

//--------------------------------------------------------void setup(void) {
Serial.begin(19200); /
if (!initBma()) {
Serial.println(F("INIT ERROR"));

Serial.println(F("INIT ERROR"));
}
}
void loop(void){
if (!readBma()) Serial.println(F("READ ERROR"));
Serial.print(F("X="));
Serial.print(xval);
Serial.print(F(" Y="));
Serial.print(yval);
Serial.print(F(" Z="));
Serial.println(zval);
delay(1000);
}
[Get Code] (http://playground.arduino.cc/Main/SoftwareI2CLibrary?action=sourceblock&num=1)

Alternative Interface
Meanwhile, I have written a wrapper around SoftI2CMaster that emulates the Wire library
(http://arduino.cc/en/Reference/Wire) (master mode only). It is another c++-header le called
SoftWire.h which you need to include instead of SoftI2CMaster.h . Directly after this include
statement you need to create a Wire instance:
#dene SDA_PORT ...
#include <SoftWire.h>
SoftWire Wire = SoftWire();
...
setup() {
Wire.begin()
...
}
[Get Code] (http://playground.arduino.cc/Main/SoftwareI2CLibrary?action=sourceblock&num=2)

This interface sacrices some of the advantages of the original library, in particular its small footprint,
but comes handy if you need a replacement of the original Wire library. The following table lists the
memory requirements. As one can see, SoftI2CMaster will be particularly useful on smaller
processors.

Flash memory
RAM

Wire
1956
208

SoftI2CMaster SoftWire
252
712
0
64

Shortcomings
The entire code had to be included in the header le, because the communication ports in the code
need to be determined at compile time. This implies that this header le should only be included once
per project (usually in the sketch).

Another shortcoming is that one cannot use ports H and above on an ATmega256. The reason is that
these ports are not directly addressable.

Share

NEWSLETTER

Enter your email to sign up

2016 Arduino

Copyright Notice (https://arduino.cc/en/Main/CopyrightNotice)

Contact us (https://arduino.cc/en/Main/ContactUs)

(https://twitter.com/arduino)
(https://plus.google.com/+Arduino)
(http://youtube.com/arduinoteam)

(http://www.facebook.com/ocial.arduino)
(http://www.ickr.com/photos/arduino_cc)