前言

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

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

一、目的

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

二、源代码说明

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

  1. /*
  2. * (C) Copyright conan liang <lknlfy@163.com>
  3. *
  4. */
  5.  
  6. /* global entry point */
  7. .globl _start
  8. _start: b reset
  9.  
  10. reset:
  11. /* disable IRQ & FIQ, set the cpu to SVC32 mode */
  12. mrs r0, cpsr
  13. and r1, r0, #0x1f
  14. teq r1, #0x1a
  15. bicne r0, r0, #0x1f
  16. orrne r0, r0, #0x13
  17. orr r0, r0, #0xc0
  18. msr cpsr, r0
  19. /* setup stack, so we can call C code */
  20. ldr sp, =( * )
  21. /* jump to main function */
  22. bl main
  23. loop:
  24. 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 << );
  17. tmp |= (0x1 << );
  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 << );
  29. tmp &= ~(0x1 << );
  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 << );
  40. tmp &= ~(0x7 << );
  41. tmp |= (0x1 << );
  42. tmp |= (0x1 << );
  43. writel(tmp, PH_CFG2);
  44. /* set PH20 and PH21 output 0 */
  45. tmp = readl(PH_DAT);
  46. tmp &= ~(0x1 << );
  47. tmp &= ~(0x1 << );
  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 () {
  60. set_led_on();
  61. udelay();
  62. set_led_off();
  63. udelay();
  64. }
  65.  
  66. return ;
  67. }

timer.c文件。一个初始化函数,一个微妙延时函数,这里设置定时器的计时频率为6MHz。

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

三、验证

使用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裸机开发之(四)定时器操作的更多相关文章

  1. Cubieboard2裸机开发之(五)看门狗操作

    前言 说到看门狗,应该不会陌生,看门狗说白了就是一个定时器,但是它有一个非常重要的功能就是复位系统.在A20里,看门狗的操作非常简单,只有两个寄存器,不需要操作时钟相关的东西,系统起来后可以直接使用, ...

  2. Cubieboard2裸机开发之(三)C语言操作LED

    前言 前面通过汇编语言点亮LED,代码虽然简单,但并不是很直观.这次使用熟悉的C语言来控制LED,但是需要注意的地方有两点,第一,要想使用C语言,首先需要在调用C语言代码之前设置好堆栈:第二,调用C语 ...

  3. Cubieboard2裸机开发之(二)板载LED交替闪烁

    前言 电路原理在文章http://www.cnblogs.com/lknlfy/p/3583806.html中已经说明,两个LED的原理图是一样的.要使两个LED交替闪烁,只需要在点亮蓝色LED,熄灭 ...

  4. Cubieboard2裸机开发之(一)点亮板载LED

    前言 CUbieboard2板载两个LED,一个绿色的,一个蓝色的,其中绿色LED通过三极管与PH20管脚连接,蓝色LED通过三极管与PH21管脚连接,这里只以蓝色LED为例,电路原理图如图1和图2所 ...

  5. S5PV210开发系列四_uCGUI的移植

    S5PV210开发系列四 uCGUI的移植 象棋小子          1048272975 GUI(图形用户界面)极大地方便了非专业用户的使用,用户无需记忆大量的命令,取而代之的是能够通过窗体.菜单 ...

  6. S3C2440—3.用点亮LED来熟悉裸机开发的详细流程

    文章目录 一.硬件知识 1.LED原理图 2.芯片手册 Ⅰ.找LED原理图 Ⅱ.找对应引脚 Ⅲ.在芯片手册中查找引脚信息 Ⅳ.查看寄存器说明 Ⅴ.配置寄存器 二.S3C2440框架与启动过程 三.要用 ...

  7. MS CRM 2011的自定义和开发(11)——插件(plugin)开发(四)

    http://www.cnblogs.com/StoneGarden/archive/2012/02/08/2343294.html MS CRM 2011的自定义和开发(11)——插件(plugin ...

  8. S3C2416裸机开发系列十六_sd卡驱动实现

    S3C2416裸机开发系列十六 sd卡驱动实现 象棋小子    1048272975 SD卡(Secure Digital Memory Card)具有体积小.容量大.传输数据快.可插拔.安全性好等长 ...

  9. Lucene.Net 2.3.1开发介绍 —— 四、搜索(一)

    原文:Lucene.Net 2.3.1开发介绍 -- 四.搜索(一) 既然是内容筛选,或者说是搜索引擎,有索引,必然要有搜索.搜索虽然与索引有关,那也只是与索引后的文件有关,和索引的程序是无关的,因此 ...

随机推荐

  1. 在线教学、视频会议 Webus Fox(2) 服务端开发手册

    上次在<在线教学.视频会议软件 Webus Fox(1)文本.语音.视频聊天及电子白板基本用法>里介绍了软件的基本用法.本文主要介绍服务器端如何配置.开发. 1. 配置 1.1 IIS配置 ...

  2. C# 数据类型与PostgreSQL 数据类型映射

    Npgsql 是基于ADO.NET 的PostgreSQL 数据驱动. Npgsql 官方 已经提供C# 数据类型与PostgreSQL数据类型的对应映射 地址: http://www.npgsql. ...

  3. Json.Net4.5 序列化问题

    1.子类序列化 依赖父类属性 [DataContract] public class pcc { [DataMember] public string Name { get; set; } } pub ...

  4. [51单片机] TFT2.4彩屏1 [文字显示 画矩形]

    >_<:因为要驱动彩屏,所以这里采用STC90C516RD+单片机[51的89C52也行,就是可能内存在接下来的实验中可能会内存不够],晶振尽量采用高一点的,这里采用24MHz的. > ...

  5. 使用media Queries实现一个响应式的菜单

    Media queries是CSS3引入的一个特性,使用它可以方便的实现各种响应式效果.在这个示例中我们将会使用media queries实现一个响应式的菜单.这个菜单会根据当前浏览器屏幕的大小变化而 ...

  6. fgets函数执行完成后,文件指针如何移动?

    用fgets执行之后,读取了文件中的一行,这时文件位置指针是自动指向文件的下一行的开头吗,还是指向当前行的结尾?如果一行的字符串没读取完会怎样? 实例结果: 如果一行的字符串没读取完会,下一次会接着上 ...

  7. FIR.im Weekly - 让炫酷 UI 为 APP 增色

    上周我看到一些不错的设计分享,挑选了几个比较全的 GitHub 资源推荐给大家.此外,还精选了一些实用的 iOS,Android 干货文章. iOS 炫酷动画资源 @荧星诉语 收集整理了主流炫酷动画框 ...

  8. javaweb回顾第七篇jsp

    1:为什么会有JSP jsp全名(java server pages)中文叫做java服务器页面.在Servlet那一篇我们发现用Servlet可以生成动态页面,但是我们却在Servlet中却写了大量 ...

  9. Struts2入门1 Struts2基础知识

    Struts2入门1 Struts2基础知识 20131130 代码下载: 链接: http://pan.baidu.com/s/11mYG1 密码: aua5 前言: 之前学习了Spring和Hib ...

  10. 为什么调用 FragmentPagerAdapter.notifyDataSetChanged() 并不能更新其 Fragment

    http://stackoverflow.com/questions/10849552/update-viewpager-dynamically if you want to switch out t ...