linux之I2C裸机驱动解析
2024-07-19 来源:cnblogs
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、CK信号:数据传输的过程中,接收器件每接收一个字节数据要产生一个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 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:rn'); 221 for(i =0; i<256;i++) 222 { 223 if(i%8==0) 224 printf('rn'); /* */ 225 226 printf('%dt',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!nr'); 233 234 read_data(dbuf,0,256); 235 236 printf('dbuf after I2C read:rn'); 237 238 for(i =0; i<256;i++) 239 { 240 if(i%8==0) 241 printf('rn'); 242 243 printf('%dt',dbuf[i]); 244 } 245 }
- 学习ARM开发(2)
- Linux帧缓冲设备驱动程序框架及图形界面GUI的移植
- Linux Kernel之flush_cache_all在ARM平台下是如何实现的
- 手把手教你写Linux设备驱动---中断(三)--workqueue实现(基于友善之臂4412开发板)
- makefile初步制作,arm-linux- (gcc/ld/objcopy/objdump)详解
- Ubuntu下安装arm-linux-gnueabi-xxx编译器
- 用Qemu运行/调试arm linux
- Linux内核异常处理体系结构详解(一)
- arm linux 移植 mtd-utils 1.x
- 基于gnu-arm-linux的LPC2220的简单工程模板