CH32-USBFS利用主机sof包时基校准HSI

       对于对HSI要求较高的串口或者CAN通信等,通常会遇到由于HSI偏差大于±1.6%,或者更多,而导致通信异常,如果客户恰好有用到USBDevice,那这样就可以通过主机的1ms sof时基对HSI进行一个校准,

与USB转串口或者USB转CAN的应用,有所帮助。

直接上代码操作。

         开启一个定时器1,开一个1ms的定时器中断,在中断程序中判断USBFS_DevEnumStatus=1的时候开启USB的sof中断,然后全局变量TIM_NUM开始自加,此时SOF_NUM也开始在USB中断中以主机的时基1ms自加,等到了SOF_NUM到了5000,(此时校准时间为5s,为了更加准确的话,可以调整到10s,也就是SOF_NUM为10000),此时定时器判断中将USB SOF中断关闭,读取全局变量TIM_NUM的值,使用的值去减TIM_NUM,然后除以5000,此时就是大致HSI偏的时间,再以8M为基准,除以HSICAL校准值的步进频率,计算出校准值写入校准寄存器即可。

全局变量 u16 TIM_NUM = 0;

u16 SOF_NUM= 0;

1-定时器初始化
    TIM1_INT_Init( 2000-1, 48000-1)//主频设置为96M。1ms进入一次中断
void TIM1_INT_Init( u16 arr, u16 psc)
{

    NVIC_InitTypeDef NVIC_InitStructure={0};
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure={0};

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE );

    TIM_TimeBaseInitStructure.TIM_Period = arr;
    TIM_TimeBaseInitStructure.TIM_Prescaler = psc;
    TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 50;
    TIM_TimeBaseInit( TIM1, &TIM_TimeBaseInitStructure);

    TIM_ClearITPendingBit( TIM1, TIM_IT_Update );

    NVIC_InitStructure.NVIC_IRQChannel =TIM1_UP_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority =1;
    NVIC_InitStructure.NVIC_IRQChannelCmd =ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    TIM_ITConfig(TIM1, TIM_IT_Update, ENABLE);

}
2-USB中断分支
    else if( intflag & USBFS_UIF_HST_SOF )
    {
      SOF_NUM++;
    }

image

 

 

3-定时器中断函数
void TIM1_UP_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
void TIM1_UP_IRQHandler(void)
{
    if(TIM_GetITStatus(TIM1, TIM_IT_Update)==SET)
    {
        if(USBFS_DevEnumStatus==1)
        {
             sofOPflag=1;
             if(sofOPflag==1)
                {
                sofOPflag=0;
                USBFSD->INT_EN |= USBFS_UIE_HST_SOF ;//USB初始化开启中断处或上USBFS_UIE_HST_SOF打开sof中断
                }
                else
                {
                  TIM_NUM++;
                  if(SOF_NUM==5000)
                  {
                  USBFSD->INT_EN &=  ~USBFS_UIE_HST_SOF ;
                  RCC_CTLR->HSITRIM &=~(0x1f);
                  RCC_CTLR->HSITRIM =16+((SOF_NUM-TIM_NUM)*8000000/5000*8000000)/20000;//注意变量超范围
                  }  
                }
         

        }
    }
    TIM_ClearITPendingBit( TIM1, TIM_IT_Update );
}

image

此方法只适用于CAN或者串口。或者与从机通信时钟比较敏感的外设可以用此方法调整

posted @ 2026-01-04 13:56  WCH_CH32  阅读(19)  评论(0)    收藏  举报