Cubieboard2裸機開發之(四)定時器操做

前言linux

        在Cubieboard2裸機開發之(三)裏用到了一個延時函數delay,它的延時時間是不精確的,所以爲了可以精確延時,就須要定時器的配合。定時器能夠精確延時的一個重要緣由是它的計時時鐘(或者說頻率)是精確的,計時時鐘越小,能實現的延時時間就越小。ide

      A20的定時器模塊比較強大,它不只有6個普通的定時器,還有4個高速定時器,計時頻率可達上百MHz,更重要的是它們操做起來很是簡單、易懂。函數

 

1、目的工具

      學習使用A20的普通定時器,實現精確延時。oop

 

2、源代碼說明學習

start.S文件。首先禁止CPU的IRQ和FIQ,設置爲管理模式,而後設置堆棧指針,最後調用C語言的main函數。spa

 1 /*
 2  * (C) Copyright 2014 conan liang <lknlfy@163.com>
 3  * 
 4  */
 5 
 6 
 7 /* global entry point */
 8 .globl _start
 9 _start: b    reset
10 
11 reset:
12     /* disable IRQ & FIQ, set the cpu to SVC32 mode */
13     mrs r0, cpsr
14     and r1, r0, #0x1f
15     teq r1, #0x1a
16     bicne r0, r0, #0x1f
17     orrne r0, r0, #0x13
18     orr r0, r0, #0xc0
19     msr cpsr, r0
20     /* setup stack, so we can call C code */
21     ldr sp, =(1024 * 10)
22     /* jump to main function */
23     bl main
24 loop:
25     b loop

main.c文件。首先初始化LED所在IO管腳,設置爲輸出功能,而且輸出低電平,即一開始兩個LED是熄滅的,接着初始化定時器0,包括設置它的時鐘,工做模式等。指針

 1 #include "timer.h"
 2 #include "io.h"
 3 
 4 /* reg define for IO of LEDs  */
 5 #define SUNXI_PIO_BASE   (0x01C20800)
 6 #define PH_CFG2          (SUNXI_PIO_BASE + 0x104)
 7 #define PH_DAT           (SUNXI_PIO_BASE + 0x10C)
 8 
 9 /* set two LEDs on */
10 static void set_led_on(void)
11 {
12     unsigned int tmp;
13     
14     /* PH20 and PH21 output 1 */
15     tmp = readl(PH_DAT);
16     tmp |= (0x1 << 20);
17     tmp |= (0x1 << 21);
18     writel(tmp, PH_DAT);
19 }
20 
21 /* set two LEDs off */
22 static void set_led_off(void)
23 {
24     unsigned int tmp;
25 
26     /* PH20 and PH21 output 0 */
27     tmp = readl(PH_DAT);
28     tmp &= ~(0x1 << 20);
29     tmp &= ~(0x1 << 21);
30     writel(tmp, PH_DAT);
31 }
32 
33 static void led_init(void)
34 {
35     unsigned int tmp;
36     
37     /* configure PH20 and PH21 output */
38     tmp = readl(PH_CFG2);
39     tmp &= ~(0x7 << 16);
40     tmp &= ~(0x7 << 20);
41     tmp |= (0x1 << 16);
42     tmp |= (0x1 << 20);
43     writel(tmp, PH_CFG2);
44     /* set PH20 and PH21 output 0 */
45     tmp = readl(PH_DAT);
46     tmp &= ~(0x1 << 20);
47     tmp &= ~(0x1 << 21);
48     writel(tmp, PH_DAT);
49 }
50 
51 /* C code entry point */
52 int main(void)
53 {
54     /* init led */
55     led_init();
56     /* init timer0 */
57     sunxi_timer0_init();
58 
59     while (1) {
60         set_led_on();
61         udelay(1000000);
62         set_led_off();
63         udelay(1000000);
64     }
65     
66     return 0;
67 }

timer.c文件。一個初始化函數,一個微妙延時函數,這裏設置定時器的計時頻率爲6MHz。code

 1 #include "timer.h"
 2 #include "io.h"
 3 
 4 
 5 /* 6MHz for timer0 count freq*/
 6 #define TIMER0_HZ    (6000000)
 7 
 8 #if 0
 9 static void sunxi_timer0_start(void)
10 {
11     unsigned int tmp;
12     
13     tmp = readl(TMR0_CTRL_REG);
14     tmp |= (1 << TMR0_EN);
15     writel(tmp, TMR0_CTRL_REG);
16 }
17 
18 static void sunxi_timer0_stop(void)
19 {
20     unsigned int tmp;
21     
22     tmp = readl(TMR0_CTRL_REG);
23     tmp &= ~(1 << TMR0_EN);
24     writel(tmp, TMR0_CTRL_REG);
25 }
26 #endif
27 
28 /* accurate delay */
29 void udelay(unsigned int usec)
30 {
31     unsigned int count;
32     unsigned int tmp;
33 
34     /* write interval value */
35     count = (TIMER0_HZ / 1000000 ) * ((unsigned int)usec);
36     writel(count, TMR0_INTV_VALUE_REG);
37     
38     /* reload and start timer0 must be operated at the same time */
39     tmp = readl(TMR0_CTRL_REG);
40     tmp |= (1 << TMR0_RELOAD);
41     tmp |= (1 << TMR0_EN);
42     writel(tmp, TMR0_CTRL_REG);
43     /* wait for interrupt */
44     while (!(readl(TMR_IRQ_STA_REG) & (1 << TMR0_IRQ_PEND)));
45     /* clear timer0 interrupt */
46     tmp = readl(TMR_IRQ_STA_REG);
47     tmp |= (1 << TMR0_IRQ_PEND);
48     writel(tmp, TMR_IRQ_STA_REG);
49 }
50 
51 void sunxi_timer0_init(void)
52 {
53     unsigned int tmp;
54 
55     /* single mode, /4 divide, clock source is OSC24M, reload . so clk_freq = 24M / 4 = 6M*/
56     tmp = (0x1 << TMR0_MODE) | (0x2 << TMR0_CLK_PRES) | (0x1 << TMR0_CLK_SRC) | (0x1 << TMR0_RELOAD);
57     writel(tmp, TMR0_CTRL_REG);
58     /* clear timer0 interrupt */
59     tmp = readl(TMR_IRQ_STA_REG);
60     tmp |= (1 << TMR0_IRQ_PEND);
61     writel(tmp, TMR_IRQ_STA_REG);
62     /* enable timer0 interrupt */
63     tmp = readl(TMR_IRQ_EN_REG);
64     tmp |= (1 << TMR0_IRQ_EN);
65     writel(tmp, TMR_IRQ_EN_REG);
66 }

 

3、驗證blog

      使用arm-linux-gnueabihf工具編譯後生成timer.b文件,再使用mksunxiboot工具在timer.b文件前面加上一個頭部,最終生成timer.bin文件,使用如下命令將timer.bin文件燒寫到TF中:

#sudo dd if=./timer.bin of=/dev/sdb bs=1024 seek=8

      將TF卡插入Cubieboard2,上電便可看到兩個LED同時閃爍,而且閃爍週期爲2秒(亮1秒,滅1秒),效果很差用圖片展現,所以就不上圖了。

相關文章
相關標籤/搜索