• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# RTC
2
3## 概述
4
5### 功能简介
6
7RTC(real-time clock)为操作系统中的实时时钟设备,为操作系统提供精准的实时时间和定时报警功能。当设备下电后,通过外置电池供电,RTC继续记录操作系统时间;设备上电后,RTC提供实时时钟给操作系统,确保断电后系统时间的连续性。
8
9### 运作机制
10
11在HDF框架中,RTC模块采用独立服务模式,在这种模式下,每一个设备对象会独立发布一个设备服务来处理外部访问,设备管理器收到API的访问请求之后,通过提取该请求的参数,达到调用实际设备对象的相应内部方法的目的。独立服务模式可以直接借助HDFDeviceManager的服务管理能力,但需要为每个设备单独配置设备节点,若设备过多会增加内存占用。通常,一个硬件系统中只需要一个RTC设备,因此RTC模块采用独立服务模式较为合适。
12
13## 使用指导
14
15### 场景介绍
16
17RTC主要用于提供实时时间和定时报警功能。
18
19### 接口说明
20
21RTC模块提供的主要接口如表1所示,具体API详见//drivers/hdf_core/framework/include/platform/rtc_if.h22
23**表1** RTC设备API接口功能介绍
24
25|  接口名  | 接口描述 |
26| -------- | -------- |
27| DevHandle RtcOpen(void) | 获取RTC设备驱动句柄 |
28| void RtcClose(DevHandle handle) | 释放RTC设备驱动句柄 |
29| int32_t RtcReadTime(DevHandle handle, struct RtcTime \*time) | 读RTC时间信息 |
30| int32_t RtcWriteTime(DevHandle handle, const struct RtcTime \*time) | 写RTC时间信息,包括年、月、星期、日、时、分、秒、毫秒 |
31| int32_t RtcReadAlarm(DevHandle handle, enum RtcAlarmIndex alarmIndex, struct RtcTime \*time) | 读RTC报警时间信息 |
32| int32_t RtcWriteAlarm(DevHandle handle, enum RtcAlarmIndex alarmIndex, const struct RtcTime \*time) | 写RTC报警时间信息 |
33| int32_t RtcRegisterAlarmCallback(DevHandle handle, enum RtcAlarmIndex alarmIndex, RtcAlarmCallback cb) | 注册报警超时回调函数 |
34| int32_t RtcAlarmInterruptEnable(DevHandle handle, enum RtcAlarmIndex alarmIndex, uint8_t enable) | 使能/去使能RTC报警中断 |
35| int32_t RtcGetFreq(DevHandle handle, uint32_t \*freq) | 读RTC外接晶振频率 |
36| int32_t RtcSetFreq(DevHandle handle, uint32_t freq) | 配置RTC外接晶振频率 |
37| int32_t RtcReset(DevHandle handle) | RTC复位 |
38| int32_t RtcReadReg(DevHandle handle, uint8_t usrDefIndex, uint8_t \*value) | 读用户自定义寄存器 |
39| int32_t RtcWriteReg(DevHandle handle, uint8_t usrDefIndex, uint8_t value) | 写用户自定义寄存器 |
40
41### 使用流程
42
43使用RTC设备的一般流程如下图所示。
44
45**图1** RTC设备使用流程图
46
47![image](figures/RTC设备使用流程图.png "RTC设备使用流程图")
48
49#### 创建RTC设备句柄
50
51RTC驱动加载成功后,使用驱动框架提供的查询接口并调用RTC设备驱动接口。
52
53> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**<br>
54> 当前操作系统仅支持一个RTC设备。
55
56```c
57DevHandle RtcOpen(void);
58```
59
60  **表2** RtcOpen参数和返回值描述
61
62| **参数** | **描述** |
63| -------- | -------- |
64| void | NA |
65| **返回值** | **描述** |
66| handle | 操作成功返回&nbsp;&nbsp;指针类型 |
67| NULL | 操作失败 |
68
69
70```c
71DevHandle  handle = NULL;
72
73/* 获取RTC句柄 */
74handle = RtcOpen();
75if (handle  == NULL) {
76    /* 错误处理 */
77}
78```
79
80#### 注册RTC定时报警回调函数
81
82系统启动后需要注册RTC定时报警回调函数,报警超时后触发回调函数。
83
84```c
85int32_t RtcRegisterAlarmCallback(DevHandle handle, enum RtcAlarmIndex alarmIndex, RtcAlarmCallback cb);
86```
87
88  **表3** RtcRegisterAlarmCallback参数和返回值描述
89
90| **参数** | **描述** |
91| -------- | -------- |
92| handle | RTC设备句柄 |
93| alarmIndex | 报警索引 |
94| cb | 定时报警回调函数 |
95| **返回值** | **描述** |
96| 0 | 操作成功 |
97| 负数 | 操作失败 |
98
99  注册RTC_ALARM_INDEX_A的定时报警处理函数, 示例如下:
100
101```c
102/* 用户注册RTC定时报警回调函数的方法 */
103int32_t RtcAlarmACallback(enum RtcAlarmIndex alarmIndex)
104{
105    if (alarmIndex == RTC_ALARM_INDEX_A) {
106        /* 报警A的处理 */
107    } else if (alarmIndex == RTC_ALARM_INDEX_B) {
108        /* 报警B的处理 */
109    } else {
110        /* 错误处理 */
111    }
112    return 0;
113}
114int32_t ret;
115/* 注册报警A的定时回调函数 */
116ret = RtcRegisterAlarmCallback(handle, RTC_ALARM_INDEX_A, RtcAlarmACallback);
117if (ret != 0) {
118    /* 错误处理 */
119}
120```
121
122
123#### 操作RTC
124
125- 读取RTC时间。
126
127    系统从RTC读取时间信息,包括年、月、星期、日、时、分、秒、毫秒,则可以通过以下函数完成:
128
129    ```c
130    int32_t RtcReadTime(DevHandle handle, struct RtcTime \*time);
131    ```
132
133    **表4** RtcReadTime参数和返回值描述
134
135    | **参数** | **描述** |
136    | -------- | -------- |
137    | handle     | RTC设备句柄                                             |
138    | time       | RTC读取时间信息,包括年、月、星期、日、时、分、秒、毫秒 |
139    | **返回值** | **描述**                                          |
140    | 0          | 操作成功                                                |
141    | 负数       | 操作失败                                                |
142
143    ```c
144    int32_t ret;
145    struct RtcTime tm;
146
147    /* 系统从RTC读取时间信息 */
148    ret = RtcReadTime(handle, &tm);
149    if (ret != 0) {
150        /* 错误处理 */
151    }
152    ```
153
154- 设置RTC时间
155
156    设置RTC时间,则可以通过以下函数完成:
157
158    ```c
159    int32_t RtcWriteTime(DevHandle handle, struct RtcTime \*time);
160    ```
161
162    **表5** RtcWriteTime参数和返回值描述
163
164    | **参数** | **描述** |
165    | -------- | -------- |
166    | handle | RTC设备句柄 |
167    | time | 写RTC时间信息,包括年、月、星期、日、时、分、秒、毫秒 |
168    | **返回值** | **描述** |
169    | 0 | 操作成功 |
170    | 负数 | 操作失败 |
171
172    > ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**<br>
173    > RTC起始时间为UTC 1970/01/01 Thursday 00:00:00,年的最大取值按照用户器件手册要求计算配置,星期不用配置。
174
175    ```c
176    int32_t ret;
177    struct RtcTime tm;
178
179    /* 设置RTC时间为 UTC 2020/01/01 00:59:00 .000 */
180    tm.year = 2020;
181    tm.month = 01;
182    tm.day = 01;
183    tm.hour= 00;
184    tm.minute = 59;
185    tm.second = 00;
186    tm.millisecond = 0;
187    /* 写RTC时间信息 */
188    ret = RtcWriteTime(handle, &tm);
189    if (ret != 0) {
190        /* 错误处理 */
191    }
192    ```
193
194- 读取RTC报警时间
195
196    如果需要读取定时报警时间,则可以通过以下函数完成:
197
198    ```c
199    int32_t RtcReadAlarm(DevHandle handle, enum RtcAlarmIndex alarmIndex, struct RtcTime \*time);
200    ```
201
202    **表6** RtcReadAlarm参数和返回值描述
203
204    | **参数** | **描述** |
205    | -------- | -------- |
206    | handle | RTC设备句柄 |
207    | alarmIndex | 报警索引 |
208    | time | RTC报警时间信息,包括年、月、星期、日、时、分、秒、毫秒 |
209    | **返回值** | **描述** |
210    | 0 | 操作成功 |
211    | 负数       | 操作失败 |
212
213    ```c
214    int32_t ret;
215    struct RtcTime alarmTime;
216
217    /* 读RTC_ALARM_INDEX_A索引的RTC定时报警时间信息 */
218    ret = RtcReadAlarm(handle, RTC_ALARM_INDEX_A, &alarmTime);
219    if (ret != 0) {
220        /* 错误处理 */
221    }
222    ```
223
224- 设置RTC报警时间
225
226    根据报警索引设置RTC报警时间,通过以下函数完成:
227
228    ```c
229    int32_t RtcWriteAlarm(DevHandle handle, enum RtcAlarmIndex  alarmIndex, struct RtcTime \*time);
230    ```
231
232    **表7** RtcWriteAlarm参数和返回值描述
233
234    | **参数** | **描述** |
235    | -------- | -------- |
236    | handle | RTC设备句柄 |
237    | alarmIndex | 报警索引 |
238    | time | RTC报警时间信息,包括年、月、星期、日、时、分、秒、毫秒 |
239    | **返回值** | **描述** |
240    | 0 | 操作成功 |
241    | 负数 | 操作失败 |
242
243    > ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**</br>
244    > RTC起始时间为UTC 1970/01/01 Thursday 00:00:00,年的最大取值按照用户器件手册要求计算配置,星期不用配置。
245
246    ```c
247    int32_t ret;
248    struct RtcTime alarmTime;
249
250    /* 设置RTC报警时间为2020/01/01 00:59:59 .000 */
251    alarmTime.year = 2020;
252    alarmTime.month = 01;
253    alarmTime.day = 01;
254    alarmTime.hour = 00;
255    alarmTime.minute = 59;
256    alarmTime.second = 59;
257    alarmTime.millisecond = 0;
258    /* 设置RTC_ALARM_INDEX_A索引的定时报警时间 */
259    ret = RtcWriteAlarm(handle, RTC_ALARM_INDEX_A, &alarmTime);
260    if (ret != 0) {
261        /* 错误处理 */
262    }
263    ```
264
265- 设置定时报警中断使能或去使能
266
267    在启动报警操作前,需要先设置报警中断使能,报警超时后会触发告警回调函数,可以通过以下函数完成:
268
269    ```c
270    int32_t RtcAlarmInterruptEnable(DevHandle handle, enum RtcAlarmIndex alarmIndex, uint8_t enable);
271    ```
272
273    **表8** RtcAlarmInterruptEnable参数和返回值描述
274
275    | **参数** | **描述** |
276    | -------- | -------- |
277    | handle     | RTC设备句柄 |
278    | alarmIndex | 报警索引 |
279    | enable     | RTC报警中断配置,1:使能,0:去使能 |
280    | **返回值** | **描述** |
281    | 0 | 操作成功 |
282    | 负数 | 操作失败 |
283
284    ```c
285    int32_t ret;
286
287    /* 设置RTC报警中断使能 */
288    ret = RtcAlarmInterruptEnable(handle, RTC_ALARM_INDEX_A, 1);
289    if (ret != 0) {
290        /* 错误处理 */
291    }
292    ```
293
294- 读取RTC外频
295
296    读取RTC外接晶体振荡频率,可以通过以下函数完成:
297
298    ```c
299    int32_t RtcGetFreq(DevHandle handle, uint32_t \*freq);
300    ```
301
302    **表9** RtcGetFreq参数和返回值描述
303
304    | **参数** | **描述** |
305    | -------- | -------- |
306    | handle | RTC设备句柄 |
307    | freq | RTC的外接晶体振荡频率,单位(HZ) |
308    | **返回值** | **描述** |
309    | 0 | 操作成功 |
310    | 负数 | 操作失败 |
311
312    ```c
313    int32_t ret;
314    uint32_t freq = 0;
315
316    /* 读取RTC外接晶体振荡频率 */
317    ret = RtcGetFreq(handle, &freq);
318    if (ret != 0) {
319        /* 错误处理 */
320    }
321    ```
322
323- 配置RTC外频
324
325    配置RTC外接晶体振荡频率,可以通过以下函数完成:
326
327    ```c
328    int32_t RtcSetFreq(DevHandle handle, uint32_t freq);
329    ```
330
331    **表10** RtcSetFreq参数和返回值描述
332
333    | **参数** | **描述** |
334    | -------- | -------- |
335    | handle | RTC设备句柄 |
336    | freq | RTC的外接晶体振荡频率,单位(HZ) |
337    | **返回值** | **描述** |
338    | 0 | 操作成功 |
339    | 负数 | 操作失败 |
340
341    ```c
342    int32_t ret;
343    uint32_t freq = 32768; /* 32768 Hz */
344
345    /* 设置RTC外接晶体振荡频率,注意按照器件手册要求配置RTC外频 */
346    ret = RtcSetFreq(handle, freq);
347    if (ret != 0) {
348        /* 错误处理 */
349    }
350    ```
351
352- 复位RTC
353
354    复位RTC,复位RTC后各配置寄存器恢复默认值,可以通过以下函数完成:
355
356    ```c
357    int32_t RtcReset(DevHandle handle);
358    ```
359
360    **表11** RtcReset参数和返回值描述
361
362    | **参数** | **描述** |
363    | -------- | -------- |
364    | handle     | RTC设备句柄 |
365    | **返回值** | **描述** |
366    | 0 | 操作成功 |
367    | 负数 | 操作失败 |
368
369    ```c
370    int32_t ret;
371
372    /* 复位RTC,各配置寄存器恢复默认值 */
373    ret = RtcReset(handle);
374    if (ret != 0) {
375        /* 错误处理 */
376    }
377    ```
378
379- 读取RTC自定义寄存器配置
380
381    按照用户定义的寄存器索引,读取对应的寄存器配置,一个索引对应一字节的配置值,通过以下函数完成:
382
383    ```c
384    int32_t RtcReadReg(DevHandle handle, uint8_t usrDefIndex, uint8_t \*value);
385    ```
386
387    **表12** RtcReadReg参数和返回值描述
388
389    | **参数** | **描述** |
390    | -------- | -------- |
391    | handle      | RTC设备句柄 |
392    | usrDefIndex | 用户定义的寄存器对应索引 |
393    | value       | 寄存器值 |
394    | **返回值**  | **描述** |
395    | 0 | 操作成功 |
396    | 负数 | 操作失败 |
397
398    ```c
399    int32_t ret;
400    uint8_t usrDefIndex = 0; /* 定义0索引对应用户定义的第一个寄存器*/
401    uint8_t value = 0;
402
403    /* 按照用户定义的寄存器索引,读取对应的寄存器配置,一个索引对应一字节的配置值 */
404    ret = RtcReadReg(handle, usrDefIndex, &value);
405    if (ret != 0) {
406        /* 错误处理 */
407    }
408    ```
409
410- 设置RTC自定义寄存器配置
411
412    按照用户定义的寄存器索引,设置对应的寄存器配置,一个索引对应一字节的配置值,通过以下函数完成:
413
414    ```c
415    int32_t RtcWriteReg(DevHandle handle, uint8_t usrDefIndex, uint8_t value);
416    ```
417
418    **表13** RtcWriteReg参数和返回值描述
419
420    | **参数** | **描述** |
421    | -------- | -------- |
422    | handle | RTC设备句柄 |
423    | usrDefIndex | 用户定义的寄存器对应索引 |
424    | value | 寄存器值 |
425    | **返回值**  | **描述** |
426    | 0 | 操作成功 |
427    | 负数 | 操作失败 |
428
429    ```c
430    int32_t ret;
431    uint8_t usrDefIndex = 0; /* 定义0索引对应用户定义第一个寄存器*/
432    uint8_t value = 0x10;
433
434    /* 按照用户的定义的寄存器索引,设置对应的寄存器配置,一个索引对应一字节的配置值 */
435    ret = RtcWriteReg(handle, usrDefIndex, value);
436    if (ret != 0) {
437        /* 错误处理 */
438    }
439    ```
440
441#### 销毁RTC设备句柄
442
443销毁RTC设备句柄,系统释放对应的资源。
444
445```c
446void RtcClose(DevHandle handle);
447```
448
449  **表14** RtcClose参数描述
450
451| **参数** | **描述** |
452| -------- | -------- |
453| handle | RTC设备句柄 |
454
455```c
456/* 销毁RTC句柄 */
457RtcClose(handle);
458```
459
460### 使用实例
461
462本例基于Hi3516DV300开发板,提供RTC接口的完整使用流程:
463
4641. 系统启动,驱动管理模块会识别系统当前的RTC器件;
465
4662. 驱动管理模块完成RTC设备的初始化和设备创建;
467
4683. 用户通过不同API,对该RTC设备进行对应的操作;
469
4704. 关闭RTC设备,释放设备资源。
471
472示例如下:
473
474```c
475#include "rtc_if.h"
476
477int32_t RtcAlarmACallback(enum RtcAlarmIndex alarmIndex)
478{
479    if (alarmIndex == RTC_ALARM_INDEX_A) {
480        /* 报警A的处理 */
481        printf("RTC Alarm A callback function\n\r");
482    } else if (alarmIndex == RTC_ALARM_INDEX_B) {
483        /* 报警B的处理 */
484        printf("RTC Alarm B callback function\n\r");
485    } else {
486        /* 错误处理 */
487    }
488    return 0;
489}
490
491void RtcTestSample(void)
492{
493    int32_t ret;
494    struct RtcTime tm;
495    struct RtcTime alarmTime;
496    uint32_t freq;
497    DevHandle handle = NULL;
498
499    /* 获取RTC设备句柄 */
500    handle = RtcOpen();
501    if (handle == NULL) {
502        /* 错误处理 */
503    }
504    /* 注册报警A的定时回调函数 */
505    ret = RtcRegisterAlarmCallback(handle, RTC_ALARM_INDEX_A, RtcAlarmACallback);
506    if (ret != 0) {
507        /* 错误处理 */
508    }
509    /* 设置RTC外接晶体振荡频率,注意按照器件手册要求配置RTC外频 */
510    freq = 32768; /* 32768 Hz */
511    ret = RtcSetFreq(handle, freq);
512    if (ret != 0) {
513        /* 错误处理 */
514    }
515    /* 设置RTC报警中断使能 */
516    ret = RtcAlarmInterruptEnable(handle, RTC_ALARM_INDEX_A, 1);
517    if (ret != 0) {
518        /* 错误处理 */
519    }
520    /* 设置RTC时间为2020/01/01 00:00:10 .990 */
521    tm.year = 2020;
522    tm.month = 01;
523    tm.day = 01;
524    tm.hour= 0;
525    tm.minute = 0;
526    tm.second = 10;
527    tm.millisecond = 990;
528    /* 写RTC时间信息 */
529    ret = RtcWriteTime(handle, &tm);
530    if (ret != 0) {
531        /* 错误处理 */
532    }
533    /* 设置RTC报警时间为2020/01/01 00:00:30 .100 */
534    alarmTime.year = 2020;
535    alarmTime.month = 01;
536    alarmTime.day = 01;
537    alarmTime.hour = 0;
538    alarmTime.minute = 0;
539    alarmTime.second = 30;
540    alarmTime.millisecond = 100;
541    /* 设置RTC_ALARM_INDEX_A索引定时报警时间信息, 定时时间到后会打印"RTC Alarm A callback function" */
542    ret = RtcWriteAlarm(handle, RTC_ALARM_INDEX_A, &alarmTime);
543    if (ret != 0) {
544        /* 错误处理 */
545    }
546
547    /* 读取RTC实时时间 */
548    ret = RtcReadTime(handle, &tm);
549    if (ret != 0) {
550        /* 错误处理 */
551    }
552    sleep(5)
553    printf("RTC read time:\n\r");
554    printf("year-month-date-weekday hour:minute:second .millisecond %04u-%02u-%02u-%u %02u:%02u:%02u .%03u",
555        tm.year, tm.month, tm.day, tm.weekday, tm.hour, tm.minute, tm.second, tm.millisecond);
556    /* 销毁RTC设备句柄 */
557    RtcClose(handle);
558}
559```