For a Linux embedded training, I need to find something fun to plug on an AVR32 board. The board used for the training is a NGW100 board. I decided to try to use the I2C bus. I have several I2C stuff on the desk, but nothing really fun and I don’t want to solder a lot of stuff, and spend a lot of time on this. I decided to use a Arduino board as a I2C slave device and plug this to the NGW100 board.
First step: Simply use the Arduino IDE and the Wire lib. I use an Seeeduino because I need an Arduino that works at 3.3v level. Here the code :
#include <Wire.h> void setup() { Wire.begin(4); // join i2c bus with address #4 Wire.onReceive(receiveEvent); // register event Wire.onRequest(requestEvent); // register event Serial.begin(38400); // start serial for output Serial.println("Boot Ok"); } void loop() { delay(100); } void receiveEvent(int howMany) { char c = NULL; while(Wire.available()) // loop through all { c = Wire.receive(); // receive byte as a character Serial.print(c); // print the character } Serial.println(); Serial.println("==="); } void requestEvent() { Serial.println("read"); Wire.send("Hello world from Arduino"); }
To test the Arduino I used a Bus Pirate, this is quite simple and fun, here a little snipset of my initial test with the BP (note the string are different). The I2C slave is at the 0×4 address (check the setup()).
Searching I2C address space. Found devices at: 0x08(0x04 W) 0x09(0x04 R) Read content from the device, 'ABCD' I2C>[0x09 rrrrrr] I2C START BIT WRITE: 0x09 ACK READ: 0x41 READ: ACK 0x42 READ: ACK 0x43 READ: ACK 0x44 READ: ACK 0xFF READ: ACK 0xFF NACK I2C STOP BIT I2C> send content to the device 'ABC' I2C>[0x08 0x41 0x42 0x43] I2C START BIT WRITE: 0x08 ACK WRITE: 0x41 ACK WRITE: 0x42 ACK WRITE: 0x43 ACK I2C STOP BIT
Second step: Plug the Arduino to the NGW100. I used the wrapping technique. Simply connect SDA, SCL, and GND. (NGW100 pinouts : SDA=>9, SCL=>10, GND=>2)
On Linux, load the I2C-GPIO kernel module. On OpenWRT (used on the NGW100), simply load the kmod-i2c-gpio package.
Final step: If everything is Ok, we can now test the communication. I used a small piece of C code to deal with I2C on Linux.
#include <string.h> #include <stdio.h> #include <stdlib.h> #include <linux/i2c-dev.h> #include <sys/ioctl.h> #include <fcntl.h> void i2c_run(void) { int file; char filename[40]; int addr = 0x4; char buf[32] = {0}; int i; sprintf(filename,"/dev/i2c-0"); if ((file = open(filename,O_RDWR)) < 0) { printf("Failed to open the bus."); exit(1); } if (ioctl(file,I2C_SLAVE,addr) < 0) { printf("Failed to acquire bus access and/or talk to slave.\n"); exit(1); } i = 24; // read I2C if (read(file,buf,i) != i) { printf("Failed to read from the i2c bus.\n"); } else { printf("Read %d bytes from I2C: [%s]\n",i,buf); } sprintf(buf,"IC2 from Linux to Arduino"); i = strlen(buf); if (write(file,buf,i) != i) { printf("Failed to write to the i2c bus.\n"); } else { printf("Sent %d bytes to I2C: [%s]\n",i,buf); } } int main() { i2c_run(); return 0; }
As you can see this code is a bit rude, but works really well : Read the I2C bus, and send a sample string, a proof ? :)
Of course, I used string values but in real life a small protocol shoud be used. Another important thing: I used a NGW100 but you can use the same idea on all Linux embedded board like the Fonera, or anything else.
Update: Of course you can use the i2c-tools on Linux to detect your own device. To do that : Grab the i2c-tools source, and cross compile it for the AVR32. (You only have to change the CC path in the Makefile).
/Enjoy small Linux