1.I2C协议
个。



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的实现
 
  内核代码(linux-2.6.24)中,通过I2C总线存取寄存器的函数都在文件drivers/i2c/busses/i2c-mpc.c中
  最重要的函数是mpc_xfer.
  

  1. static int mpc_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
  2. {
  3. struct i2c_msg *pmsg;
  4. int i;
  5. int ret = 0;
  6. unsigned long orig_jiffies = jiffies;
  7. struct mpc_i2c *i2c = i2c_get_adapdata(adap);
  8. mpc_i2c_start(i2c);    // 设置I2CCR[MEN], 使能I2C module
  9. /* Allow bus up to 1s to become not busy */
  10. //一直读I2CSR[MBB],等待I2C总线空闲下来
  11. while (readb(i2c->base + MPC_I2C_SR) & CSR_MBB) {
  12. if (signal_pending(current)) {
  13. pr_debug("I2C: Interrupted\n");
  14. writeccr(i2c, 0);
  15. return -EINTR;
  16. }
  17. if (time_after(jiffies, orig_jiffies + HZ)) {
  18. pr_debug("I2C: timeout\n");
  19. if (readb(i2c->base + MPC_I2C_SR) ==
  20. (CSR_MCF | CSR_MBB | CSR_RXAK))
  21. mpc_i2c_fixup(i2c);
  22. return -EIO;
  23. }
  24. schedule();
  25. }
  26. for (i = 0; ret >= 0 && i < num; i++) {
  27. pmsg = &msgs[i];
  28. pr_debug("Doing %s %d bytes to 0x%02x - %d of %d messages\n",
  29. pmsg->flags & I2C_M_RD ? "read" : "write",
  30. pmsg->len, pmsg->addr, i + 1, num);
  31. //根据消息里的flag进行读操作或写操作
  32. if (pmsg->flags & I2C_M_RD)
  33. ret = mpc_read(i2c, pmsg->addr, pmsg->buf, pmsg->len, i);
  34. else
  35. ret = mpc_write(i2c, pmsg->addr, pmsg->buf, pmsg->len, i);
  36. }
  37. mpc_i2c_stop(i2c);    //保证为I2CCSR[MSTA]为0,保证能触发STOP
  38. return (ret < 0) ? ret : num;
  39. }

  1. static int mpc_write(struct mpc_i2c *i2c, int target,
  2. const u8 * data, int length, int restart)
  3. {
  4. int i;
  5. unsigned timeout = i2c->adap.timeout;
  6. u32 flags = restart ? CCR_RSTA : 0;
  7. /* Start with MEN */    //以防万一,保证I2C模块使能起来
  8. if (!restart)
  9. writeccr(i2c, CCR_MEN);
  10. /* Start as master */       //写了I2CCR[CCR_MSTA],触发CPU发起START信号
  11. writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_MTX | flags);
  12. /* Write target byte */     //CPU发送一个字节,slave I2C addr和0 (写操作bit)
  13. writeb((target << 1), i2c->base + MPC_I2C_DR);
  14. if (i2c_wait(i2c, timeout, 1) < 0)    //等待slave 发ACK
  15. return -1;
  16. for (i = 0; i < length; i++) {
  17. /* Write data byte */
  18. writeb(data[i], i2c->base + MPC_I2C_DR); //CPU接着发数据,包括reg addr和data
  19. if (i2c_wait(i2c, timeout, 1) < 0)       //等待slave 发ACK
  20. return -1;
  21. }
  22. return 0;
  23. }

  1. static int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writing)
  2. {
  3. unsigned long orig_jiffies = jiffies;
  4. u32 x;
  5. int result = 0;
  6. if (i2c->irq == 0)
  7. {    //循环读I2CSR,直到I2CSR[MIF]置1
  8. while (!(readb(i2c->base + MPC_I2C_SR) & CSR_MIF)) {
  9. schedule();
  10. if (time_after(jiffies, orig_jiffies + timeout)) {
  11. pr_debug("I2C: timeout\n");
  12. writeccr(i2c, 0);
  13. result = -EIO;
  14. break;
  15. }
  16. }
  17. x = readb(i2c->base + MPC_I2C_SR);
  18. writeb(0, i2c->base + MPC_I2C_SR);
  19. } else {
  20. /* Interrupt mode */
  21. result = wait_event_interruptible_timeout(i2c->queue,
  22. (i2c->interrupt & CSR_MIF), timeout * HZ);
  23. if (unlikely(result < 0)) {
  24. pr_debug("I2C: wait interrupted\n");
  25. writeccr(i2c, 0);
  26. } else if (unlikely(!(i2c->interrupt & CSR_MIF))) {
  27. pr_debug("I2C: wait timeout\n");
  28. writeccr(i2c, 0);
  29. result = -ETIMEDOUT;
  30. }
  31. x = i2c->interrupt;
  32. i2c->interrupt = 0;
  33. }
  34. if (result < 0)
  35. return result;
  36. if (!(x & CSR_MCF)) {
  37. pr_debug("I2C: unfinished\n");
  38. return -EIO;
  39. }
  40. if (x & CSR_MAL) {    //仲裁失败
  41. pr_debug("I2C: MAL\n");
  42. return -EIO;
  43. }
  44. if (writing && (x & CSR_RXAK)) {//写后没收到ACK
  45. pr_debug("I2C: No RXAK\n");
  46. /* generate stop */
  47. writeccr(i2c, CCR_MEN);
  48. return -EIO;
  49. }
  50. return 0;
  51. }

  1. static int mpc_read(struct mpc_i2c *i2c, int target,
  2. u8 * data, int length, int restart)
  3. {
  4. unsigned timeout = i2c->adap.timeout;
  5. int i;
  6. u32 flags = restart ? CCR_RSTA : 0;
  7. /* Start with MEN */    //以防万一,保证I2C模块使能
  8. if (!restart)
  9. writeccr(i2c, CCR_MEN);
  10. /* Switch to read - restart */
  11. //注意这里,再次把CCR_MSTA置1,再触发 START
  12. writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_MTX | flags);
  13. /* Write target address byte - this time with the read flag set */
  14. //CPU发送slave I2C addr和读操作1
  15. writeb((target << 1) | 1, i2c->base + MPC_I2C_DR);

//等待Slave发ACK

  1. if (i2c_wait(i2c, timeout, 1) < 0)
  2. return -1;
  3. if (length) {
  4. if (length == 1)
  5. writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_TXAK);
  6. else //为什么不置 TXAK
  7. writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA);
  8. /* Dummy read */
  9. readb(i2c->base + MPC_I2C_DR);
  10. }
  11. for (i = 0; i < length; i++) {
  12. if (i2c_wait(i2c, timeout, 0) < 0)
  13. return -1;
  14. /* Generate txack on next to last byte */
  15. //注意这里TXAK置1,表示CPU每收到1byte数据后,会发送ACK
  16. if (i == length - 2)
  17. writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_TXAK);
  18. /* Generate stop on last byte */
  19. //注意这里CCR_MSTA [1->0] CPU会触发STOP
  20. if (i == length - 1)
  21. writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_TXAK);
  22. data[i] = readb(i2c->base + MPC_I2C_DR);
  23. }
  24. return length;
  25. }

I2C的更多相关文章

  1. I2C子系统之驱动SSD1306 OLED

    理解I2C设备驱动框架,主要围绕四个结构体去分析就容易了. struct i2c_algorithm:提供I2C协议的实现的操作,如:master_xfer实现数据收发的最基本方法. struct i ...

  2. AM335x kernel 4.4.12 i2c eeprom AT24c02驱动移植

    kernel 4.4.12 i2c eeprom AT24c02驱动移植 在kernel make menuconfig ARCH=ARM 中打开: Device Drivers ---> Mi ...

  3. I2C基础知识

    常识 两条总线线路:串行数据总线SDA,串行时钟总线SCL 每个连接到总线的器件都有唯一的地址供其他设备寻址 每个连接到总线的器件都可以作为发送器和接收器 是多主机总线,如果两个或更多主机同时初始化, ...

  4. I2C 基础原理详解

    今天来学习下I2C通信~ I2C(Inter-Intergrated Circuit)指的是 IC(Intergrated Circuit)之间的(Inter) 通信方式.如上图所以有很多的周边设备都 ...

  5. i2c协议

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

  6. I2S/PCM/IOM-2、I2C/SPI/UART/GPIO/slimbus

    概述 I2S,PCM,IOM-2都是数字音频接口,传数据的. I2C,SPI,UART,GPIO是控制接口,传控制信令的. I2S I2S(Inter-IC Sound Bus)是飞利浦公司为数字音频 ...

  7. I2C总线(异步)

    起始位与停止位的定义: 起始信号:当SCL为高期间,SDA由高到低的跳变:启动信号是一种电平跳变时序信号,而不是一个电平信号. 停止信号:当SCL为高期间,SDA由低到高的跳变:停止信号也是一种电平跳 ...

  8. Uart、SPI和I2C的区别

    串口通信:UART.SPI.I2C区别[引用]   1.UART就是两线,一根发送一根接收,可以全双工通信,线数也比较少.数据是异步传输的,对双方的时序要求比较严格,通信速度也不是很快.在多机通信上面 ...

  9. Raspberry Pi I2C驱动 (Python)

    本文参考 http://www.instructables.com/id/Raspberry-Pi-I2C-Python/all/?lang=zh 作者 AntMan232 In this instr ...

  10. S5PV210之GPIO模拟I2c时序之pcf8591与at24xx linux3.0.8驱动

    目录:一. 说明 二. 驱动程序说明及问题 三. 案例一       四. 案例二 一. 说明 mini210开发板上带了at24c08, 看了linux内核自带的at24.c的驱动程序,编译下载到看 ...

随机推荐

  1. C++ TR1 Function Bind

    在C++ 11出现以前,C++的事件一般是通过回调形试来实现,如 void (*func)(int,int,int),其实际上是一种函数指针,在C中调用时是直接写函数名在参数列表中,而在C++中,大部 ...

  2. 导出Excel

    一.asp.net中导出Execl的方法:在asp.net中导出Execl有两种方法,一种是将导出的文件存放在服务器某个文件夹下面,然后将文件地址输出在浏览器上:一种是将文件直接将文件输出流写给浏览器 ...

  3. python 中的高级函数filter()

    filter()函数是 Python 内置的另一个有用的高阶函数,filter()函数接收一个函数 f 和一个list,这个函数 f 的作用是对每个元素进行判断,返回 True或 False,filt ...

  4. Spark的WorkCount的例子

    之前为了搭建scala开发spark的环境花了几天的时间,终于搞定了,具体可以参考:http://www.cnblogs.com/ljy2013/p/4964201.html   .下面就是用一个示例 ...

  5. 2014年7月份第1周51Aspx源码发布详情

      QF万能视频播放器源码  2014-6-30 [VS2010]本源码是一个万能视频播放器源码.可实现各种格式的影片播放功能. 1.点击[开始]按钮,弹出窗口,选择影片路径,确定后即可播放.可拖拽滚 ...

  6. 活用shape、selector和layer-list来打造自己想要的背景效果

    活用shape.selector和layer-list来打造自己想要的背景效果 2016-04-27 13:52 281人阅读 评论(0) 收藏 举报 版权声明:本文为博主原创文章,未经博主允许不得转 ...

  7. Python基础知识之认识字符串

    Python有一个名为“STR”与许多方便的功能(有一个名为“串”,你不应该使用旧的模块),内置的字符串类. 字符串常量可以通过双或单引号括起来,尽管单引号更常用. 反斜杠工作单,双引号内的文字通常的 ...

  8. 一篇介绍java与js操作cookie的

    http://blog.csdn.net/xuweilinjijis/article/details/8651188

  9. 龙哥库塔法or欧拉法求解微分方程matlab实现

    举例:分别用欧拉法和龙哥库塔法求解下面的微分方程 我们知道的欧拉法(Euler)"思想是用先前的差商近似代替倒数",直白一些的编程说法即:f(i+1)=f(i)+h*f(x,y)其 ...

  10. SqlServer 数据库 引擎优化使用(六)

    一:新建模板 二:选择跟踪的语句类型: 使用模板: 把范文的行为进行记录: 开启引擎: 选择文件和数据库: 选择选项: 分析的结果: