Cubieboard2裸机开发之(四)定时器操作

前言

        在Cubieboard2裸机开发之(三)里用到了一个延时函数delay,它的延时时间是不精确的,因此为了能够精确延时,就需要定时器的配合。定时器可以精确延时的一个重要原因是它的计时时钟(或者说频率)是精确的,计时时钟越小,能实现的延时时间就越小。

      A20的定时器模块比较强大,它不仅有6个普通的定时器,还有4个高速定时器,计时频率可达上百MHz,更重要的是它们操作起来非常简单、易懂。

 

一、目的

      学习使用A20的普通定时器,实现精确延时。

 

二、源代码说明

start.S文件。首先禁止CPU的IRQ和FIQ,设置为管理模式,然后设置堆栈指针,最后调用C语言的main函数。

 1 /*
 2  * (C) Copyright 2014 conan liang 
 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。

 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 }

 

三、验证

      使用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秒),效果不好用图片展示,因此就不上图了。

 

你可能感兴趣的:(Cubieboard2裸机开发之(四)定时器操作)