CH32V307 使用PLL2配置系统时钟

发布时间 2023-11-04 14:15:29作者: ZaiLi

在进行系统时钟配置时,可以选择HSIHSEPLL作为系统时钟来源。而PLL时钟来源有几下几种,如下图:

 

以下为CH32V307时钟树框图,如下图:

 

关于使用HSEHSI作为系统时钟,在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