之内核时钟)
一、内核时钟1、内核时钟内核时钟Kernel Clock也称为系统时钟System Clock或滴答时钟Tick Timer是操作系统内核中用于时间管理的一个重要组件。它提供了精确的时间基准用于调度、延时等各种系统功能。S5p6818 linux ----操作系统的时钟频率 HZ 1000 具体的参考值是由官方提供。│ Symbol: HZ_100 [n]│ Type : boolean│ Prompt: 100 HZ│ Defined at kernel/Kconfig.hz:19│ Depends on: choice│ Location:│ - System Type│ - Timer frequency (choice [y])┌──────────── Timer frequency───────────┐│ Use the arrow keys to navigate this window or press the hotkey of ││ the item you wish to select followed by the SPACE BAR. Press ││ ? for additional information about this option. ││ ┌────────────────────────────────────────────────────────────────┐ ││ │ ( ) 100 HZ │ ││ │ ( ) 250 HZ │ ││ │ ( ) 300 HZ │ ││ │ (X) 1000 HZ │ ││ │ │ │2、内核时钟频率与硬件平台有关1) 找到linux内核源码中对S5P6818硬件初始化的源文件kernel\arch\arm\mach-s5p6818\cpu.c2) 找到机器宏extern struct sys_timer nxp_cpu_sys_timer; MACHINE_START(S5P6818, CFG_SYS_CPU_NAME) //S5P6818 4330 .atag_offset 0x00000100, .fixup cpu_fixup, .map_io cpu_map_io, .init_irq nxp_cpu_irq_init, .handle_irq gic_handle_irq, .timer nxp_cpu_sys_timer, //extern struct sys_timer nxp_cpu_sys_timer; .init_machine cpu_init_machine, #if defined CONFIG_CMA defined CONFIG_ION .reserve cpu_mem_reserve, #endif MACHINE_END struct sys_timer nxp_cpu_sys_timer { .init timer_initialize, //关于时钟频率和定时器的入口 }; static void __init timer_initialize(void) { pr_debug(%s\n, __func__); timer_source_init(CFG_TIMER_SYS_TICK_CH); //timer0 1MHZ timer_event_init(CFG_TIMER_EVT_TICK_CH); //timer1 1MHZ return; } /*------------------------------------------------------------------------------ * Timer List (SYS Source, EVT Event, WDT WatchDog) */ #define CFG_TIMER_SYS_TICK_CH 0 #define CFG_TIMER_EVT_TICK_CH 13、内核时钟频率HZ1000时钟频率(HZ)对系统有哪些好处或者缺点?好处HZ频率越高则系统的计时就越精确系统的实时性就越高缺点系统处理的时钟频率越高系统的担负也越重二、关于HZ1、HZ本身就是一个全局的常数#ifdef __KERNEL__ # define HZ CONFIG_HZ /* Internal kernel timer frequency */ # define USER_HZ 100 /* User interfaces are in ticks */ # define CLOCKS_PER_SEC (USER_HZ) /* like times() */ #else # define HZ 100 #endifCONFIG_HZ ----是由配置内核时设置的一个值 CONFIG_HZ ----.config或者 GEC6818_defconfig ----- autoconf.h(该头文件是在编译内核时自动根据配置生成的头文件)该常数可以任何位置直接使用比如printk(HZ %d,HZ);2、修改该HZ的值 ----配置内核│ Symbol: HZ_100 [n] │ Type : boolean │ Prompt: 100 HZ │ Defined at kernel/Kconfig.hz:19 │ Depends on: choice │ Location: │ - System Type │ - Timer frequency (choice [y])三、jiffies1、jiffies也是一个全局的常数。它是内核源码中的全局变量记录了linux内核从启动到现在经过了多少个内核时间周期1秒钟内jiffies增加的HZ的次数。jiffies/HZ ----linux系统启动到现在用了多少秒。# define jiffies raid6_jiffies() static inline uint32_t raid6_jiffies(void) { struct timeval tv; gettimeofday(tv, NULL); return tv.tv_sec*1000 tv.tv_usec/1000; //时间的值 }//在内核源码中的应用 unsigned long timeout jiffies 10*HZ/100; /* jiffies ----- 表示当前时间 10*HZ/100 --- 表示时间间隔为多少秒 1/10s 比如5*HZ ---表示时间间隔为5秒 timeout:表示时间间隔秒以后的时间也就是超时时间 */ if(jiffies timeout){ //超时 }else{ //未超时 }四、jiffies和ms、us、ns之间的转换函数五、linux内核动态定时器定时器是一个很常用的功能需要周期性处理的工作都要用到定时器。Linux 内核定时器采用系统时钟来实现并不是硬件定时器。Linux 内核定时器使用很简单只需要提供超时时间 (相当于定时值) 和定时处理函数即可当超时时间到了以后设置的定时处理函数就会执行不需要做一大堆的寄存器初始化工作。在使用内核定时器的时候要注意一点内核定时器并不是周期性运行的超时以后就会自动关闭因此如果想要实现周期性定时那么就需要在定时处理函数中重新开启定时器。Linux 内核使用 timer_list 结构体表示内核定时器timer_list 定义在文件 include/linux/timer.h 中定义如下 (省略掉条件编译)struct timer_list { struct list_head entry; unsigned long expires; /* 定时器超时时间单位是节拍数 */ struct tvec_base *base; void (*function)(unsigned long); /* 定时处理函数 */ unsigned long data; /* 要传递给 function 函数的参数 */ int slack; };要使用内核定时器首先要先定义一个 timer_list 变量表示定时器tiemr_list 结构体的 expires 成员变量表示超时时间单位为节拍数。比如我们现在需要定义一个周期为 2 秒的定时器那么这个定时器的超时时间就是 jiffies(2HZ)因此 expiresjiffies(2HZ)。function 就是定时器超时以后的定时处理函数我们要做的工作就放到这个函数里面需要我们编写这个定时处理函数。定义好定时器以后还需要通过一系列的 API 函数来初始化此定时器这些函数如下1、init_timer函数 init_timer 函数负责初始化 timer_list 类型变量当我们定义了一个 timer_list 变量以后一定要先用 init_timer 初始化一下。init_timer 函数原型如下void init_timer(struct timer_list *timer)函数参数和返回值含义如下timer要初始化定时器。返回值没有返回值。2、add_timer 函数add_timer 函数用于向 Linux 内核注册定时器使用 add_timer 函数向内核注册定时器以后定时器就会开始运行函数原型如下void add_timer(struct timer_list *timer)函数参数和返回值含义如下timer要注册的定时器。返回值没有返回值。3、del_timer 函数del_timer 函数用于删除一个定时器不管定时器有没有被激活都可以使用此函数删除。在多处理器系统上定时器可能会在其他的处理器上运行因此在调用 del_timer 函数删除定时器之前要先等待其他处理器的定时处理器函数退出。del_timer 函数原型如下int del_timer(struct timer_list * timer)函数参数和返回值含义如下timer要删除的定时器。返回值0定时器还没被激活1定时器已经激活。4、del_timer_sync 函数del_timer_sync 函数是 del_timer 函数的同步版会等待其他处理器使用完定时器再删除del_timer_sync 不能使用在中断上下文中。del_timer_sync 函数原型如下所示int del_timer_sync(struct timer_list *timer)函数参数和返回值含义如下timer要删除的定时器。返回值0定时器还没被激活1定时器已经激活。5、mod_timer 函数mod_timer 函数用于修改定时值如果定时器还没有激活的话mod_timer 函数会激活定时器函数原型如下int mod_timer(struct timer_list *timer, unsigned long expires)函数参数和返回值含义如下timer要修改超时时间 (定时值) 的定时器。expires修改后的超时时间。返回值0调用 mod_timer 函数前定时器未被激活1调用 mod_timer 函数前定时器已被激活。关于内核定时器常用的 API 函数就讲这些内核定时器一般的使用流程如下所示struct timer_list timer; /* 定义定时器 */ /* 定时器回调函数 */ void function(unsigned long arg) { /* * 定时器处理代码 */ /* 如果需要定时器周期性运行的话就使用 mod_timer * 函数重新设置超时值并且启动定时器。 */ mod_timer(dev-timertest, jiffies msecs_to_jiffies(2000)); } /* 初始化函数 */ void init(void) { init_timer(timer); /* 初始化定时器 */ timer.function function; /* 设置定时处理函数 */ timer.expiresjiffies msecs_to_jiffies(2000); /* 超时时间2秒 */ timer.data (unsigned long)dev; /* 将设备结构体作为参数 */ add_timer(timer); /* 启动定时器 */ } /* 退出函数 */ void exit(void) { del_timer(timer); /* 删除定时器 */ /* 或者使用 */ del_timer_sync(timer); }//[1] 定义动态定时器 static struct timer_list gec6818_timer; void gec6818timer_function(unsigned long data) { printk(jiffies %ld\n,jiffies); printk(data %ld\n,data); //[5] 修改时间 mod_timer(gec6818_timer,jiffies 1*HZ); } //[2] 初始化动态定时器 init_timer(gec6818_timer); //[3]初始化成员 gec6818_timer.function gec6818timer_function;//函数的地址void (*function)(unsigned long); gec6818_timer.expires jiffies 1*HZ; //设置超时时间 gec6818_timer.data 10; //[4] 把动态定时器加入到内核中 add_timer(gec6818_timer); //[6] 把动态定时器从内核中删除 del_timer(gec6818_timer);六、Linux内核短延时函数有时候我们需要在内核中实现短延时尤其是在Linux驱动中。Linux内核提供了毫秒、微秒和纳秒延时函数这三个函数如表所示