Home » Robots » Arduino » Bit Banged I2C Master on ROBOTC for Arduino

Bit Banged I2C Master on ROBOTC for Arduino

imageAfter spending two hours working on the changelog for the upcoming release of my driver suite, I thought I’d go play with something that was a bit more fun.

I’m part of the ROBOTC for Arduino test group, which has been a lot of fun. The Arduino build does not have I2C support in the firmware yet, so I was wondering how hard it would be to implement a bit-banged I2C master.  Turns out to be a lot easier than I thought.  The code even worked first time I ran it!  You can imagine my surprise. I haven’t tested the reading part yet, though, so there’s still room for hours of frustration and despair. The sensor I used is a Mindsensors Magic Wand.

The demo is nothing fancy, just a little running light. You can view the code below the video, as you can see it’s nothing to write home about. You can download the code here: [LINK]

 

#pragma config(CircuitBoardType, typeCktBoardDuemilanove)
#pragma config(Sensor, dgtl2, SDATA, sensorDigitalOut)
#pragma config(Sensor, dgtl3, SCLK, sensorDigitalOut)
//*!!Code automatically generated by 'ROBOTC' configuration wizard !!*//

/** file BitBangedI2CMaster.c
* brief Bit Banged I2C master
*
* BitBangedI2CMaster.c provides a very simple bit banged I2C master.
*
* Changelog:
* - 0.1: Initial release
*
* License: You may use this code as you wish, provided you give credit where its due.
*
* Credit: Adapted from http://www.keil.com/download/docs/64.asp
*
* author Xander Soldaat
* date 20 February 2011
* version 0.1
*/

const ubyte LOW = 0;
const ubyte HIGH = 1;

void i2c_start (); // Sends I2C Start
void i2c_stop (); // Sends I2C Stop
void i2c_write (ubyte output_data); // Writes data over the I2C bus
ubyte i2c_read (); // Reads data from the I2C bus
void PCF8574write(ubyte data);

task main () {
  while (true) {
    for (int i = 0; i < 8; i++) {
      PCF8574write(~(1<<i));
      wait1Msec(50);
    }
  }
}

void PCF8574write(ubyte data) {
  i2c_start();
  i2c_write(0x70); // address
  i2c_write(data); // value
  i2c_stop();
}

/**
* I2C Functions - Bit Banged
*/

/**
* Sends I2C Start Transfer
*/
void i2c_start ()
{
  SensorType[SDATA] = sensorDigitalOut;
  SensorValue[SDATA] = HIGH; // Set data line high
  SensorValue[SCLK] = HIGH; // Set clock line high
  SensorValue[SDATA] = LOW; // Set data line low (START SIGNAL)
  SensorValue[SCLK] = LOW; // Set clock line low
}

/**
* Sends I2C Stop Transfer
*/
void i2c_stop ()
{
  SensorType[SDATA] = sensorDigitalOut;
  SensorValue[SCLK] = LOW; // Set clock line low
  SensorValue[SDATA] = LOW; // Set data line low
  SensorValue[SCLK] = HIGH; // Set clock line high
  SensorValue[SDATA] = HIGH; // Set data line high (STOP SIGNAL)
  SensorType[SDATA] = sensorDigitalIn; // Put port pin into HiZ
}

/**
* Write data over the I2C bus
*
* @param output byte data to be written to the slave
*/
void i2c_write (ubyte output_data)
{
  SensorType[SDATA] = sensorDigitalOut;

  for(int i = 0; i < 8; i++) // Send 8 bits to the I2C Bus
  {
    // Output the data bit to the I2C Bus
    SensorValue[SDATA] = ((output_data & 0x80) ? HIGH : LOW);
    output_data <<= 1; // Shift the byte by one bit
    SensorValue[SCLK] = HIGH; // Clock the data into the I2C Bus
    SensorValue[SCLK] = LOW;
  }

  SensorType[SDATA] = sensorDigitalIn; // Put data pin into read mode
  SensorValue[SCLK] = HIGH; // Clock the ACK from the I2C Bus
  SensorValue[SCLK] = LOW;
}

/**
* Read data from the I2C bus
*
* @return data read from slave
*/
ubyte i2c_read ()
{
  unsigned char index, input_data;

  SensorType[SDATA] = sensorDigitalIn;// Put data pin into read mode

  input_data = 0x00;

  for(index = 0; index < 8; index++) // Send 8 bits to the I2C Bus
  {
    input_data <<= 1; // Shift the byte by one bit
    SensorValue[SCLK] = HIGH; // Clock the data into the I2C Bus
    input_data |= SensorValue[SDATA]; // Input the data from the I2C Bus
    SensorValue[SCLK] = LOW;
  }

  return input_data;
}