本文目的
本文将记录如何在沁恒的ble soc上使用rtc 以及注意事项
对于用到BLE功能,不建议直接对RTC直接操作,而是使用wch提供的"系统" TMOS的API,这里有个使用总结: https://www.cnblogs.com/iot-fan/p/13460082.html
适用芯片
- CH579/CH578/CH577
- CH573/CH571
差异部分
差异部分 | CH579/578/577 | CH573/571 |
---|---|---|
上电默认启动 | ||
触发值设置 |
说明
- 直至目前,WCH的CH57*系列芯片都是只提供了一个RTC外设
- CH57*系列的RTC外设不支持独立供电
- 该RTC只有一个触发(CC)中断,和一个定时中断
- 该RTC的时钟源不支持预分频,即为固定1s=32768当用的是32.768的外部时钟时候
- 该RTC的CNT最大值不是对齐到2的N次方-1 ,而是以1s=37268 记一天的值即0xA8C00000
使用
实际上在wch 提供的ble 工程里,有比较充分的rtc的使用方式
如下是一个CH573 ble sdk 里面的提供的代码(在CH573EVT_1.6EXAMBLEHALRTC.c)
void HAL_TimeInit( void )
{
#if( CLK_OSC32K ) //使用内部的32K RC作为RTC的时钟,由于rc振荡器是误差比较大,所以wch提供了校准函数,并且根据需求是校准到32Khz 还是32.768khz
R8_SAFE_ACCESS_SIG = 0x57;
R8_SAFE_ACCESS_SIG = 0xa8;
R8_CK32K_CONFIG &= ~(RB_CLK_OSC32K_XT|RB_CLK_XT32K_PON);
R8_CK32K_CONFIG |= RB_CLK_INT32K_PON;
Lib_Calibration_LSI(); // 32K rc的校准,如果不需要高精度(比如一些非ble应用),可以注释掉这个代码,可以省去一些RAM和flash空间
#else
R8_SAFE_ACCESS_SIG = 0x57;
R8_SAFE_ACCESS_SIG = 0xa8;
R8_CK32K_CONFIG |= RB_CLK_OSC32K_XT | RB_CLK_INT32K_PON | RB_CLK_XT32K_PON;
R8_SAFE_ACCESS_SIG = 0;
#endif
RTC_InitTime( 2020, 1, 1, 0, 0, 0 ); //RTC时钟初始化当前时间,这里实际上年月日时分秒的计算都是软件实现,如果不需要,可以注释掉.同样可以省区一些RAM和flash资源
TMOS_TimerInit( 0 ); //tmos的时间初始化,当我么没有用到tmos时候,这里注释掉即可
}
//这里传入的是RTC的值
//WCH 的rtc这里的设计比较奇葩,rtc 的cnt最大是一天的,所以这里的设置触发值最大是32768*3600*24 = 0xA8C00000,
//所以time 在传入前,需要做 if( time > 0xA8C00000 ) time -= 0xA8C00000; (出处:CH573EVT_1.6EXAMBLEHALSLEEP.c 中的CH57X_LowPower 函数)
void RTC_SetTignTime( u32 time )
{
R8_SAFE_ACCESS_SIG = SAFE_ACCESS_SIG1;
R8_SAFE_ACCESS_SIG = SAFE_ACCESS_SIG2;
R32_RTC_TRIG = time;
RTCTigFlag = 0;
}
__attribute__((interrupt("WCH-Interrupt-fast"))) // wch的硬件压栈
__attribute__((section(".highcode"))) // 需要放到RAM里面
void RTC_IRQHandler( void )
{
R8_RTC_FLAG_CTRL = ( RB_RTC_TMR_CLR | RB_RTC_TRIG_CLR ); //这里的清理中断标志位是两个都清理,实际上这样写是推荐的,在早期的一些bootloader里面某些rtc 功能打开了,可能导致这里没有清理中断标志位而卡住
RTCTigFlag = 1;
}
其中还有个唤醒配置(在CH573EVT_1.6EXAMBLEHALSLEEP.c):
void HAL_SleepInit( void )
{
#if (defined (HAL_SLEEP)) && (HAL_SLEEP == TRUE) // 蓝牙工程里面的 开启休眠的宏,由于wch 的ble只有在休眠时候,才会用到RTC的中断,所以这里有个开启宏
R8_SAFE_ACCESS_SIG = SAFE_ACCESS_SIG1;
R8_SAFE_ACCESS_SIG = SAFE_ACCESS_SIG2;
R8_SLP_WAKE_CTRL |= RB_SLP_RTC_WAKE; // RTC唤醒
R8_RTC_MODE_CTRL |= RB_RTC_TRIG_EN; // 触发模式
R8_SAFE_ACCESS_SIG = 0; //
PFIC_EnableIRQ( RTC_IRQn );
#endif
}
注意事项
- 获取当前的RTC的CNT一定要使用wch提供的函数RTC_GetCycle32k(),不要直接读寄存器,寄存器R32_RTC_CNT_32K其实是两个16bit的寄存器,在变化时候存在不同步的变化的情况,如果直接读寄存器,有几率得到一个奇怪的值;
- 如果用的是内部RC作为RTC的时钟,外部的32.768K 的晶体使能功能一定要关掉(尤其是CH579,默认是开启的);
- RTC的寄存器是复位保持的,所以一个好的习惯是在初始化时候保证用到的位都写一遍,而不是某些bit跟上电默认一致就不配置了.