转自:https://blog.csdn.net/weixin_41718085/article/details/79376823

转载:http://dpinglee.blog.163.com/blog/static/14409775320112239374615/

1.I2C协议

2条双向串行线,一条数据线SDA,一条时钟线SCL。
   SDA传输数据是大端传输,每次传输8bit,即一字节。
   支持多主控(multimastering),任何时间点只能有一个主控。
   总线上每个设备都有自己的一个addr,共7个bit,广播地址全0.
   系统中可能有多个同种芯片,为此addr分为固定部分和可编程部份,细节视芯片而定,看datasheet。

1.1 I2C位传输
   数据传输:SCL为高电平时,SDA线若保持稳定,那么SDA上是在传输数据bit;
   若SDA发生跳变,则用来表示一个会话的开始或结束(后面讲)
   数据改变:SCL为低电平时,SDA线才能改变传输的bit

1.2 I2C开始和结束信号
   开始信号:SCL为高电平时,SDA由高电平向低电平跳变,开始传送数据。
  结束信号:SCL为高电平时,SDA由低电平向高电平跳变,结束传送数据。

1.3 I2C应答信号

Master每发送完8bit数据后等待Slave的ACK。
   即在第9个clock,若从IC发ACK,SDA会被拉低。
   若没有ACK,SDA会被置高,这会引起Master发生RESTART或STOP流程,如下所示:

1.4 I2C写流程
写寄存器的标准流程为:
1.    Master发起START
2.    Master发送I2C addr(7bit)和w操作0(1bit),等待ACK
3.    Slave发送ACK
4.    Master发送reg addr(8bit),等待ACK
5.    Slave发送ACK
6.   Master发送data(8bit),即要写入寄存器中的数据,等待ACK
7.    Slave发送ACK
8.    第6步和第7步可以重复多次,即顺序写多个寄存器
9.    Master发起STOP

写一个寄存器

写多个寄存器

1.5 I2C读流程

读寄存器的标准流程为:
1.    Master发送I2Caddr(7bit)和 W操作1(1bit),等待ACK
2.    Slave发送ACK
3.    Master发送reg addr(8bit),等待ACK
4.    Slave发送ACK
5.   Master发起START
6.    Master发送I2C addr(7bit)和 R操作1(1bit),等待ACK
7.    Slave发送ACK
8.   Slave发送data(8bit),即寄存器里的值
9.   Master发送ACK
10.    第8步和第9步可以重复多次,即顺序读多个寄存器

读一个寄存器

读多个寄存器

2. PowerPC的I2C实现

Mpc8560的CCSR中控制I2C的寄存器共有6个。

2.1 I2CADR 地址寄存器

CPU也可以是I2C的Slave,CPU的I2C地址有 I2CADR指定

2.2 I2CFDR 频率设置寄存器

The serial bit clock frequency of SCL is equal to the CCB clock divided by the divider.
用来设置I2C总线频率

2.3 I2CCR 控制寄存器

MEN: Module Enable.    置1时,I2C模块使能
MIEN:Module Interrupt Enable. 置1时,I2C中断使能。
MSTA:Master/slave mode. 1 Master mode,0 Slave mode.
        当1->0时,CPU发起STOP信号
        当0->1时,CPU发起START信号
MTX:Transmit/receive mode select.0 Receive mode,1 Transmit mode
TXAK:Transfer acknowledge. 置1时,CPU在9th clock发送ACK拉低SDA
RSTA:Repeat START. 置1时,CPU发送REPEAT START
BCST:置1,CPU接收广播信息(信息的slave addr为7个0)

2.4 I2CSR 状态寄存器

MCF:0  Byte transfer is in process
     1  Byte transfer is completed

MAAS:当CPU作为Slave时,若I2CDR与会话中Slaveaddr匹配,此bit被置1

MBB:0 I2C bus idle  
     1 I2C bus busy

MAL:若置1,表示仲裁失败
BCSTM:若置1,表示接收到广播信息

SRW:When MAAS is set, SRW indicates the value of the R/W command bit of the calling address, which is sent from the master.
   0 Slave receive, master writing to slave
   1 Slave transmit, master reading from slave

MIF:Module interrupt. The MIF bit is set when an interrupt is pending, causing a processor interrupt request(provided I2CCR[MIEN] is set)

RXAK:若置1,表示收到了ACK

2.5 I2CDR 数据寄存器

这个寄存器储存CPU将要传输的数据。

3. PPC-Linux中I2C的实现
 
  内核代码中,通过I2C总线存取寄存器的函数都在文件drivers/i2c/busses/i2c-mpc.c中
  最重要的函数是mpc_xfer.

static int mpc_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, intnum)
{
    struct i2c_msg *pmsg;
    int i;
    int ret = 0;
    unsigned long orig_jiffies = jiffies;
    struct mpc_i2c *i2c = i2c_get_adapdata(adap);

mpc_i2c_start(i2c);    // 设置I2CCR[MEN], 使能I2C module

/* Allow bus up to 1s to become not busy */
    //一直读I2CSR[MBB],等待I2C总线空闲下来
    while (readb(i2c->base + MPC_I2C_SR) & CSR_MBB) {
        if (signal_pending(current)) {
            pr_debug("I2C: Interrupted\n");
            writeccr(i2c, 0);
            return -EINTR;
        }
        if (time_after(jiffies, orig_jiffies + HZ)) {
            pr_debug("I2C: timeout\n");
            if (readb(i2c->base + MPC_I2C_SR) ==
                (CSR_MCF | CSR_MBB | CSR_RXAK))
                mpc_i2c_fixup(i2c);
            return -EIO;
        }
        schedule();
    }

for (i = 0; ret >= 0 && i < num; i++) {
        pmsg = &msgs[i];
        pr_debug("Doing %s %d bytes to 0x%02x - %d of %d messages\n",
             pmsg->flags & I2C_M_RD ? "read" : "write",
             pmsg->len, pmsg->addr, i + 1, num);        //根据消息里的flag进行读操作或写操作        if (pmsg->flags & I2C_M_RD) 
            ret = mpc_read(i2c, pmsg->addr, pmsg->buf, pmsg->len, i);
        else
            ret = mpc_write(i2c, pmsg->addr, pmsg->buf, pmsg->len, i);
    }
    mpc_i2c_stop(i2c);    //保证为I2CCSR[MSTA]为0,保证能触发STOP
    return (ret < 0) ? ret : num;
}

static int mpc_write(struct mpc_i2c *i2c, int target,
             const u8 * data, int length, int restart)
{
    int i;
    unsigned timeout = i2c->adap.timeout;
    u32 flags = restart ? CCR_RSTA : 0;

/* Start with MEN */    //以防万一,保证I2C模块使能起来
    if (!restart)
        writeccr(i2c, CCR_MEN);
    /* Start as master */       //写了I2CCR[CCR_MSTA],触发CPU发起START信号
    writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_MTX | flags);
    /* Write target byte */     //CPU发送一个字节,slave I2C addr和0 (写操作bit) 
    writeb((target << 1), i2c->base + MPC_I2C_DR);

if (i2c_wait(i2c, timeout, 1) < 0)    //等待slave 发ACK
        return -1;

for (i = 0; i < length; i++) {
        /* Write data byte */
        writeb(data[i], i2c->base + MPC_I2C_DR); //CPU接着发数据,包括reg addr和data

if (i2c_wait(i2c, timeout, 1) < 0)       //等待slave 发ACK
            return -1;
    }

return 0;
}

static int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writing)
{
    unsigned long orig_jiffies = jiffies;
    u32 x;
    int result = 0;

if (i2c->irq == 0)
    {    //循环读I2CSR,直到I2CSR[MIF]置1
        while (!(readb(i2c->base + MPC_I2C_SR) & CSR_MIF)) {
            schedule();
            if (time_after(jiffies, orig_jiffies + timeout)) {
                pr_debug("I2C: timeout\n");
                writeccr(i2c, 0);
                result = -EIO;
                break;
            }
        }
        x = readb(i2c->base + MPC_I2C_SR);
        writeb(0, i2c->base + MPC_I2C_SR);
    } else {
        /* Interrupt mode */
        result = wait_event_interruptible_timeout(i2c->queue,
            (i2c->interrupt & CSR_MIF), timeout * HZ);

if (unlikely(result < 0)) {
            pr_debug("I2C: wait interrupted\n");
            writeccr(i2c, 0);
        } else if (unlikely(!(i2c->interrupt & CSR_MIF))) {
            pr_debug("I2C: wait timeout\n");
            writeccr(i2c, 0);
            result = -ETIMEDOUT;
        }

x = i2c->interrupt;
        i2c->interrupt = 0;
    }

if (result < 0)
        return result;

if (!(x & CSR_MCF)) {
        pr_debug("I2C: unfinished\n");
        return -EIO;
    }

if (x & CSR_MAL) {    //仲裁失败
        pr_debug("I2C: MAL\n");
        return -EIO;
    }

if (writing && (x & CSR_RXAK)) {//写后没收到ACK
        pr_debug("I2C: No RXAK\n");
        /* generate stop */
        writeccr(i2c, CCR_MEN);
        return -EIO;
    }
    return 0;
}

static int mpc_read(struct mpc_i2c *i2c, int target,
            u8 * data, int length, int restart)
{
    unsigned timeout = i2c->adap.timeout;
    int i;
    u32 flags = restart ? CCR_RSTA : 0;

/* Start with MEN */    //以防万一,保证I2C模块使能
    if (!restart)
        writeccr(i2c, CCR_MEN);
    /* Switch to read - restart */    //注意这里,再次把CCR_MSTA置1,再触发 START 
    writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_MTX | flags);

/* Write target address byte - this time with the read flag set */ 
    //CPU发送slave I2C addr和读操作1
    writeb((target << 1) | 1, i2c->base + MPC_I2C_DR);
      
     //等待Slave发ACK    if (i2c_wait(i2c, timeout, 1) < 0)
        return -1;

if (length) {
        if (length == 1)
            writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_TXAK);
        else //为什么不置 TXAK
            writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA);
        /* Dummy read */
        readb(i2c->base + MPC_I2C_DR);
    }

for (i = 0; i < length; i++) {
        if (i2c_wait(i2c, timeout, 0) < 0)
            return -1;

/* Generate txack on next to last byte */
        //注意这里TXAK置1,表示CPU每收到1byte数据后,会发送ACK
        if (i == length - 2) 
            writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_TXAK);

/* Generate stop on last byte */
        //注意这里CCR_MSTA [1->0] CPU会触发STOP
        if (i == length - 1)    
            writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_TXAK);

data[i] = readb(i2c->base + MPC_I2C_DR);
    }

return length;
}

很清晰的解读i2c协议【转】的更多相关文章

  1. 很清晰的解读i2c协议

    很清晰的解读i2c协议 转载:http://dpinglee.blog.163.com/blog/static/14409775320112239374615/ 1.I2C协议 2条双向串行线,一条数 ...

  2. (原创) 巩固理解I2C协议(MCU,经验)

        题外话:这几天天气突然转冷了.今天已是11月23日了,查查黄历,昨天(11月22日)刚好是小雪,一夜温度骤降,果然老祖先的经验有灵验!冬天来了,还是多加加衣服,注意保暖! 1.Abstract ...

  3. UART、SPI、I2C协议异同点

    I2C.SPI.UART都是常见的低速板级通信协议,目前主流的SoC都内置了这些通讯协议的控制器,同样,各种传感器.Touch控制器.指纹模块.蓝牙模块.WIFI模块也都兼容这三种通信方式的一种或几种 ...

  4. I2C协议学习笔记

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/wzt_007/article/detai ...

  5. i2c协议

    i2c协议 http://blog.csdn.net/g_salamander/article/details/8016698 总线设备驱动模型 http://blog.csdn.net/u01395 ...

  6. i2c协议简要分析(转载)

    声明 本文大部分内容为转载,因此标定为转载 源地址: http://www.cnblogs.com/zym0805/archive/2011/07/31/2122890.html http://blo ...

  7. LeetCode()Minimum Window Substring 超时,但觉得很清晰。

    我的超时思路,感觉自己上了一个新的台阶,虽然超时了,但起码是给出了一个方法. 遍历s 一遍即可,两个指针,当找到了一个合格的字串后,start 开始走,直到遇到s[start]在t中 如果不符合,en ...

  8. I2C协议(转)

    1.I2C协议   2条双向串行线,一条数据线SDA,一条时钟线SCL.   SDA传输数据是大端传输,每次传输8bit,即一字节.   支持多主控(multimastering),任何时间点只能有一 ...

  9. 硬件和软件兼容i2c协议的24Cxx系列EEPROM存储器(转)

    源:硬件和软件兼容i2c协议的24Cxx系列EEPROM存储器 硬件上由于24c01的A0A1A2管脚不允许悬空,故暂时的想法是兼容24c02 ---24c16 使用一个dip8封装的芯片插座,A0 ...

随机推荐

  1. 2017-12-18python全栈9期第三天第二节之str常用操作方法及for循环之判断字母数字组成

    #!/user/bin/python# -*- coding:utf-8 -*-name = 'zd123'print(name.isalnum()) #由数字或字母组成print(name.isal ...

  2. System.Web.Optimization 合并压缩技术的使用

    捆绑和压缩原理是:将多个css文件动态合并和压缩为一个css文件.多个js文件动态合并和压缩为一个js文件,如此达到减少浏览器对服务器资源文件的请求数量.缩小资源文件的尺寸来提高页面反应速度的目的.A ...

  3. Junit4学习与使用【转】

    参考: http://blog.csdn.net/qqhjqs/article/details/42219037

  4. 阅读:ECMAScript 6 入门(4)

    参考 ECMAScript 6 入门 ES6新特性概览 ES6 全套教程 ECMAScript6 (原著:阮一峰) JavaScript 教程 重新介绍 JavaScript(JS 教程) 数组的扩展 ...

  5. spring boot @Value Could not resolve placeholder

    @Configuration public class PropertySourcePlaceholderConfig { @Bean public PropertySourcesPlaceholde ...

  6. nginx配置fcgi

    1.刚开始用网上最多的方式,perl脚本实现cgi,配置最后都完成,一直是504错误,看日志是perl脚本连接超时,可能是版本太旧了吧,nginx更新用不了那种方式了,搞不清楚.貌似那种帖子都是13年 ...

  7. python+selenium 模拟登陆,自动下单

    目前写的实在太粗糙,留着,以后来写上

  8. 三十三、Linux 进程与信号——中断系统调用和函数可重入性

    33.1 中断系统调用 进程调用 “慢” 系统调用时,如果发生了信号,内核会重启系统调用. 慢系统调用 可能会永久阻塞的系统调用 从终端设备.管道或网络设备上的文件读取 向上述文件写入 某些设备上的文 ...

  9. Mac OSX常用工具

    换Mac有几个月了,刚换的那个月折腾了整整一个月,初用OSX很不适应,这是一种错觉,就好比说了十几年汉语,突然说英语肯定很别扭,适应后就会觉得英语更加实用. Life weiboX(http://we ...

  10. PHP中的会话控制—session和cookie(实现数据传值功能)

    1.session  登录上一个页面以后,长时间没有操作,刷新页面以后需要重新登录. 特点:(1)session是存储在服务器:   (2)session每个人(登陆者)存一份: (3)session ...