`
isiqi
  • 浏览: 16026635 次
  • 性别: Icon_minigender_1
  • 来自: 济南
社区版块
存档分类
最新评论

嵌入式Linux内核时钟初始化问题

阅读更多

嵌入式Linux内核时钟初始化问题

首先搞清楚RTCkernel内的作用:

linux系统有两个时钟:一个是由主板电池驱动的“Real Time Clock”也叫做RTC或者叫CMOS时钟,硬件时钟。当操作系统关机的时候,用这个来记录时间,但是对于运行的系统是不用这个时间的。另一个时间是 “System clock”也叫内核时钟或者软件时钟,是由软件根据时间中断来进行计数的,内核时钟在系统关机的情况下是不存在的,所以,当操作系统启动的时候,内核时钟是要读取RTC时间来进行时间同步。并且在系统关机的时候将系统时间写回RTC中进行同步。

如前所述,Linux内核与RTC进行互操作的时机只有两个:
1) 内核在启动时从RTC中读取启动时的时间与日期;
2) 内核在需要时将时间与日期回写到RTC中。

系统启动时,内核通过读取RTC来初始化内核时钟,又叫墙上时间,该时间放在xtime变量中。
The current time of day (the wall time) is defined in kernel/timer.c:
struct timespec xtime;

The timespec data structure is defined in as:

struct timespec {
time_t tv_sec; /* seconds */
long tv_nsec; /* nanoseconds */
};

问题1:系统启动时在哪读取RTC的值并设置内核时钟进行时间同步的呢?
最有可能读取RTC设置内核时钟的位置应该在arch/arm/kernel/time.c里的time_init函数内.

time.c为系统的时钟驱动部分.time_init函数会在系统初始化时,由init/main.c里的start_kernel函数内调用.X86架构就是在这里读RTC值并初始化系统时钟xtime的.

ARM架构的time_init代码如下:

/* arch/arm/kernel/time.c */

void __init time_init(void)
{
if (system_timer->offset == NULL)
system_timer->offset = dummy_gettimeoffset;
system_timer->init();

#ifdef CONFIG_NO_IDLE_HZ
if (system_timer->dyn_tick)
system_timer->dyn_tick->lock = SPIN_LOCK_UNLOCKED;
#endif
}

上面system_timer->init()实际执行的是时钟驱动体系架构相关(具体平台)部分定义的init函数,若是s3c2410平台,则执行的为arch/arm/mach-s3c2410/time.c里定义的s3c2410_timer_init函数.不过s3c2410_timer_init()也没有读RTC的代码.整个时钟驱动初始化的过程大致就执行这些代码.

既然在系统时钟驱动初始化的过程中没有读RTC值并设置内核时钟,那会在哪设置呢?

我搜了一下,发现内核好象只有在arch/cris/kernel/time.c里有RTC相关代码,如下:
/* arch/cris/kernel/time.c */
/* grab the time from the RTC chip */
//读RTC的函数
unsigned long get_cmos_time(void)
{
unsigned int year, mon, day, hour, min, sec;
sec = CMOS_READ(RTC_SECONDS);
min = CMOS_READ(RTC_MINUTES);
hour = CMOS_READ(RTC_HOURS);
day = CMOS_READ(RTC_DAY_OF_MONTH);
mon = CMOS_READ(RTC_MONTH);
…………
return mktime(year, mon, day, hour, min, sec);
}

这个函数会在update_xtime_from_cmos内被调用:
void update_xtime_from_cmos(void)
{
if(have_rtc) {
xtime.tv_sec = get_cmos_time();
xtime.tv_nsec = 0;
}
}

另外还有设置rtc的函数
int set_rtc_mmss(unsigned long nowtime); /* write time into RTC chip */

不过我加了printk测试了一下,好象arch/cris/kernel/time.c这个文件和这两个函数只是适用与X86?
ARM平台启动时并不走这边.因此执行不到这些函数。
那ARM平台启动时,系统是在哪读RTC的值并对内核时钟(WallTime)进行初始化的呢?

已解决:
嵌入式Linux内核(ARM)是在系统启动时执行/etc/init.d/hwclock.sh脚本,这个脚本会调用hwclock小程序读取RTC的值并设置系统时钟。
(换句话说,这要取决于你制作的文件系统里是否有这样的脚本)

/* /etc/init.d/hwclock.sh */

DAEMON1=/sbin/hwclock
start() {
local RET ERROR=

[ ! -f /etc/adjtime ] && echo "0.0 0 0.0" > /etc/adjtime
log_status_msg "Setting the System Clock using the Hardware Clock as reference..." -n

# Copies Hardware Clock time to System Clock using the correct
# timezone for hardware clocks in local time, and sets kernel
# timezone. DO NOT REMOVE.
[ "$HWCLOCKACCESS" != no ] && $DAEMON1 --hctosys $GMT $BADYEAR

#
# Now that /usr/share/zoneinfo should be available,
# announce the local time.
#
log_status_msg "System Clock set. Local time: `date`"
log_status_msg ""
return 0
}

hwclock最先读取的设备文件是 /dev/rtc ,busybox里面的hwclock是这样实现的:
static int xopen_rtc(int flags)
{
int rtc;

if (!rtcname) {
rtc = open("/dev/rtc", flags);
if (rtc >= 0)
return rtc;
rtc = open("/dev/rtc0", flags);
if (rtc >= 0)
return rtc;
rtcname = "/dev/misc/rtc";
}
return xopen(rtcname, flags);
}

2. 内核如何更新RTC时钟?
通过set_rtc函数指针指向的函数,set_rtc在arch/arm/kernel/time.c内
/* arch/arm/kernel/time.c */
/*
* hook for setting the RTC's idea of the current time.
*/
int (*set_rtc)(void);

但是set_rtc函数指针在哪初始化的呢?set_rtc应该是和RTC驱动相关的函数.

搜索kernel源码后发现,好象内核其他地方并没有对其初始化。待解决!

set_rtc在do_set_rtc内调用
static inline void do_set_rtc(void)
{
……
if (set_rtc())
/*
* rtc update failed. Try again in 60s
*/
next_rtc_update = xtime.tv_sec + 60;
else
next_rtc_update = xtime.tv_sec + 660; /* update every ~11 minutes by default*/
}

do_set_rtc在timer_tick里调用
/*
* Kernel system timer support.
*/
void timer_tick(struct pt_regs *regs)
{
profile_tick(CPU_PROFILING, regs);
do_leds();
do_set_rtc();
do_timer(1);
……
}
timer_tick为Kernel提供的体系架构无关的时钟中断处理函数,通常会在体系架构相关的时钟中断处理函数内调用它。如s3c2410是这样的:

在arch/arm/mach-s3c2410/time.c中
* IRQ handler for the timer
*/
static irqreturn_t
s3c2410_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
write_seqlock(&xtime_lock);
timer_tick(regs);
write_sequnlock(&xtime_lock);
return IRQ_HANDLED;
}

分享到:
评论

相关推荐

    深入分析Linux内核源码

    6.2 Linux内存管理的初始化 6.2.1 启用分页机制 6.2.2 物理内存的探测 6.2.3 物理内存的描述 6.2.4 页面管理机制的初步建立 6.2.5页表的建立 6.2.6内存管理区 6.3 内存的分配和回收 6.3.1 伙伴算法 6.3.2 ...

    嵌入式系统/ARM技术中的Linux的时钟及时钟中断

     操作系统时钟是操作系统软件维护的时钟系统,操作系统通过读取实时时钟来初始化系 统时钟,此后二者一直保持同步,共同维持着系统的时间。这里的同步,是指操作系统在运行 过程中,每隔一个固定的时间就会刷新或...

    linux内核 0.11版本源码 带中文注释

    // linux 初始化(仅在这个程序中被调用)。 static inline _syscall0 (int, sync) // int sync()系统调用:更新文件系统。 #include <linux/tty.h> // tty 头文件,定义了有关tty_io,串行通信方面的参数、常数...

    基于FPGA的嵌入式开发与应用 part1

     3.6.2 定制ROM初始化数据文件  3.6.3 定制ROM元件  3.6.4 使用在系统嵌入式存储器数据编辑器  3.7 嵌入式锁相环altPLL宏功能模块调用  思考题 第4章 基于FPGA的DSP算法实现 第5章 Nios II处理器结构 第6章 ...

    嵌入式系统/ARM技术中的PPCBoot在MPC8250上的移植方法

    摘要:The Bootloader(引导加载程序)是嵌入式系统CPU加电后即开始运行的第一段代码,它把Linux内核与硬件平台衔接在一起,对于嵌入式系统的后续软件开发十分重要。PPCBoot是功能十分强大的Bootloader。深入研究了...

    《精通Linux 设备驱动程序开发》.(Sreekrishnan).pdf

    5.2.1 驱动程序初始化83 5.2.2 打开与释放86 5.2.3 数据交换88 5.2.4 查找92 5.2.5 控制94 5.3 检测数据可用性95 5.3.1 轮询95 5.3.2 fasync98 5.4 和并行端口交互99 5.5 rtc子系统108 5.6 伪...

    精通LINUX设备驱动程序开发

    161 8.2 i2c核心 162 8.3 总线事务 164 8.4 设备实例:eeprom 164 8.4.1 初始化 165 8.4.2 探测设备 167 8.4.3 检查适配器的功能 169 8.4.4 访问设备 169 8.4.5 其他函数 170 8.5 设备实例:实时时钟 171 ...

    嵌入式实时操作系统small RTOS51原理及应用

    5.14 Small RTOS51初始化函数OSStart() 5.15 系统时钟节拍中断OSTickISR() 第6章 任务之间的通信和同步之信号量 6.1 概述 6.2 使Keil C51函数具有重入性的特殊方法 6.3 数据结构 6.4 IN_OS_SEM_CHK宏及相关代码 ...

    嵌入式课程设计——基于 STM32 的双人五子棋.zip

    开发工具:官方提供STM32CubeMX初始化配置工具,帮助开发者快速进行项目设置、外设配置及代码生成。此外,还有STM32CubeIDE集成开发环境,集成了编译器、调试器和仿真器支持。 软件库:STM32Cube软件包包含HAL...

    电子香味项目,通过蓝牙模块传输数据,嵌入式硬件平台暂定基于STM32.zip

    开发工具:官方提供STM32CubeMX初始化配置工具,帮助开发者快速进行项目设置、外设配置及代码生成。此外,还有STM32CubeIDE集成开发环境,集成了编译器、调试器和仿真器支持。 软件库:STM32Cube软件包包含HAL...

    基于 AVR 的单片嵌入式系统原理与实践应用

    用户程序应在系统上电复位后,对一个16位的堆栈指针寄存器SP进行初始化设置(或在子程序和中断程序被执行之前)。 在AVR中,所有的存储器空间都是线性的。数据存储器(SRAM)可以通过5种不同的寻址方式进行访问。 ...

    嵌入式实时操作系统μC/OS-II在LPC2378上的移植及应用

    嵌入式实时操作系统μC...重点阐述移植代码中堆栈初始化、任务切换、时钟中断服务程序的编写过程,并对调试中出现的程序跑飞和堆栈空间不够的问题进行了解决和修改,最后通过设计多任务应用程序证明了该移植是成功的。

    ARM Cortex-A8和Android 4.x联动报警系统

    第32节:初始化系统时钟.zip 第33节:安装USB转串口驱动及串口工具.zip 第34节:Cortex-A8串口通信原理.zip 第35节:Cortex-A8串口通信实现.zip 第36节:Cortex-A8中断原理.zip 第37节:Cortex-A8中断实现.zip 第38...

    Vxworks培训资料.pptx

    该BSP库是硬件与软件的接口,处理硬件的初始化、中断处理与产生、硬件时钟与定时管理、局部和总线内存空间的映射、内存大小定义,等等。能够自行启动目标机、初始化目标机、能够与host通信以下载Vxworks核、把控制权...

    基于超声波物理指纹的安全防护装置.zip

    开发工具:官方提供STM32CubeMX初始化配置工具,帮助开发者快速进行项目设置、外设配置及代码生成。此外,还有STM32CubeIDE集成开发环境,集成了编译器、调试器和仿真器支持。 软件库:STM32Cube软件包包含HAL...

    基于stm32、树莓派,后端使用Java的springboot架构,以微信小程序作为用户控制端的智能家居控制系统.zip

    开发工具:官方提供STM32CubeMX初始化配置工具,帮助开发者快速进行项目设置、外设配置及代码生成。此外,还有STM32CubeIDE集成开发环境,集成了编译器、调试器和仿真器支持。 软件库:STM32Cube软件包包含HAL...

    基于STM32的智能家居系统.zip

    开发工具:官方提供STM32CubeMX初始化配置工具,帮助开发者快速进行项目设置、外设配置及代码生成。此外,还有STM32CubeIDE集成开发环境,集成了编译器、调试器和仿真器支持。 软件库:STM32Cube软件包包含HAL...

    基于树莓派4B和stm32的ros机器人.zip

    开发工具:官方提供STM32CubeMX初始化配置工具,帮助开发者快速进行项目设置、外设配置及代码生成。此外,还有STM32CubeIDE集成开发环境,集成了编译器、调试器和仿真器支持。 软件库:STM32Cube软件包包含HAL...

    基于STM32的倒车雷达项目--OLED显示,HC-SR04.zip

    开发工具:官方提供STM32CubeMX初始化配置工具,帮助开发者快速进行项目设置、外设配置及代码生成。此外,还有STM32CubeIDE集成开发环境,集成了编译器、调试器和仿真器支持。 软件库:STM32Cube软件包包含HAL...

Global site tag (gtag.js) - Google Analytics