GD32 system_clock详解

时钟就是整个系统正常运行的命脉,时钟配置不对或者理解不全,后面定时器的配置就会出问题

系统运行时首先是从下图这里开始,先加载SystemInit函数,然后加载main函数

 

 SystemInit()是厂家封装好的,不用改动,只要理解就行了。

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_MODIFY;  //源代码没‘;’这会导致代码查看有问题(虽然执行上没问题)
    
  /* Reset CFG0 register */
  RCU_CFG0 = 0x00000000U;

  /* Reset HXTALEN, CKMEN and PLLEN bits */
  RCU_CTL &= ~(RCU_CTL_PLLEN | RCU_CTL_CKMEN | RCU_CTL_HXTALEN);

  /* 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_config()里,它会根据用户定义的时钟源选择相应 的时钟初始化函数

时钟源的选择要看下用户手册,然后跟硬件工程师确认下。这里我就犯了一个错误,看到GD的demo里他们用的是外部25M的高速时钟,我也理所当然的用了这个。结果调试定时器死活调不对,输出的PWM也不对。问了硬件工程师才知道,原来我们外部的高速时钟源是8M的。而内部的16M的虽然也可以用,但是它的精度不高,不推荐用。当初从STM换到GD,移植这块的时候就糊里糊涂的没细究,结果后面还是会被卡脖子。

 

 

 

我们这里选择的是外部高速时钟__SYSTEM_CLOCK_200M_PLL_8M_HXTAL

 

 

 其时钟初始化函数如下:

 7 static void system_clock_200m_25m_hxtal(void)
 8 {
 9     uint32_t timeout = 0U;
10     uint32_t stab_flag = 0U;
11     
12     /* enable HXTAL */
13     RCU_CTL |= RCU_CTL_HXTALEN;
14 
15     /* wait until HXTAL is stable or the startup time is longer than HXTAL_STARTUP_TIMEOUT */
16     do{
17         timeout++;
18         stab_flag = (RCU_CTL & RCU_CTL_HXTALSTB);
19     }while((0U == stab_flag) && (HXTAL_STARTUP_TIMEOUT != timeout));
20 
21     /* if fail */
22     if(0U == (RCU_CTL & RCU_CTL_HXTALSTB)){
23         while(1){
24         }
25     }
26          
27     RCU_APB1EN |= RCU_APB1EN_PMUEN;
28     PMU_CTL |= PMU_CTL_LDOVS;
29 
30     /* HXTAL is stable */
31     /* AHB = SYSCLK = 200M */
32     RCU_CFG0 |= RCU_AHB_CKSYS_DIV1;
33     /* APB2 = AHB/2 = 100M */
34     RCU_CFG0 |= RCU_APB2_CKAHB_DIV2;
35     /* APB1 = AHB/4 = 50M */
36     RCU_CFG0 |= RCU_APB1_CKAHB_DIV4;
37 
38     /* Configure the main PLL, PSC = 25, PLL_N = 400, PLL_P = 2, PLL_Q = 9 */ 
39     RCU_PLL = (25U | (400U << 6U) | (((2U >> 1U) - 1U) << 16U) |
40                    (RCU_PLLSRC_HXTAL) | (9U << 24U));
41 
42     /* enable PLL */
43     RCU_CTL |= RCU_CTL_PLLEN;
44 
45     /* wait until PLL is stable */
46     while(0U == (RCU_CTL & RCU_CTL_PLLSTB)){
47     }
48     
49     /* Enable the high-drive to extend the clock frequency to 200 Mhz */
50     PMU_CTL |= PMU_CTL_HDEN;
51     while(0U == (PMU_CS & PMU_CS_HDRF)){
52     }
53     
54     /* select the high-drive mode */
55     PMU_CTL |= PMU_CTL_HDS;
56     while(0U == (PMU_CS & PMU_CS_HDSRF)){
57     } 
58     
59     /* select PLL as system clock */
60     RCU_CFG0 &= ~RCU_CFG0_SCS;
61     RCU_CFG0 |= RCU_CKSYSSRC_PLLP;
62 
63     /* wait until PLL is selected as system clock */
64     while(0U == (RCU_CFG0 & RCU_SCSS_PLLP)){
65     }
66 }

1. 开启高速时钟源

RCU_CTL |= RCU_CTL_HXTALEN;

2.配置 APB1 = AHB/4

RCU_CFG0 |= RCU_APB1_CKAHB_DIV4;

3.配置PLL为系统时钟源

这样系统时钟就是200M的时钟了

那么APB1是多少呢?

根据RCU_CFG1的寄存器说明:

 

 

 

AHB = SYSCLK;
APB1 = AHB/4= 200M/4 = 50MHz;
CK_TIMERx = 2 * CK_APB1 = 100MHz
若对时钟配置寄存器 1 进行时钟配置的话,
rcu_timer_clock_prescaler_config(RCU_TIMER_PSC_MUL4);
则:
CK_TIMERx = 4 * CK_APB1 = 200MHz
 
posted @ 2021-12-03 12:58  xjxcxjx  阅读(1746)  评论(0编辑  收藏  举报