时钟初始化函数入口
时钟初始化一般是在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
|