zoukankan      html  css  js  c++  java
  • GD32F450 200M时USB不稳定

    使用GD32F450的demo修改usb驱动,发现120M和168M时正常,200M时很不稳定。怀疑USB时钟分频有问题,一查果然是,记录如下:

    200M是库函数主时钟分频代码如下

    static void system_clock_200m_25m_hxtal(void)
    {
        uint32_t timeout = 0U;
        uint32_t stab_flag = 0U;
        
        /* enable HXTAL */
        RCU_CTL |= RCU_CTL_HXTALEN;
    
        /* wait until HXTAL is stable or the startup time is longer than HXTAL_STARTUP_TIMEOUT */
        do{
            timeout++;
            stab_flag = (RCU_CTL & RCU_CTL_HXTALSTB);
        }while((0U == stab_flag) && (HXTAL_STARTUP_TIMEOUT != timeout));
    
        /* if fail */
        if(0U == (RCU_CTL & RCU_CTL_HXTALSTB)){
            while(1){
            }
        }
             
        RCU_APB1EN |= RCU_APB1EN_PMUEN;
        PMU_CTL |= PMU_CTL_LDOVS;
    
        /* HXTAL is stable */
        /* AHB = SYSCLK */
        RCU_CFG0 |= RCU_AHB_CKSYS_DIV1;
        /* APB2 = AHB/2 */
        RCU_CFG0 |= RCU_APB2_CKAHB_DIV2;
        /* APB1 = AHB/4 */
        RCU_CFG0 |= RCU_APB1_CKAHB_DIV4;
    
        /* Configure the main PLL, PLL_M = 25, PLL_N = 400, PLL_P = 2, PLL_Q = 9 */ 
        RCU_PLL = (25U | (400U << 6U) | (((2U >> 1U) - 1U) << 16U) |
                       (RCU_PLLSRC_HXTAL) | (9U << 24U));
    
        /* enable PLL */
        RCU_CTL |= RCU_CTL_PLLEN;
    
        /* wait until PLL is stable */
        while(0U == (RCU_CTL & RCU_CTL_PLLSTB)){
        }
        
        /* Enable the high-drive to extend the clock frequency to 200 Mhz */
        PMU_CTL |= PMU_CTL_HDEN;
        while(0U == (PMU_CS & PMU_CS_HDRF)){
        }
        
        /* select the high-drive mode */
        PMU_CTL |= PMU_CTL_HDS;
        while(0U == (PMU_CS & PMU_CS_HDSRF)){
        } 
        
        /* select PLL as system clock */
        RCU_CFG0 &= ~RCU_CFG0_SCS;
        RCU_CFG0 |= RCU_CKSYSSRC_PLLP;
    
        /* wait until PLL is selected as system clock */
        while(0U == (RCU_CFG0 & RCU_SCSS_PLLP)){
        }
    }

    这里注意几个重要信息,PLL_M=25,PLL_N=400,PLL_Q=9 

    再查看demo里的usb时钟配置代码,从代码里我们可以了解,USB时钟来源是PLLM_48M,而PLLM_48M是HXTAL倍频后经由PLLQ分频得到

        rcu_pll48m_clock_config(RCU_PLL48MSRC_PLLQ);
    
        rcu_ck48m_clock_config(RCU_CK48MSRC_PLL48M);
    
        rcu_periph_clock_enable(RCU_USBFS);

    对比数据手册里USB这块的时钟树我们计算下USB时钟

    输入时钟25Mhz,USB时钟=25/PLL_M*PLL_N/PLL_Q=25/25*400/9=44.44444MHz,而我们知道USB需要48MHz的时钟才能稳定工作,所以这导致了USB工作的不稳定。

    为什么120MHz和168MHz时不会有这个稳定呢?那是因为不同时钟主时钟分频函数不一样,在120MHz和168MHz时能分出48M的时钟给USB。

    知道问题哪后,就好解决了,方法如下:

    1、直接修改库函数里PLL的分频系数,这个方法新人不推荐

    2、使用内部RCK_48M作为USB的时钟源,

    rcu_ck48m_clock_config(RCU_CK48MSRC_IRC48M)
    rcu_osci_on(RCU_IRC48M)
    /* wait till RCU_IRC48M is ready */
    while(SUCCESS != rcu_osci_stab_wait(RCU_IRC48M)){
    }

    3、修改PLLM_48M由PLLAI分频来

        //使用PLLAI_Q作为PLL_SEL的输入
        rcu_pll48m_clock_config(RCU_PLL48MSRC_PLLSAIP);
        //使用PLL_SEL作为usb主频
        rcu_ck48m_clock_config(RCU_CK48MSRC_PLL48M);
    
        /* configure PLLSAI          
          PLLAI_N=192;PLL_P=192/4=48MHZ,PLL_Q=192/2=96MHZ,PLL_R=192/3=64MHZ
           注意,此处的PLL_P用于后面的USB主时钟,要确保为48MHZ
        */
        if(ERROR == rcu_pllsai_config(192, 4, 2, 3))            
        {
            while(1);
        }
        
        rcu_osci_on(RCU_PLLSAI_CK);
        
        if(ERROR == rcu_osci_stab_wait(RCU_PLLSAI_CK))
        {
            while(1);
        }
  • 相关阅读:
    vim删除某一列
    linux下在当前文件夹查找一个字符串信息
    .tar和.tar.gz的区别
    visual studio中调用masm汇编
    iconv转码失败的原因
    终端查看
    kubectl 常用命令总结
    Charles实战之Charles抓取https请求
    Fiddler实战之拟2G、3G、4G网络进行弱网测试
    Fiddler实战之使用Fiddler模拟弱网环境
  • 原文地址:https://www.cnblogs.com/zwj412/p/10026393.html
Copyright © 2011-2022 走看看