MM32F3273G8P火龙果开发板MindSDK开发教程3 - Sysclk的配置
1、时钟初始化流程
一般流程为startup_mm32f3273g.s中调用system_mm32f3273g.c中的SystemInit函数完成系统时钟的初始,而system_mm32f3273g.c中函数是空的。
原来MindSdk时钟初始化的流程放到了clock_init.c中。
2、采用外部高速时钟源
先弄清几个概念:
HSE (外部高速时钟信号)
HSI (芯片内部时钟信号)
LSE (外部低速时钟信号)
LSI (内部低速时钟信号)
PLL (锁相环)因为HSE HSI的频率都不是太高,所以ARM设计了PLL(锁相环)来进行倍频,把HSI和HSE频率拉高到百兆以上。
SycClk (系统时钟)
HCLK (AHB的时钟)
HCLK1 (APB1的时钟)
HCLK2 (APB2的时钟)
设置系统时钟SYSCLK、设置AHB分频因子(决定HCLK是多少)、设置APB2分频因子(设定PCLK2等于多少)、设置APB1分频因子(决定PCLK1等于多少);
火龙果mm32F3273开发板外接12M晶振,因此这里我们采用HSE+PLL的方式作为开发板的时钟输入信号。
3、时钟设置
关于PLL使能与设置,芯片手册上是这样写的。
而PLL输出时钟与输入时钟的关系如图:
假设我们PLLDIV设置1分频,输入时钟12M,想要获得的PLL输出时钟为120M,那么PLLMUN应为设置为19。
而PLL设置的寄存器如下:
代码中关于pll的设置如下:
/* enable HSE. */
RCC->CR |= RCC_CR_HSEON_MASK;
while ( RCC_CR_HSERDY_MASK != (RCC->CR & RCC_CR_HSERDY_MASK) )
{
}
RCC->PLLCFGR = RCC_PLLCFGR_PLLSRC(1) /* (pllsrc == 1) ? HSE : HSI. */
| RCC_PLLCFGR_PLLMUL(19) /* (12 * (19 + 1)) / 2 = 120. */
| RCC_PLLCFGR_PLLDIV(1) /*PLL分频系数*/
| RCC_PLLCFGR_PLLLDS(1) /*这个寄存器是个保留的,不设置亦可*/
| RCC_PLLCFGR_PLLICTRL(3) /*PLL Charge Pump电流控制信号*/
;
/* Enable PLL. */
RCC->CR |= RCC_CR_PLLON_MASK;
while((RCC->CR & RCC_CR_PLLRDY_MASK) == 0)
{
}
PLL设置完成,我们接下来要设置sysclk hclk hclk1 hclk2的时钟。
一般SYSCLK=PLLCLK=120MHz
HCLK,也就是AHB CLK,这里设置为1分频,即=SYSCLK=120M.
HCLK1,也就是APB1CLK,这里设置2分频,即=HCLK/2=60M。
HCLK2,也就是APB2CLK,这里设置2分频,即=HCLK/2=60M。
相关寄存器设置如图:
相关设置代码如下:
/* Setup the dividers for each bus. */
RCC->CFGR = RCC_CFGR_HPRE(0) /* div=1 for AHB freq. */
| RCC_CFGR_PPRE1(0x4) /* div=2 for APB1 freq. */
| RCC_CFGR_PPRE2(0x4) /* div=2 for APB2 freq. */
| RCC_CFGR_MCO(7) /* use PLL/2 as output. */
;
/* Switch the system clock source to PLL. */
RCC->CFGR = (RCC->CFGR & ~RCC_CFGR_SW_MASK) | RCC_CFGR_SW(2); /* use PLL as SYSCLK */
/* Wait till PLL is used as system clock source. */
while ( (RCC->CFGR & RCC_CFGR_SWS_MASK) != RCC_CFGR_SWS(2) )
{
}
至此,经过上面设置,我们将开发板设置成了120M的时钟。
4、获取时钟函数
uint32_t CLOCK_GetBootHSEValue(void)
{
uint32_t tmpreg = 0U, prediv = 0U, pllclk = 0U, pllmul = 0U;
uint32_t sysclockfreq = 0U;
tmpreg = RCC->CFGR;
/* 获取系统时钟源 */
switch(tmpreg & RCC_CFGR_SWS_MASK)
{
case RCC_SYSCLKSOURCE_STATUS_HSI:
{
sysclockfreq = HSI_VALUE;
break;
}
case RCC_SYSCLKSOURCE_STATUS_HSE:
{
sysclockfreq = HSE_VALUE;
break;
}
case RCC_SYSCLKSOURCE_STATUS_LSI:
{
sysclockfreq = LSI_VALUE;
break;
}
case RCC_SYSCLKSOURCE_STATUS_PLLCLK:
{
/* 获取PLL的输入时钟源 */
if(RCC->PLLCFGR&0x01) // HSE用作PLL的输入时钟
{
if(RCC->PLLCFGR&0x02) // HSE二分频后输入给PLL
{
pllclk = HSE_VALUE>>1;
}
else // HSE部分变频直接输出给PLL
{
pllclk = HSE_VALUE;
}
}
else // HSI用作PLL的输入时钟
{
pllclk = HSI_VALUE;
}
prediv = (RCC->PLLCFGR>>8)&0x07; // PLL的分频系数:PLLCFGR[10:8]
pllmul = (RCC->PLLCFGR>>16)&0x7F; // PLL的倍频系数: PLLCFGR[22:16]
sysclockfreq = pllclk * (pllmul+1) / (prediv+1);
break;
}
default:break;
}
return sysclockfreq;
}