I2C总线协议学习笔记

发布者:chunying最新更新时间:2015-08-11 来源: dzsc关键字:I2C  总线协议  学习笔记 手机看文章 扫描二维码
随时随地手机看文章
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发送I2C addr(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.

  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.  

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

  10.  


  11. //一直读I2CSR[MBB],等待I2C总线空闲下来

  12. while (readb(i2c->base + MPC_I2C_SR) & CSR_MBB) {

  13. if (signal_pending(current)) {

  14. pr_debug("I2C: Interruptedn");

  15. writeccr(i2c, 0);

  16. return -EINTR;

  17. }

  18. if (time_after(jiffies, orig_jiffies + HZ)) {

  19. pr_debug("I2C: timeoutn");

  20. if (readb(i2c->base + MPC_I2C_SR) ==

  21. (CSR_MCF | CSR_MBB | CSR_RXAK))

  22. mpc_i2c_fixup(i2c);

  23. return -EIO;

  24. }

  25. schedule();

  26. }

  27.  

  28. for (i = 0; ret >= 0 && i < num; i++) {

  29. pmsg = &msgs[i];

  30. pr_debug("Doing %s %d bytes to 0xx - %d of %d messagesn",

  31. pmsg->flags & I2C_M_RD ? "read" : "write",

  32. pmsg->len, pmsg->addr, i + 1, num);
  33. //根据消息里的flag进行读操作或写操作
  34. if (pmsg->flags & I2C_M_RD)

  35. ret = mpc_read(i2c, pmsg->addr, pmsg->buf, pmsg->len, i);

  36. else

  37. ret = mpc_write(i2c, pmsg->addr, pmsg->buf, pmsg->len, i);

  38. }

  39. mpc_i2c_stop(i2c); //保证为I2CCSR[MSTA]为0,保证能触发STOP

  40. return (ret < 0) ? ret : num;

  41. }
[page]

  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.  

  8. //以防万一,保证I2C模块使能起来

  9. if (!restart)

  10. writeccr(i2c, CCR_MEN);

  11. //写了I2CCR[CCR_MSTA],触发CPU发起START信号

  12. writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_MTX | flags);

  13. //CPU发送一个字节,slave I2C addr和0 (写操作bit)

  14. writeb((target << 1), i2c->base + MPC_I2C_DR);

  15.  

  16. if (i2c_wait(i2c, timeout, 1) < 0) //等待slave 发ACK

  17. return -1;

  18.  

  19. for (i = 0; i < length; i++) {


  20. writeb(data[i], i2c->base + MPC_I2C_DR); //CPU接着发数据,包括reg addr和data

  21.  

  22. if (i2c_wait(i2c, timeout, 1) < 0) //等待slave 发ACK

  23. return -1;

  24. }

  25.  

  26. return 0;

  27. }


  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.  

  7. if (i2c->irq == 0)

  8. { //循环读I2CSR,直到I2CSR[MIF]置1

  9. while (!(readb(i2c->base + MPC_I2C_SR) & CSR_MIF)) {

  10. schedule();

  11. if (time_after(jiffies, orig_jiffies + timeout)) {

  12. pr_debug("I2C: timeoutn");

  13. writeccr(i2c, 0);

  14. result = -EIO;

  15. break;

  16. }

  17. }

  18. x = readb(i2c->base + MPC_I2C_SR);

  19. writeb(0, i2c->base + MPC_I2C_SR);

  20. } else {


  21. result = wait_event_interruptible_timeout(i2c->queue,

  22. (i2c->interrupt & CSR_MIF), timeout * HZ);

  23.  

  24. if (unlikely(result < 0)) {

  25. pr_debug("I2C: wait interruptedn");

  26. writeccr(i2c, 0);

  27. } else if (unlikely(!(i2c->interrupt & CSR_MIF))) {

  28. pr_debug("I2C: wait timeoutn");

  29. writeccr(i2c, 0);

  30. result = -ETIMEDOUT;

  31. }

  32.  

  33. x = i2c->interrupt;

  34. i2c->interrupt = 0;

  35. }

  36.  

  37. if (result < 0)

  38. return result;

  39.  

  40. if (!(x & CSR_MCF)) {

  41. pr_debug("I2C: unfinishedn");

  42. return -EIO;

  43. }

  44.  

  45. if (x & CSR_MAL) { //仲裁失败

  46. pr_debug("I2C: MALn");

  47. return -EIO;

  48. }

  49.  

  50. if (writing && (x & CSR_RXAK)) {//写后没收到ACK

  51. pr_debug("I2C: No RXAKn");


  52. writeccr(i2c, CCR_MEN);

  53. return -EIO;

  54. }

  55. return 0;

  56. }

  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.  

  8. //以防万一,保证I2C模块使能

  9. if (!restart)

  10. writeccr(i2c, CCR_MEN);

  11. //注意这里,再次把CCR_MSTA置1,再触发 START

  12. writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_MTX | flags);

  13.  

  14.  


  15. //CPU发送slave I2C addr和读操作1

  16. writeb((target << 1) | 1, i2c->base + MPC_I2C_DR);

//等待Slave发ACK
  1. if (i2c_wait(i2c, timeout, 1) < 0)

  2. return -1;

  3.  

  4. if (length) {

  5. if (length == 1)

  6. writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_TXAK);

  7. else //为什么不置 TXAK

  8. writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA);


  9. readb(i2c->base + MPC_I2C_DR);

  10. }

  11.  

  12. for (i = 0; i < length; i++) {

  13. if (i2c_wait(i2c, timeout, 0) < 0)

  14. return -1;

  15.  


  16. //注意这里TXAK置1,表示CPU每收到1byte数据后,会发送ACK

  17. if (i == length - 2)

  18. writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_TXAK);

  19.  


  20. //注意这里CCR_MSTA [1->0] CPU会触发STOP

  21. if (i == length - 1)

  22. writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_TXAK);

  23.  

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

  25. }

  26.  

  27. return length;

  28.  
  29. }
关键字:I2C  总线协议  学习笔记 引用地址:I2C总线协议学习笔记

上一篇:白话现场总线
下一篇:PROFIBUS-DP总线连接器终端电阻的作用

推荐阅读最新更新时间:2024-05-02 23:52

STM32学习笔记(三) STM32的GPIO的深入学习
STM32的开发学习主要涉及软硬件两个部分的实现,包含众多外设和总线的理解配置。STM32的整个学习曲线并不陡峭,但入门却相当困难,因此在学习之初,多动手实验和测试相当重要,GPIO作为整个STM32与外部连接的端口,难度不高,却十分重要。从深入解析GPIO外设开始,一步步熟悉掌握STM32各个模块,就是STM32的整个学习流程。 GPIO模块回顾 在嵌入式软件开发中,几乎所有功能的实现都需要GPIO端口输出才能发挥作用。GPIO端口的操作包括时钟使能,寄存器配置,端口信息修改。这些基础的东西上一章已经讲过,我这里就不在细说,我这里主要讲GPIO涉及到的其它库函数。 1. 读取GPIO端口数据函数 GPIO_ReadInp
[单片机]
STM32<font color='red'>学习</font><font color='red'>笔记</font>(三) STM32的GPIO的深入<font color='red'>学习</font>
STM32单片机/I2C通信(上篇)
本文使用STM32FI03RCT6型号的单片机, 基于正点原子的函数库进行总结讲解 复制 想来单片机这块儿除了USART串口通信外,常见的便是I2C通信了,因为I2C通信 硬件连接简单,可扩展性强,但是这种硬件连线的简洁,是以协议的复杂来弥补的。I2C通信是一种半双工通信,也就是可以双向传输数据但不能同时进行。 STM32单片机是可以进行硬件I2C通信或者软件模拟进行I2C通信的,硬件I2C通信只需要对I2C引脚以及通信模式这两个结构体进行初始化即可,但I2C硬件通信由于硬件原因并不稳定(原子哥说的),不过在STM32F4系列有所改善,但我都没试过(寒假在家手头硬件条件不足)。 下面我们基于软件I2C模拟进行说明。 I2C通信
[单片机]
STM32单片机/<font color='red'>I2C</font>通信(上篇)
嵌入式学习笔记13——51单片机之D/A转换器
1. 在很多应用系统中,测控对象是模拟量,单片机只能处理数字量,因此必须进行数字量和模拟量之间的转换。这就需要A/D和D/A转换器件。 2. 假如某D/A可输入8位数字,最高输出5V电压,则输入x,输出电压值为x*(5/256)V。 3. 分辨率是指输入数字量的最低有效位(LSB)发生变化时,所对应的的输出模拟量(电压或电流)的变化量。它反映了输出模拟量的最小变化值。即,最大输出模拟量/(2^位数)。 4. 线性度(也称非线性误差)是实际转换特性曲线与理想直线特性之间的最大偏差。常以相对于满量程(即最大输出模拟量)的百分数表示。(假设DAC位8位,满量程为5V,则理想直线为连接(0,0V)和(255,5V)之间的直线。 5.
[单片机]
STM32学习笔记之USART
USART功能概述 接口通过三个引脚与其他设备连接在一起(见图248)。任何USART双向通信至少需要两个脚:接收数据输入(RX)和发送数据输出(TX)。 RX:接收数据串行输。通过过采样技术来区别数据和噪音,从而恢复数据。 TX:发送数据输出。当发送器被禁止时,输出引脚恢复到它的I/O端口配置。当发送器被激活,并且不发送数据时,TX引脚处于高电平。在单线和智能卡模式里,此I/O口被同时用于数据的发送和接收。 ● 总线在发送或接收前应处于空闲状态 ● 一个起始位 ● 一个数据字(8或9位),最低有效位在前 ● 0.5,1.5,2个的停止位,由此表明数据帧的结束 ● 使用分数波特率发生器 12位整数和4位小数的表示方法
[单片机]
I2C串行总线的组成据工作原理
1、常用的串行扩展总线有:I2C总线、单总线、SPI总线 2、I2C总线只有两根双向信号线。一种是数据线SDA,另一种是时钟线SCL。 3、I2C总线通过上拉电阻接正电源。当总线空闲时,两根线均为高电平。连到总线上的 任一器件输出的低电平,都将使总线的信号变低,即各器件的SDA及SCL都是线“与”关 系。 4、I2C总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保持稳定, 只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。 5、SCL线为高电平期间,SDA线由高电平向低电平的变化表示起始信号;SCL线为高电平 期间,SDA线由低电平向高电平的变化表示终止信号。 6、起始和终止信
[单片机]
51proteus仿真:I2c总线和EEPROM2404的读写
仿真电路图: 仿真程序: #include reg52.h #include INTRINS.H #define uchar unsigned char #define uint unsigned int sbit SCL=P1^0; sbit SDA=P1^1; void delay(void) { _nop_(); _nop_(); _nop_(); _nop_(); } void InitI2C(void) { SDA = 1; SCL = 1; } void I2CStart(void) { SDA=1; delay(); SCL=1; delay(); SDA=0; delay(); SCL=0; }
[单片机]
51proteus仿真:<font color='red'>I2c</font>总线和EEPROM2404的读写
Microwire总线协议
Microwire串行接口是SPI的精简接口,能满足通常外设的需求。Microwire总线是美国国家半导体(NS)公司推出的三线同步串行总线。这种总线由一根数据输出线(SO)、一根数据输入线(SI)和一根时钟线(SK)组成 (但每个器件还要接一根片选线)。原始的Microwire总线上只能连接一片单片机作为主机,总线上的其它设备都是从机。此后,NS公司推出了8位的COP800单片机系列,仍采用原来的Microwire总线,但单片机上的总线接口改成既可由自身发出时钟,也可由外部输入时钟信号,也就是说,连接到总线上的单片机既可以是主机,也可以是从机。为了区别于原有的Microwire总线,称这种新产品为增强型的Microwire/PLU
[嵌入式]
如何将I2C LCD与STM32F103C8T6连接?
在本教程中,我将向您展示如何将I2C LCD与基于STM32F103C8T6 MCU的STM32 Blue Pill Board接口。如果您还记得“将16X2 LCD与STM32F103C8T6接口”的教程,我已经向您展示了将LCD与STM32连接并显示一些信息有多么简单。该项目将非常有趣,因为我将利用I2C通讯与16×2 LCD进行通讯。 介绍 小型的字母数字字符显示器(如非常流行的16×2 LCD显示器)是非常有用的小组件,因为您可以使用它们来显示与项目相关的一些重要信息。LCD上显示的信息可以与项目本身相关,如从温度传感器读取的信息或特殊数据(如调试消息或错误代码)。 我在很多项目中都使用了16×2 LCD显示模块,其中
[单片机]
如何将<font color='red'>I2C</font> LCD与STM32F103C8T6连接?
小广播
最新嵌入式文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved