Raspberry Pi‎ > ‎GPIO Driver and Library‎ > ‎I2C‎ > ‎

I2C Python

eeprom 

Read and Write eeprom 

I2C and ISA Tools Documentation

This page documents our I2C and ISA debugging tools i2cdetecti2cdumpisadumpi2cgeti2cset and isaset.

These tools can be invaluable for hardware monitoring device identification and troubleshooting.

The ISA tools are included in the lm_sensors package in the directory prog/dump. The I2C tools used to be included the lm_sensors package as well, but how live in their own separate package named i2c-tools. They are low-level tools that should be used only after you have run our high-level user tool, sensors-detect.

Here is a summary of the tools:

I2C bus ISA bus
Bus scanning i2cdetect --
Device register dumping i2cdump isadump
Device register reading i2cget --
Device register setting i2cset isaset

All i2c tools operate on a specific i2c bus which is identified by number. The applicable i2c bus driver must be installed first. The bus numbers are assigned in the order the i2c bus drivers are installed.

The i2c bus number assignments can be listed by i2cdetect -l.

Using I2C tools for device identification

This is a small step-by-step example that is intended to give you an idea on how these tools can be used. Before you go on, please note that it is possible to break your hardware with these tools. Therefore you should be very careful when using them, you should know what you are doing and why you are doing it. If you don't really know what you are doing and you can't afford losing part of your hardware, please stop now.

Step 1: Identify the I2C buses

Here is an example of using i2cdetect to query an i2c bus.

# i2cdetect -l
i2c-0       smbus           SMBus ALI15X3 adapter at e800           Non-I2C SMBus adapter 
i2c-1       i2c             I2C Voodoo3/Banshee adapter             Bit-shift algorithm 
i2c-2       i2c             DDC Voodoo3/Banshee adapter             Bit-shift algorithm 

See also: i2cdetect(8) man page

Step 2: Query the I2C bus

It is apparent that bus 0 is the motherboard's SMBus. Use the bus number 0 as the argument to i2cdetect:

# i2cdetect 0
WARNING! This program can confuse your I2C bus, cause data loss and worse!
I will probe file /dev/i2c-0.
I will probe address range 0x03-0x77.
Continue? [Y/n] 
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- 2d -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- 48 49 -- -- -- -- -- --
50: 50 51 52 -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- 69 -- -- -- -- -- --
70: -- -- -- -- -- -- -- --

See also: i2cdetect(8) man page

Step 3: Identify the likely sensors device

The i2cdetect output above shows devices at addresses 0x2d, 0x48, 0x49, 0x50-52, and 0x69.

From consulting the chart below we can attempt to figure out what chips are likely to be sensors. I2C devices generally appear at standard bus addresses as shown below. This chart may prove helpful in device identification. Beware that this is only a hint though, virtually any type of device can live at any I2C address.

0 1 2 3 4 5 6 7 8 9 a b c d e f
00 battery
charger
battery
manager
smart
battery
10 sensor sensor sensor
20 sensor sensor sensor sensor
30 eeprom eeprom eeprom eeprom eeprom eeprom eeprom eeprom
40 sensor sensor sensor sensor sensor sensor sensor sensor
50 eeprom eeprom eeprom eeprom eeprom eeprom eeprom eeprom
60 clock
70 FSC
sensor

So, back to our example above: the devices at 0x2d, 0x48, and 0x49 are probably sensors (actually a single Winbond hardware monitoring chip responding at three addresses). The devices at 0x50 - 0x52 are most certainly EEPROMs on the three SDRAM DIMMs installed on the motherboard. And the device at 0x69 would be a clock chip.

Step 4: Dump the I2C device registers

Here is an example of using i2cdump to view the registers of an i2c device. This is useful to developers debugging the driver for the device. Warning: it is strongly advised that you do not run i2cdump on a device unless you have a preliminary idea of what this device could be. If you are looking for a sensor chip, you only want to try the addresses in the ranges 0x18-0x1a, 0x2c-0x2f and 0x48-0x4f, as documented in the chart above (and, for Fujitsu-Siemens computers, 0x73). Other addresses are very unlikely to be sensor chips, and attempting to dump them could harm your system.

Use the bus number as the first argument and the chip address as the second argument:

# i2cdump 0 0x2d
No size specified (using byte-data access)
WARNING! This program can confuse your I2C bus, cause data loss and worse!
I will probe file /dev/i2c-0, address 0x2d, mode byte
Continue? [Y/n]
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 
10: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 
20: 8a 8b de bb c9 d8 d0 1d ff ff aa c1 9e c1 9e e3 
30: ba cc a8 d8 b2 ed c2 e4 bb 3c 32 e1 e1 e1 00 00 
40: 01 c3 00 00 00 00 40 50 2d 01 01 40 01 95 00 a3 
50: 10 01 80 ff ff ff 00 00 11 ff ff ff ff ff ff ff 
60: 8a 8b de bb c9 d6 d1 1d ff ff aa c1 9e c1 9e e3 
70: ba cc a8 d8 b2 ed c2 e4 bb 3c 32 e1 e1 e1 00 00 
80: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 
90: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 
a0: 8b 8b de bb c8 d9 d1 1d ff ff ab c1 9e c1 9e e3 
b0: ba cc a8 d8 b2 ed c2 e4 bb 3c 32 e1 e1 e1 00 00 
c0: 01 c3 00 00 00 00 40 50 2d 01 01 40 01 95 00 a3 
d0: 10 01 80 ff ff ff 00 00 11 ff ff ff ff ff ff ff 
e0: 8a 8a de bb c9 d8 d1 1d ff ff aa c1 9e c1 9e e3 
f0: ba cc a8 d8 b2 ed c2 e4 bb 3c 32 e1 e1 e1 00 00  

See also: i2cdump(8) man page

Step 5: Identify the device

From looking at the bottom of this document of supported devices, we can see that the value 0xA3 at location 0x4F identifies this device as likely manufactured by Winbond. From here we could go to the Winbond web site and attempt to identify the device by scanning datasheets. Another approach is to look on the motherboard for devices with a Winbond logo.

isadump

For devices on the ISA bus, use isadump instead of i2cdumpisadump takes two arguments, the address and data port addresses.

For the typical device which is located at a base address of 0x290, use the command line isadump 0x295 0x296. For a device using a 'flat' address space instead of address and data ports, use the command line isadump -f 0xbase where base is the base address in hex.

See also: isadump(8) man page

i2cget and i2cset

For advanced debugging you can use the i2cget and i2cset commands to read from, respectively write to, an I2C device. As fori2cdump, you should be very careful when using these commands, if you don't know what you're doing, chances are that you'll break something. The general usage is:

i2cget <bus> <chip> <register>
i2cset <bus> <chip> <register> <value>

For example, the following writes the value 0x22 to register 0x10 of device 0x2d on i2c bus 0:

# i2cset 0 0x2d 0x10 0x22

See also: i2cget(8) man pagei2cset(8) man page

isaset

For advanced debugging you can use the isaset command to write to an ISA device. It is the ISA equivalent of i2cset. Again, you better know what you are doing when using this command. The usage is:

isaset <addrreg> <datareg> <register> <value>

For example, the following writes the value 0x22 to register 0x10 of an ISA device present at address 0x290:

# isaset 0x295 0x296 0x10 0x22

*****************************************************************************************************

Using i2c-tools

The faster way to do the first experiments with this board is by installing and using the i2c-tools.

i2c-tools is a package contains a heterogeneous set of I2C tools for Linux such as:

  • a bus probing tool
  • a chip dumper
  • a register-level access helpers
  • an EEPROM decoding scripts
  • ...and more

To install i2c-tools on the FOX Board just type:

~# apt-get update
~# apt-get install i2c-tools

Using i2cdetect

i2cdetect is an userspace program to scan an I2C bus for devices. It outputs a table with the list of detected devices on the specified bus.

Example of use:

~# i2cdetect -y 0
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f                             
00:          -- -- -- -- -- -- -- -- -- -- -- -- --                             
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --                             
20: 20 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --                             
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --                             
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --                             
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --                             
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --                             
70: -- -- -- -- -- -- -- --                                                     

In this case a device has been detected on address 20 hex.

Using i2cset and i2cset

i2cget is a small helper program to set registers visible through the I2C bus.

The follow simple command writes the byte value 255 to the I2C device at address 20 hex on the i2c bus 0 (/dev/i2c-0).

~# i2cset -y 0 0x20 255

If for example you are using a DAISY-22 module with a PCF8574 I2C I/O expander this command will set all the GPIO lines to 1.

i2cget i2cget is a small helper program to read registers visible through the I2C bus.

The follow simple command read a byte from an I2C device at address 20 hex on the i2c bus 0 (/dev/i2c-0).

~# i2cget -y 0 0x20
0x01

Python code example

python-smbus is a Python module allows SMBus access through the I2C /dev interface on Linux hosts. The host kernel must have I2C support, I2C device interface support, and a bus adapter driver.

Write a register

The following example sends a sequence of values from 0 to 255 to the PCF8574 I2C I/O expander at address 0x20.

  • write.py
    import smbus
    import time
     
    bus = smbus.SMBus(0)
     
    for a in range(0,256):
    	bus.write_byte(0x20,a)
    	time.sleep(0.1)

Run it by typing:

~# python write.py

Read a register

The following read the GPIO status of a PCF8574 I2C I/O expander at address 0x20. Note that we have to write 1 on the input line we want to read.

  • read.py
    import smbus
     
    I2C_ADDRESS = 0x20 
     
    bus = smbus.SMBus(0)
     
    #Set all ports in input mode
    bus.write_byte(I2C_ADDRESS,0xFF)
    
    #Read all the unput lines
    value=bus.read_byte(I2C_ADDRESS)
    print "%02X" % value

Run it by typing:

~# python read.py

C code example

Write a register

The following example sends a sequence of values from 0 to 255 to the PCF8574 I2C I/O expander at address 0x20 in C language.

  • write.c
    #include <stdio.h>
    #include <fcntl.h>
    #include <linux/i2c-dev.h>
    #include <errno.h>
    
    #define I2C_ADDR 0x20
     
    int main (void) {
    	int value;
    	int fd;
    
    	fd = open("/dev/i2c-0", O_RDWR);
    
    	if (fd < 0) {
    		printf("Error opening file: %s\n", strerror(errno));
    		return 1;
    	}
    
    	if (ioctl(fd, I2C_SLAVE, I2C_ADDR) < 0) {
    		printf("ioctl error: %s\n", strerror(errno));
    		return 1;
    	}
    
    	for (value=0; value<=255; value++) {
    		if (write(fd, &value, 1) != 1) {
    			printf("Error writing file: %s\n", strerror(errno));
    		}
    		usleep(100000);
    	}
    	return 0;
    }
    

Compile it by typing:

~# gcc write.c -o write

Then launch it:

~# ./write

Read a register

The following example get the state of the GPIO line from a PCF8574 I2C I/O expander at address 0x20.

  • read.c
    #include <stdio.h>
    #include <fcntl.h>
    #include <linux/i2c-dev.h>
    #include <errno.h>
    
    #define I2C_ADDR 0x20
     
    int main (void) {
    	char buffer[1];
    	int fd;
    
    	fd = open("/dev/i2c-0", O_RDWR);
    
    	if (fd < 0) {
    		printf("Error opening file: %s\n", strerror(errno));
    		return 1;
    	}
    
    	if (ioctl(fd, I2C_SLAVE, I2C_ADDR) < 0) {
    		printf("ioctl error: %s\n", strerror(errno));
    		return 1;
    	}
    
    	buffer[0]=0xFF;
    	write(fd, buffer, 1);
    	
    	read(fd, buffer, 1);
    	printf("0x%02X\n", buffer[0]);
    	return 0;
    }

Compile it by typing:

~# gcc read.c -o read

Then launch it:

~# ./read

************************************************************

本篇文章將講述如何使用 Raspberry Pi 進行讀/寫 EEPROM,以及 i2c-tool 的基本使用方式。

使用設備

要完成本篇文章所描述的部份,你需要以下幾種器材

  • 1. Raspberry Pi
  • 2. EEPROM 24c02
  • 3. 麵包板
  • 4. 單蕊線

硬體線路

下面的硬體線路使用 Fritzing 軟體來繪製,連線到 EEPROM 的線路很簡單,只要將 I²C 所需要使用的線路連接就好,其中 EEPROM 的 A0~A2 為位址線,這邊將其全部接地,因此此設備在 I²C 上的位址為 0x50 。(下載設計檔案)

麵包板連線

rsp_24c04_bb.png

電路連接

rsp_24c04_schem.png

讓 Raspberry Pi 可以讀取 i2c 設備

  • 1. 將 i2c 模組從黑名單中移除

    雖然我不清楚為什麼 i2c 模組並不會預設被 Raspberry Pi 載入,但是如果沒有將這個模組從黑名單中移除的話,你是無法使用 modeprobe 這個命令載入 i2c 模組的,移除的方式如下,首先編輯

    /etc/modprobe.d/raspi-blacklist.conf
    

    將裏面的資訊變成如下

    # blacklist spi and i2c by default (many users don't need them)
    
    blacklist spi-bcm2708
    # blacklist i2c-bcm2708
    

    完成後先進行重新啟動

  • 2. 載入 i2c 模組

    Raspberry Pi 預設沒有載入 i2c 模組,因此我們必須手動載入他

    pi@raspberrypi:/home/pi$ sudo modprobe i2c-dev
    

    如果你覺得每次都要手動載入很麻煩,可以修改 /etc/modules,將 i2c-dev 加入到檔案裏面,這樣重開之後,Raspberry Pi 會自動載入該載入的模組。

    載入好模組後,你會看到 /dev 下面多增加了 i2c-0 以及 i2c-1 兩個設備節點

    pi@raspberrypi:/home/pi$ ls /dev/i2c*
    /dev/i2c-0  /dev/i2c-1
    

安裝 i2c-tools

我們在這邊使用最常用的 i2c-tools,因為這個套件並沒有被預先安裝,因此你必須自己安裝

pi@raspberrypi:/home/pi$ sudo apt-get install i2c-tools

安裝完後,你會增加以下幾個命令

i2cdetect  i2cdump    i2cget     i2cset

這些命令的用途如下:

  • i2cdetect – 用來列舉 I2C bus 和上面所有的裝置
  • i2cdump – 顯示裝置上所有暫存器 (register) 數值
  • i2cget – 讀取裝置上某個暫存器值
  • i2cset – 修改裝置上的暫存器數值

使用 i2cdetect 察看目前有多少個 i2c bus

你可以使用以下命令來察看目前的系統有多少個 i2c bus,以我手上的 Raspberry Pi 為例

pi@raspberrypi:/home/pi$ sudo i2cdetect -l

會得到

i2c-0   i2c             bcm2708_i2c.0                           I2C adapter
i2c-1   i2c             bcm2708_i2c.1                           I2C adapter

在 rev.1 版本的 Raspberry Pi 上,i2c bus 是使用 i2c-0,而在現在販售的 rev.2 版本,則都改成使用 i2c-1 作為 i2c bus。

使用 i2cdetect 察看目前掛在 i2c bus 上的設備

知道你要查詢的 I²C bus 後,我們可以使用

pi@raspberrypi:/home/pi$ sudo si2cdetect -y 1

來查詢 i2c-1 bus 上的所有設備,所得到的結果如下

root@raspberrypi:/home/pi# i2cdetect -y 1
    0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: 50 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- UU -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --

這樣代表共有兩個裝置掛在 i2c-1 上,其中標示為 UU 的代表該設備有被偵測到並正在被 kernel driver 使用著,而在這邊顯示 0x50 的就是我們所使用的 EEPROM。

使用 i2cdump 查詢設備內所有暫存器

我們現在知道 EEPROM 是掛在 i2c-1 上的 0x50,若想知道 EEPROM 裏面的資訊,則可以使用 i2cdump 來獲得,i2cdump 的使用方式如下

Usage: i2cdump [-f] [-y] [-r first-last] I2CBUS ADDRESS [MODE [BANK [BANKREG]]]
I2CBUS is an integer or an I2C bus name
ADDRESS is an integer (0x03 - 0x77)
MODE is one of:
  b (byte, default)
  w (word)
  W (word on even register addresses)
  s (SMBus block)
  i (I2C block)
  c (consecutive byte)
  Append p for SMBus PEC

因此我們取得 i2c-1 上的 0x50 資訊,就使用

i2cdump -y 1 0x50

你會得到

root@raspberrypi:/home/pi# i2cdump -y 1 0x50
No size specified (using byte-data access)
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f    0123456789abcdef
00: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
10: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
20: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
30: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
40: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
50: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
60: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
70: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
80: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
90: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
a0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
b0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
c0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
d0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
f0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................

這邊 EEPROM 內的資訊都是 0xFF ,這是出廠時的預設狀況,我們可以使用 i2cset 來修改他的數值。

使用 i2cset 修改設備暫存器數值

如果我們想修改 EEPROM 裏面的數值,那要怎麼辦呢?這時候可以使用 i2cset 來幫忙完成,i2cset 的使用方式如下

Usage: i2cset [-f] [-y] [-m MASK] I2CBUS CHIP-ADDRESS DATA-ADDRESS [VALUE] ... [MODE]
  I2CBUS is an integer or an I2C bus name
  ADDRESS is an integer (0x03 - 0x77)
  MODE is one of:
    c (byte, no value)
    b (byte data, default)
    w (word data)
    i (I2C block data)
    s (SMBus block data)
    Append p for SMBus PEC

假如我們想要修改位於 i2c-1 上 0x50 的 0x12 暫存器,並將其數值修改為 5,我們命令就可以這樣下

i2cset -f -y 1 0x50 0x12 5

再一次使用 i2cdump,你會發現不再是清一色的 0xFF 了

root@raspberrypi:/home/pi# i2cdump -y 1 0x50
No size specified (using byte-data access)
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f    0123456789abcdef
00: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
10: ff ff 05 ff ff ff ff ff ff ff ff ff ff ff ff ff    ..?.............
20: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
30: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
40: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
50: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
60: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
70: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
80: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
90: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
a0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
b0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
c0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
d0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
f0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................

使用 i2cget 來取得暫存器的數值

有些時候我們只想要看某個暫存器位址,這時候使用 i2cget 是最快的選擇, i2cget 命令格式如下

Usage: i2cget [-f] [-y] I2CBUS CHIP-ADDRESS [DATA-ADDRESS [MODE]]
I2CBUS is an integer or an I2C bus name
ADDRESS is an integer (0x03 - 0x77)
MODE is one of:
  b (read byte data, default)
  w (read word data)
  c (write byte/read byte)
  Append p for SMBus PEC

因此,若我們要察看剛剛所設定的 0x12 暫存器,則可以用以下方式得到該暫存器的數值

root@raspberrypi:/home/pi# i2cget  -y 1 0x50 0x12
0x05

Python Script

#With the 16kB EEPROM used here, this does not work very well, because addresses
# use 2 bytes. Therefore we need an additional abstraction layer to read and write data. 
#Note, that the following program code is not final and only shown as an example.# #Simple I2C EEPROM routines
# works with 16-bit addressable EEPROMs (up to 64kB)
# Assume 24C16 ~ should be 2048 bytes
#
from smbus import SMBus

smb=SMBus(1);
# slaveaddr depends on i2cdetect -y 0/1
slaveaddr=0x50;

def eeprom_set_current_address(addr):
  a1=addr/256;
  a0=addr%256;
  smb.write_i2c_block_data(slaveaddr,a1,[a0]);

def eeprom_write_block(addr,data):
  a1=addr/256;
  a0=addr%256;
  data.insert(0,a0);
  smb.write_i2c_block_data(slaveaddr,a1,data);

def eeprom_read_byte(addr):
  eeprom_set_current_address(addr);
  return smb.read_byte(slaveaddr);

eeprom_set_current_address(0);

# Write eeprom -------------------------
#eeprom_write_block(1024,[3,1,4,1,5])

# Read eeprom --------------------------
for x in range(0,10):
  print eeprom_read_byte(x);

for x in range(1024,1030):
  print eeprom_read_byte(x);

Reference


 



Comments