S5PV210 I2C总线

来源:互联网 发布:unity3d 实现拍照功能 编辑:程序博客网 时间:2024/05/02 21:00

I2C(Inter-Integrated Circuit)总线是一种由 Philips 公司开发的两线式串行总线,用于连接微控制器及其外围设备。I2C 总线只有两根连接接口(串行数据 SDA 和串行时钟 SCL 

线) ,具有使用方便,连接简单,占用空间小,并且支持多主控等优点。因此,在嵌入式系统中,I2C 总线被广泛应用于许多重要外扩设备的连接.


总线上发送数据的器件被称作发送器,接收数据的器件被称作接收器。控制信息交换的器件被称作主器件(CPU) ,受主器件控制的器件则被称作从器件(AT24Cxx 芯片在总

线中作为从器件工作) 。主器件产生串行时钟 SCL,控制总线的访问状态、产生 S 和 P 信号.只有当总线处于空闲状态时才可以启动数据传输,每次数据传输都始于 S 信号,

结束于P 信号,二者之间传输的数据字节没有限制,由总线上的主器件决定,数据以字节(8bit)为单位传输,第 9 位时由接收器产生应答.

I2C 总线的信号类型

①  起始信号(S): SCL 为高电平时, SDA 由高电平向低电平跳变,开始传送数据。

②  结束信号(P): SCL 为高电平时, SDA 由低电平向高电平跳变,结束传送数据。

③  响应信号(ACK):接收设备在接收到 8 位的数据后,在第 9 个时钟周期,拉低 SDA 电平。(注意:谁接收数据,就由谁发出 ACK 信号)

SDA 上传送的数据必须在 SCL 为高电平期间保持稳定,SDA 上的数据只能在SCL 为低电平期间变化

S5PV210 I2C 

S5PV210 RISC 微处理器可以支持 4 条多主设备 I2C 总线串行接口。 专用串行数据线(SDA)和串行时钟线(SCL)承载总线主设备和连接 I2C 总线的外围设备之间的信息SDA
 
和 SCL 线都是双向的

相关寄存器

多主设备 I2C 总线控制寄存器--I2CCON

多主设备 I2C 总线控制状态寄存器 -- I2CSTAT

多主设备 I2C 总线接收/发送数据移位寄存器 -- I2CDS

多主设备 I2C 总线地址寄存器 -- I2CADD.

当 I2C 总线为空闲时,SDA 和 SCL 总线都应被置为高电平。SDA 从高到低的变化能够初始化一个起始条件。当 SCL 保持稳定在高电平,SDA 从低到高的变化可以初始化一个停止条件,起始和停止条件都是由主设备生成的。 在第一个字节中的一个 7 位地址的值可以决定一个由主设备选择的从设备,其地址在起始条件初始化后被放到总线上。第 8 位决定的是传输方向(读或写),放到 SDA 线上的每个数据字节总共应该是 8 位。在总线传输期间,该字节可以被无限制地发送或接收。数据发送总是先对 MSB,每个字节应该紧跟一个应答位(ACK bit)。

数据传输格式:

开始信号 | 地址(7 位) | 读/写控制信号 | 应答 | 数据(8 位) | 应答 | 停止信号

S5PV210 I2C 读写操作

在发送模式下,如果数据传输后,I2C 总线接口会等待直到 I2C 总线数据移位寄存器(I2CDS)接收到一个新的数据。在新的数据写入寄存器之前,SCL 线将保持低电平,然

后再数据写入后释放。S5PV210 应该保持中断来识别当前数据发送是否完成。在 CPU 收到中断请求后,它应该再写一个数据到 I2CDS 寄存器


在接收模式下,如果数据收到后,I2C 总线接口会等待直到 I2C 总线数据移位寄存器被读出。在新的数据被读出寄存器之前,SCL 线将保持低电平,然后再数据被读出后再释

放。S5PV210 应该保持中断来识别当前数据接收是否完成。在CPU 收到中断请求后,它应该从 I2CDS 寄存器读取数据。


如果一个从接收器不能应答从属设备地址的确认, 它应该保持 SDA 线的电平为高。在这种情况下,主设备应该生成一个停止条件并终止数据的传输。如果主设备的接收器也参

与了被终止传输, 它应该通过在从设备收到最后自己后取消 ACK 信号的生成, 给从设备传输操作的最后发信号。 从设备发送器应该释放 SDA 线以允许主设备产生一个停止条件。


#include "i2c.h"#include "lib.h"#include "led.h"#define WRDATA      (1)#define RDDATA      (2)typedef struct tI2C {    unsigned char *pData;   /* 数据缓冲区 */    volatile int DataCount; /* 等待传输的数据长度 */    volatile int Status;    /* 状态 */    volatile int Mode;      /* 模式:读/写 */    volatile int Pt;        /* pData中待传输数据的位置 */}t210_I2C, *pt210_I2C;static t210_I2C g_t210_I2C;void i2c_init(void){/* 选择引脚功能:GPD1_0:IIC0_SDA, GPD1_1:IIC0_SCL */GPD1CON |= 0x22;// GPD1CON[7:4] = 0b0010,GPD1CON[3:0] = 0b0010GPD1PUD |= 0x5;// GPD1PUD[3:0] = 0b0101  禁止上拉/* bit[7] = 1, 使能ACK*  bit[6] = 0, IICCLK = PCLK/16*  bit[5] = 1, 使能中断*  bit[3:0] = 0xf, Tx clock = IICCLK/16*  PCLK = 66.7MHz, IICCLK = 4.1MHz*/IICCON = (1<<7) | (0<<6) | (1<<5) | (0xf);  // 0xafIICSTAT = 0x10;     // I2C串行输出使能(Rx/Tx)}/* * 主机发送 * slvAddr : 从机地址,buf : 数据存放的缓冲区,len : 数据长度  */void i2c_write(unsigned int slvAddr, unsigned char *buf, int len){    g_t210_I2C.Mode = WRDATA;   // 写操作    g_t210_I2C.Pt   = 0;        // 索引值初始为0    g_t210_I2C.pData = buf;     // 保存缓冲区地址    g_t210_I2C.DataCount = len; // 传输长度        IICDS   = slvAddr;    IICSTAT = 0xf0;             // 主机发送,启动,后续的传输工作将在中断服务程序中完成        /* 等待直至数据传输完毕 */        while (g_t210_I2C.DataCount != -1);}        /* * 主机接收 * slvAddr : 从机地址,buf : 数据存放的缓冲区,len : 数据长度  */void i2c_read(unsigned int slvAddr, unsigned char *buf, int len){    g_t210_I2C.Mode = RDDATA;   // 读操作    g_t210_I2C.Pt   = -1;       // 索引值初始化为-1,表示第1个中断时不接收数据(地址中断)    g_t210_I2C.pData = buf;     // 保存缓冲区地址    g_t210_I2C.DataCount = len; // 传输长度        IICDS        = slvAddr;    IICSTAT      = 0xb0;        // 主机接收,启动,后续的传输工作将在中断服务程序中完成        /* 等待直至数据传输完毕 */        while (g_t210_I2C.DataCount != 0);}/*  真正的I2C中断服务函数 */void do_i2c_irq(void) {unsigned int i;//用于简单延时switch (g_t210_I2C.Mode){    case WRDATA://写中断{if((g_t210_I2C.DataCount--) == 0){// 下面两行用来恢复I2C操作,发出P信号IICSTAT = 0xd0;// 发出P信号,但由于IICCON[4]仍为1,P信号实际还没有发出IICCON  = 0xaf;//当清除IICCON[4]后,P信号才真正发出信号delay(10000);  // 等待一段时间以便P信号已经发出break;    }IICDS = g_t210_I2C.pData[g_t210_I2C.Pt++];// 将数据写入IICDS后,需要一段时间才能出现在SDA线上for (i = 0; i < 10; i++);   IICCON = 0xaf;      // 恢复I2C传输,IICCON[4] = 0break;}case RDDATA:  //读中断{if (g_t210_I2C.Pt == -1){// 这次中断是发送I2C设备地址后发生的,没有数据// 只接收一个数据时,不要发出ACK信号g_t210_I2C.Pt = 0;if(g_t210_I2C.DataCount == 1)IICCON = 0x2f;   // 恢复I2C传输,开始接收数据,接收到数据时不发出ACKelse IICCON = 0xaf;   // 恢复I2C传输,开始接收数据,接收到数据时发出ACKbreak;}g_t210_I2C.pData[g_t210_I2C.Pt++] = IICDS;g_t210_I2C.DataCount--;if (g_t210_I2C.DataCount == 0){// 下面两行恢复I2C操作,发出P信号IICSTAT = 0x90;IICCON  = 0xaf;delay(10000);  // 等待一段时间以便P信号已经发出break;    }      else{           // 接收最后一个数据时,不要发出ACK信号if(g_t210_I2C.DataCount == 1)IICCON = 0x2f;   // 恢复I2C传输,接收到下一数据时无ACKelse IICCON = 0xaf;   // 恢复I2C传输,接收到下一数据时发出ACK}break;}default:    break;      }// 清中断向量VIC0ADDRESS = 0x0;VIC1ADDRESS = 0x0;VIC2ADDRESS = 0x0;VIC3ADDRESS = 0x0;IICCON &= ~(1<<4); //第4位用于中断的标志,当接收或发送数据后一定要对该位,进行清零,以清除中断标志} /* 需要根据AT24Cxx芯片手册的读字节协议 */unsigned char at24cxx_read(unsigned char address){unsigned char val;i2c_write(0xA0, &address, 1);//AT24C02的设备地址为0xa0i2c_read(0xA0, (unsigned char *)&val, 1);return val;}/* 需要根据AT24Cxx芯片手册的写字节协议 */void at24cxx_write(unsigned char address, unsigned char data){unsigned char val[2];val[0] = address;val[1] = data;i2c_write(0xA0, val, 2);}











0 0