[STM32F0] STM32F030的RTC精度问题

[复制链接]
3287|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函数一直不起作用,所以还是只用了前两步。
附代码,请各位大佬指点。
为避免代码运行的时间,导致本地时间与网络时间的差异放大,所有此处用网络时间差与本地时间差进行比较。
  1. uint16_t SynchPrediv = 0;
  2. uint32_t time_ntp1=0,time_ntp2=0,time_rtc1=0,time_rtc2=0;
  3. float time_ntp_sub=0,time_rtc_sub=0,time_ntp_rtc_sub=0;
  4. float time_cal_num=0;
  5. float time_cal_cnt=0;
  6. int time_get(device_status_t *dev_stat)
  7. {
  8.                 char *p1,*p2;
  9.                 char buffer[64]={0};
  10.                 char val_buffer[15]={0};
  11.                 uint32_t time_ntp=0;
  12.                 static uint8_t time_get_num=0;


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

  15.                 if(ring_length() > 0)
  16.                 {
  17.                         ring_buf_read(&g_uart_rx_buf,sizeof(buffer),(uint8_t *)buffer);
  18.                 }
  19.                
  20.                 if(strstr(buffer,"{"time":"))
  21.                 {
  22.                         p1 = strstr(buffer,"":"");
  23.                         p2 = strstr(p1+3,""}");
  24.                         strncpy(val_buffer,p1+3,(p2-(p1+3)-3));//舍去最后三位的毫秒
  25.                         time_ntp = atoi(val_buffer);
  26.                         covUnixTimeStp2Beijing(time_ntp,&tempBeijing1);//网络时间

  27.                         switch(time_get_num)
  28.                         {
  29.                                 case 0:
  30.                                         /***
  31.                                         STEP0:首次获取网络时间
  32.                                         记录初次ntp时间、初次本地时间,用于差值计算
  33.                                         ****/
  34.                                                                 time_ntp1 = time_ntp;
  35.                                                                 time_rtc1 = time_ntp;
  36.                                                                 set_rtc_time(&tempBeijing1);                //保存到RTC
  37.                                                                 time_get_num = 1;
  38.                                                                 break;
  39.                                 case 1:
  40.                                         /***
  41.                                         STEP1:初略校准
  42.                                         利用两次时间同步的ntp时间差、本地时间差,计算本地时间的初略误差,调整同步分频数
  43.                                         ****/
  44.                                                                 time_ntp2 = time_ntp;
  45.                                                                 time_ntp_sub = time_ntp2 -time_ntp1;
  46.                                                                 time_ntp1 = time_ntp2;
  47.                                 
  48.                                                                 get_rtc_time(&tempBeijing2);//本地时间
  49.                                                                 time_rtc2 = covBeijing2UnixTimeStp(&tempBeijing2);        
  50.                                                                 time_rtc_sub = time_rtc2 - time_rtc1;
  51.                                                                 time_rtc1 = time_rtc2;
  52.                                 
  53.                                                                 if(time_ntp_sub >0 && time_rtc_sub >0)
  54.                                                                 {
  55.                                                                         if(time_ntp_sub > time_rtc_sub) //慢了
  56.                                                                         {
  57.                                                                                 time_ntp_rtc_sub = time_ntp_sub-time_rtc_sub;
  58.                                                                                 if(time_ntp_rtc_sub > 1)
  59.                                                                                 {
  60.                                                                                         SynchPrediv = (1 - (time_ntp_rtc_sub / time_ntp_sub) * 0.9) * (SynchPrediv+1) - 1;
  61.                                                                                         HAL_RTC_DeInit(&hrtc);
  62.                                                                                         MX_RTC_Init();
  63.                                                                                         set_rtc_time(&tempBeijing1);                //保存到RTC
  64.                                                                                         time_rtc1 = time_ntp2;
  65.                                                                                 }
  66.                                                                                 else
  67.                                                                                 {
  68. //                                                                                        time_get_num = 2;
  69.                                                                                 }
  70.                                                                         }
  71.                                                                         else if(time_ntp_sub < time_rtc_sub)//快了
  72.                                                                         {
  73.                                                                                 time_ntp_rtc_sub = time_rtc_sub - time_ntp_sub;
  74.                                                                                 if(time_ntp_rtc_sub > 1)
  75.                                                                                 {
  76.                                                                                   SynchPrediv = (1 + (time_ntp_rtc_sub / time_ntp_sub) * 0.9) * (SynchPrediv+1) - 1;
  77.                                                                                         HAL_RTC_DeInit(&hrtc);
  78.                                                                                         MX_RTC_Init();
  79.                                                                                         set_rtc_time(&tempBeijing1);                //保存到RTC
  80.                                                                                         time_rtc1 = time_ntp2;
  81.                                                                                 }
  82.                                                                                 else
  83.                                                                                 {
  84. //                                                                                        time_get_num = 2;
  85.                                                                                 }
  86.                                                                         }
  87.                                                                         else
  88.                                                                         {
  89.                                                                                 
  90.                                                                         }
  91.                                                                 }
  92.                                                                 break;
  93.                                 case 2:
  94.                                         /***
  95.                                         STEP2:精密数字校准计算方法:
  96.                                         24*3600/32s=2700;以32s修正间隔,每24小时有2700个周期
  97.                                         1s/2700 = 3.7*10-4;以24小时差1s为修正目标,计算每个周期需要减少的秒数
  98.                                         3.7*10-4/(1/32767) ≈ 12;以32767为同步分频数为例,计算每个周期减少的秒速等于多少个rtc周期
  99.                                         ****/
  100.                                                                 time_ntp2 = time_ntp;
  101.                                                                 time_ntp_sub = time_ntp2 -time_ntp1;
  102.                                                                 time_ntp1 = time_ntp2;
  103.                                 
  104.                                                                 get_rtc_time(&tempBeijing2);//本地时间
  105.                                                                 time_rtc2 = covBeijing2UnixTimeStp(&tempBeijing2);        
  106.                                                                 time_rtc_sub = time_rtc2 - time_rtc1;
  107.                                                                 time_rtc1 = time_rtc2;
  108.                                 
  109.                                                                 if(time_ntp_sub >0 && time_rtc_sub >0)
  110.                                                                 {
  111.                                                                         if(time_ntp_sub > time_rtc_sub)
  112.                                                                         {
  113.                                                                                 time_ntp_rtc_sub = time_ntp_sub-time_rtc_sub;
  114.                                                                                 time_cal_num = ((float)(time_ntp_rtc_sub * (60*24/2))) / 2700;
  115.                                                                                 time_cal_cnt = time_cal_num/(1/(float)40000);
  116.                                                                                 HAL_RTCEx_SetSmoothCalib(&hrtc, RTC_SMOOTHCALIB_PERIOD_32SEC, RTC_SMOOTHCALIB_PLUSPULSES_SET, (uint32_t)time_cal_cnt);
  117.                                                                                 set_rtc_time(&tempBeijing1);                //保存到RTC
  118.                                                                                 time_rtc1 = time_ntp2;
  119.                                                                         }
  120.                                                                         else if(time_ntp_sub < time_rtc_sub)
  121.                                                                         {
  122.                                                                                 time_ntp_rtc_sub = time_rtc_sub - time_ntp_sub;
  123.                                                                                 
  124.                                                                                 time_cal_num = ((float)(time_ntp_rtc_sub * (60*24/2))) / 2700;
  125.                                                                                 time_cal_cnt = time_cal_num/(1/(float)40000);
  126.                                                                                 HAL_RTCEx_SetSmoothCalib(&hrtc, RTC_SMOOTHCALIB_PERIOD_32SEC, RTC_SMOOTHCALIB_PLUSPULSES_RESET, (uint32_t)time_cal_cnt);
  127.                                                                                 set_rtc_time(&tempBeijing1);                //保存到RTC
  128.                                                                                 time_rtc1 = time_ntp2;
  129.                                                                         }
  130.                                                                         else
  131.                                                                         {
  132.                                                                                 
  133.                                                                         }
  134.                                                                 }
  135.                                                                 break;
  136.                                 case 3:
  137.                                         /***
  138.                                         STEP3:时刻同步计算方法
  139.                                         本地毫秒比远程快了590-200=390ms,390ms/(1s/256) ≈ 100
  140.                                         ****/                                                        
  141.                                                                 HAL_RTCEx_SetSynchroShift(&hrtc, RTC_SHIFTADD1S_RESET, 100);
  142.                                                                 break;
  143.                                 default:
  144.                                         break;
  145.                         }
  146.                         return SUCCESS;
  147.                 }
  148.                 return ERROR;
  149. }






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精度比差多了
xyz549040622 发表于 2021-1-19 14:15 | 显示全部楼层
为什么不用LSE(32.768kHz)呢?能不能校准要看数据手册
 楼主| djz1992 发表于 2021-1-19 15:22 | 显示全部楼层
wsmysyn 发表于 2021-1-19 13:41
内部rc,修调精度有限,看手册可能也就1%精度,和晶体10ppm精度比差多了

难受。。
 楼主| djz1992 发表于 2021-1-19 15:23 | 显示全部楼层
xyz549040622 发表于 2021-1-19 14:15
为什么不用LSE(32.768kHz)呢?能不能校准要看数据手册

引脚全用完了。。
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自研的,中国只有一台,在某个研究所。。工厂没有能量产使用的这类设备,我们一般也不会做这样的设计。。因为做了,你没有设备来实现,或者实现起来效率特别的低,也没用
gx_huang 发表于 2021-1-19 16:01 | 显示全部楼层
这是设计时欠考虑,还是修改方案吧。
比如有人使用CAN,但是不用晶体时钟源,误差超标,这个危害更大,大批量会死人的,胎里病。
m564522634 发表于 2021-1-19 17:38 | 显示全部楼层
方案有问题
imdx 发表于 2021-1-19 22:09 | 显示全部楼层
40k的LSI,实际频率是30k~50k,能用吗?一小时快1分钟表现已经很好了。
ddllxxrr 发表于 2021-1-20 08:19 | 显示全部楼层
想个办法呗,每一小时看看差多少,伤停补时一下
tom_xu 发表于 2021-1-20 09:46 | 显示全部楼层
要用32.768K的时钟。
 楼主| djz1992 发表于 2021-1-20 10:01 | 显示全部楼层
wsmysyn 发表于 2021-1-19 15:48
这个工艺上片上R和C做的精度很高,要花费很大力气
我的上一个项目片内也是有rc32,trim的step只有255,RT ...

网络同步时间我这也可以的,请教一个事情。
网络同步的频率应该怎么定?因为现在一分钟就会差几秒,看这样子得一分钟就校准一次。同步频率太低,容易引起本地时间的突变,对一些按时工作的任务很不好。
 楼主| djz1992 发表于 2021-1-20 10:03 | 显示全部楼层
dirtwillfly 发表于 2021-1-19 12:14
内部时钟一般是rc震荡器的原理,不准的。有条件的话换外部晶振呢,我记得这个料支持外部晶振 ...

之前一分钟差一秒多,加了段网络校准分频数,至少差的没那么多了,五分钟网络同步一次。。
 楼主| djz1992 发表于 2021-1-20 10:04 | 显示全部楼层
xyz549040622 发表于 2021-1-19 14:15
为什么不用LSE(32.768kHz)呢?能不能校准要看数据手册

加了校准,为什么HAL_RTCEx_SetSmoothCalib没效果呢
dirtwillfly 发表于 2021-1-20 11:27 | 显示全部楼层
djz1992 发表于 2021-1-20 10:03
之前一分钟差一秒多,加了段网络校准分频数,至少差的没那么多了,五分钟网络同步一次。。 ...

够用就好,实际上大部分应用不需要那么精确的时钟
gwsan 发表于 2021-2-5 16:18 | 显示全部楼层
有些型号的还不能校准吗
kxsi 发表于 2021-2-5 16:20 | 显示全部楼层
感觉差不多够用就行了
nawu 发表于 2021-2-5 16:22 | 显示全部楼层
哈哈 怎么感觉咱们都要求不高呢
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

115

主题

620

帖子

5

粉丝
快速回复 在线客服 返回列表 返回顶部