Tiny4412之重力感应器驱动

冷暖自知 提交于 2020-03-30 02:07:17

一: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
regs.h
 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  );

 

  

 

  

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!