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


    前言

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

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

    一、目的

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

    二、源代码说明

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

     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。

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

  • 相关阅读:
    Jmeter实际操作
    Windows+JMeter+InfluxDB+Grafana搭建可视化实时监控
    c# 新语法
    js 判断打印或取消 打印插件
    BACnet协议
    串口偶尔出现串口乱码原因
    面向流程葵花宝典
    lwip框架示意图
    linux 算法介绍
    什么是序列化与反序列化
  • 原文地址:https://www.cnblogs.com/lknlfy/p/3596357.html
Copyright © 2020-2023  润新知