打印
[研电赛技术支持]

以GD32F405芯片为例介绍MCU初始化时钟的过程

[复制链接]
333|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
wiba|  楼主 | 2023-8-15 13:25 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
时钟初始化函数入口
时钟初始化一般是在APP程序刚进入时设置,以GD32F405MCU为例在,时钟初始化函数在SystemInit()中,如下代码

;/* reset Handler */
Reset_Handler   PROC
                EXPORT  Reset_Handler                     [WEAK]
                IMPORT  SystemInit
                IMPORT  __main
                LDR     R0, =SystemInit
                BLX     R0
                LDR     R0, =__main
                BX      R0
                ENDP


学会看时钟树
时钟树中常见符号说明
++ 梯形,窄边代表输出端,宽边代表输入端,梯形边上的竖线对应的代表寄存器位数

GD32F405时钟树,基本外设使用的时钟部分在AHB节点后,AHB节点后根据对应的分频系数基本都能确定对应外设使用频率,一般来说主要需要理解AHB如何获取即可。

如何获取AHB时钟频率具体说明如下图所示

通过函数理解具体实现过程,时钟频率函数如下
/*!
    \brief      setup the microcontroller system, initialize the system
    \param[in]  none
    \param[out] none
    \retval     none
*/
void SystemInit (void)
{
  /* FPU settings ------------------------------------------------------------*/
  #if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
    SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2));  /* set CP10 and CP11 Full Access */
  #endif
  /* Reset the RCU clock configuration to the default reset state ------------*/
  /* Set IRC16MEN bit */
  RCU_CTL |= RCU_CTL_IRC16MEN;                //RCU_CTL为时钟控制寄存器,设置IRC16M时钟做为系统时钟时

  RCU_MODIFY                        /*#define RCU_MODIFY      {volatile uint32_t i; \
                         RCU_CFG0 |= RCU_AHB_CKSYS_DIV2; \
                         for(i=0;i<50000;i++);}
                         设置AHB总线频率并等待执行*/

  /* Reset CFG0 register */
  RCU_CFG0 = 0x00000000U;                        //初始化,不太理解为什么设置为后又要清空,可能官方有其他考虑

  /* Reset HXTALEN, CKMEN and PLLEN bits */
  RCU_CTL &= ~(RCU_CTL_PLLEN | RCU_CTL_CKMEN | RCU_CTL_HXTALEN);//异或操作,将RCU_CTL_PLLEN | RCU_CTL_CKMEN | RCU_CTL_HXTALEN位置0,其他位置1

  /* Reset PLLCFGR register */
  RCU_PLL = 0x24003010U;                                //设置锁相环寄存器

  /* Reset HSEBYP bit */
  RCU_CTL &= ~(RCU_CTL_HXTALBPS);

  /* Disable all interrupts */
  RCU_INT = 0x00000000U;

  /* Configure the System clock source, PLL Multiplier and Divider factors,
     AHB/APBx prescalers and Flash settings ----------------------------------*/
  system_clock_config();                        //上面主要是将时钟初始化,这个函数开始具体配置系统时钟
}



根据对应宏定义开启进入对应函数,官方给出的是进入system_clock_200m_irc16m()函数

/*!
    \brief      configure the system clock
    \param[in]  none
    \param[out] none
    \retval     none
*/
static void system_clock_config(void)
{
#ifdef __SYSTEM_CLOCK_IRC16M
    system_clock_16m_irc16m();
#elif defined (__SYSTEM_CLOCK_HXTAL)
    system_clock_hxtal();
#elif defined (__SYSTEM_CLOCK_120M_PLL_IRC16M)
    system_clock_120m_irc16m();
#elif defined (__SYSTEM_CLOCK_120M_PLL_8M_HXTAL)
    system_clock_120m_8m_hxtal();
#elif defined (__SYSTEM_CLOCK_120M_PLL_25M_HXTAL)
    system_clock_120m_25m_hxtal();
#elif defined (__SYSTEM_CLOCK_168M_PLL_IRC16M)
    system_clock_168m_irc16m();
#elif defined (__SYSTEM_CLOCK_168M_PLL_8M_HXTAL)
    system_clock_168m_8m_hxtal();
#elif defined (__SYSTEM_CLOCK_168M_PLL_25M_HXTAL)
    system_clock_168m_25m_hxtal();
#elif defined (__SYSTEM_CLOCK_200M_PLL_IRC16M)
    system_clock_200m_irc16m();
#elif defined (__SYSTEM_CLOCK_200M_PLL_8M_HXTAL)
    system_clock_200m_8m_hxtal();
#elif defined (__SYSTEM_CLOCK_200M_PLL_25M_HXTAL)
    system_clock_200m_25m_hxtal();
#endif /* __SYSTEM_CLOCK_IRC16M */   
}



/*!
    \brief      configure the system clock to 200M by PLL which selects IRC16M as its clock source
    \param[in]  none
    \param[out] none
    \retval     none
*/
static void system_clock_200m_irc16m(void)
{
    uint32_t timeout = 0U;
    uint32_t stab_flag = 0U;

    /* enable IRC16M */
    RCU_CTL |= RCU_CTL_IRC16MEN;                                //设置时钟源为IRC16

    /* wait until IRC16M is stable or the startup time is longer than IRC16M_STARTUP_TIMEOUT */
    do{
        timeout++;
        stab_flag = (RCU_CTL & RCU_CTL_IRC16MSTB);
    }while((0U == stab_flag) && (IRC16M_STARTUP_TIMEOUT != timeout));//等待时钟稳定,对应寄存器置位或者超时

    /* if fail */
    if(0U == (RCU_CTL & RCU_CTL_IRC16MSTB)){
        while(1){
        }
    }

    RCU_APB1EN |= RCU_APB1EN_PMUEN;                        //PMU时钟使能
    PMU_CTL |= PMU_CTL_LDOVS;                                //PMU时钟控制寄存器高电压,应该是

    /* IRC16M is stable */
    /* AHB = SYSCLK */
    RCU_CFG0 |= RCU_AHB_CKSYS_DIV1;                        //设置AHB分频系数为1
    /* APB2 = AHB/2 */
    RCU_CFG0 |= RCU_APB2_CKAHB_DIV2;                //设置APB2分频系数为2
    /* APB1 = AHB/4 */
    RCU_CFG0 |= RCU_APB1_CKAHB_DIV4;                //设置APB1分频系数为4

    /* Configure the main PLL, PSC = 16, PLL_N = 400, PLL_P = 2, PLL_Q = 9 */
    RCU_PLL = (16U | (400U << 6U) | (((2U >> 1U) - 1U) << 16U) |
                   (RCU_PLLSRC_IRC16M) | (9U << 24U));                //设置锁相环的分频系数为16,PLL_N为400,PLL_P系数为2,PLL_Q系数为9,因此CK_PLL_P = ICR16*PLL_N /(PSC *PLL_P )                                CK_PLL_Q = ICR16*PLL_N /(PSC *PLL_Q )                               

    /* enable PLL */
    RCU_CTL |= RCU_CTL_PLLEN;                //打开PLL锁相环作为时钟输入源

    /* wait until PLL is stable */
    while(0U == (RCU_CTL & RCU_CTL_PLLSTB)){                //等待PLL锁相环设置成功
    }

    /* 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;                                                        //高速晶体振荡器(HXTAL) 使能
    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_P作为CK_SYS的不太理解,如果有理解的朋友可以在评论区大致讲一下,感谢
————————————————
版权声明:本文为CSDN博主「熊熊在加油」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_33441744/article/details/131903962

使用特权

评论回复
沙发
hfdy01| | 2023-10-22 10:23 | 只看该作者
很详细的关于以GD32F405芯片为例介绍MCU初始化时钟的过程的资料

使用特权

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

本版积分规则

77

主题

3305

帖子

3

粉丝