arm的时钟芯片有哪些系统为什么这么复杂

扫一扫,手机访问
您好,欢迎来到维库电子市场网
您所在的位置:&&&&&&&&ARM学习之时钟体系结构
版权与免责声明
凡本网注明“出处:维库电子市场网”的所有作品,版权均属于维库电子市场网,转载请必须注明维库电子市场网,http://www.dzsc.com,违反者本网将追究相关法律责任。
本网转载并注明自其它出处的作品,目的在于传递更多信息,并不代表本网赞同其观点或证实其内容的真实性,不承担此类作品侵权行为的直接责任及连带责任。其他媒体、网站或个人从本网转载时,必须保留本网注明的作品出处,并自负版权等法律责任。
如涉及作品内容、版权等问题,请在作品发表之日起一周内与本网联系,否则视为放弃相关权利。
相关技术资料
热门技术资料
最新技术资料arm9为何上电时候要改变系统时钟
注意:本文摘自
因为在没有上电时候,开发板是工作在12Mhz,那么用到时钟的硬件资源比如cpu 内存
uart等也工作在12Mhz,那么我知道正常情况下也即上电的话,开发板是工作在500Mhz,这样的话,需要一个切换的过程,这个过程如下:
在对系统时钟进行提速之前,让我们先来了解下上的工作时钟频率,,,,其中主要为内核提供工作频率,如图所示:
ARM920T内核结构
主要为总线()上挂接硬件提供工作频率,总线主要挂接有内存,,控制器等硬件,如图所示:
图总线上挂接硬件
主要为总线提供工作频率,由图所示,总线主要挂接串口,等硬件控制器。
图总线挂接硬件
也就是说,对于一些需要时钟工作的硬件,如果切断其时钟源 ,就不会再工作,从而达到降低功耗的目的,这也是便携嵌入式设备里的一个特点。
时钟源:为了减少外界环境对开发板电磁干扰,降低制作成本,通常开发板的外部晶振时钟频率都很低,开发板由的晶振来提供时钟源,要想让运行在更高的频率就要通过时钟控制逻辑单元(锁相环)来提高主频。
里有两个:和,用来产生,,的高频工作时钟,用来为提供工作频率。
图系统时钟初始化时序
开发板上电后,晶振开始提供晶振时钟,由于系统刚刚上电,电压信号等都还不稳定,这时复位信号()拉低,这时虽然默认启动,但是如果不向中写入值,那么外部晶振则直接作为系统时钟,过几毫秒后,复位信号上拉,开始取指运行,这时可以通过代码设置启动,启动需要一定锁定时间(),这是因为输出频率还没有稳定,在这期间都停止输出,停止工作,过了后时钟稳定输出,工作在新设置的频率下,这时可以通过设置,和三者的频率比例来产生不同总线上需要的不同频率,下面详细介绍开启的过程:
设置变频锁定时间
设置与晶振输入频率()的倍数
设置,,三者之间的比例
变频锁定时间由寄存器(见下表)来设置,由于变频后开发板所有依赖时钟工作的硬件都需要一小段调整时间,该时间计数通过设置寄存器来设置(时钟锁相环)调整时间,通过设置寄存器 设置调整时间,这两个调整时间数值一般用其默认值即可。
表变频锁定时间寄存器
复位默认值
变频锁定时间寄存器
对的锁定时间值
对于,,的锁定时间值
FCLK与Fin的倍数通过MPLLCON寄存器设置,三者之前有以下关系:
MPLL(FCLK) = (2*m*Fin)/(p*2^s)
其中:m = MDIV + 8, p = PDIV + 2, s = SDIV
当设置完之后,就会自动进入变频锁定期间,之后,输出稳定时钟频率。
表配置寄存器
复位默认值
配置寄存器
主分频器控制位
预分频器控制位
后分频器控制位
通过上述算法比较难以找到合适的值,下表给出了官方推荐的一些参考设置:
表 官方推荐MPLL
,,三者之间的比例通过寄存器进行设置,时钟设置时,还要额外设置寄存器,如下表,,分别与对应,下表列出了各种时钟比例:
表设置比例
如果设置为非,的总线模式要进行改变,默认情况下,工作在快速总线模式下,设置为非后, 与不再相等,要将改为异步总线模式,可以通过下面的嵌入汇编代码实现:
关于与指令,请查看与内存保护的实现章节。
表时钟分频器控制寄存器()
复位默认值
时钟分频器控制寄存器
选择寄存器(必须对提供)
是和相同时钟
:是和相同时钟
表摄像头时钟分频控制寄存器()
复位默认值
摄像头时钟分频控制寄存器
分频因子选择位(当位为时有效)
分频因子选择位(当位为时有效)
系统时钟驱动可以分别用汇编和语言两个版本实现。
汇编版本:
以下为时钟相关寄存器地址
0x4c000000&&&&&&&&
EQU&&&&&&&&&&&&&&&&&&
0x4c000004&&&&&&&
EQU&&&&&&&&&&&&&&&&&&
0x4c000014
EQU&&&&&&&&&&&&&&&&&&
0x4c000018
; 时钟初始化代码
; 设置变频锁定时间
ldr r1, =0x00ffffff
str r1, [r0]
; 设置分频比
; 由于位初始值为,寄存器未使用,这儿不用再设置其值
ldr r0, =CLKDIVN
mov r1, #0x05
str r1, [r0]
; 修改总线模式
mrc&& p15, 0, r1,
r1, r1, #0xc0000000
p15, 0, r1, c1, c0, 0
ldr r0, =MPLLCON
=0x5c011&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
; MPLL = 400MHz
; 函数调用返回
该汇编代码入口处先设置了变频锁定时间为,然后设置的分频比,由于系统时钟已经改变,需要修改总线模式,最后设置系统时钟工作频率。
语言版本:
LOCKTIME = 0x00
CLKDIVN& =
mrc&& p15, 0, r1,
r1, r1, #0xc0000000
mcr p15, 0, r1, c1, c0, 0
MPLLCON = MPLL_400MHz;
语言版本与汇编版本一样,只是由于修改总线模式时要使用指令,因此只能使用语言嵌入汇编方式来实现。
系统时钟驱动实验:
系统时钟初始化实验
EQU&&&&&&&&&
; 看门狗控制寄存器
EQU&&&&&&&&&
; 看门狗数据寄存器
0x4c000000&&&&&&&&
; 变频锁定时间寄存器
EQU&&&&&&&&&
0x4c000004&&&&&&&
; MPLL寄存器
EQU&&&&&&&&&
0x4c000014&&&&&&&
; 分频比寄存器
; LED控制寄存器
; LED数据寄存器
; 上拉电阻设置寄存器
0x8fff&&&&&&&&&&&&&&&&&
; 延时数值
CLOCK, CODE, READONLY
0x&&&&&&&&&&&&&&&&&&&&&
; 看门狗关闭代码
mov &r1, #0
&clock_init&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
; 调用时钟初始化函数
&led_on&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
; 调用点亮函数
; 时钟初始化代码
; 设置锁频时间
=LOCKTIME&&&&&&&&&&&&&&&&&&&&&&&&
; 取得寄存器地址
=0x00ffffff&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
; LOCKTIME寄存器设置数据
[r0]&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
; 将设置数据写入寄存器
; 设置分频数
=CLKDIVN&&&&&&&&&&&&&&&&&&&&&&&&&&
; 取得寄存器地址
#0x05&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
; CLKDIVN寄存器设置数据
[r0]&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
; 将设置数据写入寄存器
; 修改总线模式
p15, 0, r1, c1, c0, 0
r1, r1, #0xc0000000
p15, 0, r1, c1, c0, 0
ldr r0, =MPLLCON
=0x5c011&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
; MPLL is 400MHz
str r1, [r0]
mov pc, lr
; 亮点函数
; Led初始化开始
r0,=GPBCON&&
&&&&&&&&&&&&&&&&&&&&
; 将控制寄存器地址放入
&r1,[r0]&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
; 将控制寄存器里的值读出放入
r1,r1,#0x3fc00&&&&&&&&&&&&&&&&&&&&&&&&&
; 将里的值(控制寄存器里的值)
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
; bit[10]~bit[17]清位,其它位不变
r1,r1,#0x15400&&&&&&&&&&&&&&&&&&&&&&&&
; 设置控制寄存器
r1,[r0]&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
; 将里的值写入控制寄存器
; 禁止-端口的上拉电阻
ldr& r1,[r0]
r1,r1,#0x1e0
str& r1,[r0]
; Led初始化结束
; 循环点亮
r2,=GPBDAT&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&
; 将数据寄存器的地址放入
r3,[r2]&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&
; 将数据寄存器()里的值放入
r3,r3,#0x1e0&
&&&&&&&&&&&&&&&&&&&&&&&&&&&
; 清除,代表
r3,r3,#0x1c0&
&&&&&&&&&&&&&&&&&&&&&&&&&&&
; 清对应位亮灯,设置相应位灭灯(点亮)
str& r3,[r2]
&&&&&&&&&&&&&&&&&&&&&&&&&&&
; 将控制亮灯数据写入数据寄存器
ldr r0,=DELAYVAL
&&&&&&&&&&&&&&&&&&
; 设置延迟数
bl&& delay
&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&
; 调用延迟子程序
r3,[r2]&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&
; 将数据寄存器()里的值放入
r3,r3,#0x1e0&
&&&&&&&&&&&&&&&&&&&&&&&&&&&
; 清除,代表
r3,r3,#0x1a0&
&&&&&&&&&&&&&&&&&&&&&&&&&&&
; 清对应位亮灯,设置相应位灭灯(点亮)
str& r3,[r2]
&&&&&&&&&&&&&&&&&&&&&&&&&&&
; 将控制亮灯数据写入数据寄存器
r0,=DELAYVAL&&&&&&&&&&&&&&&
; 设置延迟数
&&&&&&&&&&&&&&&&&&&&&&&&&&&
; 调用延迟子程序
r3,[r2]&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&
; 将数据寄存器()里的值放入
r3,r3,#0x1e0&
&&&&&&&&&&&&&&&&&&&&&&&&&&&
; 清除,代表
orr& r3,r3,#0x160
&&&&&&&&&&&&&&&&&&&&&&&&&&&
; 清对应位亮灯,设置相应位灭灯(点亮)
str& r3,[r2]
&&&&&&&&&&&&&&&&&&&&&&&&&&&
; 将控制亮灯数据写入数据寄存器
r0,=DELAYVAL&&&&&&&&&&&&&&&
; 设置延迟数
&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&
; 调用延迟子程序
r3,[r2]&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&
; 将数据寄存器()里的值放入
r3,r3,#0x1e0&
&&&&&&&&&&&&&&&&&&&&&&&&&&&
; 清除,代表
r3,r3,#0xe0&&&&&&&&&&&&
; 清对应位亮灯,设置相应位灭灯(点亮)
str& r3,[r2]
&&&&&&&&&&&&&&&&&&&&&&&&&&&
; 将控制亮灯数据写入数据寄存器
r0,=DELAYVAL&&&&&&&&&&&&&&&
; 设置延迟数
&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&
; 调用延迟子程序
b led_loop
r0,r0,#1&&&&&&&
&&&&&&&&&&&&&&&&&&&&
cmp r0,#0x0
&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&
; 将的值与相比较
&&&&&&&&&&&&&&&&&&
; 比较的结果不为,继续调用
&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&
END&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&
; 程序结束符
该实验首先关闭了看门狗定时器,然后修改系统时钟,将默认系统工作频率Hz提高到,由于工作在较高频率下,其执行速度明显比未启动系统时钟时高的多,可以通过注释掉系统时钟初始化代码跳转指令
,对比的跑马灯效果可以证明。
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。扫一扫体验手机阅读
ARM cortex a 之时钟系统2
<span type="1" blog_id="1840561" userid='
16篇文章,6089人气,0粉丝
运维开发全攻略
¥51.0019人订阅
大数据时代的微服务之路
¥51.00503人订阅Atmel SAM4S:抽丝剥茧大话时钟系统 - ARM系列专区 - Microchip技术社区
后使用快捷导航没有帐号?
查看: 3088|回复: 7
Atmel SAM4S:抽丝剥茧大话时钟系统
本帖最后由 kunluo 于
09:12 编辑
时钟是每个学习arm技术的朋友不能逃避的问题,彻底掌握较为复杂的时钟系统将使学习过程不在稀里糊涂。本人有幸从与非网拿到一块SAM4S的板卡,经过一周的学习,对SAM4S的时钟有了初步的认识,我也将尽数与大家分享。希望能起到抛砖引玉的作用,看到更多网友的积极分享。共分为以下几个部分:<font color="#.& && &SAM4S板载时钟源有哪些?<font color="#.& && &SAM4S时钟系统全面介绍及工作流程<font color="#.& && &如何使用ASF对时钟系统进行编程,获得自己需要的时钟频率?
下边先说第一部分。我们依据SAM4S的数据手册来说明,先看数据手册中关于时钟源的描述:
图一.png (40.46 KB, 下载次数: 1)
23:09 上传
把上图稍加翻译和整理,可以把时钟源分成以下两个部分:一、& &MCU内集成的时钟源,包括有:1.& && &32K内部集成晶振:RC晶振2.& && &4/8/12M晶振:RC晶振-可通过编程选择具体频率由于这两个晶振集成在MCU内部,所以我们无法看到他们长什么样子。二、& &板载外部晶振,包括有:1.& && &板载32K晶振2.& && &板载12M晶振如图:
图二.png (656.37 KB, 下载次数: 7)
23:09 上传
大家可以清楚的看到板载的12M晶振和32K晶振。这四个晶振将担任SAM4S的所有时钟源,可谓是功不可没。若论功劳来排名,板载的12M晶振妥妥的排到第一位。
但这四个晶振究竟是如何协调工作产生系统时钟的呢?SAM4S时钟系统是怎么工作的?这些问题我们下一篇再详细聊聊。重头戏即将到来。。。。。。
大话时钟系列文章:
等待下一篇的问题解释。
等待下一篇的问题解释。
已经出来,记得来看啊
写的很好,多谢分享。
感谢分享,长知识了
可否附上一周学习的相关技术文档,比如SAM4S的数据手册?
可否附上一周学习的相关技术文档,比如SAM4S的数据手册?
数据手册网上随便就能找到
详尽,一看就知道怎么回事
站长推荐 /5
经典AVR图书合集,23本!免费下载!
( ̄▽ ̄)~*φ(>ω<*) ?(?????)?ヾ(?°?°?)??
模拟实在是太太太难?那么,先把这些经典资料收集起来吧~会有一些帮助哒
PIC图书集合!基础原理、c语言、模块详解,超全书单任你选
新年大礼包!官方视频/封装文件/文档/开源项目/图书,资料多多,收藏起来~ヾ(?°?°?)??
历年Microchip精英年会资料!高清PDF下载;对于想去年会而囿于环境限制的朋友们来说,是非常好的资料
&2018 Microchip Corporation
Tel: 3-8072
& 2010 - 2018 苏州灵动帧格网络科技有限公司 版权所有.
ICP经营许可证 苏B2-&
Powered by1. Linux下有两类时钟:
1.1 实时钟RTC
它由板上电池驱动的“Real Time Clock”也叫做RTC或者叫CMOS时钟,硬件时钟。当操作系统关机的时候,用这个来记录时间,但是对于运行的系统是不用这个时间的。
1.2 系统时钟
“System clock”也叫内核时钟或者软件时钟,是由软件根据时间中断来进行计数的,内核时钟在系统关机的情况下是不存在的,所以,当操作系统启动的时候,内核时钟是要读取RTC时间来进行时间同步.
2.1 时钟滴答计时(jiffies)的几个基本参数
2.1.1 时钟周期(clock cycle)的频率-晶振频率
计时器Timer晶体振荡器在1秒内产生的时钟脉冲个数就是时钟周期的频率, 要注意把这个Timer的时钟周期频率与时钟中断的频率区别开来,
Linux用宏CLOCK_TICK_RATE来表示计时器的输入时钟脉冲的频率(比如我的为#define CLOCK_TICK_RATE
1193180),该宏定义在arm/mach-xxx/include/mach/timex.h头文件中。
2.1.2 时钟中断(clock tick)
我们知道当计数器减到0值时,它就在IRQ0上产生一次时钟中断,也即一次时钟中断, 计数器的初始值决定了要过多少时钟周期才产生一次时钟中断,因此也就决定了一次时钟滴答的时间间隔长度.
2.1.3 时钟中断的频率(HZ)
即1秒时间内Timer所产生的时钟中断次数。确定了时钟中断的频率值后也就可以确定Timer的计数器初值。Linux内核用宏HZ来表示时钟中断的频率,而且在不同的平台上HZ有不同的定义值。对于SPARC、MIPS、ARM和i386等平台HZ的值都是100。该宏在ARM平台上的定义如下(/arch/arm/include/asm/param.h)
2.1.4 计数器的初始值
计数器的初始值由宏LATCH定义在文件:include/linux/jiffies.h
#define LATCH
((CLOCK_TICK_RATE + HZ/2) / HZ) /* For divider */
2.1.5 jiffies
在 Linux 内核中,时间由一个名为 jiffies 的全局变量衡量,该变量标识系统启动以来经过的滴答数。在最低的级别上,计算滴答数的方式取决于正在运行的特定硬件平台;但是,滴答计数通常在一次中断期间仍然继续进行。
标准计时器 API 作为 Linux 内核的一部分已经有很长一段时间了(自从 Linux 内核的早期版本开始)。尽管它提供的精确性比高精确度计时器要低,但它对于在处理物理设备时提供错误覆盖的传统驱动程序超时来说比较理想。在很多情况下,这些超时实际上从不触发,而是被启动,然后被删除。
简单内核计时器使用计时器轮(timer wheel) 实现。这个主意是由 Finn Arne Gangstad 在 1997 年首次引入的。它不理睬管理大量计时器的问题,而是很好地管理数量合理的计时器 — 典型情况。(原始计时器实现只是按照过期顺序将计时器实现双重链接。尽管在概念上比较简单,但这种方法是不可伸缩的。)时间轮是一个 buckets 集合,其中每个 bucker 表示将来计时器过期的一个时间块。这些 buckets 使用基于
5 个 bucket 的对数时间定义。使用 jiffies 作为时间粒度,定义了几个组,它们表示将来的过期时段(其中每个组通过一列计时器表示)。计时器插入使用具有 O(1) 复杂度的列表操作发生,过期发生在 O(N) 时间内。计时器过期以串联的形式出现,其中计时器被从高粒度 buckets 删除,然后随着它们的过期时间的下降被插入到低粒度 buckets 中。现在我们查看一下针对这个计时器实现的 API。
2.2 计时器 API
Linux 提供了一个简单的 API 来构造和管理计时器。它包含一些函数(和助手函数),用于创建、取消和管理计时器。
计时器通过 timer_list 结构定义,该结构包括实现一个计时器所需的所有数据(其中包括列表指针和在编译时配置的可选计时器统计数据)。从用户角度看,timer_list 包含一个过期时间,一个回调函数(当/如果计时器过期),以及一个用户提供的上下文。用户必须初始化计时器,可以采取几种方法,最简单的方法是调用 setup_timer,该函数初始化计时器并设置用户提供的回调函数和上下文。或者,用户可以设置计时器中的这些值(函数和数据)并简单地调用
init_timer。注意,init_timer 由 setup_timer 内部调用。
void init_timer( struct timer_list *timer );
void setup_timer( struct timer_list *timer,
void (*function)(unsigned long), unsigned long data );
拥有一个经过初始化的计时器之后,用户现在需要设置过期时间,这通过调用 mod_timer 来完成。由于用户通常提供一个未来的过期时间,他们通常在这里添加 jiffies 来从当前时间偏移。用户也可以通过调用 del_timer 来删除一个计时器(如果它还没有过期):
int mod_timer( struct timer_list *timer, unsigned long expires );
void del_timer( struct timer_list *timer );
最后,用户可以通过调用 timer_pending(如果正在等待,将返回 1)来发现计时器是否正在等待(还没有发出):
int timer_pending( const struct timer_list *timer );
2.3 计时器示例
我们来检查一下这些 API 函数的实际运行情况。下面的代码提供了一个简单的内核模块,用于展示简单计时器 API 的核心特点。在 init_module 中,您使用 setup_timer 初始化了一个计时器,然后调用 mod_timer 来启动它。当计时器过期时,将调用回调函数 my_timer_callback。最后,当您删除模块时,计时器删除(通过 del_timer)发生。(注意来自 del_timer 的返回检查,它确定计时器是否还在使用。)
#include &linux/kernel.h&
#include &linux/module.h&
#include &linux/timer.h&
MODULE_LICENSE("GPL");
static struct timer_list my_
void my_timer_callback( unsigned long data )
printk( "my_timer_callback called (%ld).\n", jiffies );
int init_module( void )
printk("Timer module installing\n");
// my_timer.function, my_timer.data
setup_timer( &my_timer, my_timer_callback, 0 );
printk( "Starting timer to fire in 200ms (%ld)\n", jiffies );
ret = mod_timer( &my_timer, jiffies + msecs_to_jiffies(200) );
if (ret) printk("Error in mod_timer\n");
void cleanup_module( void )
ret = del_timer( &my_timer );
if (ret) printk("The timer is still in use...\n");
printk("Timer module uninstalling\n");
3. 高精确度计时器(hrtimer)
高精确度计时器(简称 hrtimers)提供一个高精确度的计时器管理框架,这个框架独立于此前讨论过的标准计时器框架,原因是合并这两个框架太复杂。尽管计时器在 jiffies 粒度上运行,hrtimers 在纳秒粒度上运行。
hrtimer 框架的实现方式与标准计时器 API 不同。hrtimer 不使用 buckets 和串联操作,而是维护一个按时间排序的计时器数据结构(按时间顺序插入计时器,以最小化激活时的处理)。这个数据结构是一个 “红-黑” 树,对于注重性能的应用程序很理想(且恰好作为内核中的一个库普遍可用)。
hrtimer 框架作为内核中的一个 API 可用,用户空间应用程序也可以通过 nanosleep、itimers 和 Portable Operating System Interface (POSIX)-timers interface 使用它。hrtimer 框架被主线化(mainlined)到 2.6.21 内核中。
3.1 高精确度计时器 API
hrtimer API 与传统 API 有些相似,但它们之间的一些根本差别是它能够进行额外的时间控制。应该注意的第一点是:时间不是用 jiffies 表示的,而是以一种名为 ktime 的特殊数据类型表示。这种表示方法隐藏了在这个粒度上有效管理时间的一些细节。hrtimer API 正式确认(formalize)了绝对时间和相对时间之间的区别,要求调用者指定类型。
union ktime {
#if BITS_PER_LONG != 64 && !defined(CONFIG_KTIME_SCALAR)
# ifdef __BIG_ENDIAN
与传统的计时器 API 类似,高精确度计时器通过一个结构表示 — 这里是 hrtimer。这个结构从用户角度定义定时器(回调函数、过期时间等)并包含了管理信息(其中计时器存在于 “红-黑” 树、可选统计数据等中)。
定义过程首先通过 hrtimer_init 初始化一个计时器。这个调用包含计时器、时钟定义和计时器模式(绝对或相对)。使用的时钟在 ./include/linux/time.h 中定义,表示系统支持的各种时钟(比如实时时钟或者单一时钟,后者只表示从一个起点[比如系统启动]开始的时间)。计时器被初始化之后,就可以通过 hrtimer_start 启动。这个调用包含过期时间(在
ktime_t 中)和时间值的模式(绝对或相对值)。
struct hrtimer {
struct rb_node
enum hrtimer_restart
(*function)(struct hrtimer *);
struct hrtimer_clock_base *
unsigned long
#ifdef CONFIG_TIMER_STATS
start_comm[16];
void hrtimer_init( struct hrtimer *time, clockid_t which_clock,
enum hrtimer_mode mode );
int hrtimer_start(struct hrtimer *timer, ktime_t time, const
enum hrtimer_mode mode);
hrtimer 启动后,可以通过调用 hrtimer_cancel 或 hrtimer_try_to_cancel 来取消。每个函数都包含将被停止的计时器的 hrtimer 引用。这两个函数的区别在于:hrtimer_cancel 函数试图取消计时器,但如果计时器已经发出,那么它将等待回调函数结束;hrtimer_try_to_cancel 函数也试图取消计时器,但如果计时器已经发出,它将返回失败。
int hrtimer_cancel(struct hrtimer *timer);
int hrtimer_try_to_cancel(struct hrtimer *timer);
可以通过调用 hrtimer_callback_running 来检查 hrtimer 是否已经激活它的回调函数。注意,这个函数由 hrtimer_try_to_cancel 内部调用,以便在计时器的回调函数被调用时返回一个错误。
int hrtimer_callback_running(struct hrtimer *timer);
3.2 一个 hrtimer 示例
#include &linux/kernel.h&
#include &linux/module.h&
#include &linux/hrtimer.h&
#include &linux/ktime.h&
MODULE_LICENSE("GPL");
#define MS_TO_NS(x) (x * 1E6L)
static struct hrtimer hr_
enum hrtimer_restart my_hrtimer_callback( struct hrtimer *timer )
printk( "my_hrtimer_callback called (%ld).\n", jiffies );
return HRTIMER_NORESTART;
int init_module( void )
unsigned long delay_in_ms = 200L;
printk("HR Timer module installing\n");
ktime = ktime_set( 0, MS_TO_NS(delay_in_ms) );
hrtimer_init( &hr_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL );
hr_timer.function = &my_hrtimer_
printk( "Starting timer to fire in %ldms (%ld)\n", delay_in_ms, jiffies );
hrtimer_start( &hr_timer, ktime, HRTIMER_MODE_REL );
void cleanup_module( void )
ret = hrtimer_cancel( &hr_timer );
if (ret) printk("The timer was still in use...\n");
printk("HR Timer module uninstalling\n");
关于 hrtimer API,还有许多内容这里没有涉及到。一个有趣的方面是它能够定义回调函数的执行上下文(比如在 softirq 或 hardiirq 上下文中)。您可以在 ./include/linux/hrtimer.h 文件中进一步了解 hrtimer API。
处理器一条指令需要几个时钟周期?
CPU性能衡量参数-主频,MIPS,CPI,时钟周期,机器周期,指令周期
嵌入式linux C语言 如何同步系统时钟到硬件时钟
arm-linux开机读取硬件时钟,设置系统时钟。
没有更多推荐了,}

我要回帖

更多关于 时钟芯片ds1302 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信