iot-fan

联系: iotfan123#163.com
注意:
1,本博客之内容来源于网上收集以及相关技术人员提供,如果有侵犯到您的权益,请电邮我沟通;
2,本博客之内容乃分享,交流,学习,研究之目的,作者不对内容的真实性,有效性,及时性负责,也不对因本博客的任何内容导致的任何后果负责;
3,本博客之内容禁止转发到CSDN网站,转到别的网站请保留出处.

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

本文目的

本文将记录如何在沁恒的ble soc上使用rtc 以及注意事项
对于用到BLE功能,不建议直接对RTC直接操作,而是使用wch提供的"系统" TMOS的API,这里有个使用总结: https://www.cnblogs.com/iot-fan/p/13460082.html

适用芯片

  • CH579/CH578/CH577
  • CH573/CH571
  • CH583/CH582/CH581

差异部分

差异部分 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(32768 *3600 *24U)
  • RTC的触发值设置范围为[1,0xA8C00000],设置其他值将会永远不触发,设置0xA8C00000 对应的唤醒CNT是0

使用

实际上在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
}

时间戳映射

很多时候我们需要把时间映射成时间戳(按照秒为单位的计数器),然后再用一些通用的方法,把时间戳转换成时间
wch的rtc也可以变相的实现该时间的方式:

//获取时间戳

//修改时间戳

注意事项

  • 获取当前的RTC的CNT一定要使用wch提供的函数RTC_GetCycle32k(),不要直接读寄存器,寄存器R32_RTC_CNT_32K其实是两个16bit的寄存器,在变化时候存在不同步的变化的情况,如果直接读寄存器,有几率得到一个奇怪的值;
  • 如果用的是内部RC作为RTC的时钟,外部的32.768K 的晶体使能功能一定要关掉(尤其是CH579,默认是开启的);
  • RTC的寄存器是复位保持的,所以一个好的习惯是在初始化时候保证用到的位都写一遍,而不是某些bit跟上电默认一致就不配置了.
posted on 2021-08-31 17:18  iot-fan  阅读(2690)  评论(0编辑  收藏  举报