CH32V307 使用PLL2配置系统时钟
在进行系统时钟配置时,可以选择HSI、HSE、PLL作为系统时钟来源。而PLL时钟来源有几下几种,如下图:
以下为CH32V307时钟树框图,如下图:
关于使用HSE或HSI作为系统时钟,在CH32V307 EVT都有相应例程,在system_ch32v30x.c文件中直接使用相关宏定义即可,如下图:
本篇文章主要讲解使用PLL2配置系统时钟的配置方式,以配置96MHz系统时钟为例,代码如下。注意该方式只适用于CH32V305、307系列,其他CH32V30x系列时钟框图不同,该方法不适用。
/********************************************************************* * @fn SetSysClockTo96 * * @brief Sets System clock frequency to 96MHz and configure HCLK, PCLK2 and PCLK1 prescalers. * * @return none */ static void SetSysClockTo96(void) { __IO uint32_t StartUpCounter = 0, HSEStatus = 0; RCC->CTLR |= ((uint32_t)RCC_HSEON); /* Wait till HSE is ready and if Time out is reached exit */ do { HSEStatus = RCC->CTLR & RCC_HSERDY; StartUpCounter++; } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT)); if ((RCC->CTLR & RCC_HSERDY) != RESET) { HSEStatus = (uint32_t)0x01; } else { HSEStatus = (uint32_t)0x00; } if (HSEStatus == (uint32_t)0x01) { /* HCLK = SYSCLK */ RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1; /* PCLK2 = HCLK */ RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1; /* PCLK1 = HCLK */ RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2; #ifdef CH32V30x_D8C RCC_PREDIV2Config(RCC_PREDIV2_Div1); RCC_PLL2Config(RCC_PLL2Mul_4); RCC_PLL2Cmd(ENABLE); while((RCC->CTLR & (1<<27)) == 0) { } #endif RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE | RCC_PLLMULL)); #ifdef CH32V30x_D8 /* PLL configuration: PLLCLK = HSE * 12 = 96 MHz */ RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL12); #else /* PLL configuration: PLLCLK = HSE/1*4/2*6 = 96 MHz */ RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL6_EXTEN); RCC_PREDIV1Config(RCC_PREDIV1_Source_PLL2, RCC_PREDIV1_Div2); #endif /* Enable PLL */ RCC->CTLR |= RCC_PLLON; /* Wait till PLL is ready */ while((RCC->CTLR & RCC_PLLRDY) == 0) { } /* Select PLL as system clock source */ RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW)); RCC->CFGR0 |= (uint32_t)RCC_SW_PLL; /* Wait till PLL is used as system clock source */ while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08) { } } else { /* * If HSE fails to start-up, the application will have wrong clock * configuration. User can add here some code to deal with this error */ } }
该部分代码在使用HSE配置系统时钟的基本上修改,加粗标红部分为添加部分。关于这几行代码,解释如下:
RCC_PREDIV2Config(RCC_PREDIV2_Div1);
/*********************************************************************
* @fn RCC_PREDIV2Config
*
* @brief Configures the PREDIV2 division factor.
*
* @param RCC_PREDIV2_Div - specifies the PREDIV2 clock division factor.
* This parameter can be RCC_PREDIV2_Divx where x:[1,16]
* Note-
* - This function must be used only when both PLL2 and PLL3 are disabled.
*
* @return none
*/
void RCC_PREDIV2Config(uint32_t RCC_PREDIV2_Div)
{
uint32_t tmpreg = 0;
tmpreg = RCC->CFGR2;
tmpreg &= ~CFGR2_PREDIV2;
tmpreg |= RCC_PREDIV2_Div;
RCC->CFGR2 = tmpreg;
}
该函数主要对 时钟配置寄存器2(RCC_CFGR2)进行配置,设置PREDIV2分频因子为1分频,即不分频。
RCC_PLL2Config(RCC_PLL2Mul_4); /********************************************************************* * @fn RCC_PLL2Config * * @brief Configures the PLL2 multiplication factor. * * @param RCC_PLL2Mul - specifies the PLL2 multiplication factor. * This parameter can be RCC_PLL2Mul_x where x:{[8,14], 16, 20} * Note- * - This function must be used only when the PLL2 is disabled. * * @return none */ void RCC_PLL2Config(uint32_t RCC_PLL2Mul) { uint32_t tmpreg = 0; tmpreg = RCC->CFGR2; tmpreg &= ~CFGR2_PLL2MUL; tmpreg |= RCC_PLL2Mul; RCC->CFGR2 = tmpreg; }
该函数主要对 时钟配置寄存器2(RCC_CFGR2)进行配置,设置PLL2倍频因子,此处设置4倍频。
RCC_PLL2Cmd(ENABLE);
/*********************************************************************
* @fn RCC_PLL2Cmd
*
* @brief Enables or disables the PLL2.
*
* @param NewState - new state of the PLL2. This parameter can be
* ENABLE or DISABLE.
* Note-
* - The PLL2 can not be disabled if it is used indirectly as system clock
* (i.e. it is used as PLL clock entry that is used as System clock).
*
* @return none
*/
void RCC_PLL2Cmd(FunctionalState NewState)
{
if(NewState)
{
RCC->CTLR |= (1 << 26);
}
else
{
RCC->CTLR &= ~(1 << 26);
}
}
该函数主要对 时钟控制寄存器(RCC_CTLR)进行配置,使能开启PLL2时钟。
while((RCC->CTLR & (1<<27)) == 0) { }
该函数主要等待PLL2时钟就绪锁定,如下图:
RCC_PREDIV1Config(RCC_PREDIV1_Source_PLL2, RCC_PREDIV1_Div2); /********************************************************************* * @fn RCC_PREDIV1Config * * @brief Configures the PREDIV1 division factor. * * @param RCC_PREDIV1_Source - specifies the PREDIV1 clock source. * RCC_PREDIV1_Source_HSE - HSE selected as PREDIV1 clock * RCC_PREDIV1_Source_PLL2 - PLL2 selected as PREDIV1 clock * RCC_PREDIV1_Div - specifies the PREDIV1 clock division factor. * This parameter can be RCC_PREDIV1_Divx where x[1,16] * Note- * - This function must be used only when the PLL is disabled. * * @return none */ void RCC_PREDIV1Config(uint32_t RCC_PREDIV1_Source, uint32_t RCC_PREDIV1_Div) { uint32_t tmpreg = 0; tmpreg = RCC->CFGR2; tmpreg &= ~(CFGR2_PREDIV1 | CFGR2_PREDIV1SRC); tmpreg |= RCC_PREDIV1_Source | RCC_PREDIV1_Div; RCC->CFGR2 = tmpreg; }
该函数主要对 时钟配置寄存器2(RCC_CFGR2)进行配置,设置PREDIV1 分频因子为2分频,同时设置PREDIV1的时钟源为PLL2。
以上为相关函数的介绍,根据下图圈出部分,如下图:
可计算出系统时钟大小为:HSE/1*4/2*6,即8Mhz/1*4/2*6=96Mhz