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;
}

Tags