Android系统RTC调试从驱动到应用(一)
软件开发平台:android P 源码。
硬件开发平台:nxp imx8m mini开发板,RTC 型号8025T。
本文记录在nxp 8m mini 硬件平台, android P 源码的软件平台上调试RTC8025T驱动,RTC的framework 层android 已经写好了即 AlarmManagerService , APP 应用层通过((AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE)) 提供的接口来读取和设置 RTC 。
一.RTC相关驱动调试
先来了解下 RTC 8025T 操作模式:
操作模式 :
1 ) 实时时钟模式
实时时 钟模式
该功能被用来设定和读取年,月,日,星期,时,分,秒 时间信息。年份为后两位数字表示,
任何可以被 4 整除的年份被当成闰年处理。(2000 年到 2099 年)
2 ) 固定周期的中断发生功能:
固定周期的中断发生功能
固定周期定时中断发生功能可以产生一个固定周期的中断事件,固定周期可在 244.14uS 到
4095 分钟之间的 任意时间设定。
3)定时更新中断功能:
该功能可以根据内部时钟的定时设定,每秒或每分钟产生一个中断事件。
当中断事件产生,UF 标志位的值变成 1 同时/INT 引脚变成低电平表示一个中断事件的产生。
4 ) 闹钟中断功能
闹钟 中断功能:
中断功能
该功能可以根据报警设定来产生一个中断。
硬件电路设计如下:
Nxp 平台有有完整的RTC驱动框架,所以只需要完善8025T相关的读写功能就可以了。
初始化8025T
static int rx8025_probe(struct i2c_client *client, const struct i2c_device_id *id){ struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); struct rx8025_data *rx8025; int err = 0; //可以看到RTC 驱动初始化的上下文 dump_stack(); rx8025 = devm_kzalloc(&client->dev, sizeof(*rx8025), GFP_KERNEL); rx8025->client = client; i2c_set_clientdata(client, rx8025); err = rx8025_init_client(client); // 将设备操作函数rx8025_rtc_ops 和设备关联起来 rx8025->rtc = devm_rtc_device_register(&client->dev, client->name, &rx8025_rtc_ops, THIS_MODULE); //irq? if (client->irq > 0) { //注册中断回调函数 rx8025_handle_irq err = devm_request_threaded_irq(&client->dev, client->irq, NULL, rx8025_handle_irq, IRQF_ONESHOT, "rx8025", client); } rx8025->rtc->max_user_freq = 1; /* the rx8025 alarm only supports a minute accuracy */ rx8025->rtc->uie_unsupported = 1; err = rx8025_sysfs_register(&client->dev); printk("%s end\r\n", __func__);/*Herber*/ return err;}
这里重点关注 rx8025_rtc_ops,实现这里的读写函数就可以了。
static const struct rtc_class_ops rx8025_rtc_ops = {
.read_time = rx8025_get_time,
.set_time = rx8025_set_time,
.read_alarm = rx8025_read_alarm,
.set_alarm = rx8025_set_alarm,
.alarm_irq_enable = rx8025_alarm_irq_enable,
};
Struct rtc_class_ops 定义在rtc.h
struct rtc_class_ops {
int (*ioctl)(struct device *, unsigned int, unsigned long);
int (*read_time)(struct device *, struct rtc_time *);
int (*set_time)(struct device *, struct rtc_time *);
int (*read_alarm)(struct device *, struct rtc_wkalrm *);
int (*set_alarm)(struct device *, struct rtc_wkalrm *);
int (*proc)(struct device *, struct seq_file *);
int (*set_mmss64)(struct device *, time64_t secs);
int (*set_mmss)(struct device *, unsigned long secs);
int (*read_callback)(struct device *, int data);
int (*alarm_irq_enable)(struct device *, unsigned int enabled);
int (*read_offset)(struct device *, long *offset);
int (*set_offset)(struct device *, long offset);
};
这里分析下写入rtc寄存器
将dt的 tm_sec等,转成bcd码 写入RX8025_REG_SEC寄存器。
static int rx8025_set_time(struct device *dev, struct rtc_time *dt){ struct rx8025_data *rx8025 = dev_get_drvdata(dev); u8 date[7]; int ret; dump_stack(); printk("%s( %d %d %d %d %d %d %d %d %d)\n",__func__,dt->tm_sec,dt->tm_min,dt->tm_hour ,dt->tm_mday, dt->tm_mon,dt->tm_year, dt->tm_wday,dt->tm_yday, dt->tm_isdst ); if ((dt->tm_year < 100) || (dt->tm_year > 199)) { printk("%s set Year Err %d === \r\n",__func__,dt->tm_year); return -EINVAL; } /* * Here the read-only bits are written as "0". I'm not sure if that * is sound. */ date[RX8025_REG_SEC] = bin2bcd(dt->tm_sec); date[RX8025_REG_MIN] = bin2bcd(dt->tm_min); if (rx8025->ctrl1 & RX8025_BIT_CTRL1_1224) date[RX8025_REG_HOUR] = bin2bcd(dt->tm_hour); else date[RX8025_REG_HOUR] = (dt->tm_hour >= 12 ? 0x20 : 0) | bin2bcd((dt->tm_hour + 11) % 12 + 1); date[RX8025_REG_WDAY] = bin2bcd(dt->tm_wday); date[RX8025_REG_MDAY] = bin2bcd(dt->tm_mday); date[RX8025_REG_MONTH] = bin2bcd(dt->tm_mon + 1); date[RX8025_REG_YEAR] = bin2bcd(dt->tm_year - 100); ret = rx8025_write_regs(rx8025->client, RX8025_REG_SEC, 7, date); if (ret < 0) return ret; return rx8025_reset_validity(rx8025->client); }
下面是 读取rtc的寄存器
static int rx8025_get_time(struct device *dev, struct rtc_time *dt){ struct rx8025_data *rx8025 = dev_get_drvdata(dev); u8 date[7]; int err; dump_stack(); //从RX8025_REG_SEC 读7位到 date err = rx8025_read_regs(rx8025->client, RX8025_REG_SEC, 7, date); printk("%s para 0x%02x,0x%02x,0x%02x=== \r\n",__func__,date[0],date[1],date[2]);/*Herber*/ if (err){ printk("%s S3,Err +++++\r\n",__func__); return err; } dt->tm_sec = bcd2bin(date[RX8025_REG_SEC] & 0x7f); dt->tm_min = bcd2bin(date[RX8025_REG_MIN] & 0x7f); if (rx8025->ctrl1 & RX8025_BIT_CTRL1_1224) dt->tm_hour = bcd2bin(date[RX8025_REG_HOUR] & 0x3f); else dt->tm_hour = bcd2bin(date[RX8025_REG_HOUR] & 0x1f) % 12 + (date[RX8025_REG_HOUR] & 0x20 ? 12 : 0); dt->tm_mday = bcd2bin(date[RX8025_REG_MDAY] & 0x3f); dt->tm_mon = bcd2bin(date[RX8025_REG_MONTH] & 0x1f) - 1; dt->tm_year = bcd2bin(date[RX8025_REG_YEAR]) + 100; dev_dbg(dev, "%s: date %ds %dm %dh %dmd %dm %dy\n", __func__, dt->tm_sec, dt->tm_min, dt->tm_hour, dt->tm_mday, dt->tm_mon, dt->tm_year); return rtc_valid_tm(dt);}
可以看到rtc 驱动只提供了简单的设定和读取年,月,日,星期,时,分,秒 时间信息的功能。
#define CFG_RTC_I2C_DEV "/dev/rtc0" #include int main(void){ int fd_i2c,retval; struct rtc_time new, current; printf("==== RTC TIME operates ====\n"); fd_i2c = open(CFG_RTC_I2C_DEV, O_RDWR); if (fd_i2c < 0) { printf("Open i2c device %s failed!\n", CFG_RTC_I2C_DEV); return -1; } scanf("%d-%d-%d", &new.tm_mday, &new.tm_mon, &new.tm_year); printf("\r\n"); scanf("%d:%d:%d", &new.tm_hour, &new.tm_min, &new.tm_sec); printf("\r\n"); printf("Test will set RTC date/time to %d-%d-%d, %02d:%02d:%02d.\n", new.tm_mday, new.tm_mon + 1, new.tm_year + 1900, new.tm_hour, new.tm_min, new.tm_sec); /* Write the new date in RTC */ printf("renew data in RTC Module \r\n"); retval = ioctl(fd_i2c, RTC_SET_TIME, &new); if (retval == -1) { printf("--RTC_SET_TIME ioctl Err--\r\n"); //close(fd); goto err;//exit(errno); } /* Read back */ retval = ioctl(fd_i2c, RTC_RD_TIME, ¤t); if (retval == -1) { printf("---RTC_RD_TIME ioctl Err ---\r\n"); goto err;exit(errno); } printf("\n\nCurrent RTC date/time is %d-%d-%d, %02d:%02d:%02d.\n", current.tm_mday, current.tm_mon + 1, current.tm_year + 1900, current.tm_hour, current.tm_min, current.tm_sec); close(fd_i2c); return 0;err: if (fd_i2c) close(fd_i2c); return -1; }
以上代码可以测试 rtc 的读写功能.
再梳理下rtc驱动的流程,在内核启动时 初始化rtc即rx8025_probe, 再将rtc 的时间给了系统。
static int __init rtc_hctosys(void){int err = -ENODEV;struct rtc_time tm;struct timespec64 tv64 = {.tv_nsec = NSEC_PER_SEC >> 1,};struct rtc_device *rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);err = rtc_read_time(rtc, &tm);tv64.tv_sec = rtc_tm_to_time64(&tm);err = do_settimeofday64(&tv64);dev_info(rtc->dev.parent,"setting system clock to ""%d-%02d-%02d %02d:%02d:%02d UTC (%lld)\n",tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,tm.tm_hour, tm.tm_min, tm.tm_sec,(long long) tv64.tv_sec);return err;}late_initcall(rtc_hctosys);
这样系统时间就和rtc 的时间对齐了。
更多相关文章
- Android(安卓)中指纹识别
- INSTALL_FAILED_MISSING_FEATURE
- Android中GridView实现长按多选功能
- 用百度地图API实现Android定位功能(2.6版本为例)
- wifi 架构
- Android(安卓)记录一次开发微信分享功能的吐槽与思考
- Android(安卓)Browser 支持屏蔽webaudio的功能
- android debug工具集
- android分享软件功能的实现