linux之I2C裸机驱动解析(转),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-Start
122     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到IICSTAT
199     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 }

 

相关内容