你的位置:首页 > 操作系统

[操作系统]linux之I2C裸机驱动解析(转)


1      硬件特性

1.1 概述

I2C总线是由Philips公司开发的两线式串行总线,这两根线为时钟线(SCL)和双向数据线(SDA)。由于I2C总线仅需要两根线,因此在电路板上占用的空间更少,带来的问题是带宽较窄。I2C在标准模式下传输速率最高100Kb/s,在快速模式下最高可达400kb/s。属于半双工。

在嵌入式系统中,I2C应用非常广泛,大多数微控制器中集成了I2C总线,一般用于和RTC,EEPROM,智能电池电路,传感器,LCD以及其他类似设备之间的通信。

 

1.2 I2C总线传输时序

 

1.3 I2C总线的信号状态

1、  空闲状态:SDA和SCL都是高电平;

2、  开始条件(S):SCL为高电平时,SDA由高电平向低电平跳变,开始传输数据;

3、  结束条件(P):SCL为高电平时,SDA由低电平向高电平跳变,结束传输数据;

4、  数据有效:在SCL的高电平期间,SDA保持稳定,数据有效。SDA的改变只能发生在SCL的低电平期间;

5、  ACK信号:数据传输的过程中,接收器件每接收一个字节数据要产生一个ACK信号,向发送器件发出特定的低电平脉冲,表示已经收到数据。

 

1.4 从设备地址


I2C总线从设备使用7位地址,最后一个为读写控制位。下图是eeprom的原理图,我们可以计算出它的地址为0x50。

 

1.5 I2C读写方式

多字节写的时序

多字节读的时序

具体可参考datasheet

附:ok6410裸机I2C代码。

 1 #define INTPND (*(volatile unsigned long*)0x4a000010) 2 #define SRCPND (*(volatile unsigned long*)0x4a000000) 3 #define INTMSK (*(volatile unsigned long*)0x4a000008) 4 #define GPECON (*(volatile unsigned long*)0x56000040) 5 #define GPEUP (*(volatile unsigned long*)0x56000048) 6  7 #define IICCON  (*(volatile unsigned char*)0x54000000) 8 #define IICSTAT  (*(volatile unsigned char*)0x54000004) 9 #define IICDS   (*(volatile unsigned char*)0x5400000C) 10  11 #define SLAVE_WRITE_ADD 0xa0 /* 写入数据时;方向位(第0位)为0 */ 12 #define SLAVE_READ_ADD 0xa1  /* 读取数据时;方向位(第0位)为1 */ 13  14  15 void delay(int i) 16 { 17  int j = 0; 18  while (i--)   19   { 20    for (j=0;j<100;j++) 21     {   22       ; 23     }  24   }   25 } 26  27  28 void i2c_init() 29 { 30   //1.a 初始化中断 31   INTPND |= (1<<27); 32   SRCPND |= (1<<27);  33   INTMSK &= ~(1<<27); 34    35   IICCON |= (1<<5);  36    37   //1.b 设置scl时钟 38   IICCON &= ~(1<<6); 39   IICCON &= ~(0xf<<0); 40   IICCON |= (0x5<<0); 41    42   //2. 设置IICSTAT   43   IICCON |= (1<<4); 44    45   //3.设置引脚功能 46   GPECON |= (0x2<<28)|(0x2<<30); 47   GPEUP |= (0x3<<14); 48    49   //4.允许产生ACK 50   IICCON |= (1<<7); 51 } 52  53  54 void write_byte(unsigned char xchar, unsigned char daddr)  55 { 56   /* 写入数据时,每发送一个数据收到一个ACK就产生一次中断 57    * 写入下次发送的数据之后要清除中断           */ 58  59   //1. 设置处理器为主设备+发送模式 60   IICSTAT |= (3<<6); 61    62   //2. 将从设备的地址写入到IICDS寄存器 63   IICDS = SLAVE_WRITE_ADD; 64  65   //清除中断 66   IICCON &= ~(1<<4); 67    68   //3. 写入0xF0写入IICSTAT M/T Start 69   IICSTAT = 0xF0; 70    71   //4. 等待ACK的产生 72   while ((IICCON & (1<<4)) == 0 ) 73     delay(100); 74    75   //5.1写入字节的地址到IICDS寄存器 76   IICDS = daddr; 77  78  79   //5.2清除中断 80   IICCON &= ~(1<<4);   81  82   //5.3等待ACK的产生 83   while ((IICCON & (1<<4)) == 0 ) 84     delay(100); 85    86   //6. 将要传输的字节数据写入IICDS寄存器 87   IICDS = xchar; 88  89   //7. 清除中断 90   IICCON &= ~(1<<4);  91    92   //8. 等待ACk的产生 93   while ((IICCON & (1<<4)) == 0 ) 94     delay(100); 95    96   //9. 写入0xD0到IICSTAT 97   IICSTAT = 0xD0; 98    99   //10. 清除中断  100   IICCON &= ~(1<<4);  101   102   delay(100);103 }104 105 void read_data(unsigned char *buf, unsigned char daddr, int length) /* 结合eeprom手册 */106 {107   /* 每接收一个数据产生一个中断 */108 109   int j =0;110   unsigned char unusedata;111   112   //1. 设置处理器为主设备+发送模式113   IICSTAT |= (3<<6);114   115   //2. 将从设备的地址写入到IICDS寄存器116   IICDS = SLAVE_WRITE_ADD;117 118   //清除中断119   IICCON &= ~(1<<4);120   121   //3. 写入0xF0写入IICSTAT M/T-Start122   IICSTAT = 0xF0;123   124   //4. 等待ACK的产生125   while ((IICCON & (1<<4)) == 0 )126     delay(100);127   128   //5.1写入eeprom内部地址129   IICDS = daddr;130 131 132   //5.2清除中断133   IICCON &= ~(1<<4);  134 135   //5.3等待ACK的产生136   while ((IICCON & (1<<4)) == 0 )137     delay(100);138 139   /**************eeprom代码**************/140   /**************************************/141   /***************i2c代码****************/142 143   //设置为主设备接收模式144   IICSTAT &= ~(3<<6);145   IICSTAT |= (2<<6);146   147   148   //2.写入从设备地址到IICDS /* 从设备地址成功发送之后产生中断,故要清除中断 */149   IICDS = SLAVE_READ_ADD;150   //清除中断151   IICCON &= ~(1<<4);152   153   154   //3.写入0xB0到IICSTAT开始接收,每接收道一个数据就产生一个中断155   IICSTAT = 0xb0;156 157   //等待中断158   while ((IICCON & (1<<4)) == 0 )159     delay(100);160     161 #if 0  162   /***写入设备内部地址***/163   IICDS = daddr;164   IICCON &= ~(1 << 4);165   while((IICCON & (1 << 4)) == 0)166   {167     delay(100);168   }  169 #endif 170   171   //***丢掉收到的第1个字节 第一个数据无效 丢弃!172   unusedata = IICDS;173   IICCON &= ~(1<<4);174   while ((IICCON & (1<<4)) == 0 )175       delay(100);176   177 178 179   for(j=0;j<length;j++)180   {181     if(j == (length - 1))182     {183      IICCON &= ~(1<<7);     184     }185  186   //5.1 从IICDS里取出数据187     buf[j]=IICDS;188   189   //5.2 清除中断190     IICCON &= ~(1<<4);191   192   //4.等待中断193     while ((IICCON & (1<<4)) == 0 )194       delay(100);195   }196     197     198   //写入0x90到IICSTAT199   IICSTAT = 0x90;200   201 202   // 清除中断203   IICCON &= ~(1<<4);204 }205 206 void i2c_test()207 {208   int i=0;209   unsigned char sbuf[256]={0};210   unsigned char dbuf[256]={0};  211   212   i2c_init();213   214   for(i=0;i<256;i++)215   {216     sbuf[i] = i+1;217     dbuf[i] = 0;218   }219   220   printf("dbuf befor I2C read:\r\n");  221   for(i =0; i<256;i++)222   {223    if(i%8==0)224      printf("\r\n"); /* */225      226    printf("%d\t",dbuf[i]);  /*t-空格 */227   }  228   229   for(i=0;i<256;i++)230     write_byte(sbuf[i],i);231     232   printf("i2c reading, plese wait!\n\r");233   234   read_data(dbuf,0,256);235   236   printf("dbuf after I2C read:\r\n");237   238   for(i =0; i<256;i++)239   {240    if(i%8==0)241      printf("\r\n");242      243    printf("%d\t",dbuf[i]);  244   }  245 }