转载: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. 【AXI】解读AXI协议事务属性(Transaction Attributes)

    芯片设计验证社区·芯片爱好者聚集地·硬件相关讨论社区·数字verifier星球 四社区联合力荐!近500篇数字IC精品文章收录! [数字IC精品文章收录]学习路线·基础知识·总线·脚本语言·芯片求职· ...

  2. 【数字IC】深入浅出理解I2C协议

    深入浅出理解I2C协议 一.什么是I2C协议 二.I2C,SPI,UART协议的区别 三.I2C的信号线 四.I2C的连接方式 4.1 单主设备,单从设备 4.2 单主设备,多从设备 4.3 多主设备 ...

  3. 【AXI】解读AXI协议双向握手机制的原理

    解读AXI协议双向握手机制的原理 一.写在前面 二.AXI 双向握手机制简介 2.1 信号列表 2.2 双向握手目的 2.3 握手过程 2.3.1 CASE1(READY信号先于VALID信号改变) ...

  4. 22.裸板--I2C协议

    I2C详解(一)_sternlycore的博客-CSDN博客_i2c I2C协议靠这16张图彻底搞懂(超详细)_GREYWALL-CSDN博客_i2c协议 I2C总线通讯协议 - micro虾米 - ...

  5. 看江湖老炮用尽洪荒之力解读网络协议(下)

    作者言:老炮总结的有些协议比喻也不是很恰当,毕竟网络协议是一门科学,而江湖规矩是口口相传的道义:如果把此文当成一份凉菜,"老炮如是说"的话语只能做为一点调味,具体调的好不好,老炮也 ...

  6. 基于I2C协议利用STM32进行温湿度传感器的数据采集

    目录 一.I2C总线通信协议的介绍 1.I2C简介 2.I2C总线时序图 3.五种速率 4.四种信号 5.I2C的优缺点 6.软件IIC和硬件IIC 二.创建工程 1.实验目的 2.工具的选择 3.相 ...

  7. STM32F103完成基于I2C协议的AHT20温湿度传感器的数据采集

    文章目录 一.I2C总线通讯协议 1.I2C总线简介 2.I2C 协议的物理层和协议层 2.1物理层 2.2协议层 3.I2C的两种方式--硬件I2C和软件I2C 3.1硬件I2C 3.2软件I2C ...

  8. 沧小海详解面试的必答题——I2C协议

    目录 第一部分:I2C协议的概述 第二部分:I2C协议的阐述 第三部分:AT24C04简述 第四部分:基于verilog的程序设计(暂无) 对于大多从事FPGA行业的应届生来说,在面试过程中很可能会被 ...

  9. 第019课 I2C协议详解及裸机程序分析

    第001节_I2C协议与EEPROM I2C协议 I2C在硬件上的接法如下(图19-1)所示,主控芯片引出两条线SCL,SDA线,在一条I2C总线上可以接很多I2C设备,我们还会放一个上拉电阻(放一个 ...

  10. I2C 协议图文解析

    转自:https://blog.csdn.net/EastonWoo/article/details/52712826 i2c协议注意几点就很好的使用它: 1)由一个主设备,一个或多个从设备组成,所有 ...

最新文章

  1. IntelliJ IDEA(五) :酷炫插件系列
  2. Luogu-P3205-HNOI2010-合唱队
  3. 梁俊斌:音频技术可以延展众多应用场景
  4. kafka源码编译及开发环境搭建
  5. android照片添加gps,如何利用Exif为图片文件添加GPS坐标信息
  6. 日留存、周留存、月留存,究竟怎样才能让更多的用户留下来?
  7. 计算机多媒体最新参考文献,计算机多媒体论文
  8. 修改卡巴斯基注册表,无限试用
  9. Java基础语法练习题
  10. (Adobe Premiere Pro CS4)[ISO]《Adobe非线性视频编辑软件》
  11. 三次hermite插值多项式例题_2点三次Hermite插值多项式解析.ppt
  12. [R语言] R语言快速入门教程
  13. 2019仿互站网源码T5友价内核PC+社区+博客+手机+整站数据 全新运营
  14. 西瓜书之误差逆传播公式推导、源码解读及各种易混淆概念
  15. python中ix用法_在python的pandas模块中,DataFrame对象,如何选择一行?索引、loc、iloc、ix的用法及区别...
  16. 普适计算-2014/04/04
  17. 在html页头设置不缓存
  18. 基于STM32F103单片机的智能温室大棚RS485通信温湿度监测
  19. 全网最新最细最全最牛的jmeter接口测试,性能测试,没有之一,如有雷同纯属抄袭。
  20. 天融信学习笔记---DOS命令

热门文章

  1. ‘javah‘ 不是内部或外部命令,也不是可运行的程序 或批处理文件
  2. 一文搞懂Android抓包
  3. C++配置OpenCv:一劳永逸
  4. B3610 [图论与代数结构 801] 无向图的块
  5. 数据包络分析CCR、BCC模型
  6. 三种1:4传输线变压器巴伦的分析
  7. python 压力测试
  8. ubuntu2004 安装protoc
  9. 大学学计算机考试大一,大学计算机基础大一考试必备题库[1].pdf
  10. c语言循环接收按键,C语言中,如何用键盘输入来退出循环