你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32F103 IWDG时钟准确度的疑问

[复制链接]
adarly 提问时间:2017-3-25 15:12 /
看文档上面介绍IWDG使用的内部低速时钟LSI,大约40K,可是当我配置IWDG预分频为32,装载值位2500(40K/16),也就是2秒钟不喂狗重启,但我测试下来结果却是10秒钟不喂狗才重启。这是为何,40K的LSI不可能误差这么多吧?IWDG配置如下:IWDG_SetPrescaler(IWDG_Prescaler_32);

IWDG_SetReload(40000 / 16);

另外我测试了下RTC也使用内部的40K LSI,来实现秒中断,测试下来1分钟触发58次,也就是说LSI的误差在1/30左右。
看到有关文档上结束如下:
看门狗超时时间(40kHz的输入时钟(LSI))(1)
最短时间(ms)
RL[11:0] = 0x000
最长时间(ms)
RL[11:0] = 0xFFF
预分频系数 PR[2:0]
/4 0 0.1 409.6
/8 1 0.2 819.2
/16 2 0.4 1638.4
/32 3 0.8 3276.8
/64 4 1.6 6553.6
/128 5 3.2 13107.2
/256 (67) 6.4 26214.4

“这些时间是按照40kHz时钟给出。实际上, MCU内部的RC频率会在30kHz到60kHz之间变化。
此外,即使RC振荡器的频率是精确的,确切的时序仍然依赖于APB接口时钟与RC振荡器时钟
之间的相位差,因此总会有一个完整的RC周期是不确定的。”  


APB接口时钟与RC振荡器时钟之间的相位差,请问会对IWDG的时钟产生这么大的影响吗?有没有大神知道的?
收藏 1 评论3 发布时间:2017-3-25 15:12

举报

3个回答
xmshao 回答时间:2017-3-26 11:30:55
不可能这么大误差 再确认下配置参数
或者说配置写进去没有?
adarly 回答时间:2017-3-27 11:34:22
多谢,楼上的提醒,的确是预分频寄存器PR的值没有设进去,但重载寄存器RLR的值却设进去了。很是奇怪。
初始化步骤如下:
void IWDG_Init(void)
{
    IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
    IWDG_SetPrescaler(IWDG_Prescaler_32);
    IWDG_SetReload(CLK_LSI / 16);
    IWDG_ReloadCounter();
    IWDG_Enable();
}

然后通过串口打印会读的寄存器值PR RLR SR_PVU SR_RVU如下:
PR[6], RLR[2500], PVU[0], RVU[0]
预分频寄存器PR的值却是默认的256分频!!!
于是做了如下处理:
void IWDG_Init(void)
{
    IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
    while(IWDG_GetFlagStatus(IWDG_FLAG_PVU));
    IWDG_SetPrescaler(IWDG_Prescaler_32);
    while(IWDG_GetFlagStatus(IWDG_FLAG_RVU));
    IWDG_SetReload(CLK_LSI / 16);
    IWDG_ReloadCounter();
    IWDG_Enable();
}

实验测试,却是陷入上面的死循环,MCU起不来了。于是继续测试:
uint16 ptimeout;
uint16 rtimeout;
void IWDG_Init(void)
{
    ptimeout = 0;
    rtimeout = 0;
    IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
    while(IWDG_GetFlagStatus(IWDG_FLAG_PVU))
    {
        ptimeout ++;
        if (ptimeout >= 500)
        {
            break;
        }
    }
    IWDG_SetPrescaler(IWDG_Prescaler_32);
    while(IWDG_GetFlagStatus(IWDG_FLAG_RVU))
    {
        rtimeout ++;
        if (rtimeout >= 500)
        {
            break;
        }
    }
    IWDG_SetReload(CLK_LSI / 16);
    IWDG_ReloadCounter();
    IWDG_Enable();
}
初始化后打印的结果如下:
PR[6], RLR[2500], PVU[0], RVU[0], ptimeout[500], rtimeout[0]
原来是硬件上一直没有将SR_PVU清0.。。。
无奈在上点开机几秒钟之后,再次手动初始化IWDG,此时再查下寄存器终于好了:
PR[3], RLR[2500], PVU[0], RVU[0], ptimeout[0], rtimeout[0]

那么问题又来了,为什么刚开机初始化时,SR_PVU一直不清0呢,有没有大神遇到过这种情况呀?
Dylan疾风闪电 回答时间:2017-3-27 15:56:05
  1. /** <summary>
  2.   * 打开IWDG。
  3.   * </summary>
  4.   * <param name="pr">40KHz看门狗时钟的预分频值。</param>
  5.   * <param name="rlr">看门狗倒计数的最大值,Max=0xFFF。</param>
  6.   * <exception cref=""></exception>
  7.   */
  8. void OpenIWDG(uint8_t pr, uint16_t rlr)
  9. {
  10.   IWDG->KR = 0x5555;        //使能对IWDG->PR和IWDG->RLR的写
  11.   IWDG->PR = pr;                //LSI/32=40Khz/(4*2^pre) //4、8、16、32、64、128、256
  12.   IWDG->RLR = rlr;                //从加载寄存器 IWDG->RLR,Max=0xFFF。因为看门狗计数器正是从这个值开始向下计数。
  13.   IWDG->KR = 0xAAAA;        //reload
  14.   IWDG->KR = 0xCCCC;        //使能看门狗
  15. }

  16. /** <summary>
  17.   * 给IWDG喂狗。
  18.   * </summary>
  19.   * <param name=""></param>
  20.   * <exception cref=""></exception>
  21.   */
  22. void FeedIWDG(void)
  23. {
  24.   IWDG->KR = 0xAAAA;        //reload
  25. }
复制代码


好像只要这样就可以的
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版