RTC定时开机闹钟
RTC是Real Time Clock的简称,它在硬件电路上单独供电,当系统关机时,CPU和其他外部硬件设备全部掉电,但是RTC仍然继续工作.
HWCR (Hibernate Wakeup Control Register)是一个控制休眠唤醒的寄存器,如果我们要使用休眠状态下RTC唤醒的功能,我们需要打开它的第0位ELAM(RTC Alarm Wakeup enable),当ELAM置1时,使能ELAM功能。
RTCSR (RTC Second Registe)是一个32位的寄存器,它的值以1Hz的频率加1,即每秒自动加1。
RTCSAR (RTC Second Alarm Register)是一个以秒为单位的闹钟寄存器,我们可以将设置的格林威治时间转换成相应的秒数然后写进这个寄存器,即完成了我们设置的闹钟。我们打开HWCR中的ELAM,按power键关机,当RTC检测到RTCSR == RTCSAR的值时,RTC将会唤醒CPU,并从XBOOT开始进行开机启动。
对于设置RTCSAR的操作,我们可以用一个应用rtc_test.c来完成:
#include <stdio.h>
#include <linux/rtc.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h> /*
* This expects the new RTC class driver framework, working with
* clocks that will often not be clones of what the PC-AT had.
* Use the command line to specify another RTC if you need one.
*/
static const char default_rtc[] = "/dev/rtc0";
int main(int argc, char **argv)
{
int i, fd, retval, irqcount = , alarm_time = ;
unsigned long tmp, data;
struct rtc_time rtc_tm;
const char *rtc = default_rtc;
switch (argc)
{
case :
rtc = argv[];
/* FALLTHROUGH */
case :
break;
default:
fprintf(stderr, "usage: rtctest [rtcdev]\n");
return ;
}
fd = open(rtc, O_RDONLY);
if (fd == -)
{
perror(rtc);
exit(errno);
}
fprintf(stderr, "\n\t\t\tRTC Driver Test Example.\n\n"); #if 0
/* Turn on update interrupts (one per second) */
retval = ioctl(fd, RTC_UIE_ON, );
if (retval == -)
{
if (errno == ENOTTY)
{
fprintf(stderr, "\n...Update IRQs not supported.\n");
goto test_READ;
}
perror("RTC_UIE_ON ioctl");
exit(errno);
}
fprintf(stderr, "Counting 5 update (1/sec) interrupts from reading %s:\n",rtc);
fflush(stderr);
for (i=; i<; i++)
{
/* This read will block */
retval = read(fd, &data, sizeof(unsigned long));
if (retval == -)
{
perror("read");
exit(errno);
}
fprintf(stderr, " %d",i);
fflush(stderr);
irqcount++;
}
fprintf(stderr, "\nAgain, from using select(2) on /dev/rtc:");
fflush(stderr);
for (i=; i<; i++)
{
struct timeval tv = {, }; /* 5 second timeout on select */
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(fd, &readfds);
/* The select will wait until an RTC interrupt happens. */
retval = select(fd+, &readfds, NULL, NULL, &tv);
if (retval == -)
{
perror("select");
exit(errno);
}
/* This read won't block unlike the select-less case above. */
retval = read(fd, &data, sizeof(unsigned long));
if (retval == -)
{
perror("read");
exit(errno);
}
fprintf(stderr, " %d",i);
fflush(stderr);
irqcount++;
}
/* Turn off update interrupts */
retval = ioctl(fd, RTC_UIE_OFF, );
if (retval == -)
{
perror("RTC_UIE_OFF ioctl");
exit(errno);
}
#endif
//test_READ:
/* Read the RTC time/date */ printf("Set the alarm time after: ");
scanf("%d", &alarm_time);
fprintf(stderr, "seconds");
//fprintf(stderr, "Set the alarm time after %d seconds", alarm_time); retval = ioctl(fd, RTC_RD_TIME, &rtc_tm);
if (retval == -)
{
perror("RTC_RD_TIME ioctl");
exit(errno);
}
fprintf(stderr, "\n\nCurrent RTC date\time is %d-%d-%d, %02d:%02d:%02d.\n",rtc_tm.tm_mday, rtc_tm.tm_mon + , rtc_tm.tm_year + ,rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec);
/* Set the alarm to 5 sec in the future, and check for rollover */
rtc_tm.tm_sec += alarm_time;
if (rtc_tm.tm_sec >= )
{
rtc_tm.tm_sec %= ;
rtc_tm.tm_min++;
}
if (rtc_tm.tm_min == )
{
rtc_tm.tm_min = ;
rtc_tm.tm_hour++;
}
if (rtc_tm.tm_hour == )
rtc_tm.tm_hour = ;
retval = ioctl(fd, RTC_ALM_SET, &rtc_tm);
if (retval == -)
{
if (errno == ENOTTY)
{
fprintf(stderr,"\n...Alarm IRQs not supported.\n");
//goto test_PIE;
}
perror("RTC_ALM_SET ioctl");
exit(errno);
}
/* Read the current alarm settings */
retval = ioctl(fd, RTC_ALM_READ, &rtc_tm);
if (retval == -)
{
perror("RTC_ALM_READ ioctl");
exit(errno);
}
fprintf(stderr, "Alarm time now set to %02d:%02d:%02d.\n",rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec);
fflush(stderr);
/* Enable alarm interrupts */
retval = ioctl(fd, RTC_AIE_ON, );
if (retval == -)
{
perror("RTC_AIE_ON ioctl");
exit(errno);
}
#if 0
//fprintf(stderr, "Waiting %d seconds for alarm...", alarm_time);
//fflush(stderr);
///* This blocks until the alarm ring causes an interrupt */
//retval = read(fd, &data, sizeof(unsigned long));
//if (retval == -1)
//{
// perror("read");
// exit(errno);
//}
//irqcount++;
//fprintf(stderr, " okay. Alarm rang.\n");
/* Disable alarm interrupts */
retval = ioctl(fd, RTC_AIE_OFF, );
if (retval == -)
{
perror("RTC_AIE_OFF ioctl");
exit(errno);
}
#endif
#if 0
test_PIE:
/* Read periodic IRQ rate */
retval = ioctl(fd, RTC_IRQP_READ, &tmp);
if (retval == -)
{
/* not all RTCs support periodic IRQs */
if (errno == ENOTTY)
{
fprintf(stderr, "\nNo periodic IRQ support\n");
goto done;
}
perror("RTC_IRQP_READ ioctl");
exit(errno);
}
fprintf(stderr, "\nPeriodic IRQ rate is %ldHz.\n", tmp);
fprintf(stderr, "Counting 20 interrupts at:");
fflush(stderr);
/* The frequencies 128Hz, 256Hz, ... 8192Hz are only allowed for root. */
for (tmp=; tmp<=; tmp*=)
{
retval = ioctl(fd, RTC_IRQP_SET, tmp);
if (retval == -)
{
/* not all RTCs can change their periodic IRQ rate */
if (errno == ENOTTY)
{
fprintf(stderr,"\n...Periodic IRQ rate is fixed\n");
goto done;
}
perror("RTC_IRQP_SET ioctl");
exit(errno);
}
fprintf(stderr, "\n%ldHz:\t", tmp);
fflush(stderr);
/* Enable periodic interrupts */
retval = ioctl(fd, RTC_PIE_ON, );
if (retval == -)
{
perror("RTC_PIE_ON ioctl");
exit(errno);
}
for (i=; i<; i++)
{
/* This blocks */
retval = read(fd, &data, sizeof(unsigned long));
if (retval == -)
{
perror("read");
exit(errno);
}
fprintf(stderr, " %d",i);
fflush(stderr);
irqcount++;
}
/* Disable periodic interrupts */
retval = ioctl(fd, RTC_PIE_OFF, );
if (retval == -)
{
perror("RTC_PIE_OFF ioctl");
exit(errno);
}
}
done:
#endif
fprintf(stderr, "\n\n\t\t\t *** Test complete ***\n");
close(fd);
return ;
}
上面的程序中我只保留了设置RTC ALARM的操作,其他的全注释掉了。设置ALARM时需要ioctl RTC_ALM_SET和RTC_AIE_ON两个宏定义,其中RTC_ALM_SET设置的闹钟只有在24内有效,我们通过120~132行的代码也可以看出应用只设置了以时分秒为单位的值,假入我们将天/月/年也设上,133行的
retval = ioctl(fd, RTC_ALM_SET, &rtc_tm);
会调到kernel/drivers/rtc/rtc-dev.c的rtc_dev_ioctl中:
case RTC_ALM_SET:
mutex_unlock(&rtc->ops_lock); if (copy_from_user(&alarm.time, uarg, sizeof(tm)))
return -EFAULT; alarm.enabled = ;
alarm.pending = ;
alarm.time.tm_wday = -;
alarm.time.tm_yday = -;
alarm.time.tm_isdst = -; /* RTC_ALM_SET alarms may be up to 24 hours in the future.
* Rather than expecting every RTC to implement "don't care"
* for day/month/year fields, just force the alarm to have
* the right values for those fields.
*
* RTC_WKALM_SET should be used instead. Not only does it
* eliminate the need for a separate RTC_AIE_ON call, it
* doesn't have the "alarm 23:59:59 in the future" race.
*
* NOTE: some legacy code may have used invalid fields as
* wildcards, exposing hardware "periodic alarm" capabilities.
* Not supported here.
*/
{
unsigned long now, then; err = rtc_read_time(rtc, &tm);
if (err < )
return err;
rtc_tm_to_time(&tm, &now); alarm.time.tm_mday = tm.tm_mday;
alarm.time.tm_mon = tm.tm_mon;
alarm.time.tm_year = tm.tm_year;
err = rtc_valid_tm(&alarm.time);
if (err < )
return err;
rtc_tm_to_time(&alarm.time, &then); /* alarm may need to wrap into tomorrow */
if (then < now) {
rtc_time_to_tm(now + * * , &tm);
alarm.time.tm_mday = tm.tm_mday;
alarm.time.tm_mon = tm.tm_mon;
alarm.time.tm_year = tm.tm_year;
}
} return rtc_set_alarm(rtc, &alarm);
在rtc-dev.c的rtc_dev_ioctl中,RTC_ALM_SET的case会先将RTC寄存器RTCSR中的时间读出来,并转换成格林威治时间,应用设置下来的rtc_tm的天/月/年会被读取出来的tm中的天/月/年所覆盖,所以即使应用设置了也没有用。如果应用需要设置超过24小时以外的闹钟可以ioctl RTC_WKALM_SET 的rtc_tm到驱动中。
ioctl RTC_ALM_SET后还需再ioctl一次RTC_AIE_ON。如果应用不ioctl RTC_AIE_ON的话,应用设置的rtc_tm不会被设到rtc驱动中struct rtc_class_ops的.set_alarm成员指针指向的函数,即rtc_tm的值不会被设到RTCSAR寄存器中,闹钟设置不会生效。
在Android4.3环境上交叉编译成rtc_test的可执行文件,rtc_test.c和Android.mk都放在external/test/下,其中Android.mk书写如下:
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := rtc_test
LOCAL_SRC_FILES := $(call all-subdir-c-files)
LOCAL_C_INCLUDES:= $(LOCAL_C_INCLUDES)\
$(PATH)\
kernel/arch/mips/xburst/soc-/include\
kernel/arch/mips/include/asm/mach-generic
include $(BUILD_EXECUTABLE)
在项目目录执行 source build/envsetup.h和lunch后,再到external/test下执行mm,编译好的rtc_test放在out/target/product/xxxx/system/bin/rtc_test
adb push rtc_test到开发板的/system/bin下,并设置成777权限后即可使用此应用设置RTC的ALARM。
执行rtc_test时需要我们输入一个距离现在时间的定时闹钟,假如我们输入60,即60s,然后按power键关机,待到过了60s(RTCAR == RTCSAR)时,RTC会唤醒CPU启动开机流程。
由于我们在按power键关机后有几种不同的状态,比如板子不接USB充电线/板子接USB充电线/板子接USB充电线但隔了一段时间后又拔除,这几种情况都处于不同的XBOOT流程,所以我们还需在XBOOT中加入处于不同关机状态的RTC唤醒代码。
RTC定时开机闹钟的更多相关文章
- 吃我一记咸鱼突刺——使用板载RTC定时开机
前言 原创文章,转载引用务必注明链接.水平有限,欢迎指正. 2016年3月30日 Lemuntu(Base On Jessie) 3.10.37 原载于Lemaker论坛.汇总于此. 看ATC2603 ...
- 技嘉 gigabyte b75m d3v 主板 定时开机无效问题解决
BIOS 里面设置定时开机后发现到点并没有正常启动~~~ 百思不得解.后来发现原来是WIN8系统下的控制面板的关机并非正常关机,而是不保存设置的非正常关机,在开始菜单右键——关闭或注销——关闭计算机 ...
- Azure 基础 : 使用 Automation 定时开机
不知何时 Azure 为虚机提供了自动关机的功能.这是一个很棒的功能,可以帮助我们定时关闭虚机并释放掉资源以节省开支.如果某台虚机在夜间不需要提供服务,我们就可以把它配置为晚上的某个时间点自动关机: ...
- win7电脑定时开机设置方法
在BIOS设置主界面中选择“Power Management Setup”,进入“电源管理”窗口. 注:缺省情况下,“Resume By Alarm”定时开机选项是关闭的. 将鼠标移到“Resume ...
- Windows定时开机并开启工作软件
开启休眠功能 在搜索窗口中输入“cmd.exe”,在结果中看见了“cmd.exe”,右击选择“以管理员权限运行程序”打开“cmd.exe”命令窗口,输入命令“powercfg -h on”即可开启计算 ...
- wake on lan定时开机部署
在Linux下通过Wake On LAN实现网络唤醒远程开机 我们经常有这样的场景或需求,人在外面,需要将家里的机器或公司的机器开启,进行远程控制操作. 有几种方式可以实现远程开机,一是通过主板的来电 ...
- BeagleBone Black Industrial系统更新设置一贴通
前言 原创文章,转载引用务必注明链接.水平有限,欢迎指正. 本文使用markdown写成,为获得更好的阅读体验,推荐访问我的博客原文: http://www.omoikane.cn/2016/09/1 ...
- Android 每天定时提醒功能实现
android要实现定时的功能那肯定就要用到闹铃相关的技术, 那么android闹铃实现是基于 AlarmManager 这个类的,首先我们来看一下它的几个主要的方法. 打开AlarmManager的 ...
- ***linux下用cron定时执行任务的方法
名称 : crontab 使用权限 : 所有使用者 使用方式 : crontab file [-u user]-用指定的文件替代目前的crontab. crontab-[-u user]-用标准输入 ...
随机推荐
- CAShapeLayer + UIBezierPath
UIBezierPath: UIBezierPath是在 UIKit 中的一个类,继承于NSObject,可以创建基于矢量的路径.使用此类可以定义常见的圆形.多边形等形状 .我们使用直线.弧(arc) ...
- html基础之 input:type
Input表示Form表单中的一种输入对象,其又随Type类型的不同而分文本输入框,密码输入框,单选/复选框,提交/重置按钮等,下面一一介绍.1,type=text输入类型是text,这是我们见的最多 ...
- JavaScript实现div宽、高自动缓慢拉伸
最近打算实现一个带有滤镜效果的地自动拉伸图片.发现使用css3浏览器兼容性得需要特别关注.这里我使用js实现了一个div边框自动拉伸和缩小.源码如下: <!DOCTYPE html>< ...
- Hadoop配置文件-mapred-site.xml
name value Description hadoop.job.history.location job历史文件保存路径,无可配置参数,也不用写在配置文件里,默认在logs的history文件 ...
- java中静态代码块的用法 static用法详解
(一)java 静态代码块 静态方法区别一般情况下,如果有些代码必须在项目启动的时候就执行的时候,需要使用静态代码块,这种代码是主动执行的;需要在项目启动的时候就初始化,在不创建对象的情况下,其他程序 ...
- arrayAccess的接口使用
<?php //get the methods instance of ArrayAccess //get the properties instance of ArrayAccess $ref ...
- 串口调试工具(Python2.7+pyserial+Tkinter)
需要与串口设备进行通讯,那么一个调试工具是必须的. 根据我自己的需要,写了个简易版本的串口调试工具: 预览图: ====================== 项目结构: COM --SerialHel ...
- 畅通工程--hdu1232(并查集)
畅通工程 Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submis ...
- UVA 10129 Play on Words
欧拉回路 以字母为结点,单词为边:注意两个相同的单词表示两条边. 并查集判断是否连通,出度,入度判断是否是欧拉回路 #include <iostream> #include <cst ...
- MySQL与unix时间问题
1.select unix_timestamp() -->可以返回以秒记的unix时间. 2.select from_unixtime('1455804595','%Y年%m月%d号'); -- ...