|
Table of Contents
|
This information corresponds to the I2C driver that's in the main (master) branch of the GIT tree. This is not a flattened driver yet, but is working.
Xilinx I2C Driver Kernel Configuration
I2C is not enabled in the current default kernel configuration. The following steps may be used to enable the driver in the kernel configuration
- From the device drivers menu, select I2C support
- Select I2C device interface to allow access from user space thru the device interface
- Deselect Autoselect pertinent helper modules if it is selected
- Select I2C algorithms
- Select Xilinx IIC interface
Reading The I2C EEPROM From A User Space Application
The following example reads the I2C EEPROM on the ML507 board. This examle can be downloaded at the bottom of this page by clicking on Files.
This assumes the /dev/i2c/0 device file was created by the user or using udev.
NOTE: The EEPROM higher level driver referenced below cannot be built into the kernel for this example to work. An error that indicates the application cannot set the I2C address will occur if this is the case.
/* Read input line for args of offset and bytes to read from IIC device.
Do read and dump contents.
Modified to have EEPROM_ADDR as parameter
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include "i2c.h"
#include "i2c-dev.h"
#include "buffDump.h"
int main(int argc, char** argv)
{
unsigned offsetAddr;
unsigned eepromAddr;
int count, bytesToRead;
unsigned char *i2c_buffer;
unsigned char i2c_ptr[2];
unsigned argRead, bytesRead;
int dev_i2c;
if(argc != 4) {
printf("Usage i2c_read 0xXXXX (EPROM Addr) 0xXXXX (offset) 0xXXXX (bytes to read)\n");
return(-1);
}
argRead = sscanf(argv[1],"0x%x", &eepromAddr);
argRead += sscanf(argv[2],"0x%x", &offsetAddr);
argRead += sscanf(argv[3],"0x%x", &bytesToRead);
if(argRead != 3 || bytesToRead <= 0) {
printf("Couldn't scan Address, offset & bytes\n");
return(-1);
}
printf("Reading from I2C EEPROM at 0x%X, Offset=0x%X, Bytes0x%X\n", eepromAddr, offsetAddr, bytesToRead);
i2c_buffer = malloc(sizeof(char) * bytesToRead);
if(i2c_buffer == NULL) {
printf("STATUS: Couldn't malloc buffer.\n");
return(-1);
}
// Open and read i2c
if ((dev_i2c = open("/dev/i2c/0", O_RDWR)) < 0) {
printf("Cannot Open I2C Master Device\n");
exit(1);
}
if (ioctl(dev_i2c, I2C_SLAVE, eepromAddr) < 0) {
printf("Cannot set I2C address\n");
exit(1);
}
// Set address using 16 or 8 bit address, default to 8 bit address
#ifdef ADDR_16
i2c_ptr[1] = (offsetAddr) & 0xFF;
i2c_ptr[0] = (offsetAddr>>8) & 0xFF;
if(write(dev_i2c, i2c_ptr, 2) != 2) {
printf("I2C write failed\n");
exit(1);
}
#else
i2c_ptr[0] = (offsetAddr) & 0xFF;
if(write(dev_i2c, i2c_ptr, 1) != 1) {
printf("I2C write failed\n");
exit(1);
}
#endif
// Read from device
bytesRead = read(dev_i2c, i2c_buffer, bytesToRead);
if(bytesRead != bytesToRead) {
printf("I2C read failed. Return code = %u\n", bytesRead);
exit(1);
}
// Dump what we read
buffDump(i2c_buffer, bytesToRead);
return(0);
}
Using An I2C EEPROM Driver As A Higher Layer
A bug was corrected in the I2C driver on 10/6/08 such that you may need to pull the latest code for this to work.
I2C EEPROM Driver Kernel Configuration
There are higher layer drivers that allow the I2C driver to be used to access other devices such as the I2C serial EEPROM on the ML507 board. The following steps may be used to enable the driver in the kernel configuration.
- From the device drivers menu, select I2C support
- Select Miscellaneous I2C Chip support
- Select EEPROMs from most vendors
Adding An I2C EEPROM To The Device Tree
The following example shows adding the I2C EEPROM for the ML507 to it's device tree. The value of 0x050 is the I2C address of the EEPROM.
The device-tree generator for the EDK does not create this device on the I2C bus.
IIC: i2c@81600000 {
compatible = "xlnx,xps-iic-2.00.a";
interrupt-parent = <&xps_intc_0>;
interrupts = < 6 2 >;
reg = < 0x81600000 0x10000 >;
xlnx,clk-freq = <0x5f5e100>;
xlnx,family = "virtex5";
xlnx,gpo-width = <0x1>;
xlnx,iic-freq = <0x186a0>;
xlnx,scl-inertial-delay = <0x0>;
xlnx,sda-inertial-delay = <0x0>;
xlnx,ten-bit-adr = <0x0>;
#address-cells = <1>;
#size-cells = <0>;
m24c08@50 {
compatible = "at,24c08";
reg = <0x50>;
};
} ;
Kernel Console Output
The following kernel output (or similar) shows the EEPROM driver was started.
Device Tree Probing 'i2c'
81600000.i2c #0 at 0x81600000 mapped to 0xD1020000, irq=20
at24 0-0050: 1024 byte 24c08 EEPROM (writable)
SysFs Interface
The EEPROM driver allows the contents of the EEPROM to be seen in the sys file system at /sys/bus/i2c/devices/0-0050/eeprom. The file, eeprom, is a file that can be read and
written from user space.
If the sys file system is not mounted (no /sys dir), then the following commands will create and mount it.
bash>mkdir /sys
bash>mount - t sysfs sysfs sys
The following shell commands can view the contents of the eeprom by 1st capturing it and then displaying the file as binary data.
bash>more /sys/bus/i2c/devices/0-0050/eeprom > eeprom.txt | od -x
The following command will write "01234567890DEADBEEFCAFE" to the EEPROM. Be careful as the ethernet MAC address is in the EEPROM and can be overwritten.
bash>echo 0123456789DEADBEEFCAFE > /sys/bus/i2c/devices/0-0050/eeprom
Using An Aardvark I2C/SPI Activity Board For I2C EEPROM Testing
TotalPhase, the company that sells the Aardvark I2C test equipment, also sells a small board that we can use for our own testing, independent of the Aardvark. The board has an I2C EEPROM and an SPI EEPROM on it such that it can be connected to an FPGA board pretty easy.
http://www.totalphase.com/products/activity_board/
http://www.totalphase.com/download/pdf/activity-board-v1.00.pdf
http://www.totalphase.com/products/split_cable/
The point of this exercise is to have a standard test for the I2C that can be used across all boards.
See the following page, I2C With The Aardvark Board, for more information on how to do it.





