I2C学习
来源:互联网 发布:手机淘宝抠图 编辑:程序博客网 时间:2024/06/16 18:31
一、I2C总线介绍
1.1 I2C电气特性
1.1 I2C电气特性
I2C(Inter-Integrated Circuit)总线是由PHILIPS公司开发的两线式串行总线,用于连接微控制器及其外围设备。
![](/attachment/201612/6/29512885_1481034497nLvF.png)
I2C总线只有两根双向信号线。
1.2 总线寻址
从设备的地址由固定部分和用户自定义部分组成。
![](/attachment/201612/6/29512885_1481034497nLvF.png)
I2C总线只有两根双向信号线。
SDA: Serial Data Line-数据线
SCL :Serial Clock-时钟线
1.2 总线寻址
I2C总线协议规定:从设备采用7位的地址。D7~D1:从设备地址。
D0位:数据传送方向位,为“0”时表示主设备向从设备写数据,为“1”时表示主机由从设备读数据。
主设备发送地址时,总线上的每个从设备都将这7位地址码与自己的地址进行比较,如果相同,则认为自己正被主设备寻址,根据R/W位将自己确定为发送器或接收器。
D0位:数据传送方向位,为“0”时表示主设备向从设备写数据,为“1”时表示主机由从设备读数据。
主设备发送地址时,总线上的每个从设备都将这7位地址码与自己的地址进行比较,如果相同,则认为自己正被主设备寻址,根据R/W位将自己确定为发送器或接收器。
从设备的地址由固定部分和用户自定义部分组成。
1. 固定部分:D7-D4 共4位决定的。这是由从设备的生产厂商生产时就已确定的值。
2. 用户自定义部分: D3-D1 共3位。这3位通常对应设备的3个引脚(A0~A2)。把3个引脚接到不同的电平上,就可以形成一个3位的数值。
![](/attachment/201612/6/29512885_1481035935aU1g.png)
硬件设置A0,A1,A2拉低,I2C就可以按照000来寻找了。
二、I2C总线时序
2.1 空闲状态
I2C总线总线的SDA和SCL两条信号线同时处于高电平时,规定为总线的空闲状态。
![](/attachment/201612/6/29512885_1481036040pXw8.png)
2.2 起始状态
在时钟线SCL保持高电平期间,数据线SDA上的电平被拉低(即负跳变),定义为I2C总线总线的启动信号,它标志着一次数据传输的开始。
2.3 结束状态
在时钟线SCL保持高电平时,数据线SDA被释放,使得SDA返回高电平(即正跳变),称为I2C总线的停止信号。
2.4 数据位传送
I2C总线上的所有数据(地址和数据)都是以8位一个字节为单位传送的。
2.5 应答位
发送器每发送一个字节,就在时钟脉冲第9位释放数据线,由接收器反馈一个应答信号。 应答信号为低电平时,定为有效应答位ACK,表示接收器已经成功地接收了该字节;应答信号为高电平时,定为非应答位(NACK),表示接收器没有成功接收该字节。
三、LINUX-I2C子系统
3.1 I2C子系统架构
①I2C设备驱动:用户自写驱动、通用驱动+用户层驱动
②I2C总线驱动:I2C-ADAPTER;adapter.algo
③I2C核心:①和②联系作用,包含注册、注销的方法
![](/attachment/201612/12/29512885_1481552254Wkkw.png)
3.2 I2C总线驱动
![](/attachment/201612/12/29512885_1481552510kzh9.png)
描述一个I2C控制器
i2c_algorithm:
i2c-s3c2410.c>>i2c_adap_s3c_init()>>s3c2410_i2c_driver>>s3c24xx_i2c_probe:
s3c24xx_i2c_init:
i2c_algorithm:
s3c24xx_i2c_xfer:
s3c24xx_i2c_doxfer>>s3c24xx_i2c_message_start:
s3c24xx_i2c_irq:
![](/attachment/201612/6/29512885_1481035935aU1g.png)
硬件设置A0,A1,A2拉低,I2C就可以按照000来寻找了。
二、I2C总线时序
2.1 空闲状态
I2C总线总线的SDA和SCL两条信号线同时处于高电平时,规定为总线的空闲状态。
![](/attachment/201612/6/29512885_1481036040pXw8.png)
2.2 起始状态
在时钟线SCL保持高电平期间,数据线SDA上的电平被拉低(即负跳变),定义为I2C总线总线的启动信号,它标志着一次数据传输的开始。
2.3 结束状态
在时钟线SCL保持高电平时,数据线SDA被释放,使得SDA返回高电平(即正跳变),称为I2C总线的停止信号。
2.4 数据位传送
I2C总线上的所有数据(地址和数据)都是以8位一个字节为单位传送的。
2.5 应答位
发送器每发送一个字节,就在时钟脉冲第9位释放数据线,由接收器反馈一个应答信号。 应答信号为低电平时,定为有效应答位ACK,表示接收器已经成功地接收了该字节;应答信号为高电平时,定为非应答位(NACK),表示接收器没有成功接收该字节。
三、LINUX-I2C子系统
3.1 I2C子系统架构
①I2C设备驱动:用户自写驱动、通用驱动+用户层驱动
②I2C总线驱动:I2C-ADAPTER;adapter.algo
③I2C核心:①和②联系作用,包含注册、注销的方法
![](/attachment/201612/12/29512885_1481552254Wkkw.png)
3.2 I2C总线驱动
![](/attachment/201612/12/29512885_1481552510kzh9.png)
描述一个I2C控制器
- struct i2c_adapter {
- struct module *owner;
- unsigned int id;
- unsigned int class; /* classes to allow probing for */
- const struct i2c_algorithm *algo; /* the algorithm to access the bus */
- void *algo_data;
- /* --- administration stuff. */
- int (*client_register)(struct i2c_client *) __deprecated;
- int (*client_unregister)(struct i2c_client *) __deprecated;
- /* data fields that are valid for all devices */
- u8 level; /* nesting level for lockdep */
- struct mutex bus_lock;
- struct mutex clist_lock;
- int timeout; /* in jiffies */
- int retries;
- struct device dev; /* the adapter device */
- int nr;
- struct list_head clients; /* DEPRECATED */
- char name[48];
- struct completion dev_released;
- };
- struct i2c_algorithm {
- int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs, //描述数据传输的一些方法
- int num);
- int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr,
- unsigned short flags, char read_write,
- u8 command, int size, union i2c_smbus_data *data);
- u32 (*functionality) (struct i2c_adapter *);
- };
- static int s3c24xx_i2c_probe(struct platform_device *pdev)
- {
- struct s3c24xx_i2c *i2c;
- struct s3c2410_platform_i2c *pdata;
- struct resource *res;
- int ret;
- ............................
- /* initialise the i2c controller */
- ret = s3c24xx_i2c_init(i2c); //初始化i2c_init
- if (ret != 0)
- goto err_iomap;
- /* find the IRQ for this unit (note, this relies on the init call to
- * ensure no current IRQs pending
- */
- i2c->irq = ret = platform_get_irq(pdev, 0);
- if (ret <= 0) {
- dev_err(&pdev->dev, "cannot find IRQ\n");
- goto err_iomap;
- }
- ret = request_irq(i2c->irq, s3c24xx_i2c_irq, IRQF_DISABLED,
- dev_name(&pdev->dev), i2c);
- if (ret != 0) {
- dev_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq);
- goto err_iomap;
- }
- ret = s3c24xx_i2c_register_cpufreq(i2c);
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to register cpufreq notifier\n");
- goto err_irq;
- }
- /* Note, previous versions of the driver used i2c_add_adapter()
- * to add the bus at any number. We now pass the bus number via
- * the platform data, so if unset it will now default to always
- * being bus 0.
- */
- i2c->adap.nr = pdata->bus_num;
- ret = i2c_add_numbered_adapter(&i2c->adap); //注册i2c控制器(CPU内部),类似函数还有i2c_add_adpater(CPU外接控制器)。由I2C核心提供
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to add bus to i2c core\n");
- goto err_cpufreq;
- }
- platform_set_drvdata(pdev, i2c);
- dev_info(&pdev->dev, "%s: S3C I2C adapter\n", dev_name(&i2c->adap.dev));
- return 0;
- err_cpufreq:
- s3c24xx_i2c_deregister_cpufreq(i2c);
- err_irq:
- free_irq(i2c->irq, i2c);
- err_iomap:
- iounmap(i2c->regs);
- err_ioarea:
- release_resource(i2c->ioarea);
- kfree(i2c->ioarea);
- err_clk:
- clk_disable(i2c->clk);
- clk_put(i2c->clk);
- err_noclk:
- kfree(i2c);
- return ret;
- }
- static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c)
- {
- unsigned long iicon = S3C2410_IICCON_IRQEN | S3C2410_IICCON_ACKEN; //赋值IICCON寄存器
- struct s3c2410_platform_i2c *pdata;
- unsigned int freq;
- /* get the plafrom data */
- pdata = i2c->dev->platform_data;
- /* inititalise the gpio */ //初始化GPIO引脚
- if (pdata->cfg_gpio)
- pdata->cfg_gpio(to_platform_device(i2c->dev));
- /* write slave address */
- writeb(pdata->slave_addr, i2c->regs + S3C2410_IICADD); //写入从设备地址
- dev_info(i2c->dev, "slave address 0x%02x\n", pdata->slave_addr);
- writel(iicon, i2c->regs + S3C2410_IICCON);
- /* we need to work out the divisors for the clock... */
- if (s3c24xx_i2c_clockrate(i2c, &freq) != 0) {
- writel(0, i2c->regs + S3C2410_IICCON);
- dev_err(i2c->dev, "cannot meet bus frequency required\n"); //设置时钟频率
- return -EINVAL;
- }
- /* todo - check that the i2c lines aren't being dragged anywhere */
- dev_info(i2c->dev, "bus frequency set to %d KHz\n", freq);
- dev_dbg(i2c->dev, "S3C2410_IICCON=0x%02lx\n", iicon);
- /* check for s3c2440 i2c controller */
- if (s3c24xx_i2c_is2440(i2c))
- writel(0x0, i2c->regs + S3C2440_IICLC);
- return 0;
- }
- static const struct i2c_algorithm s3c24xx_i2c_algorithm = {
- .master_xfer = s3c24xx_i2c_xfer,
- .functionality = s3c24xx_i2c_func,
- };
- static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,
- struct i2c_msg *msgs, int num)
- {
- struct s3c24xx_i2c *i2c = (struct s3c24xx_i2c *)adap->algo_data;
- int retry;
- int ret;
- for (retry = 0; retry < adap->retries; retry++) {
- ret = s3c24xx_i2c_doxfer(i2c, msgs, num); //调用doxfer函数
- if (ret != -EAGAIN)
- return ret;
- dev_dbg(i2c->dev, "Retrying transmission (%d)\n", retry);
- udelay(100);
- }
- return -EREMOTEIO;
- }
- static void s3c24xx_i2c_message_start(struct s3c24xx_i2c *i2c,
- struct i2c_msg *msg)
- {
- unsigned int addr = (msg->addr & 0x7f) << 1;
- unsigned long stat;
- unsigned long iiccon;
- stat = 0;
- stat |= S3C2410_IICSTAT_TXRXEN;
- if (msg->flags & I2C_M_RD) {
- stat |= S3C2410_IICSTAT_MASTER_RX; //设置IICSTAT模式
- addr |= 1;
- } else
- stat |= S3C2410_IICSTAT_MASTER_TX;
- if (msg->flags & I2C_M_REV_DIR_ADDR)
- addr ^= 1;
- /* todo - check for wether ack wanted or not */
- s3c24xx_i2c_enable_ack(i2c);
- iiccon = readl(i2c->regs + S3C2410_IICCON);
- writel(stat, i2c->regs + S3C2410_IICSTAT);
- dev_dbg(i2c->dev, "START: %08lx to IICSTAT, %02x to DS\n", stat, addr);
- writeb(addr, i2c->regs + S3C2410_IICDS); //设置从设备地址
- /* delay here to ensure the data byte has gotten onto the bus
- * before the transaction is started */
- ndelay(i2c->tx_setup);
- dev_dbg(i2c->dev, "iiccon, %08lx\n", iiccon);
- writel(iiccon, i2c->regs + S3C2410_IICCON);
- stat |= S3C2410_IICSTAT_START; //写入OXF0
- writel(stat, i2c->regs + S3C2410_IICSTAT); //传输
- }
- static irqreturn_t s3c24xx_i2c_irq(int irqno, void *dev_id)
- {
- struct s3c24xx_i2c *i2c = dev_id;
- unsigned long status;
- unsigned long tmp;
- status = readl(i2c->regs + S3C2410_IICSTAT);
- if (status & S3C2410_IICSTAT_ARBITR) {
- /* deal with arbitration loss */
- dev_err(i2c->dev, "deal with arbitration loss\n");
- }
- if (i2c->state == STATE_IDLE) {
- dev_dbg(i2c->dev, "IRQ: error i2c->state == IDLE\n");
- tmp = readl(i2c->regs + S3C2410_IICCON);
- tmp &= ~S3C2410_IICCON_IRQPEND;
- writel(tmp, i2c->regs + S3C2410_IICCON);
- goto out;
- }
- /* pretty much this leaves us with the fact that we've
- * transmitted or received whatever byte we last sent */
- i2s_s3c_irq_nextbyte(i2c, status); //处理程序
- out:
- return IRQ_HANDLED;
- }
0
上一篇:MTD系统架构和yaffs2使用、Nandflash驱动设计
下一篇:I2C用户态驱动设计
相关热门文章
- SHTML是什么_SSI有什么用...
- 查看linux中某个端口(port)...
- 卡尔曼滤波的原理说明...
- shell中字符串操作
- 关于java中的“错误:找不到或...
给主人留下些什么吧!~~
评论热议
阅读全文
0 0
- I2C学习
- I2C学习
- I2C学习
- I2C学习
- I2C 学习
- I2C时序学习笔记
- I2C总线的学习
- I2C原理学习总结
- I2C驱动学习笔记
- I2C总线学习(一)
- STM32学习之I2C
- I2C Tools 学习笔记
- ARM-I2C学习
- I2C总线学习记录
- I2C学习总结
- I2C学习记录
- I2C学习中
- Linux I2C框架学习
- drawerlayout侧滑
- 触摸屏驱动分析和编程
- LCD驱动程序架构和分析
- 块设备驱动系统架构和简单设计
- MTD系统架构和yaffs2使用、Nandflash驱动设计
- I2C学习
- 蓝牙搜索
- I2C用户态驱动设计
- SpringBoot的热部署
- I2C自编设备驱动设计
- crontab执行shell脚本和直接运行的结果不一样
- SPI总线介绍和裸机编程分析
- SPI子系统
- Boa中关于StaticText的一个坑
原创粉丝点击
热门IT博客
热门问题
老师的惩罚
人脸识别
我在镇武司摸鱼那些年
重生之率土为王
我在大康的咸鱼生活
盘龙之生命进化
天生仙种
凡人之先天五行
春回大明朝
姑娘不必设防,我是瞎子
画家王琳
画家人物
画家价格
画家传记
画家李唐
画家黄胄
画家崔如琢
刘小东画家
画家名字
画家张萍
中世纪画家
花鸟画家
画家介绍
画家范增
美术画家
范增画家
清朝画家
画家黄永玉
画家简介
画家名人
黄慎画家
有名画家
画家韩冰
油画画家
画家石齐
素描画家
画家系列
画家 刘大为
画家张钰
画家赵卫
画家杨彦
画家美林
画家邢少臣
画家蒋孝游
画家杨喜元
画家邓辉楚
画家刘文西去世
画家有哪些人
千里江山图画家
中国画家排名
粗心的小画家