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_PINS I2C2_PINS_EAST_TX_RX #define EEPROM_POWER_PIN EAST_D2_PIN #define EEPROM_WRITE_PROTECT_PIN EAST_D3_PIN #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 Body.reflex('i',incrementCount); } 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"