I2C总线的使用 --- EEPROM 存储器使用

I2C电气特性

I2C(Inter-Integrated Circuit)总线是由PHILIPS公司开发的两线式串行总线,用于连接微控制器及其外围设备。

如下图所示:
这里写图片描述

I2C总线只有两根双向信号线
SDA : Serial Data Line : 数据线
SCL : Serial Clock : 时钟线

总线寻址

I2C总线协议规定:从设备采用7位的地址。D7~D1:从设备地址。D0位:数据传送方向位,为“0”时表示主设备向从设备写数据,为“1”时表示主机由从设备读数据。主设备发送地址时,总线上的每个从设备都将这7位地址码与自己的地址进行比较,如果相同,则认为自己正被主设备寻址,根据R/W位将自己确定为发送器或接收器。

如下图所示:
这里写图片描述

从设备的地址由固定部分用户自定义部分组成:
1、 固定部分:D7-D4 共4位决定的。这是由从设备的生产厂商生产时就已确定的值。
2、 用户自定义部分:D3-D1 共3位。这3位通常对应设备的3个引脚(A0~A2)。把3个引脚接到不同的电平上,就可以形成一个3位的数值。

举例说明:EEPROM芯片AT24C08
这里写图片描述

I2C总线时序

空闲状态:
I2C总线总线的SDA和SCL两条信号线同时处于高电平时,规定为总线的空闲状态。

起始状态:
在时钟线SCL保持高电平期间,数据线SDA上的电平被拉低(即负跳变),定义为I2C总线总线的启动信号,它标志着一次数据传输的开始。

数据位传送:
I2C总线上的所有数据(地址和数据)都是以8位一个字节为单位传送的。

应答位:
发送器每发送一个字节,就在时钟脉冲第9位释放数据线,由接收器反馈一个应答信号。应答信号为低电平时,定为有效应答位ACK,表示接收器已经成功地接收了该字节;应答信号为高电平时,定为非应答位(NACK),表示接收器没有成功接收该字节。在第9位,SCL线为高电平(ACK),应答信号在SDA线上。

结束状态:
在时钟线SCL保持高电平时,数据线SDA被释放,使得SDA返回高电平(即正跳变),称为I2C总线的停止信号。

时序如下图所示:
这里写图片描述

EEPROM简介 — (在I2C中作为从机)

EEPROM (Electrically Erasable Programmable Read-Only Memory),电可擦可编程只读存储器,是一种类似于flash的固态存储器,但是与flash相比又存在一些区别:
1、EEPROM 可以按位擦写,而FLASH只能大片擦除。
2、EEPROM 一般容量都不大,一般都在64Kbit以下。

地址查找:
可以通过 开发板的原理图 和 EEPROM的芯片手册 查找到EEPROM的地址:

开发板原理图,以TQ2440为例:
这里写图片描述

EEPROM芯片以AT24C02A为例,在芯片手册中有:
这里写图片描述

红框中就是该芯片的地址。前四位是固定部分,后四位是用户通过电路自定义的部分。

I2C裸机代码编写 — EEPROM的使用

以TQ2440为例,初始化:
这里写图片描述

时序图:
这里写图片描述

发送数据:
这里写图片描述
在上图中,在写入数据之前还需要加上:写入字节的地址。

读取数据:
这里写图片描述
具体的流程应该以参考代码中为准,以下图所示:

这里写图片描述

参考代码:

//I2C总线和EEPROM的使用
#define INTPND (*(volatile unsigned long*)0x4a000010)
#define SRCPND (*(volatile unsigned long*)0x4a000000)
#define INTMSK (*(volatile unsigned long*)0x4a000008)
#define GPECON (*(volatile unsigned long*)0x56000040)
#define GPEUP  (*(volatile unsigned long*)0x56000048)

#define IICCON   (*(volatile unsigned char*)0x54000000)
#define IICSTAT  (*(volatile unsigned char*)0x54000004)
#define IICDS    (*(volatile unsigned char*)0x5400000C)

#define SLAVE_WRITE_ADD 0xa0
#define SLAVE_READ_ADD  0xa1

void delay(int i)
{
    int j = 0;
    while (i--) 
        for(j=0;j<100;j++);
}

void i2c_init()
{
    //1.a 初始化中断
    INTPND |= (1<<27);
    SRCPND |= (1<<27);  
    INTMSK &= ~(1<<27);

    IICCON |= (1<<5); 

    //1.b 设置scl时钟
    IICCON &= ~(1<<6);
    IICCON &= ~(0xf<<0);
    IICCON |= (0x5<<0);

    //2. 设置IICSTAT  
    IICCON |= (1<<4);

    //3.设置引脚功能
    GPECON |= (0x2<<28)|(0x2<<30);
    GPEUP |= (0x3<<14);

    //4.允许产生ACK
    IICCON |= (1<<7);
}

void write_byte(unsigned char xchar, unsigned char daddr)
{   
    //1.设置处理器为主设备+发送模式
    IICSTAT |= (3<<6);

    //2.将从设备的地址写入到IICDS寄存器
    IICDS = SLAVE_WRITE_ADD;
    IICCON &= ~(1<<4);

    //3.写入0xF0写入IICSTAT
    IICSTAT = 0xF0;

    //4.等待ACK的产生
    while ((IICCON & (1<<4)) == 0 )
        delay(100);

    //5.1写入字节的地址到IICDS寄存器
    IICDS = daddr;
    IICCON &= ~(1<<4);

    //5.2等待ACK的产生
    while ((IICCON & (1<<4)) == 0 )
        delay(100);

    //6.将要传输的字节数据写入IICDS寄存器
    IICDS = xchar;
    IICCON &= ~(1<<4);   

    //7.等待ACk的产生
    while ((IICCON & (1<<4)) == 0 )
        delay(100);

    //8.写入0xD0到IICSTAT
    IICSTAT = 0xD0;

    //9.清除中断    
    IICCON &= ~(1<<4); 

    delay(100);
}

void read_data(unsigned char *buf, unsigned char daddr, int length)
{
    int j =0;
    unsigned char unusedata;

    //设置为主设备发送模式
    IICSTAT |= (3<<6);

    //写入从设备地址
    IICDS = SLAVE_WRITE_ADD;
    IICCON &= ~(1<<4);

    //写入0xF0到IICSTAT
    IICSTAT = 0xF0;

    //等待ACK
    while ((IICCON & (1<<4)) == 0 )
        delay(100);

    //写入eeprom内部地址
    IICDS = daddr;
    IICCON &= ~(1<<4);

    //等待ACK
    while ((IICCON & (1<<4)) == 0 )
        delay(100);

    //设置为主设备接收模式
    IICSTAT &= ~(3<<6);
    IICSTAT |= (2<<6);

    //写入从设备地址到IICDS
    IICDS = SLAVE_READ_ADD;
    IICCON &= ~(1<<4);

    //写入0xB0到IICSTAT开始接收
    IICSTAT = 0xb0;
    while ((IICCON & (1<<4)) == 0 )
        delay(100);

    //写入设备内部地址
    IICDS = daddr;
    IICCON &= ~(1 << 4);
    while((IICCON & (1 << 4)) == 0)
        delay(100);

    //丢掉收到的第1个字节
    unusedata = IICDS;
    IICCON &= ~(1<<4);
    while ((IICCON & (1<<4)) == 0 )
        delay(100);

    for(j=0;j<length;j++)
    {
        if(j == (length -1))
            IICCON &= ~(1<<7);         

        //从IICDS里取出数据
        buf[j]=IICDS;

        //清除中断
        IICCON &= ~(1<<4);

        //等待中断
        while ((IICCON & (1<<4)) == 0 )
            delay(100);
    }

    //写入0x90到IICSTAT
    IICSTAT = 0x90;

    //清除中断
    IICCON &= ~(1<<4);
}

void i2c_test()
{
    int i=0;
    unsigned char sbuf[256]={0};
    unsigned char dbuf[256]={0};    

    i2c_init();

    for(i=0;i<256;i++)
    {
        sbuf[i] = i+1;
        dbuf[i] = 0;
    }

    printf("dbuf befor I2C read:\r\n");

    for(i =0; i<256;i++)
    {
       if(i%8==0)
           printf("\r\n");

       printf("%d\t",dbuf[i]);  
    }   

    for(i=0;i<256;i++)
        write_byte(sbuf[i],i);

    printf("i2c reading, plese wait!\n\r");

    read_data(dbuf,0,256);

    printf("dbuf after I2C read:\r\n");

    for(i =0; i<256;i++)
    {
       if(i%8==0)
           printf("\r\n");

       printf("%d\t",dbuf[i]);  
    }   
}
  • 4
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
dsp中使用i2c协议来存储eeprom是一种常见的应用场景,下面我将通过一个实例来详细介绍这个过程。 首先,i2c是一种串行通信协议,用于在主设备和从设备之间进行数据传输。而eeprom是一种电子可擦写可编程只读存储器,可以在电源关闭的情况下持久保存数据。 在dsp中,使用i2c协议访问eeprom通常需要按照以下步骤进行: 1. 初始化i2c总线:在使用i2c之前,需要初始化i2c总线,设置控制寄存器和时钟等参数。这些参数通常根据eeprom的规格手册来配置。 2. 设置从设备地址:根据eeprom的规格手册,设置该eeprom的从设备地址。在i2c总线上,每个从设备都有一个唯一的地址,通过这个地址可以识别和访问该设备。 3. 写入数据:使用i2c协议,发送写入命令和数据到eeprom,将要保存的数据写入到eeprom的存储区域。 4. 读取数据:使用i2c协议,发送读取命令到eeprom,并从eeprom的存储区域读取数据。可以通过读取指定地址或者连续读取多个地址的方式获取需要的数据。 5. 关闭i2c总线:在完成数据读写操作后,关闭和释放i2c总线资源。 总结起来,dsp中使用i2c存储eeprom的实例分析主要涉及初始化i2c总线、设置从设备地址、写入数据、读取数据以及关闭i2c总线等过程。这些步骤可以根据具体的dsp和eeprom的规格手册进行具体的实现和调试。通过使用i2c协议来存储eeprom,可以实现dsp与外部存储器之间的数据交互,扩展dsp系统的存储容量和功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值