打印
[STM32F0]

STM32F030的RTC精度问题

[复制链接]
2558|21
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
djz1992|  楼主 | 2021-1-19 11:42 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 djz1992 于 2021-1-20 09:40 编辑

STM32F030,采用HSI内部始终,RTC采用LSI,40KHZ
分频设置40000/100/400=1HZ。
主要是不准,一小时能快1分钟。
采用HSI的话,是不是没法校准?
@dirtwillfly @xyz549040622 @m564522634 @ufbycd

修改了一下,加入了一点通过网络校准同步分频值的功能。从网上到处找帖子,找到一篇不错的帖子,精密校准HAL_RTCEx_SetSmoothCalib。附上链接:https://blog.csdn.net/u012183892/article/details/103405972
然后打算是分四步校准。
第一步同步网络时间;
第二步:粗调同步分频值;
第三步:精密调整;
第四步:补齐误差;


最后试了一下,精密校准HAL_RTCEx_SetSmoothCalib函数一直不起作用,所以还是只用了前两步。
附代码,请各位大佬指点。
为避免代码运行的时间,导致本地时间与网络时间的差异放大,所有此处用网络时间差与本地时间差进行比较。
uint16_t SynchPrediv = 0;
uint32_t time_ntp1=0,time_ntp2=0,time_rtc1=0,time_rtc2=0;
float time_ntp_sub=0,time_rtc_sub=0,time_ntp_rtc_sub=0;
float time_cal_num=0;
float time_cal_cnt=0;
int time_get(device_status_t *dev_stat)
{
                char *p1,*p2;
                char buffer[64]={0};
                char val_buffer[15]={0};
                uint32_t time_ntp=0;
                static uint8_t time_get_num=0;


                wifi_printf("AT+GETSNTP\r\n");
                rt_thread_mdelay(50);

                if(ring_length() > 0)
                {
                        ring_buf_read(&g_uart_rx_buf,sizeof(buffer),(uint8_t *)buffer);
                }
               
                if(strstr(buffer,"{\"time\":"))
                {
                        p1 = strstr(buffer,"\":\"");
                        p2 = strstr(p1+3,"\"}");
                        strncpy(val_buffer,p1+3,(p2-(p1+3)-3));//舍去最后三位的毫秒
                        time_ntp = atoi(val_buffer);
                        covUnixTimeStp2Beijing(time_ntp,&tempBeijing1);//网络时间

                        switch(time_get_num)
                        {
                                case 0:
                                        /***
                                        STEP0:首次获取网络时间
                                        记录初次ntp时间、初次本地时间,用于差值计算
                                        ****/
                                                                time_ntp1 = time_ntp;
                                                                time_rtc1 = time_ntp;
                                                                set_rtc_time(&tempBeijing1);                //保存到RTC
                                                                time_get_num = 1;
                                                                break;
                                case 1:
                                        /***
                                        STEP1:初略校准
                                        利用两次时间同步的ntp时间差、本地时间差,计算本地时间的初略误差,调整同步分频数
                                        ****/
                                                                time_ntp2 = time_ntp;
                                                                time_ntp_sub = time_ntp2 -time_ntp1;
                                                                time_ntp1 = time_ntp2;
                                
                                                                get_rtc_time(&tempBeijing2);//本地时间
                                                                time_rtc2 = covBeijing2UnixTimeStp(&tempBeijing2);        
                                                                time_rtc_sub = time_rtc2 - time_rtc1;
                                                                time_rtc1 = time_rtc2;
                                
                                                                if(time_ntp_sub >0 && time_rtc_sub >0)
                                                                {
                                                                        if(time_ntp_sub > time_rtc_sub) //慢了
                                                                        {
                                                                                time_ntp_rtc_sub = time_ntp_sub-time_rtc_sub;
                                                                                if(time_ntp_rtc_sub > 1)
                                                                                {
                                                                                        SynchPrediv = (1 - (time_ntp_rtc_sub / time_ntp_sub) * 0.9) * (SynchPrediv+1) - 1;
                                                                                        HAL_RTC_DeInit(&hrtc);
                                                                                        MX_RTC_Init();
                                                                                        set_rtc_time(&tempBeijing1);                //保存到RTC
                                                                                        time_rtc1 = time_ntp2;
                                                                                }
                                                                                else
                                                                                {
//                                                                                        time_get_num = 2;
                                                                                }
                                                                        }
                                                                        else if(time_ntp_sub < time_rtc_sub)//快了
                                                                        {
                                                                                time_ntp_rtc_sub = time_rtc_sub - time_ntp_sub;
                                                                                if(time_ntp_rtc_sub > 1)
                                                                                {
                                                                                  SynchPrediv = (1 + (time_ntp_rtc_sub / time_ntp_sub) * 0.9) * (SynchPrediv+1) - 1;
                                                                                        HAL_RTC_DeInit(&hrtc);
                                                                                        MX_RTC_Init();
                                                                                        set_rtc_time(&tempBeijing1);                //保存到RTC
                                                                                        time_rtc1 = time_ntp2;
                                                                                }
                                                                                else
                                                                                {
//                                                                                        time_get_num = 2;
                                                                                }
                                                                        }
                                                                        else
                                                                        {
                                                                                
                                                                        }
                                                                }
                                                                break;
                                case 2:
                                        /***
                                        STEP2:精密数字校准计算方法:
                                        24*3600/32s=2700;以32s修正间隔,每24小时有2700个周期
                                        1s/2700 = 3.7*10-4;以24小时差1s为修正目标,计算每个周期需要减少的秒数
                                        3.7*10-4/(1/32767) ≈ 12;以32767为同步分频数为例,计算每个周期减少的秒速等于多少个rtc周期
                                        ****/
                                                                time_ntp2 = time_ntp;
                                                                time_ntp_sub = time_ntp2 -time_ntp1;
                                                                time_ntp1 = time_ntp2;
                                
                                                                get_rtc_time(&tempBeijing2);//本地时间
                                                                time_rtc2 = covBeijing2UnixTimeStp(&tempBeijing2);        
                                                                time_rtc_sub = time_rtc2 - time_rtc1;
                                                                time_rtc1 = time_rtc2;
                                
                                                                if(time_ntp_sub >0 && time_rtc_sub >0)
                                                                {
                                                                        if(time_ntp_sub > time_rtc_sub)
                                                                        {
                                                                                time_ntp_rtc_sub = time_ntp_sub-time_rtc_sub;
                                                                                time_cal_num = ((float)(time_ntp_rtc_sub * (60*24/2))) / 2700;
                                                                                time_cal_cnt = time_cal_num/(1/(float)40000);
                                                                                HAL_RTCEx_SetSmoothCalib(&hrtc, RTC_SMOOTHCALIB_PERIOD_32SEC, RTC_SMOOTHCALIB_PLUSPULSES_SET, (uint32_t)time_cal_cnt);
                                                                                set_rtc_time(&tempBeijing1);                //保存到RTC
                                                                                time_rtc1 = time_ntp2;
                                                                        }
                                                                        else if(time_ntp_sub < time_rtc_sub)
                                                                        {
                                                                                time_ntp_rtc_sub = time_rtc_sub - time_ntp_sub;
                                                                                
                                                                                time_cal_num = ((float)(time_ntp_rtc_sub * (60*24/2))) / 2700;
                                                                                time_cal_cnt = time_cal_num/(1/(float)40000);
                                                                                HAL_RTCEx_SetSmoothCalib(&hrtc, RTC_SMOOTHCALIB_PERIOD_32SEC, RTC_SMOOTHCALIB_PLUSPULSES_RESET, (uint32_t)time_cal_cnt);
                                                                                set_rtc_time(&tempBeijing1);                //保存到RTC
                                                                                time_rtc1 = time_ntp2;
                                                                        }
                                                                        else
                                                                        {
                                                                                
                                                                        }
                                                                }
                                                                break;
                                case 3:
                                        /***
                                        STEP3:时刻同步计算方法
                                        本地毫秒比远程快了590-200=390ms,390ms/(1s/256) ≈ 100
                                        ****/                                                        
                                                                HAL_RTCEx_SetSynchroShift(&hrtc, RTC_SHIFTADD1S_RESET, 100);
                                                                break;
                                default:
                                        break;
                        }
                        return SUCCESS;
                }
                return ERROR;
}






使用特权

评论回复
沙发
dirtwillfly| | 2021-1-19 12:14 | 只看该作者
内部时钟一般是rc震荡器的原理,不准的。有条件的话换外部晶振呢,我记得这个料支持外部晶振

使用特权

评论回复
板凳
djz1992|  楼主 | 2021-1-19 13:15 | 只看该作者
dirtwillfly 发表于 2021-1-19 12:14
内部时钟一般是rc震荡器的原理,不准的。有条件的话换外部晶振呢,我记得这个料支持外部晶振 ...

一天差个几秒啥的都没问题。。。一小时就差几分钟这还咋整。。。

使用特权

评论回复
地板
wsmysyn| | 2021-1-19 13:41 | 只看该作者
内部rc,修调精度有限,看手册可能也就1%精度,和晶体10ppm精度比差多了

使用特权

评论回复
5
xyz549040622| | 2021-1-19 14:15 | 只看该作者
为什么不用LSE(32.768kHz)呢?能不能校准要看数据手册

使用特权

评论回复
6
djz1992|  楼主 | 2021-1-19 15:22 | 只看该作者
wsmysyn 发表于 2021-1-19 13:41
内部rc,修调精度有限,看手册可能也就1%精度,和晶体10ppm精度比差多了

难受。。

使用特权

评论回复
7
djz1992|  楼主 | 2021-1-19 15:23 | 只看该作者
xyz549040622 发表于 2021-1-19 14:15
为什么不用LSE(32.768kHz)呢?能不能校准要看数据手册

引脚全用完了。。

使用特权

评论回复
8
wsmysyn| | 2021-1-19 15:48 | 只看该作者

这个工艺上片上R和C做的精度很高,要花费很大力气
我的上一个项目片内也是有rc32,trim的step只有255,RTC时钟16k到32k之间才可以修调,超出范围修不回来。未修调,频率有18K,20K,甚至还有不到16k的,这还是TSMC 28nm成熟工艺。频率比较分散。trim完凑合用吧。一般用我们芯片的大多是网络校准时间,rtc也就没有开放给客户

上家公司做USB2.0 HS控制器,phy里边有2个45ohm电阻需要精确修调,还有一个电流源要修调,做了20多根laser fuse,需要组合使用,测试完wafer还要用激光修调机来烧fuse,烧完还要回到测试台上再次测试,也就把电阻修调到44.5~45.5ohm左右。已经挺精确的了。但是测试成本可高了

之前听说有一种先进的连续修调技术,边测试边trim,能达到很高精度的电阻修调。那个好像是ADI的专利,设备好像是ADI自研的,中国只有一台,在某个研究所。。工厂没有能量产使用的这类设备,我们一般也不会做这样的设计。。因为做了,你没有设备来实现,或者实现起来效率特别的低,也没用

使用特权

评论回复
9
gx_huang| | 2021-1-19 16:01 | 只看该作者
这是设计时欠考虑,还是修改方案吧。
比如有人使用CAN,但是不用晶体时钟源,误差超标,这个危害更大,大批量会死人的,胎里病。

使用特权

评论回复
10
m564522634| | 2021-1-19 17:38 | 只看该作者
方案有问题

使用特权

评论回复
11
imdx| | 2021-1-19 22:09 | 只看该作者
40k的LSI,实际频率是30k~50k,能用吗?一小时快1分钟表现已经很好了。

使用特权

评论回复
12
ddllxxrr| | 2021-1-20 08:19 | 只看该作者
想个办法呗,每一小时看看差多少,伤停补时一下

使用特权

评论回复
13
tom_xu| | 2021-1-20 09:46 | 只看该作者
要用32.768K的时钟。

使用特权

评论回复
14
djz1992|  楼主 | 2021-1-20 10:01 | 只看该作者
wsmysyn 发表于 2021-1-19 15:48
这个工艺上片上R和C做的精度很高,要花费很大力气
我的上一个项目片内也是有rc32,trim的step只有255,RT ...

网络同步时间我这也可以的,请教一个事情。
网络同步的频率应该怎么定?因为现在一分钟就会差几秒,看这样子得一分钟就校准一次。同步频率太低,容易引起本地时间的突变,对一些按时工作的任务很不好。

使用特权

评论回复
15
djz1992|  楼主 | 2021-1-20 10:03 | 只看该作者
dirtwillfly 发表于 2021-1-19 12:14
内部时钟一般是rc震荡器的原理,不准的。有条件的话换外部晶振呢,我记得这个料支持外部晶振 ...

之前一分钟差一秒多,加了段网络校准分频数,至少差的没那么多了,五分钟网络同步一次。。

使用特权

评论回复
16
djz1992|  楼主 | 2021-1-20 10:04 | 只看该作者
xyz549040622 发表于 2021-1-19 14:15
为什么不用LSE(32.768kHz)呢?能不能校准要看数据手册

加了校准,为什么HAL_RTCEx_SetSmoothCalib没效果呢

使用特权

评论回复
17
dirtwillfly| | 2021-1-20 11:27 | 只看该作者
djz1992 发表于 2021-1-20 10:03
之前一分钟差一秒多,加了段网络校准分频数,至少差的没那么多了,五分钟网络同步一次。。 ...

够用就好,实际上大部分应用不需要那么精确的时钟

使用特权

评论回复
18
gwsan| | 2021-2-5 16:18 | 只看该作者
有些型号的还不能校准吗

使用特权

评论回复
19
kxsi| | 2021-2-5 16:20 | 只看该作者
感觉差不多够用就行了

使用特权

评论回复
20
nawu| | 2021-2-5 16:22 | 只看该作者
哈哈 怎么感觉咱们都要求不高呢

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:人生苦短,冬日苦长,正是青葱,却无骄阳

115

主题

620

帖子

5

粉丝