EEPROM I2C操作说明.docx

上传人:b****7 文档编号:9015080 上传时间:2023-02-02 格式:DOCX 页数:15 大小:278.79KB
下载 相关 举报
EEPROM I2C操作说明.docx_第1页
第1页 / 共15页
EEPROM I2C操作说明.docx_第2页
第2页 / 共15页
EEPROM I2C操作说明.docx_第3页
第3页 / 共15页
EEPROM I2C操作说明.docx_第4页
第4页 / 共15页
EEPROM I2C操作说明.docx_第5页
第5页 / 共15页
点击查看更多>>
下载资源
资源描述

EEPROM I2C操作说明.docx

《EEPROM I2C操作说明.docx》由会员分享,可在线阅读,更多相关《EEPROM I2C操作说明.docx(15页珍藏版)》请在冰豆网上搜索。

EEPROM I2C操作说明.docx

EEPROMI2C操作说明

I2C协议

  

  2条双向串行线,一条数据线SDA,一条时钟线SCL。

  SDA传输数据是大端传输,每次传输8bit,即一字节。

  支持多主控(multimastering),任何时间点只能有一个主控。

  总线上每个设备都有自己的一个addr,共7个bit,广播地址全0.

  系统中可能有多个同种芯片,为此addr分为固定部分和可编程部份,细节视芯片而定,看datasheet。

1.1I2C位传输

  数据传输:

SCL为高电平时,SDA线若保持稳定,那么SDA上是在传输数据bit;

            若SDA发生跳变,则用来表示一个会话的开始或结束(后面讲)

  数据改变:

SCL为低电平时,SDA线才能改变传输的bit

1.2I2C开始和结束信号

   

  开始信号:

SCL为高电平时,SDA由高电平向低电平跳变,开始传送数据。

  结束信号:

SCL为高电平时,SDA由低电平向高电平跳变,结束传送数据。

  

1.3I2C应答信号

   

  Master每发送完8bit数据后等待Slave的ACK。

  即在第9个clock,若从IC发ACK,SDA会被拉低。

  若没有ACK,SDA会被置高,这会引起Master发生RESTART或STOP流程,如下所示:

1.4I2C写流程

写寄存器的标准流程为:

1.   Master发起START

2.   Master发送I2Caddr(7bit)和w操作0(1bit),等待ACK

3.   Slave发送ACK

4.   Master发送regaddr(8bit),等待ACK

5.   Slave发送ACK

6.   Master发送data(8bit),即要写入寄存器中的数据,等待ACK

7.   Slave发送ACK

8.   第6步和第7步可以重复多次,即顺序写多个寄存器

9.   Master发起STOP

写一个寄存器

写多个寄存器

1.5I2C读流程

读寄存器的标准流程为:

1.   Master发送I2Caddr(7bit)和w操作1(1bit),等待ACK

2.   Slave发送ACK

3.   Master发送regaddr(8bit),等待ACK

4.   Slave发送ACK

5.   Master发起START

6.   Master发送I2Caddr(7bit)和r操作1(1bit),等待ACK

7.   Slave发送ACK

8.   Slave发送data(8bit),即寄存器里的值

9.   Master发送ACK

10.   第8步和第9步可以重复多次,即顺序读多个寄存器

读一个寄存器

读多个寄存器

1.前言

  对于大多数工程师而言,I2C永远是一个头疼的问题。

相比UART和SPI而言,I2C的时序要复杂一些,I2C组合变化也丰富一些。

在这里以AT24C04为例说明I2C使用过程中的一些注意点。

2.AT24C04操作示意图

图AT24C04操作示意图

示意图说明:

示意图分阐述了4种不同的操作方式,例如写单个存储单元,写多个存储单元,读单个存储单元和写单个存储单元。

对于单个操作而言,上部为MCU通过I2C输出的相关指令,下部为I2C设备的响应。

例如写单个存储单元操作时,MCU发出I2C启动,设备地址,写标志位等,而I2C设备输出多个ACK。

3.若干说明

3.1基本操作方式

I2C设备的操作可分为写单个存储字节,写多个存储字节,读单个存储字节和读多个存储字节。

相对于AT24C04而言,这些读写动作相对于内部的存储单元而言,对于其他的具备I2C接口的AD或传感器而言,存储单元变成了寄存器单元。

虽然存在概念上的差别,但是其操作原理确实一样的。

3.2无应答

在以上4种情况中,无应答为MCU发出,无应答意为MCU不需要从机输出数据,MCU将会停止本次I2C操作。

需要说明的是,无应答并不是一种异常情况。

3.3I2C设备并不只有一个设备地址

这一点往往被忽略,一般情况下认为在I2C启动信号之后的字节为I2C从机地址(7位)。

对于AT24C04而言,内部具有4Kb存储位,合计512字节。

若需要访问512字节内容,总共需要9根地址线(8位宽度),那么上图中的存储地址(8位长度)显然还差了一位,那么就需要从设备地址中“借”1位,这就使得AT24C04具有两个I2C地址,例如0x50和0x51。

3.4存储地址

相对于AT24C04而言,存储地址占1个字节。

若换成其他I2C设备,例如ADXL345,存储地址被寄存器地址替代即可,其他操作方式相似。

但是像AT24C32或AT24C64这样的大容量EEPROM,则存储地址需要2字节描述,也就意味着需要连续发送两个字节地址信息且高字节在前。

其他像BH1750这样的光照芯片,存储地址被具体的操作命令替代,使用I2C设备时需要因地制宜,切不可照搬教条。

3.5连续读和连续写限制

AT24C04中存在页的概念,一页的大小为8字节,若果在单页的范围内,存储地址累加,若超过该页的最大地址,存储地址回到页开始处。

所以对于连续读和连续写而言,最大的操作字节数为8。

若需要操作的字节内容超过8字节,则需要进行翻页操作,即写入下一页的起始存储地址。

4总结

  I2C设备有很多种,若掌握基本原理,便可见招拆招,那是I2C总线就不那么难了。

5.参考资料

2.PowerPC的I2C实现

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

2.1I2CADR地址寄存器

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

 

2.2I2CFDR频率设置寄存器

TheserialbitclockfrequencyofSCLisequaltotheCCBclockdividedbythedivider.

用来设置I2C总线频率

2.3I2CCR控制寄存器

MEN:

ModuleEnable.   置1时,I2C模块使能

MIEN:

ModuleInterruptEnable.置1时,I2C中断使能。

MSTA:

Master/slavemode.1Mastermode,0Slavemode.

      当1->0时,CPU发起STOP信号

      当0->1时,CPU发起START信号

MTX:

Transmit/receivemodeselect.0Receivemode,1Transmitmode

TXAK:

Transferacknowledge.置1时,CPU在9thclock发送ACK拉低SDA

RSTA:

RepeatSTART.置1时,CPU发送REPEATSTART

BCST:

置1,CPU接收广播信息(信息的slaveaddr为7个0)

2.4I2CSR状态寄存器

MCF:

0 Bytetransferisinprocess

    1 Bytetransferiscompleted

MAAS:

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

MBB:

0I2Cbusidle  

    1I2Cbusbusy

MAL:

若置1,表示仲裁失败

BCSTM:

若置1,表示接收到广播信息

SRW:

WhenMAASisset,SRWindicatesthevalueoftheR/Wcommandbitofthecallingaddress,whichissentfromthemaster.

  0Slavereceive,masterwritingtoslave

  1Slavetransmit,masterreadingfromslave

MIF:

Moduleinterrupt.TheMIFbitissetwhenaninterruptispending,causingaprocessorinterruptrequest(providedI2CCR[MIEN]isset)

RXAK:

若置1,表示收到了ACK

2.5I2CDR数据寄存器

这个寄存器储存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.

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

10.

11.    /*Allowbusupto1stobecomenotbusy*/

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

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

14.        if (signal_pending(current)) {

15.            pr_debug("I2C:

Interrupted\n");

16.            writeccr(i2c, 0);

17.            return -EINTR;

18.        }

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

20.            pr_debug("I2C:

timeout\n");

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

22.                (CSR_MCF | CSR_MBB | CSR_RXAK))

23.                mpc_i2c_fixup(i2c);

24.            return -EIO;

25.        }

26.        schedule();

27.    }

28.

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

30.        pmsg = &msgs[i];

31.        pr_debug("Doing%s%dbytesto0x%02x-%dof%dmessages\n",

32.             pmsg->flags & I2C_M_RD ?

 "read" :

 "write",

33.             pmsg->len, pmsg->addr, i + 1, num);

34.        //根据消息里的flag进行读操作或写操作

35.        if (pmsg->flags & I2C_M_RD) 

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

37.        else

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

39.    }

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

41.    return (ret < 0) ?

 ret :

 num;

42.}

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.    u32flags = restart ?

 CCR_RSTA :

 0;

7.

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

9.    if (!

restart)

10.        writeccr(i2c, CCR_MEN);

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

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

13.    /*Writetargetbyte*/     //CPU发送一个字节,slaveI2Caddr和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.        /*Writedatabyte*/

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

22.

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

24.            return -1;

25.    }

26.

27.    return 0;

28.}

1.static int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writing)

2.{

3.    unsigned long orig_jiffies = jiffies;

4.    u32x;

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:

timeout\n");

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.        /*Interruptmode*/

22.        result = wait_event_interruptible_timeout(i2c->queue,

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

24.

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

26.            pr_debug("I2C:

waitinterrupted\n");

27.            writeccr(i2c, 0);

28.        } else if (unlikely(!

(i2c->interrupt & CSR_MIF))) {

29.            pr_debug("I2C:

waittimeout\n");

30.            writeccr(i2c, 0);

31.            result = -ETIMEDOUT;

32.        }

33.

34.        x = i2c->interrupt;

35.        i2c->interrupt = 0;

36.    }

37.

38.    if (result < 0)

39.        return result;

40.

41.    if (!

(x & CSR_MCF)) {

42.        pr_debug("I2C:

unfinished\n");

43.        return -EIO;

44.    }

45.

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

47.        pr_debug("I2C:

MAL\n");

48.        return -EIO;

49.    }

50.

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

52.        pr_debug("I2C:

NoRXAK\n");

53.        /*generatestop*/

54.        writeccr(i2c, CCR_MEN);

55.        return -EIO;

56.    }

57.    return 0;

58.}

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.    u32flags = restart ?

 CCR_RSTA :

 0;

7.

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

9.    if (!

restart)

10.        writeccr(i2c, CCR_MEN);

11.    /*Switchtoread-restart*/

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

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

14.

15.

16.    /*Writetargetaddressbyte-thistimewiththereadflagset*/ 

17.    //CPU发送slaveI2Caddr和读操作1

18.    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.        /*Dummyread*/

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

11.    }

12.

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

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

15.            return -1;

16.

17.        /*Generatetxackonnexttolastbyte*/

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

19.        if (i == length - 2) 

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

21.

22.        /*Generatestoponlastbyte*/

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

24.        if (i == length - 1)    

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

26.

27.        data[i] = readb(i2c-

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 农学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1