This sketch talks to a small, inexpensive I2C EEPROM chip. This sketch, unfortunately, is somewhat larger and more involved than many of our 'demo sketches'; but unfortunately, talking I2C is a somewhat larger and more involved process than blinking an LED..

In particular, to do I2C one must inevitably be prepared to dive into the datasheet of whatever particular I2C device one is talking to. The I2C bus protocol itself is only about the 'shape' of communications -- how to take turns talking, when 'words' and 'sentences' end, and so forth -- but specifies basically nothing about the actual 'language' being 'spoken'. In true Tower of Babel style, each I2C device basically speaks its own language, described in its datasheet.

/*                                             -*- mode:C++ -*-
 * Sketch description: Demo connecting an I2C EEPROM to an IXM.  Count
 *   how many times the button has been pushed since reset, and store
 *   that in an external EEPROM.
 *   EEPROM used: M24C02-WBN6P (ST Microelectronics, 256x8bit, $0.47
 *   qty 1 at mouser.com 3/20/11).  All references to 'sections',
 *   below, refer to sections of the ST M24C02 datasheet.
 *   (And yes, talking to a 2Kb external EEPROM is a little silly,
 *   since the IXM has a bigger EEPROM onboard, but the M24C02-WBN6P
 *   was "I2C demo friendly": Low power, through-hole, and cheap.)
 * Sketch author: Dave Ackley
 * Schematic:
 *  U1: IXM
 *  U2: M24C02-WBN6P.  I2C device code is 0x50 (7 bit, section 3.5)
 * +--------------+                +------+
 * | U1   N    GND|-          +--E0|1    8|Vcc--D2
 * |            D3|-/WC       +--E1|2 U2 7|/WC--D3
 * |     LED    Tx|-SDA       +--E2|3    6|SCL--Rx
 * | W   FACE  12V|-          +-Vss|4    5|SDA--Tx
 * |            Rx|-SCL       |    +------+
 * |            D2|-Vcc       |
 * |      S    GND|-Vss      GND
 * +--------------+

#define I2C_BLOCK I2C_2
#define I2C_DEVICE_ADDRESS 0x50

#define EEPROM_COUNT_ADDRESS 124   // Any multiple of four from 0 to 252 is safe..

SFBHWI2C i2c(I2C_BLOCK);           // Allocate the I2C control object.
u8 buf[5];                         // Data buffer; only need 1+4 bytes for this sketch

// I2C transactions run asynchronously; this function just waits until
// the status says it's done (or some error state occurred).
void letI2CFinish() {
  while (i2c.status() > I2C_MODE_DONE) delay(1);

// Here we do a 'page write' to the EEPROM.  Section 3.6.2 says not to
// cross a 16 byte boundary in a single write -- and a multiple of
// four starting address guarantees that (but is somewhat overkill).
void writeCount(u32 newValue) {
  buf[0] = EEPROM_COUNT_ADDRESS;             // EEPROM address at which to start writing
  for (int i = 0; i<4; ++i)                  // Loop to extract bytes..
    buf[i+1] = (newValue>>(i*8))&0xff;       // ..from the value provided
  i2c.transmit(I2C_DEVICE_ADDRESS, 5, buf);  // Start transmission of addr + four bytes
  letI2CFinish();                            // Wait for I2C transaction to finish
  delay(5);                                  // + another 5ms (worst-case EEPROM write time)

// Here we do a 'random address sequential read' to the EEPROM
// (sections 3.7.1 and 3.7.3).  This function uses the 'transceive'
// method which combines a transmitting phase and a receiving phase
// into a single I2C transaction.  (If there's only a single I2C bus
// master, this could also be done with sequential transmit() and
// receive() calls.)
u32 readCount() {
  buf[0] = EEPROM_COUNT_ADDRESS;             // EEPROM address to start reading from
  i2c.transceive(I2C_DEVICE_ADDRESS, 1, buf, 4, buf);  // xmt buf[0] then rcv buf[0..3]
  letI2CFinish();                            // Wait for I2C transaction to finish

  u32 count = 0;                             // Place to develop count
  for (int i = 0; i<4; ++i)                  // Scan received data
    count |= buf[i]<<(i*8);                  // Pack bytes back into u32
  return count;                              // Return result

// Count management functions (with unused optional argument, to be reflexes)
void resetCount(u8* = 0) {
  writeCount(0);                             // Aw, all those counts, forgotten..
  logNormal("Button push count reset\n");    // Announce we did it
void incrementCount(u8* = 0) {
  u32 count = readCount()+1;                 // Get the count, bump it
  writeCount(count);                         // Store it
  logNormal("Button pushes = %d\n",count);   // Report it

void setup() {
  pinMode(EEPROM_POWER_PIN, OUTPUT);          // U2 draws <=3mA, so we power it via a pin
  pinMode(EEPROM_WRITE_PROTECT_PIN, OUTPUT);  // Write protect feature, not used in this..
  digitalWrite(EEPROM_WRITE_PROTECT_PIN, LOW);// ..sketch; we allow all EEPROM writes

  i2c.init(I2C_PINS,400);                     // Init I2C at 400KHz

  digitalWrite(EEPROM_POWER_PIN, LOW);        // Power down the EEPROM for good measure
  delay(10);                                  // Wait a bit
  digitalWrite(EEPROM_POWER_PIN, HIGH);       // Power it up

  Body.reflex('r',resetCount);                // Set up reflexes

void loop() {
  if (buttonDown()) {                         // Wait for button push
    incrementCount();                         // Log it
    while (buttonDown()) delay(10);           // Wait for button release
  ledSet(BODY_RGB_BLUE_PIN, millis()&0x480);  // Blink V for victory (in morse code..)

#define SFB_SKETCH_CREATOR_ID B36_4(d,a,v,e)
#define SFB_SKETCH_PROGRAM_ID B36_5(i,2,c,e,e)
#define SFB_SKETCH_COPYRIGHT_NOTICE "2011 Dave Ackley Placed in the public domain"

Generated on Fri Apr 22 06:54:10 2011 for SFB by doxygen 1.5.9