本文目的
本文將記錄如何在沁恆的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.6\EXAM\BLE\HAL\RTC.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.6\EXAM\BLE\HAL\SLEEP.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.6\EXAM\BLE\HAL\SLEEP.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跟上電默認一致就不配置了.