完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
一、基础知识 1. 概念 RTC是real-time clock的缩写,其主要用途就是产生一个独立运行的计时器,Linux或者Windows系统启动后需要从这个计时器中读取时间,来设置系统时间。RTC具有断电保存的特性,防止因为意外断电导致系统时间混乱. 2. 硬件设备 2.1 I2c接口设备 Dallas/MaximDS1307/37/38/39/40, ST M41T00, EPSON RX-8025 Dallas/MaximDS1374 Dallas/Maxim DS1672 Dallas/Maxim DS3232 MaximMAX6900 Ricoh R2025S/D,RS5C372A/B, RV5C386, RV5C387A Intersil ISL1208Intersil ISL12022 Xicor/IntersilX1205 PhilipsPCF8563/Epson RTC8564 PhilipsPCF8583 STM41T62/65/M41T80/81/82/83/84/85/87 TI BQ32000 SeikoInstruments S-35390A Ramtron FM3130 EpsonRX-8581 Epson RX-8025SA/NB EMMicroelectronic EM3027 Micro CrystalRTC 2.2 SPI接口设备 PC-style 'CMOS' Dallas DS1286Dallas DS1511 Maxim/DallasDS1553 Maxim/Dallas DS1742/1743 Simtek STK17TA8 ST M48T86/DallasDS12887 ST M48T35 STM48T59/M48T08/M48T02 Oki MSM6242 TI BQ4802 RicohRP5C01 EMMicroelectronic V3020 2.3 CPU自带设备 ARM AMBA PL030RTC ARM AMBA PL031 RTC NS2816 RTC 二、RTC驱动架构1. 核心文件 l myir_ricoboard.dts和am4372.dtsi文件在arch/arm/boot/dts文件夹下,设置rtc设备树数据 l rtc-omap.c cpu提供的与rtc设备相关的驱动,与硬件层和上层交互的函数。 l /include/linux/rtc.h rtc基础数据结构 l Class.c rtc类注册文件,rtc相关最早加载,并主动通过rtc_dev_init加载rtc-dev.c,通过rtc_sysfs_init加载rtc-sysfs.c,提供一些相关函数如:devm_rtc_device_register /kernel/dirvers/rtc l rtc-dev.c 注册char驱动rtc, l rtc-sysfs.c sysfs相关文件 l rtc-proc.c 与/proc设备节点相关文件 l systohc.c Save NTPsynchronized time to the RTC l hctosys.c linux开机启动系统时间设置 l rtc-lib.c 时间转换相关函数实现 2. 驱动模型 说明:应用层可以通过三种方式访问RTC硬件,因为代码实现方式不同目前只有一种方式可写,其他方式只读。 1. 重要数据结构体 1.1 dts数据结构 myir_ricoboard.dts文件中加载rtc设备树 &rtc{ status = "okay"; }; am4372.dtsi文件中定义rtc数据结构 rtc: rtc@44e3e000 { compatible= "ti,am4372-rtc","ti,da830-rtc"; reg =<0x44e3e000 0x1000>; interrupts= GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods= "rtc"; clocks =<&clk_32768_ck>; clock-names= "fck"; status ="disabled"; }; 1.2 rtc设备驱动加载相关数据结构 static struct platform_device_idomap_rtc_devtype[] = { { .name = DRIVER_NAME, }, [OMAP_RTC_DATA_AM3352_IDX]= { .name = "am3352-rtc", .driver_data= OMAP_RTC_HAS_KICKER | OMAP_RTC_HAS_IRQWAKEEN, }, [OMAP_RTC_DATA_DA830_IDX]= { .name = "da830-rtc", .driver_data= OMAP_RTC_HAS_KICKER, }, {}, }; MODULE_DEVICE_TABLE(platform,omap_rtc_devtype); static const struct of_device_idomap_rtc_of_match[] = { { .compatible = "ti,da830-rtc", .data =&omap_rtc_devtype[OMAP_RTC_DATA_DA830_IDX], }, { .compatible = "ti,am3352-rtc", .data = &omap_rtc_devtype[OMAP_RTC_DATA_AM3352_IDX], }, {}, }; MODULE_DEVICE_TABLE(of, omap_rtc_of_match); 1.3 rtc设备驱动与硬件层交互相关数据结构, static struct rtc_class_ops omap_rtc_ops ={ .read_time = omap_rtc_read_time, .set_time = omap_rtc_set_time, .read_alarm = omap_rtc_read_alarm, .set_alarm = omap_rtc_set_alarm, .alarm_irq_enable= omap_rtc_alarm_irq_enable, }; 1.4 rtc设备驱动与GPIO设置相关数据结构 #define OMAP_RTC_BASE 0xfffb4800 /* OMAP_RTC_KICKER values */ #define KICK0_VALUE 0x83e70b13 #define KICK1_VALUE 0x95a4f1e0 1.5 rtc设备驱动与/dev设备节点交互相关数据结构 static const struct file_operationsrtc_dev_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .read = rtc_dev_read, .poll = rtc_dev_poll, .unlocked_ioctl = rtc_dev_ioctl, .open = rtc_dev_open, .release = rtc_dev_release, .fasync = rtc_dev_fasync, }; ATTRIBUTE_GROUPS(rtc); 1.6 rtc设备驱动与/proc设备节点交互相关数据结构 static const struct file_operationsrtc_proc_fops = { .open = rtc_proc_open, .read = seq_read, .llseek = seq_lseek, .release = rtc_proc_release, }; 1.7 rtc设备驱动与/sys/class/rtc相关数据结构 CONFIG_RTC_HCTOSYS_DEVICE="rtc0" static struct attribute *rtc_attrs[] = { &dev_attr_name.attr, &dev_attr_date.attr, &dev_attr_time.attr, &dev_attr_since_epoch.attr, &dev_attr_max_user_freq.attr, &dev_attr_hctosys.attr, NULL, }; 1.8 时间转换相关结构体 static const unsigned charrtc_days_in_month[] = { 31,28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; static const unsigned shortrtc_ydays[2][13] = { /*Normal years */ {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, /*Leap years */ {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } }; 三、RTC驱动重要函数介绍1. 驱动加载函数 1.1 rtc_init函数 static int __init rtc_init(void) { rtc_class= class_create(THIS_MODULE, "rtc"); if(IS_ERR(rtc_class)) { pr_err("couldn'tcreate classn"); returnPTR_ERR(rtc_class); } rtc_class->pm= RTC_CLASS_DEV_PM_OPS; rtc_dev_init(); rtc_sysfs_init(rtc_class); return0; } subsys_initcall(rtc_init); 1.2 omap_rtc_int #if 0 module_platform_driver_probe(omap_rtc_driver, omap_rtc_probe); #else static int __init omap_rtc_driver_init(void) { printk("=1=omap_rtc_driver_initmodule_initn"); returnplatform_driver_probe(&(omap_rtc_driver), omap_rtc_probe); } module_init(omap_rtc_driver_init); static void __exit omap_rtc_driver_exit(void) { platform_driver_unregister(&(omap_rtc_driver)); } module_exit(omap_rtc_driver_exit); #endif 1.3 rtc_hctosys加载函数 static int __init rtc_hctosys(void) { ……… } late_initcall(rtc_hctosys); voidrtc_proc_add_device(struct rtc_device *rtc) { if (is_rtc_hctosys(rtc)) proc_create_data("driver/rtc",0, NULL, &rtc_proc_fops, rtc); } 2. Probe探针函数 static int __init omap_rtc_probe(structplatform_device *pdev) { //of_match_device //omap_rtc_timer //omap_rtc_alarm //platform_get_device_id //devm_rtc_device_register //rtc gpio设置 } devm_rtc_device_register –>rtc_device_register { rtc_dev_prepare; device_register; rtc_dev_add_device; //创建/dev/rtc*设备节点 rtc_sysfs_add_device; //创建/sys/class/rtc/rtc0设备节点 rtc_proc_add_device) //创建/proc/driver/rtc设备节点 } 3. 设备节点创建,操作函数 3.1 /dev/rtc*设备节点 3.1.1 创建函数 void rtc_dev_prepare(structrtc_device *rtc) { if(!rtc_devt) return; if(rtc->id >= RTC_DEV_MAX) { dev_dbg(&rtc->dev,"%s: too many RTC devicesn", rtc->name); return; } rtc->dev.devt= MKDEV(MAJOR(rtc_devt), rtc->id); #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL INIT_WORK(&rtc->uie_task,rtc_uie_task); setup_timer(&rtc->uie_timer,rtc_uie_timer, (unsigned long)rtc); #endif cdev_init(&rtc->char_dev,&rtc_dev_fops);//在这里静态初始化/dev设备节点,访问函数在rtc_dev_fops结构体中定义。 rtc->char_dev.owner= rtc->owner; } void rtc_dev_add_device(struct rtc_device*rtc) { if(cdev_add(&rtc->char_dev, rtc->dev.devt, 1))//将初始化的设备节点加载到系统中 dev_warn(&rtc->dev,"%s: failed to add char device %d:%dn", rtc->name,MAJOR(rtc_devt), rtc->id); else dev_dbg(&rtc->dev,"%s: dev (%d:%d)n", rtc->name, MAJOR(rtc_devt),rtc->id); } 3.1.2 open函数 static int rtc_dev_open(struct inode*inode, struct file *file) { interr; structrtc_device *rtc = container_of(inode->i_cdev, structrtc_device, char_dev); conststruct rtc_class_ops *ops = rtc->ops; printk("=1=rtc_dev_openn"); if(test_and_set_bit_lock(RTC_DEV_BUSY, &rtc->flags)) return-EBUSY; printk("=2=rtc_dev_openn"); file->private_data= rtc; printk("=3=rtc_dev_openn"); err= ops->open ? ops->open(rtc->dev.parent) : 0; if(err == 0) { spin_lock_irq(&rtc->irq_lock); rtc->irq_data= 0; spin_unlock_irq(&rtc->irq_lock); return0; } printk("=4=rtc_dev_openn"); /*something has gone wrong */ clear_bit_unlock(RTC_DEV_BUSY,&rtc->flags); returnerr; }//open函数相应打开设备节点动作 } 3.1.3 rtc_dev_ioctl函数 static long rtc_dev_ioctl(struct file*file, unsignedint cmd, unsigned long arg) {//这里是此设备节点读写的实现,注意其会继续调用 case RTC_RD_TIME: mutex_unlock(&rtc->ops_lock); err =rtc_read_time(rtc, &tm); if (err <0) returnerr; if(copy_to_user(uarg, &tm, sizeof(tm))) err= -EFAULT; return err; case RTC_SET_TIME: mutex_unlock(&rtc->ops_lock); if(copy_from_user(&tm, uarg, sizeof(tm))) return-EFAULT; returnrtc_set_time(rtc, &tm); ….. } 3.1.4 rtc_read_time函数 int rtc_read_time(struct rtc_device *rtc,struct rtc_time *tm) { interr; err= mutex_lock_interruptible(&rtc->ops_lock); if(err) returnerr; err= __rtc_read_time(rtc, tm); mutex_unlock(&rtc->ops_lock); returnerr; } EXPORT_SYMBOL_GPL(rtc_read_time); 3.1.5 rtc_set_time函数 int rtc_set_time(struct rtc_device *rtc,struct rtc_time *tm) { interr; err= rtc_valid_tm(tm); if(err != 0) returnerr; err= mutex_lock_interruptible(&rtc->ops_lock); if(err) returnerr; if(!rtc->ops) err= -ENODEV; elseif (rtc->ops->set_time) err= rtc->ops->set_time(rtc->dev.parent, tm); elseif (rtc->ops->set_mmss) { unsignedlong secs; err= rtc_tm_to_time(tm, &secs); if(err == 0) err= rtc->ops->set_mmss(rtc->dev.parent, secs); }else err= -EINVAL; mutex_unlock(&rtc->ops_lock); /*A timer might have just expired */ schedule_work(&rtc->irqwork); returnerr; } EXPORT_SYMBOL_GPL(rtc_set_time); 3.1.6 omap_rtc_set_time函数 static int omap_rtc_set_time(struct device*dev, struct rtc_time *tm) { if(tm2bcd(tm) < 0) return-EINVAL; local_irq_disable(); rtc_wait_not_busy(); rtc_write(tm->tm_year,OMAP_RTC_YEARS_REG); rtc_write(tm->tm_mon,OMAP_RTC_MONTHS_REG); rtc_write(tm->tm_mday,OMAP_RTC_DAYS_REG); rtc_write(tm->tm_hour,OMAP_RTC_HOURS_REG); rtc_write(tm->tm_min,OMAP_RTC_MINUTES_REG); rtc_write(tm->tm_sec,OMAP_RTC_SECONDS_REG); local_irq_enable(); return0; } 3.1.7 omap_rtc_read_time函数 static int omap_rtc_read_time(struct device*dev, struct rtc_time *tm) { /*we don't report wday/yday/isdst ... */ local_irq_disable(); rtc_wait_not_busy(); tm->tm_sec= rtc_read(OMAP_RTC_SECONDS_REG); tm->tm_min= rtc_read(OMAP_RTC_MINUTES_REG); tm->tm_hour= rtc_read(OMAP_RTC_HOURS_REG); tm->tm_mday= rtc_read(OMAP_RTC_DAYS_REG); tm->tm_mon= rtc_read(OMAP_RTC_MONTHS_REG); tm->tm_year= rtc_read(OMAP_RTC_YEARS_REG); local_irq_enable(); bcd2tm(tm); return0; } 3.1.8 omap_rtc_set_time函数 3.2 /sys/class/rtc/rtc0设备节点 3.2.1 注册函数 void __init rtc_sysfs_init(struct class*rtc_class) { printk("=1=rtc_sysfs_initn"); rtc_class->dev_groups= rtc_groups;//将与设备节点相关的操作初始化 } 上面的赋值需要下面的结构体和ATTRIBUTE_GROUPS宏线运行。 static struct attribute *rtc_attrs[] = { &dev_attr_name.attr, &dev_attr_date.attr, &dev_attr_time.attr, &dev_attr_since_epoch.attr, &dev_attr_max_user_freq.attr, &dev_attr_hctosys.attr, NULL, }; ATTRIBUTE_GROUPS(rtc);// void rtc_sysfs_add_device(struct rtc_device*rtc) { interr; /*not all RTCs support both alarms and wakeup */ if(!rtc_does_wakealarm(rtc)) return; err= device_create_file(&rtc->dev, &dev_attr_wakealarm);//设备节点真正创建 if(err) dev_err(rtc->dev.parent, "failedto create alarm attribute, %dn", err); } 3.2.2 操作节点相关函数 static DEVICE_ATTR_RO(name);注意其是RO模式 static ssize_t name_show(struct device *dev, structdevice_attribute *attr, char *buf) { returnsprintf(buf, "%sn", to_rtc_device(dev)->name); } static DEVICE_ATTR_RO(date); static DEVICE_ATTR_RO(time); static DEVICE_ATTR_RO(since_epoch); static DEVICE_ATTR_RW(max_user_freq); static DEVICE_ATTR_RO(hctosys); ATTRIBUTE_GROUPS(rtc); static DEVICE_ATTR(wakealarm, S_IRUGO |S_IWUSR, rtc_sysfs_show_wakealarm,rtc_sysfs_set_wakealarm); 3.3 /proc/driver/rtc设备节点 3.3.1 设备节点创建 static const struct file_operationsrtc_proc_fops = { .open = rtc_proc_open, .read = seq_read, .llseek = seq_lseek, .release = rtc_proc_release, }; void rtc_proc_add_device(struct rtc_device*rtc) { printk("=1=rtc_proc_add_devicen"); if(is_rtc_hctosys(rtc)) proc_create_data("driver/rtc",0, NULL, &rtc_proc_fops, rtc); printk("=2=rtc_proc_add_devicen"); } 3.3.2 Open函数 static int rtc_proc_open(struct inode*inode, struct file *file) { intret; structrtc_device *rtc = PDE_DATA(inode); if(!try_module_get(THIS_MODULE)) return-ENODEV; ret= single_open(file, rtc_proc_show, rtc); if(ret) module_put(THIS_MODULE); returnret; } 3.3.3 rtc_proc_show函数实现。 static int rtc_proc_show(struct seq_file*seq, void *offset) { interr; structrtc_device *rtc = seq->private; conststruct rtc_class_ops *ops = rtc->ops; structrtc_wkalrm alrm; structrtc_time tm; err= rtc_read_time(rtc, &tm); if(err == 0) { seq_printf(seq, "rtc_timet:%02d:%02d:%02dn" "rtc_datet:%04d-%02d-%02dn", tm.tm_hour,tm.tm_min, tm.tm_sec, tm.tm_year+ 1900, tm.tm_mon + 1, tm.tm_mday); } err= rtc_read_alarm(rtc, &alrm); if(err == 0) { seq_printf(seq,"alrm_timet: "); if((unsigned int)alrm.time.tm_hour <= 24) seq_printf(seq,"%02d:", alrm.time.tm_hour); else seq_printf(seq,"**:"); if((unsigned int)alrm.time.tm_min <= 59) seq_printf(seq,"%02d:", alrm.time.tm_min); else seq_printf(seq,"**:"); if((unsigned int)alrm.time.tm_sec <= 59) seq_printf(seq,"%02dn", alrm.time.tm_sec); else seq_printf(seq,"**n"); seq_printf(seq,"alrm_datet: "); if((unsigned int)alrm.time.tm_year <= 200) seq_printf(seq,"%04d-", alrm.time.tm_year + 1900); else seq_printf(seq,"****-"); if((unsigned int)alrm.time.tm_mon <= 11) seq_printf(seq,"%02d-", alrm.time.tm_mon + 1); else seq_printf(seq,"**-"); if(alrm.time.tm_mday && (unsigned int)alrm.time.tm_mday <= 31) seq_printf(seq,"%02dn", alrm.time.tm_mday); else seq_printf(seq,"**n"); seq_printf(seq,"alarm_IRQt: %sn", alrm.enabled? "yes" : "no"); seq_printf(seq,"alrm_pendingt: %sn", alrm.pending? "yes" : "no"); seq_printf(seq,"update IRQ enabledt: %sn", (rtc->uie_rtctimer.enabled)? "yes" : "no"); seq_printf(seq,"periodic IRQ enabledt: %sn", (rtc->pie_enabled)? "yes" : "no"); seq_printf(seq,"periodic IRQ frequencyt: %dn", rtc->irq_freq); seq_printf(seq,"max user IRQ frequencyt: %dn", rtc->max_user_freq); } seq_printf(seq,"24hrtt: yesn"); if(ops->proc) ops->proc(rtc->dev.parent,seq); return0; } 3.3.4 seq_read实现,与proc文件系统密切相关。 4. GPIO相关函数 rtc_read rtc_write rtc_writel 5. 时间转换函数 跟01-01-1970 00:00:00转化秒数为time结构体时间,函数比较多就不一一列举。 Convert seconds since 01-01-1970 00:00:00 to Gregoriandate. void rtc_time_to_tm(unsigned long time,struct rtc_time *tm) { unsignedint month, year; intdays; days= time / 86400; time-= (unsigned int) days * 86400; /*day of the week, 1970-01-01 was a Thursday */ tm->tm_wday= (days + 4) % 7; year= 1970 + days / 365; days-= (year - 1970) * 365 +LEAPS_THRU_END_OF(year - 1) -LEAPS_THRU_END_OF(1970 - 1); if(days < 0) { year-= 1; days+= 365 + is_leap_year(year); } tm->tm_year= year - 1900; tm->tm_yday= days + 1; for(month = 0; month < 11; month++) { intnewdays; newdays= days - rtc_month_days(month, year); if(newdays < 0) break; days= newdays; } tm->tm_mon= month; tm->tm_mday= days + 1; tm->tm_hour= time / 3600; time-= tm->tm_hour * 3600; tm->tm_min= time / 60; tm->tm_sec= time - tm->tm_min * 60; tm->tm_isdst= 0; } 四、用户层应用 1. 通过/proc文件系统访问rtc 1.1 源代码 直接通过cat命令访问设备节点cat /proc/driver/rtc 1.2 Kernel log和驱动响应 root@m437x-evm:~# cat /proc/driver/rtc =1=rtc_proc_open =2=rtc_proc_open =3=rtc_proc_open =4=rtc_proc_open =1=rtc_read_time =1=__rtc_read_time =1=omap_rtc_read_time =2=omap_rtc_read_time =2=__rtc_read_time =2=rtc_read_time rtc_time : 14:38:18 rtc_date : 2016-11-09 alrm_time : 00:00:00 alrm_date : 2000-01-01 alarm_IRQ : no alrm_pending : no update IRQ enabled :no periodic IRQ enabled : no periodic IRQ frequency : 1 max user IRQ frequency : 64 24hr : yes 2. 通过/sys文件系统访问rtc 直接使用cat对/sys/class/rtc/rtc0下面的节点进行访问,不过只能读而已。 root@m437x-evm:/sys/class/rtc/rtc0# catdate =1=rtc_read_time =1=__rtc_read_time =1=omap_rtc_read_time =2=omap_rtc_read_time =2=__rtc_read_time =2=rtc_read_time 2016-11-09 root@m437x-evm:/sys/class/rtc/rtc0# cattime =1=rtc_read_time =1=__rtc_read_time =1=omap_rtc_read_time =2=omap_rtc_read_time =2=__rtc_read_time =2=rtc_read_time 14:39:40 3. 通过/dev目录访问rtc 3.1 源代码 /******************************************************************** * copyright(C) 2014 all rights reserved * @file: rtc_test.c * @Created: 2014-8-7 10:30 * @Author: conway chen * @Description: read and write rtc time * @modify Date: 2014-8-7 10:30 *********************************************************************/ #include #include #include #include #include #include #include #include #include #include #include static const char default_rtc[] ="/dev/rtc0"; static char *program_name; /** *@brief: print help message */ static void help(void) { fprintf(stderr, "tUsage: %s [OPTION]...n" "t-h,--help helpn" "t-s,--set set date/time given with you.ntinputformat:./rtc_test [hour] [minute] [second] [year] [month] [day]n" "t-r,--show read hardware clock and print resultn" "n", program_name); } /** *@brief: read RTC date and time *@Param: fd: the file descriptor of rtc device */ void rtc_read_time(int fd) { intretval; structrtc_time rtc_tm; /*readthe RTC time/date*/ retval= ioctl(fd, RTC_RD_TIME, &rtc_tm); if(retval == -1) { perror("RTC_RD_TIMEioctl"); exit(errno); } fprintf(stderr,"ntCurrent RTC date/time is %d-%d-%d, %02d:%02d:%02d.nn", rtc_tm.tm_mday,rtc_tm.tm_mon + 1, rtc_tm.tm_year + 1900, rtc_tm.tm_hour,rtc_tm.tm_min, rtc_tm.tm_sec); } /** *@brief: set rtc date and time *@Param: fd: the file descriptor of rtc device *@Param: hour: the hour to set *@Param: minute: the minute to set *@Param: second: the hour to set *@Param: year: the year to set *@Param: month: the month to set *@Param: day: the day to set */ void rtc_set_time(int fd, int hour, intminute, int second, int year, int month, int day) { intretval; structrtc_time rtc_tm; rtc_tm.tm_mday= day; rtc_tm.tm_mon= month - 1; rtc_tm.tm_year= year - 1900; rtc_tm.tm_hour= hour; rtc_tm.tm_min= minute; rtc_tm.tm_wday= rtc_tm.tm_yday = rtc_tm.tm_isdst = 0; rtc_tm.tm_sec= second; /*setthe RTC time/date*/ retval= ioctl(fd, RTC_SET_TIME, &rtc_tm); if(retval == -1) { perror("RTC_SET_TIMEioctl"); exit(errno); } fprintf(stderr,"nttdate/time is updated to: %d-%d-%d, %02d:%02d:%02d.nn", rtc_tm.tm_mday,rtc_tm.tm_mon + 1, rtc_tm.tm_year + 1900, rtc_tm.tm_hour,rtc_tm.tm_min, rtc_tm.tm_sec); } /** *@brief: main function *@Param: argc: number of parameters *@Param: argv: parameters list */ int main(int argc, char *argv[]) { intfd, retval, c; intset_flag = 0, read_flag = 0; structrtc_time rtc_tm; constchar *rtc = default_rtc; structoption long_option[] = { {"help", 0, NULL, 'h'}, {"set", 1, NULL, 's'}, {"show", 0, NULL, 'r'}, {NULL, 0, NULL, 0}, }; program_name = argv[0]; while (1) { if ((c = getopt_long(argc, argv,"hs:r", long_option, NULL)) < 0) break; switch (c) { case'h': help(); break; case's': if(argc < 8) { fprintf(stderr,"ntttime format error!nn"); exit(errno); } set_flag= 1; break; case'r': read_flag= 1; break; case'?': help(); break; default: abort(); } } /* open rtc device */ fd = open(rtc, O_RDWR); if(fd == -1) { perror(rtc); exit(errno); } if(argc == 1) { rtc_read_time(fd); } if (set_flag) rtc_set_time(fd,atoi(argv[2]), atoi(argv[3]), atoi(argv[4]), atoi(argv[5]), atoi(argv[6]),atoi(argv[7])); if(read_flag) rtc_read_time(fd); close(fd); return0; } 3.2 驱动响应代码和Kernel log 4. linux系统命令hwclock hwclock -w//将系统时钟写入硬件时钟 hwclock -s//将硬件时钟写入系统时钟 hwclock –r//显示硬件时钟 root@m437x-evm:/opt# hwclock -r =1=rtc_dev_open =2=rtc_dev_open =3=rtc_dev_open =RTC_RD_TIME=rtc_dev_ioctl =1=rtc_read_time =1=__rtc_read_time =1=omap_rtc_read_time =2=omap_rtc_read_time =2=__rtc_read_time =2=rtc_read_time Sat Nov 19 11:15:12 2011 0.000000 seconds 5. linux系统命令date root@m437x-evm:/opt# date Wed Nov 9 14:43:25 UTC 2016 知识点总结: 1.RTC相关概念,驱动代码简单分析; 2.linux设置,读取RTC时钟的方式和大概流程; 3.proc和alarm相关知识后面有时间在详细总结。 |
|
相关推荐
|
|
只有小组成员才能发言,加入小组>>
【米尔-紫光MYB-J7A100T国产FPGA开发板试用】米尔-紫光PG2L100H国产FPGA开发板开箱评测
1027 浏览 0 评论
【米尔-紫光PG2L100H国产FPGA开发板试用】官方LED例程测试体验
5074 浏览 0 评论
【米尔-紫光PG2L100H国产FPGA开发板试用】上电测试报告
4720 浏览 0 评论
【米尔-紫光PG2L100H国产FPGA开发板试用】开箱评测!米尔电子PG2L100H开发板深度体验报告
994 浏览 0 评论
【米尔-Xilinx XC7A100T FPGA开发板试用】+04.SFP之Aurora测试(zmj)
818 浏览 0 评论
【米尔-瑞米派兼容树莓派扩展模块-试用体验】基于ROS系统的三麦轮小车自主导航
3656浏览 2评论
【米尔NXP i.MX 93开发板试用评测】5、安装Debian和排除启动故障
730浏览 2评论
【米尔NXP i.MX 93开发板试用评测】2、异构通信环境搭建和源码编译
871浏览 2评论
【米尔-瑞米派兼容树莓派扩展模块-试用体验】Free RTOS应用开发环境部署
1461浏览 1评论
【米尔-芯驰D9开发板- 国产平台试用】- 03- 外设接口测试-U盘、485总线
6819浏览 1评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-23 04:54 , Processed in 0.923560 second(s), Total 69, Slave 50 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号