1 Introduction
The I2C (Inter-Integrated Circuit) bus is a two-wire serial bus developed by PHILIPS for connecting microcontrollers and their peripherals. The main advantages of the I2C bus are its simplicity and effectiveness. Since the interface is directly on the component, the I2C bus occupies very little space, reducing the space on the circuit board and the number of chip pins, and reducing the cost of interconnection. The I2C bus was originally developed for audio and video equipment, and is now used in various service and management occasions to configure or master the functional status of components, such as power supply, system fan, system temperature and other parameters, increasing system security and facilitating management.
2 I2C Bus Overview
The I2C bus is a serial bus consisting of a data line SDA and a clock SCL. It can send and receive data, and each device has a unique address identification. The I2C protocol uses master/slave bidirectional communication. A device that sends data to the bus is defined as a transmitter, and a device that receives data is defined as a receiver. Both the master device and the slave device can work in the receiving and sending states. The bus must be controlled by a master device (usually a microcontroller). The master device generates a serial clock (SCL) to control the transmission direction of the bus and generate start and stop conditions. The data state on the SDA line can only change when SCL is low. During the period when SCL is high, the change of the SDA state is used to indicate the start and stop conditions.
There are three types of signals in the I2C bus during data transmission, namely: start signal, end signal and response signal.
Start signal: When SCL is at a high level, SDA jumps from a high level to a low level to start data transmission.
End signal: When SCL is at a low level, SDA jumps from a low level to a high level to end data transmission.
Response signal: After receiving 8-bit data, the IC receiving data sends a specific low-level pulse to the IC sending data, indicating that the data has been received. After the CPU sends a signal to the controlled unit, it waits for the controlled unit to send a response signal. After receiving the response signal, the CPU determines whether to continue transmitting the signal based on the actual situation. If no response signal is received, it is determined that the controlled unit has a fault.
3 I2C driver framework for Linux
The I2C bus driver in Linux is divided into two parts, bus driver (BUS) and device driver (DEVICE). The bus driver's responsibility is to add corresponding read and write methods for each I2C bus in the system. However, the bus driver itself does not perform any communication, it just exists there, waiting for the device driver to call its function, see Figure 1.
The device driver is a driver that communicates with specific devices on the I2C bus. Through the functions provided by the I2C bus driver, the device driver can ignore the differences between different bus controllers and communicate with hardware devices without considering their implementation details.
Figure 1 Linux kernel I2C bus driver architecture
There are three folders, algos, busses, and chips, under the i2c folder of our Linux driver, and two files, i2c-core.c and i2c-dev.c. The i2c-core.c file implements the I2C core framework, which is the core part of I2C used by the Linux kernel to maintain and manage. It maintains two static lists, which record the I2C driver structure and I2C adapter structure in the system respectively. The I2C core provides interface functions, allowing an I2C adatper, I2C driver, and I2C client to register in the I2C core during initialization, and to unregister when exiting. It also provides a general interface for I2C bus read and write access, which is mainly used in I2C device drivers.
The i2c-mpc.c file in the Busses folder implements the I2C bus adapter driver under PowerPC, defines the i2c_adapter data structure of the specific I2C bus adapter, and implements the specific method of accessing the I2C bus at a relatively low level. The I2C adapter constructs a data structure for the I2C core layer interface, and registers a controller to the I2C core through the interface function. The I2C adapter mainly implements the algorithm for accessing the I2C bus. The iic_xfer() function is the implementation of the I2C adapter's low-level read and write methods for the I2C bus. At the same time, the I2C adapter also implements the processing function for the I2C controller interrupt.
The i2c-dev.c file implements the I2C driver, provides a general I2C device driver, implements the access interface of character type devices, implements the interface to the user application layer, and provides the user program with an interface to access the I2C device, including the interface functions for implementing standard file operations such as open, release, read, write, and the most important ioctl. We can open the I2C device file through the open function, set the address of the slave device to be accessed through the ioctl function, and then complete the read and write operations on the I2C device through the read and write functions.
The general method provided by the I2C driver can access any I2C device, but the read, write and ioctl functions implemented are completely based on the implementation of general devices. All operation data are based on byte streams and have no clear format and meaning. In order to use I2C devices more conveniently and effectively, we can develop a specific I2C device driver for a specific I2C device, complete the interpretation of the specific data format and implement some special functions in the driver. [page]
4 I2C specific driver development under Linux
TMP75 is a digital temperature sensor based on I2C bus launched by TI. It has low power consumption and high digital resolution. It is widely used in power supply temperature monitoring, computer peripheral protection, notebooks and cellular phones. In developing the driver for this device, since the I2C core framework and I2C bus adapter driver have been implemented in the Linux system, and a general I2C device driver is provided through the i2c-dev.c file, our driver development is mainly focused on the TMP75 device driver layer, which is used to interpret the data format of the TMP75 device and implement some special functions.
According to the specific register address and function definition of TMP75:
#define TMP75_REG_TEMP 0x00 //Temperature register address
#define TMP75_REG_CONF 0x01 //Configuration register address
#define TMP75_REG_TEMP_LOW 0x02 // Low temperature threshold register address
#define TMP75_REG_TEMP_HIGH 0x03 //High temperature threshold register address
Define a TMP75_data structure and a series of functions to implement device detection and loading during bus initialization and data operations during device deletion.
struct TMP75_data {
struct i2c_client client;
struct semaphore update_lock;
char valid; /* !=0 if following fields are valid */
unsigned long last_updated; /* In jiffies */
u16 temp_input; /* Register values */
u16 temp_max;
u16 temp_hyst;
};
static int TMP 75_attach_adapter(struct i2c_adapter *adapter);
static int TMP 75_detect(struct i2c_adapter *adapter, int address, int kind);
static void TMP 75_init_client(struct i2c_client *client);
static int TMP 75_detach_client(struct i2c_client *client);
static int TMP 75_read_value(struct i2c_client *client, u8 reg);
static int TMP 75_write_value(struct i2c_client *client, u8 reg, u16 value);
static struct TMP 75_data *tmp75_update_device(struct device *dev);
The two functions that define TMP75 register reading and writing for the specific format of TMP75 device registers are as follows:
static int TMP75_write_value(struct i2c_client *client, u8 reg, u16 value)
{
if (reg == TMP75_REG_CONF)
return i2c_smbus_write_byte_data(client, reg, value);
else
return i2c_smbus_write_word_data(client, reg, swab16(value));
}
static int TMP75_read_value(struct i2c_client *client, u8 reg)
{
if (reg == TMP 75_REG_CONF)
return i2c_smbus_read_byte_data(client, reg);
else
return swab16(i2c_smbus_read_word_data(client, reg));
}
After the specific device driver is completed, add the configuration options of the TMP75 device driver to the kconfig file in the chips folder, so that the TMP75 device driver can be added to the kernel when configuring the kernel options.
5 I2C application development under Linux
In Linux, if an application wants to use this driver to access an external I2C device, it must first open the driver using open() and then close it using close().
int fd;
fd = open("/dev/i2c/0", O_RDWR);
…
close(fd);
The API function provided by the I2C bus controller driver provides the ioctl() function for setting some parameters of the I2C bus controller. This application calls the ioctl function to set the I2C bus to 7-bit address mode and set the I2C slave address.
ioctl(fd, I2C_TENBIT, 0)
ioctl(fd,I2C_SLAVE,SLAVE_ADDR)
The initialization of TMP75 is achieved by calling the write() function, which is used to initialize the configuration register, high temperature threshold and low temperature threshold register.
// Initialize the configuration registers
senbuf[0]=0x01;
senbuf[1]=I2C_CONF_INITDATA;
write(fd, sendbuf, 2);
The current operating temperature of TMP75 is read by calling the write() function to first write the address of the temperature register, and then calling the read() function to read the 2-byte temperature data of the register.
write(fd, 0x0, 1);
read(fd, recbuf, 2);
6 Conclusion
The I2C bus structure is simple and easy to use. The I2C driver under the Linux system has a clear hierarchical structure. With the help of mature driver examples, users can easily develop corresponding drivers for their own products. This article analyzes the I2C driver structure under the Linux system, and implements a specific I2C device driver on this basis, and on this basis gives a user application implementation for accessing the I2C bus.
References
[1]Philips Corporation, I2C bus specification version 2.1, 2000
[2] Aless and Robin, translated by Wei Yongming et al., LINUX Device Drivers (Second Edition). Beijing: China Electric Power Press, 2004
[3]Texas Instruments, inc. USA. TMP75 Datasheet, 2004
[4] Zheng Xuyang, Li Bingbing, Huang Xinping. Research and software design of multi-master communication based on simulated I2C bus. Microcontroller and Embedded System Application, 2005