[May 1 Creation] Linux---I2C Application Programming

Table of contents

Foreword:

1. I2C protocol

(1 Overview

(2) I2C hardware framework:

(3) I2C software framework

(4) I2C data format

2. SMBus protocol

Three, the important structure of the I2C system

4. Access I2C device (AP3216C)

(1) Using the SMBus protocol:​​​​

 (2) Use the I2C protocol:

 (3) I2C-Tools source code analysis:

5. Write APP to access EEPROM (AT24C02)

(1) AT24C02 access method

1. Device address

2. Write data

3. Read data

(2) Programming with I2C-Tools

1. Specific example: (SMBus)

2. Compilation, actual effect


Foreword:

Classic Link: Thinking and Practice with Questions

(1) I2C protocol

  • What is I2C? What are the characteristics?
  • What is the specific process of I2C transmission data?
  • How does I2C generate start signal (S), end signal (P), response signal (ACK) and send data?
  • I2C is bidirectional transmission, so how to realize bidirectional transmission on SDA?

(2) SMBus protocol

  • What is the SMBus protocol?
  • What are the similarities and differences between it and I2C?

(3) I2C implementation in Linux

  • In Linux, how to represent I2C controller, I2C device and data to be transmitted?

(4) I2C application programming practice

  • AP3216C
  • EEPROM-AT24C02

The content of the following article will answer the above questions in detail. If it helps, please support me and give me more motivation to create.

1. I2C protocol

(1 Overview

What is I2C? What are the characteristics?

In consumer electronics, industrial electronics and other fields, various types of chips are used, such as microcontrollers, power management, display drivers, sensors, memories, converters, etc., they have different functions, and sometimes require fast data interaction , in order to use the simplest way to interconnect these chips, so I2C was born. I2C ( Inter-Integrated Circuit ) is a general bus protocol. It is a simple two-way two-wire bus protocol standard developed by Philips (Philips), now NXP (NXP) Semiconductor .

For hardware designers, only 2 pins, very few connecting lines and areas are needed to realize the communication between chips. For software developers, the same I2C driver library can be used to realize the realization of different devices. The driver greatly reduces the software development time. The extremely low working current reduces the power consumption of the system, and the perfect response mechanism greatly enhances the reliability of communication.

The features are as follows:

  • I2C is half duplex
  • I2C supports multi-master and multi-slave mode
  • From the perspective of GPIO occupation, I2C occupies two GPIOs
  • I2C has a response mechanism, and the data reliability is higher
  • The I2C rate will not be too high, the maximum rate is 3.4Mbps
  • I2C selects the slave through the device address, and the increase in the number of slaves will not lead to an increase in GPIO
  • I2C performs data sampling on the SCL high level device.
  • Most of them are used in short-distance communication of on-board devices.

(2) I2C hardware framework:

  • Inside a chip (Soc), there are one or more I2C controllers.
  • On one I2C controller, one or more I2C devices can be connected. --- Must know the address
  • The I2C bus only needs two lines: the clock line SCL and the data line SDA.
  • There are pull-up resistors on the SCL and SDA lines of the I2C bus.

(3) I2C software framework

On Linux, the APP accesses the I2C device through the I2C Device Driver to parse the data and the I2C Controller Driver to send and receive data.

Take the storage device AT24C02 with I2C interface as an example:

  • APP:
    • Make a request: write the string "hello world!" to the beginning of address 16 of AT24C02
    • Does not care about the details of the underlying implementation, it only needs to call the interface provided by the device driver
  • AT24C02 driver:
    • It knows the address and data format required by AT24C02
    • It knows what signal to send to make AT24C02 perform erasing and programming work
    • It knows how to judge whether the data is programmed successfully. It constructs a series of data and sends them to the I2C controller.
  • I2C Controller Driver
    • It sends out various signals according to the I2C protocol: I2C device address, I2C storage address, data
    • It judges according to the I2C protocol

(4) I2C data format

What is the specific process of I2C transmission data?

Take the write operation as an example: 

  • The main chip needs to send a start signal
  • Then send out a device address (used to determine whether the device exists), and then you can transmit data
  • The master device sends a byte of data to the slave device and waits for a response
  • Every time a byte of data is transmitted, the receiver needs a response signal (determines whether the data is accepted), and then transmits the next data
  • After the data is sent, the main chip will send a stop signal.

How does I2C generate start signal (S), end signal (P), response signal (ACK) and send data?

As shown below:

  • Start signal: SDA is high to low, and when SCL remains high, a start signal (S) is generated
  • End signal: SCL remains high, SDA goes from low to high, and an end signal (P) is generated
  • Response signal: After the receiver receives 8-bit data, it will pull down SDA in the 9th clock cycle to generate a response signal (ACK)

There are two core points of specific data transmission, as shown in the following figure:

  • When SCL is high, the SDA data should remain stable.
  • When SCL is low, SDA can change (SDA high (1), low (0)).
  • At this time, when SCL is at a high level, query the level on SDA to obtain data.

From the above we can see that I2C is bidirectional transmission, so how to realize bidirectional transmission on SDA?

  1. According to the above situation, there are two drivers (master device and slave device), if they are directly connected, if there is a failure, one outputs high level and the other outputs low level, and the circuit will be short-circuited.
  2. When one of the two devices sends data, how can the other not affect the data on SDA?

A triode or CMOS tube is used here to regulate and prevent this problem. Examples are as follows:

The truth table corresponding to the above circuit is as follows:

 From the truth table and circuit we know:

  • When a certain chip does not want to affect the SDA line, it does not drive the triode
  • If you want SDA to output high level, neither side will drive the triode
  • If you want SDA to output low level, drive the triode

In such a case, data transmission can be implemented like this:

  • For the first 8 clks, the slave device does not drive the triode, and the master device determines the data; it does not drive when sending 1, and drives the triode when sending 0.
  • In the ninth clk, the master device does not drive the triode, and the slave device determines the data; in response to the signal, it drives the triode to make SDA 0.

 Note: Why use a pull-up resistor?

After the 9th clock, if one party needs more time to process data, it can drive the transistor to pull SCL low.

2. SMBus protocol

SMBus: System Management Bus, system management bus.

SMBus is based on the I2C protocol, which has stricter requirements and is a subset of the I2C protocol. It is used to connect various devices including power related devices, system sensors, EEPROM communication devices and more.

What are the stricter requirements for SMBus? What is the difference with the general I2C protocol?

  • The limit value of VDD is different

    • I2C protocol: wide range, even up to 12V discussed

    • SMBus:1.8V~5V

  • Minimum clock frequency, maximum Clock Stretching (when a device needs more time for internal processing, it can pull SCL low to occupy the I2C bus)

    • I2C: There is no limit to the minimum clock frequency, and there is no limit to the duration of Clock Stretching

    • SMBus: The minimum clock frequency is 10KHz, and the maximum time value of Clock Stretching is also limited

  • Address Acknowledge: After an I2C device receives its device address, must it send an acknowledgment signal?

    • I2C protocol: there is no mandatory requirement to send a response signal

    • SMBus: It is mandatory to send a response signal so that the other party knows the status of the device: busy, failed, or removed

  • The SMBus protocol specifies the data transmission format

    • I2C protocol: It only defines how to transmit data, but does not define the format of the data, which is completely defined by the device

    • SMBus: Several data formats are defined

  • REPEATED START Condition (repeated S signal)---SMBus

    • Between writing and reading, the P signal may not be sent out, but the S signal is directly sent out: this S signal is REPEATED START.

SMBus protocol analysis, its specific content:

SMBus symbols (symbols): 

It adds command code (command byte, generally indicates the register address inside the chip), byte count (data length), data byte (data byte, supports 8-bit, 16-bit) and PEC check code on the basis of I2C protocol mechanism. 

Take SMBus Block Read (complex) as an example:

  • Function in I2C-tools: i2c_smbus_read_block_data().

  • First issue the command code (understanding and analysis: Address is the address of the slave device, and the command code is generally the address of the register inside the chip)
  • re-initiate the read operation
    • First read a byte (Block count), indicating the number of bytes to be read later
    • Then read all data

To learn more about data formats, refer to the following articles: 

SMBus protocol driven by Linux system_i2c_smbus_read_byte_data_Wei Dongshan's blog-CSDN blog

注:在很多设备都实现了 SMBus,而不是更宽泛的 I2C 协议,所以优先使用SMBus。
即使 I2C 控制器没有实现 SMBus,软件方面也是可以使用 I2C 协议来模拟 SMBus。
所以: Linux 建议优先使用 SMBus。

Three, the important structure of the I2C system

From the hardware framework of the first piece of content I2C, I2C transmission focuses on the I2C controller, I2C device and the transmitted data.

How to represent I2C Controller? 

  • Is the number of I2C Controller        
  • How does the I2C Controller send and receive data?

Here the I2C Controller is represented by i2c_adapter, and the corresponding structure is as follows: 

  • nr indicates the number of I2C Controller
  • i2c_algorithm, which contains the transfer function of the I2C BUS, used to send and receive I2C data 

 How to represent I2C device?

  • Must have device address
  • Which I2C Controller is it mounted on --- what is the corresponding I2C_adapter?

 Here the I2C device is represented by i2c_client, and the corresponding structure is as follows:

  • addr: device address
  • adapter: which I2C Controller corresponds to

 How to represent the data to be transferred?

 Here the data is represented by i2c_msg:

  • The flags in i2c_msg are used to indicate the direction of transmission: bit 0 is equal to I2C_M_RD for reading, bit 0 is equal to 0 for writing

  • Example: For the EEPROM whose device address is 0x50, to read a byte stored in it with address 0x10, two i2c_msg should be constructed

    • The first i2c_msg indicates a write operation, and sends the storage address 0x10 to be accessed to the device
    • The second i2c_msg indicates a read operation
  • Focus on addr (address), flags (direction), len (length), buf (data)

4. Access I2C device (AP3216C)

The APP needs a driver to access the hardware. For I2C devices, you can call the driver drivers/i2c/i2c-dev.c provided by the kernel. Through it, you can directly use the adapter driver in the I2C Controller Driver to access the I2C device (AP3216C). 

AP3216C is a three-in-one sensor of infrared, light intensity, and distance. Taking the reading of light intensity and distance as an example, the steps are as follows:

  • Reset: write 0x4 to register 0
  • Enable: write 0x3 to register 0
  • Read light intensity: read register 0xC, 0xD to get 2 bytes of light intensity
  • Read distance: read register 0xE, 0xF to get the distance value of 2 bytes 

Here you can use I2C-Tools to operate the sensor AP3212C, there are two ways (SMBus and I2C) to access the device:

(1) Using the SMBus protocol:​​​​

i2cset和i2cget函数用法,后面依次为:
命令(-f、-y)
I2CBUS(0)
设备地址
寄存器地址
数据data

 (2) Use the I2C protocol:

i2ctransfer函数用法,后面依次为:
命令(-f、-y)
I2CBUS(0)
描述符(读写w1/w2 + @设备地址 )
寄存器地址
数据data

 (3) I2C-Tools source code analysis:

Combined with the above process analysis, the specific process steps:

  • Opening the /dev/i2c-0 node (open) will access the devices under the I2C controller. (Note: i2c-dev.c generates a device node for each I2C controller (I2C Bus, I2C Adapter): /dev/i2c-0, /dev/i2c-1, etc.;)
  • Specifies the address of the I2C device (optional: ioctl(file, I2C_SLAVE, address), mandatory: ioctl(file, I2C_SLAVE_FORCE, address) )
  • Then use the corresponding SMBus data format and use the ioctl(file, I2C_SMBUS, &args) function to transfer data.

5. Write APP to access EEPROM (AT24C02)

(1) AT24C02 access method

1. Device address

 According to the data sheet and the hardware A2A1A0 are grounded, the device address of AT24C02 is 0b1010000, which is 0x50.

2. Write data

The data timing here is:

  • start bit + device address + write + corresponding bit
  • Register address + data 

3. Read data

One byte can be read, or multiple bytes can be read continuously. When there are multiple consecutive bytes, the address inside the chip will automatically accumulate. When the address reaches the last address of the storage space, it will start from 0. As shown below:

(2) Programming with I2C-Tools

1. Specific example: (SMBus)

#include <sys/ioctl.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <i2c/smbus.h>
#include "i2cbusses.h"
#include <time.h>


/* ./at24c02 <i2c_bus_number> w "100ask.taobao.com"
 * ./at24c02 <i2c_bus_number> r
 */

int main(int argc, char **argv)
{
	unsigned char dev_addr = 0x50;
	unsigned char mem_addr = 0;
	unsigned char buf[32];

	int file;
	char filename[20];
	unsigned char *str;

	int ret;

	struct timespec req;
	
	if(argc != 3 && argc != 4)
	{
		printf("Usage:\n");
		printf("%Write EEprom: %s /dev/i2c-0|1|2 w str\n", argv[0]);
		printf("%Read  EEprom: %s /dev/i2c-0|1|2 r str\n", argv[0]);
		return -1;
	}

	//第一步:打开节点
	file = open_i2c_dev(argv[1][0] - '0', filename, sizeof(filename), 0);
	if(file < 0)
	{
		printf("can't open %s\n", filename);
		return -1;
	}
	
	if(set_slave_addr(file, dev_addr, 1))
	{
		printf("can't set_slave_addr\n");
		return -1;
	}
	
	//第二步:I2C读写数据
	if(argv[2][0] == 'w')
	{
		//write
		str = argv[3];
        
        //这里添加一定的休眠时间,完成1字节数据传输后,EEPROM会进入一个写循环(需要时间)
		req.tv_sec  = 0;
		req.tv_nsec = 20000000; /* 20ms */

		while(*str)
		{
			//mem_addr, *str
			//mem_addr++, str++
			ret = i2c_smbus_write_byte_data(file, mem_addr, *str);
			if(ret)
			{
				printf("i2c_smbus_write_byte_data err\n");
				return -1;

			}
			//等待EEPROM写完数据
			nanosleep(&req, NULL);
			mem_addr++;
			str++;
		}
		ret = i2c_smbus_write_byte_data(file, mem_addr, 0); // string end char
		if (ret)
		{
			printf("i2c_smbus_write_byte_data err\n");
			return -1;
		}

	}
	else
	{
		//read
		ret = i2c_smbus_read_i2c_block_data(file, mem_addr, sizeof(buf), buf);
		if (ret < 0)
		{
			printf("i2c_smbus_read_i2c_block_data err\n");
			return -1;
		}
		
		buf[31] = '\0';
		printf("get data: %s\n", buf);
	}
}

2. Compilation, actual effect

a. Set up the cross-compilation toolchain

export ARCH=arm
export CROSS_COMPILE=arm-buildroot-linux-gnueabihf-
export PATH=$PATH:/home/book/100ask_imx6ull-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/bin

b. Write Makefile: After setting up the tool chain, make will execute the program

all:
$(CROSS_COMPILE)gcc -I ./include -o at24c02_test at24c02_test.c i2cbusses.c smbus.c

   The library files are useful here: i2cbusses.c i2cbusses.h smbus.c

c. On-machine test

//nfs挂载
mount -t nfs -o nolock,vers=3 192.168.5.11:/home/book/nfs_rootfs /mnt

//复制、执行程序
cp /mnt/at24c02_test /bin
at24c02_test 0 w helloworld
at24c02_test 0 r

Guess you like

Origin blog.csdn.net/weixin_42373086/article/details/130466485