一:Tiny4412 裸板重力感应驱动编写
整个编写过程大概分为如下几步:
(1)在底板上找到重力感应器的所在位置,找到芯片型号(我用的板子上重力感应器芯片型号为:MMA7660FC)
(2)通过型号查看重力感应器电路图,了解每个引脚的功能
(3)找到引脚对应的网标(EINT,SDL,SCL)配置其相应的gpio口
(4)配置芯片相关寄存器
(5)使用I2C来读取重力感应器相应寄存器的值
下面是整个驱动的简单流程图:

通过看底板我们知道了重力感应器的控制芯片型号为:MMA7660FC,接下来我们就在看看改芯片的电路图(如下):

由上图我们可以看出它的外部中断XEINT25,用到的i2c总线为SDA3、SCL3
通过网标我们可以看到它是怎么连接到核心板上的(soc)

![]()
由上图可知,XEINT25、I2CSDA3、SCL3所对应的gpio分别为GPA1_2、GPA1_3、GPX3_1,之后我们就可以配置gpio口为相应的功能
通过datasheet我们可以找到它的外部中断号为64,如下图:
![]()
简单了解了mma7660的电路图之后我们就需要看芯片的datasheet,了解里面寄存器的配置及功能
首先看一下整个芯片与我们核心板的连接图:

由上图我们可以看出,芯片连接到我们核心板(soc)的总共为三根线:INT( 中断信号),SDA、SCL(通i2c来进行寄存器的配置和读取)
下面看一下该芯片的几种工作模式:


今天我们实验的所需要的就是就当板子在晃动的时候它会出发中断,我们利用i2c来读取它相应寄存器的值,来判断前后左右以及X、Y、Z的值

下面是该芯片的寄存器及功能:

由上图我们可以看出寄存器:0x00、0x01、0x02它的底六位分别存储着对应的X、Y、Z的值,因此在之后的试验中我们就可以利用i2c来读取它里面的值
0x03这个寄存器的具体功能如下所所示、它里面存储了前后左右上下的值:

下面的几个寄存器是我们需要配置的:
这个寄存是:该芯片里面的中断寄存器,我们需要配置相应值来响应中断,光配置外部中断是不可以的,我们需要配置该寄存器来响应我们的外部中断

该寄存器是配置相应的模式,我们需要配置它为shake,当我们在晃动板子是可以出发中断;配置好这两个寄存器之后,我们就可以使用I2C来读取对应寄存器的值了

接下来我们需要做的就是设置相应的gpio口,以及配置好I2C的相应寄存器:
I2C总线驱动在上一篇中已经介绍了,I2C总线设备分为四种模式:主端发送、主端接收,从端发送、从端接收,在该驱动中我们用到的只有主发跟主收,下面是相应的流程图,整个I2C的读写都是按照这个流程:
主端发送:

主端接收:

配置好整个I2C之后我们就可以对芯片进行相应的设置和读取了,下面贴出真个重力感应驱动的代码:

1 #ifndef __REGS_H 2 #define __REGS_H 3 4 #define printf(...) (((int (*)(const char *, ...))0xc3e114d8)(__VA_ARGS__)) 5 6 #define GPA1CON (*(volatile unsigned long *)0x11400020) 7 #define I2CCON3 (*(volatile unsigned long *)0x13890000) 8 #define I2CADD3 (*(volatile unsigned long *)0x13890008) 9 #define I2CSTAT3 (*(volatile unsigned long *)0x13890004) 10 #define I2CDS3 (*(volatile unsigned long *)0x1389000C) 11 #define I2CLC3 (*(volatile unsigned long *)0x13890010) 12 13 #define GPD1CON (*(volatile unsigned long *)0x114000C0) 14 #define GPD1PUD (*(volatile unsigned long *)0x114000C8) 15 #define I2CCON1 (*(volatile unsigned long *)0x13870000) 16 #define I2CADD1 (*(volatile unsigned long *)0x13870008) 17 #define I2CSTAT1 (*(volatile unsigned long *)0x13870004) 18 #define I2CDS1 (*(volatile unsigned long *)0x1387000C) 19 #define I2CLC1 (*(volatile unsigned long *)0x13870010) 20 21 #define ICCICR_CPU0 (*(volatile unsigned long *)0x10480000) 22 #define ICCPMR_CPU0 (*(volatile unsigned long *)0x10480004) 23 #define ICDDCR (*(volatile unsigned long *)0x10490000) 24 #define ICDIPR15_CPU0 (*(volatile unsigned long *)0x1049043C) 25 #define ICDIPTR15_CPU0 (*(volatile unsigned long *)0x1049083C) 26 #define ICDISER1_CPU0 (*(volatile unsigned long *)0x10490104) 27 #define ICDSGIR (*(volatile unsigned long *)0x10490f00) 28 #define ICCIAR_CPU0 (*(volatile unsigned long *)0x1048000C) 29 #define ICCEOIR_CPU0 (*(volatile unsigned long *)0x10480010) 30 31 #define GPX1CON (*(volatile unsigned long *)0x11000C20) 32 33 #define EXT_INT41_CON (*(volatile unsigned long *)0x11000E04) 34 #define EXT_INT41_MASK (*(volatile unsigned long *)0x11000F04) 35 #define EXT_INT41_PEND (*(volatile unsigned long *)0x11000F44) 36 37 #define GPX3CON (*(volatile unsigned long *)0x11000c60) 38 #define GPX3DAT (*(volatile unsigned long *)0x11000c64) 39 #define GPD0CON (*(volatile unsigned long *)0x110000a0) 40 #define GPD0DAT (*(volatile unsigned long *)0x110000a4) 41 42 #define ICCICR_CPU0 (*(volatile unsigned long *)0x10480000) 43 #define ICCPMR_CPU0 (*(volatile unsigned long *)0x10480004) 44 #define ICDDCR (*(volatile unsigned long *)0x10490000) 45 #define ICDIPR16_CPU0 (*(volatile unsigned long *)0x10490440) 46 #define ICDIPTR16_CPU0 (*(volatile unsigned long *)0x10490840) 47 #define ICDISER2_CPU0 (*(volatile unsigned long *)0x10490108) 48 #define ICDSGIR (*(volatile unsigned long *)0x10490f00) 49 #define ICCIAR_CPU0 (*(volatile unsigned long *)0x1048000C) 50 #define ICCEOIR_CPU0 (*(volatile unsigned long *)0x10480010) 51 52 #define EXT_INT43_CON (*(volatile unsigned long *)0x11000E0C) 53 #define EXT_INT43_MASK (*(volatile unsigned long *)0x11000F0C) 54 #define EXT_INT43_PEND (*(volatile unsigned long *)0x11000F4C) 55 56 #endif
1 #ifndef __MMA_H 2 #define __MMA_H 3 4 void mma_set(); 5 void mma_read(); 6 void i2c_gpio_set(); 7 int master_write(unsigned char slaveaddr, unsigned char subaddr, unsigned char *data); 8 int master_read(unsigned char slaveaddr, unsigned char subaddr, unsigned char *data); 9 void i2c_init(); 10 void i2c_exit(); 11 void irq_init(); 12 void do_irq(); 13 void enable_mmu(); 14 void init_table(unsigned long *addr); 15 void memcpy(unsigned char *dest, unsigned char *src, unsigned int len); 16 17 extern unsigned long vector_start; 18 19 #endif //MMA_H
1 #include "mma.h"
2 #include "regs.h"
3
4 void (*udelay)(int ) = 0xc3e04fec;
5
6 int main(void)
7 {
8 *(unsigned long *)0x47000000 = do_irq;
9 enable_mmu();
10 i2c_gpio_set();
11 mma_set();
12 irq_init();
13 memcpy(0x0, vector_start, 0x1000);
14 }
15
16 void do_irq()
17 {
18 if(EXT_INT43_PEND & (1 << 1)) {//judge interrupt occurs
19 EXT_INT43_PEND |= (1 << 1);//clear interrupt
20 mma_read();
21 }
22 }
23
24 void mma_set()
25 {
26 /*$06: Interrupt Setup Register
27 0x98 <--> 芯片地址 0x6 <---> 寄存器地址
28 */
29 master_write(0x98, 0x6, 0xe3); // e3 1110 0011
30 /*
31 -----------------------------------------------------------
32 D7 D6 D5 D4 D3 D2 D1 D0
33 SHINTX SHINTY SHINTZ GINT ASINT PDINT PLINT FBINT
34 1 1 1 0 0 0 1 1
35 -----------------------------------------------------------
36 FBINT
37 0: Front/Back position change does not cause an interrupt
38 1: Front/Back position change causes an interrupt
39 PLINT
40 0: Up/Down/Right/Left position change does not cause an
41 interrupt
42 1: Up/Down/Right/Left position change causes an interrupt
43 PDINT
44 0: Successful tap detection does not cause an interrupt
45 1: Successful tap detection causes an interrupt
46 ASINT
47 0: Exiting Auto-Sleep does not cause an interrupt
48 1: Exiting Auto-Sleep causes an interrupt
49 GINT
50 0: There is not an automatic interrupt after every
51 measurement
52 1: There is an automatic interrupt after every measurement,
53 SHINTX
54 0: Shake on the X-axis does not cause an interrupt or set the
55 Shake bit in the TILT register
56 1: Shake detected on the X-axis causes an interrupt, and sets
57 the Shake bit in the TILT register
58 SHINTY
59 0: Shake on the Y-axis does not cause an interrupt or set the
60 Shake bit in the TILT register
61 1: Shake detected on the Y-axis causes an interrupt, and sets
62 the Shake bit in the TILT register
63 SHINTZ
64 0: Shake on the Z-axis does not cause an interrupt or set the
65 Shake bit in the TILT register
66 1: Shake detected on the Z-axis causes an interrupt, and sets
67 the Shake bit in the TILT register.
68
69 */
70
71 /*$07: Mode Register (Read/Write)*/
72 master_write(0x98, 0x7, 0xd9); //d9 1101 1001
73 /*
74 -----------------------------------------------------------
75 D7 D6 D5 D4 D3 D2 D1 D0
76 IAH IPP SCPS ASE AWE TON - MODE
77 1 1 0 1 1 0 0 1
78 -----------------------------------------------------------
79 MODE
80 0: Standby mode or Test Mode depending on state of TON
81 1: Active mode
82 TON
83 0: Standby Mode or Active Mode depending on state of MODE
84 1: Test Mode
85 AWE
86 0: Auto-Wake is disabled
87 1: Auto-Wake is enabled.
88 ASE
89 0: Auto-Sleep is disabled
90 1: Auto-Sleep is enabled
91 SCPS
92 0: The prescaler is divide-by-1. The 8-bit internal Sleep
93 Counter input clock is the samples per second set by
94 AMSR[2:0]
95 1: Prescaler is divide-by-16. The 8-bit Sleep Counter input
96 clock is the samples per second set by AMSR[2:0] divided by
97 16,
98 IPP
99 0: Interrupt output INT is open-drain.
100 1: Interrupt output INT is push-pull
101 IAH
102 0: Interrupt output INT is active low
103 1: Interrupt output INT is active high
104 */
105 }
106
107 void mma_read()
108 {
109 unsigned char val;
110 unsigned char i;
111 for(i = 0; i < 4; i++)
112 while(1) {
113 master_read(0x98, i, &val); //read
114 if((val & (1 << 6)) == 0) {
115 if(0 == i) {
116 printf("X is %d\n", 0x3f & val); //6-bit output value X
117 }
118 if(1 == i) {
119 printf("Y is %d\n", 0x3f & val); //6-bit output value Y
120 }
121 if(2 == i) {
122 printf("Z is %d\n", 0x3f & val); //6-bit output value Z
123 }
124 if(3 == i) {
125 /*BaFro[1:0]
126 *01: Front
127 *10: Back
128 */
129 if((val & 3) == 1)
130 printf("Front\n");
131
132 if((val & 3) == 2)
133 printf("Back\n");
134 /*PoLa[2:0]
135 * 001: Left
136 * 010: Right
137 * 101: Down
138 * 110: Up
139 * */
140 if(((val >> 2) & 0x7) == 1)
141 printf("Left\n");
142
143 if(((val >> 2) & 0x7) == 2)
144 printf("Right\n");
145
146 if(((val >> 2) & 0x7) == 5)
147 printf("Down\n");
148
149 if(((val >> 2) & 0x7) == 6)
150 printf("Up\n");
151
152 }
153 break;
154 }
155 }
156 }
157
158 int master_write(unsigned char slaveaddr, unsigned char subaddr, unsigned char *data)
159 {
160 i2c_init();
161
162 unsigned char timeout = 50;
163 while(timeout) {
164 udelay(20);
165 if(!(I2CSTAT3 & (1 << 5))){ //judge I2C-bus busy signal (0 busy or no busy)
166 I2CCON3 |= (1 << 7); //I2C-bus acknowledge enable
167 I2CDS3 = slaveaddr; // slave addr
168 I2CSTAT3 = 0xf0; // Master transmit mode
169 udelay(20);
170
171 timeout = 50;
172 while(timeout) {
173 udelay(20);
174 if(I2CCON3 & (1 << 4)) {//Interrupt is pending
175 I2CDS3 = subaddr; //register addr
176 udelay(10);
177 I2CCON3 &= ~(1 << 4); //Clears pending condition and resumes the operation
178 udelay(20);
179 break;
180 }
181 timeout --;
182 }
183 if(0 == timeout)
184 return -1;
185
186 timeout = 50;
187 while(timeout) {
188 udelay(20);
189
190 if(I2CCON3 & (1 << 4)) { // interrupt is pending
191 I2CDS3 = data; //write data
192 udelay(10);
193 I2CCON3 &= ~(1 << 4); //Clear pending bit to resume.(每次都要写0才会发送)
194 udelay(10);
195 break;
196 }
197 timeout--;
198 if(0 == timeout)
199 return -1;
200 }
201
202 timeout = 50;
203 while(timeout) {
204 udelay(20);
205 if(I2CCON3 & (1 << 4)) {//interrupt is pending
206 I2CSTAT3 = 0xd0; //Master transmit mode stop
207 udelay(10);
208 I2CCON3 &= ~(1 << 4);
209 udelay(10);
210 break;
211 }
212 timeout--;
213 }
214 if(0 == timeout)
215 return -1;
216
217 while(1 == (I2CSTAT3 & (1 << 5))) {// Wait until the stop condition takes effect
218 ;
219 }
220 i2c_exit(); //exit i2c
221 return 0;
222 }
223 timeout--;
224 }
225 return -1;
226 }
227
228 int master_read(unsigned char slaveaddr, unsigned char subaddr, unsigned char *data)
229 {
230 i2c_init();
231 unsigned char count = 0;
232 unsigned char buf[14];
233 unsigned char timeout = 50;
234
235 //-------------write------------------
236 while(timeout)
237 {
238 udelay(20);
239 if(!(I2CSTAT3 & (1 << 5)))//判断忙与不忙
240 {
241 I2CCON3 |= (1 << 7); //开启I2C总线ack信号
242 I2CDS3 = slaveaddr; //写入要读的芯片地址
243 I2CSTAT3 = 0xf0; //选择主端发送模式
244 udelay(20);
245 timeout = 50;
246 while(timeout)
247 {
248 udelay(20);
249 if( I2CCON3 & (1<<4)) //等待中断(ACK信号)
250 {
251 I2CDS3 = subaddr; //写入要读的寄存器地址
252 udelay(10);
253 I2CCON3 &= ~(1 << 4); //向这一位写0,发送,清楚等待条件,恢复操作
254 udelay(20);
255 break;
256
257 }
258 timeout--;
259 }
260 if(0 == timeout)
261 return -1;
262 timeout = 50;
263 while(timeout)
264 {
265 udelay(20);
266 if(I2CCON3 & (1 << 4))
267 {
268 I2CSTAT3 = 0xd0; //set Read Not busy (If Read)
269 udelay(10);
270 I2CCON3 &= ~(1<<4);
271 udelay(10);
272 break;
273 }
274 timeout--;
275 }
276 if(0 == timeout)
277 return -1;
278
279 //------------read------------------
280 timeout = 50;
281 while(timeout)
282 {
283 udelay(20);
284 if(!(I2CSTAT3 & (1 << 5)))
285 {
286 I2CCON3 |= (1 << 7);
287 I2CDS3 = slaveaddr;//写入芯片地址
288 I2CSTAT3 = 0xb0; //选择主端接收模式
289 udelay(10);
290 break;
291 }
292 timeout--;
293 }
294 if(0 == timeout)
295 return -1;
296
297 timeout = 100;
298 while(timeout)
299 {
300 udelay(20);
301 if(I2CCON3 & (1 << 4))
302 {
303 buf[count] = I2CDS3; //read
304 count++;
305 if(12 == count)
306 I2CCON3 &= ~(1 << 7);//I2C-bus acknowledge Disable
307
308 I2CCON3 &= ~(1 << 4); //Clear pending bit to resume
309 udelay(10);
310 if(12 == count)
311 break;
312 }
313 timeout--;
314 }
315 if(0 == timeout)
316 return -1;
317
318 timeout = 50;
319 while(timeout)
320 {
321 udelay(20);
322 if(I2CCON3 & (1 << 4))//wait ack
323 {
324 I2CSTAT3 = 0x90;//主端接受模式结束
325 I2CCON3 &= ~(1 << 4);
326 udelay(10);
327 break;
328 }
329 timeout--;
330 }
331 if(0 == timeout)
332 return -1;
333
334 while(1 == (I2CSTAT3 & (1 << 5))) //Wait until the stop condition takes effect
335
336 {
337 printf("in while read \n");;
338 }
339 i2c_exit(); //exit i2c
340 *data = buf[subaddr + 1];
341
342 return 0;
343 }
344 timeout--;
345 }
346 return -1;
347 }
348
349 /*SDA3 <---> GPA1_2 SCL3 <-->GPA1_3 */
350 void i2c_gpio_set()
351 {
352 printf("i2c_gpio_set\n");
353 GPA1CON &= ~(0xff << 8);
354 GPA1CON |= (0x33 << 8);
355 }
356
357 void i2c_init()
358 {
359 I2CCON3 = 1 | (1 << 5) | (1 << 6);
360 I2CSTAT3 = (1 << 4);
361 I2CLC3 = 0x7;
362 }
363
364 void i2c_exit()
365 {
366 I2CCON3 = 0;
367 I2CSTAT3 = 0;
368 I2CLC3 = 0;
369
370 }
371
372 void irq_init()
373 {
374 //step 1: enable cpu cpsr
375 __asm__ __volatile__(
376 "mrs r0, cpsr\n"
377 "bic r0, r0, #0x80\n"
378 "msr cpsr, r0\n"
379 ::: "r0"
380 );
381
382 //step 2: GIC NO.62
383 ICCICR_CPU0 = 1;//global enable interrupt (total switch)
384 ICCPMR_CPU0 = 0xff;//This register provides an interrupt priority filter.
385 ICDDCR = 1;//This register enables forwarding of pending interrupts to the CPU interfaces
386
387 /*一共有1024个中断源,只有160个中断号*/
388 //id = 64. 一个ICDIPR 控制4个中断,64 / 4 = 16 ...0, so ICDIPR=16
389 ICDIPR16_CPU0 = (1 << 0);//the zero is the highest priority
390 ICDIPTR16_CPU0 = (1 << 0);//0x1 ---> for cpu0
391 ICDISER2_CPU0 = (1 << 0);// enable interrupt 0
392
393 //step 4:set ext_int
394 EXT_INT43_CON &= ~(0xf << 4);
395 EXT_INT43_CON |= (0x4 << 4);//falling edge; low level
396 EXT_INT43_MASK = 0;//enable extint43_1
397
398 //step 3: set gpio
399 GPX3CON &= ~(0xf << 4);
400 GPX3CON |= (0xf << 4);//xeint25 <==> gpx3_1 ---->0xF = EXT_INT43[1]
401
402 printf("irq over\n");
403 }
404
405
406 void enable_mmu()
407 {
408 /*构建表*/
409 unsigned long addr = 0x50000000;
410 init_table(addr);
411
412 /*打开mmu*/
413 unsigned long mmu = 0;
414 mmu = 1 | (1 << 1) | (1 << 3) | (1 << 8);
415
416 __asm__ __volatile__ (
417 "mov r0, #3\n"
418 "MCR p15, 0, r0, c3, c0, 0\n"//设置为管理员
419 "MCR p15, 0, %0, c2, c0, 0\n"//设置表的地址
420 "MCR p15, 0, %1, c1, c0, 0\n"//开启mmu
421 :
422 : "r" (addr), "r" (mmu)
423 :
424 );
425
426 }
427
428 void init_table(unsigned long *addr)
429 {
430 unsigned long va = 0;
431 unsigned long phys = 0;
432
433 //0x40000000-0x80000000 -> 0x40000000-0x80000000
434 for(va = 0x40000000; va < 0x80000000; va += 0x100000) {
435 phys = va;
436 addr[va >> 20] = phys | 2;
437 }
438
439 //0x10000000-0x14000000 -> 0x10000000-0x140000000
440 for(va = 0x10000000; va < 0x14000000; va += 0x100000) {
441 phys = va;
442 addr[va >> 20] = phys | 2;
443 }
444 //0x10000000-0x14000000 -> 0x10000000-0x140000000
445 for(va = 0x0; va < 0x10000000; va += 0x100000) {
446 phys = va + 0x70000000;
447 addr[va >> 20] = phys | 2;
448 }
449
450 }
451
452 void memcpy(unsigned char *dest, unsigned char *src, unsigned int len)
453 {
454 int i = 0;
455 for(i = 0; i < len; i++) {
456 dest[i] = src[i];
457 }
458 }
459
460 __asm__(
461
462 /*异常向量表*/
463 "vector: \n"
464 " b reset\n"
465 " b und\n"
466 " b swi\n"
467 " b pre_abt\n"
468 " b data_abt\n"
469 " .word 0x0\n"
470 " b irq\n"
471 " b fiq\n"
472 "reset:\n"
473 "und:\n"
474 " mov sp, #0x47000000\n"
475 " stmdb sp!, {r0-r12, lr}\n"
476
477 " ldr r3, =0x47000004\n"
478 " ldr r2, [r3]\n"
479 " blx r2\n"
480
481 " mov sp, #0x47000000\n"
482 " ldmdb sp, {r0-r12, pc}^ \n"
483
484 "swi:\n"
485 " mov sp, #0x47000000\n"
486 " stmdb sp!, {r0-r12, lr}^\n"
487
488 " mov sp, #0x47000000\n"
489 " ldmdb sp, {r0-r12, pc}^ \n"
490
491 "pre_abt:\n"
492
493 "data_abt:\n"
494 " mov sp, #0x47000000\n"
495 " sub lr, lr, #4\n"
496 " stmdb sp!, {r0-r12, lr}\n"
497
498 " ldr r3, =0x47000008\n"
499 " ldr r2, [r3]\n"
500 " blx r2\n"
501
502 " mov sp, #0x47000000\n"
503 " ldmdb sp, {r0-r12, pc}^ \n"
504 "irq:\n"
505
506 " mov sp, #0x47000000\n"
507 " sub lr, lr, #4\n"
508 " stmdb sp!, {r0-r12, lr}\n"
509
510 " ldr r3, =0x47000000\n" //跳转到c语言
511 " ldr r2, [r3]\n"
512 " blx r2\n"
513
514 " mov sp, #0x47000000\n"
515 " ldmdb sp, {r0-r12, pc}^ \n"
516
517 "fiq:\n"
518
519 ".global vector_start\n"
520 "vector_start: \n"
521 ".word vector \n "
522
523 );
来源:https://www.cnblogs.com/wenqiang/p/4957641.html
