嵌入式第六十六天(I2C子系统架构)
I2C通信与其他通信方式的比较
UART
- 串行、异步、全双工通信
- 适用于多台不同终端设备间的通信
- 典型速率:10kbps
I2C
- 串行、同步、半双工通信
- 适用于同一硬件平台上的不同芯片间通信
- 数据量较少时使用(如传感器)
- 典型速率:100kbps、400kbps、1Mbps
SPI
- 串行、同步、全双工通信
- 适用于同一硬件平台上的不同芯片间通信
- 数据量较大时使用(如存储、显示屏)
- 典型速率:1Mbps至十几Mbps
更高速率通信方式
- 并行传输
- USB
- 网口(千兆速率)
I2C与SPI的区别
通信速率
SPI的速率通常高于I2C。
硬件资源占用
I2C占用资源较少,仅需SCL、SDA和GND三根线。
SPI占用资源较多,需要SCL、MOSI、MISO、CS和GND五根线。
通信模式
SPI为全双工通信,I2C为半双工通信。
I2C基础知识
I2C的线数
SCL(时钟线)、SDA(数据线)、GND(地线)。
硬件接线注意事项
SCL和SDA工作在开漏模式,必须加上拉电阻(常用阻值:4.7kΩ、10kΩ)。
软件I2C与硬件I2C
- 软件I2C:通过GPIO模拟I2C时序。
- 硬件I2C:使用I2C控制器生成时序(推荐使用硬件I2C)。
IMX6ULL的I2C控制器数量
4个I2C控制器。
I2C总线传输特性
- 支持一主多从,理论上支持多主多从。
- 通信由主机发起,一次通信方向不可改变。
I2C通信时序
- 起始信号:SCL为高电平时,SDA由高电平跳变为低电平。
- 结束信号:SCL为高电平时,SDA由低电平跳变为高电平。
- 数据发送:SCL为高电平时采样SDA,SCL为低电平时SDA变化。
- 每个字节传输后需发送ACK/NACK确认。
I2C总线挂载设备数量
- 从机地址为7位,理论上最多支持127个从机设备。
基于I2C用户空间实现传感器读取
芯片厂商已提供I2C控制器驱动,开发工作集中在应用层代码编写。通过Linux系统提供的I2C用户空间接口(如/dev/i2c-N
),可直接使用ioctl
或read/write
等系统调用操作传感器寄存器,无需涉及内核驱动开发。
基于I2C子系统编写设备驱动
I2C子系统驱动框架分为三个核心模块:
I2C控制器驱动(i2c_adapter)
由芯片厂商(如NXP)基于Platform总线架构实现,负责硬件寄存器操作和时序控制,开发者通常无需修改。
I2C核心层(i2c_bus_type)
Linux内核提供的核心逻辑,包括总线注册、设备匹配、通信协议处理等,为设备驱动提供标准化接口。
I2C设备驱动(i2c_client)
开发者需基于I2C子系统架构实现,包括设备树配置、数据读写逻辑、与具体传感器通信的协议(如SMBus或自定义指令)。需实现probe
、remove
等回调函数,并通过i2c_driver
结构注册到内核。
Im75_userspace.c
#include <stdio.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>int main(void)
{int fd = 0;unsigned char data[2];unsigned char regaddr = 0x00;unsigned char slaveaddr = 0x48;fd = open("/dev/i2c-0", O_RDWR);if (-1 == fd){perror("fail to open");return -1;}ioctl(fd, I2C_SLAVE, slaveaddr);while (1){write(fd, ®addr, sizeof(regaddr));read(fd, &data, sizeof(data));printf("temp = %.2lf\n", (((data[0] << 8) | data[1]) >> 7) * 0.5);sleep(1);}close(fd);return 0;
}
Makefile
CC := arm-linux-gnueabihf-gcc OBJS := lm75_userspace.c OBJ := lm75_userspace $(OBJ):$(OBJS)$(CC) $^ -o $@cp $(OBJ) ~/nfs/rootfs.PHONY:
clean:rm $(OBJ)
distclean:rm $(OBJ)rm ~/nfs/rootfs/$(OBJ)