1 /*
2  * Copyright (c) 2020-2022, CQ 100ask Development Team
3  *
4  * Change Logs:
5  *   Date           Author          Notes
6  * 2022-05-29        Alen       first version
7  */
8 
9 #include "board.h"
10 #include "hal_rcc.h"
11 
12 static uint32_t SystemClockFreq = HSI_VALUE;
13 static uint32_t AHBClockFreq = HSI_VALUE;
14 static uint32_t APB1ClockFreq = HSI_VALUE;
15 static uint32_t APB2ClockFreq = HSI_VALUE;
16 
17 static void update_systemclock(void);
18 static void update_ahb_clock(void);
19 static void update_apb1_clock(void);
20 static void update_apb2_clock(void);
21 
SystemClock_Config(void)22 void SystemClock_Config(void)
23 {
24     /* 使能总线外设时钟 */
25     RCC->AHB1ENR |= (1u << 13u);    // 使能FLASH外设
26     FLASH->ACR |= (4<<0);           // 设置Flash的等待周期
27 
28     /* 使能PWR/DBG */
29     RCC->APB1ENR |= (1<<28);
30     PWR->CR1 &= ~(2<<14);
31     PWR->CR1 |= (2<<14);    // 如果系统时钟需要达到最大频率 120MHz,需要将 VOS 设置为 2’b10 即 1.7V
32 
33     RCC->CR &= ~((1<<16) | (1<<24) ); // 关闭HSE/PLL
34 
35     /* 配置HSE和PLL */
36     RCC->CR |= (1<<16);             // 使能HSE
37     while(0 == ((RCC->CR)&(1<<17)));// 等待HSE稳定
38 
39     RCC->PLLCFGR |= (1<<0);         // 配置PLL的时钟源HSE
40     RCC->PLLCFGR &= ~(1<<1);        // 配置PLL的时钟源HSE不分频后再作为时钟输入源
41     RCC->PLLCFGR &= ~(0x7F<<16);
42     RCC->PLLCFGR |= (19<<16);       // 配置PLL的倍频系数:20倍 -> 12MHz/2*20 = 120MHz
43     RCC->PLLCFGR &= ~(0x7<<8);
44     RCC->PLLCFGR |= (1<<8);         // 配置PLL的分频系数:2
45 
46     RCC->CR |= (1<<24);             // 使能PLL
47     while(0 == (RCC->CR & (1<<25)));// 等待PLL时钟稳定
48 
49     /* 配置系统时钟、AHB、APB时钟 */
50     RCC->CFGR |= (0<<4);            // AHB不分频
51     RCC->CFGR |= (4<<8);            // APB1 2分频
52     RCC->CFGR |= (4<<11);           // APB2 2分频
53     RCC->CFGR |= (2<<22);           // PLL输出时钟3分频后输出给USB:120MHz/3=40MHz
54     RCC->CFGR |= (7<<24);           // PLL输出时钟2分频后输出到MCO
55     RCC->CFGR |= (2<<0);            // 选择PLL输出用作系统时钟
56     while(0 == (RCC->CFGR & (2<<2)));   // 等待PLL输出用作系统时钟稳定
57 
58     update_systemclock();
59     update_ahb_clock();
60     update_apb1_clock();
61     update_apb2_clock();
62 }
63 
update_systemclock(void)64 static void update_systemclock(void)
65 {
66     uint32_t tmpreg = 0U, prediv = 0U, pllclk = 0U, pllmul = 0U;
67     uint32_t sysclockfreq = HSI_VALUE;
68 
69     tmpreg = RCC->CFGR;
70     /* 获取系统时钟源 */
71     switch(tmpreg & RCC_CFGR_SWS_MASK)
72     {
73         case RCC_SYSCLKSOURCE_STATUS_HSI:
74         {
75             sysclockfreq = HSI_VALUE;
76             break;
77         }
78         case RCC_SYSCLKSOURCE_STATUS_HSE:
79         {
80             sysclockfreq = HSE_VALUE;
81             break;
82         }
83         case RCC_SYSCLKSOURCE_STATUS_LSI:
84         {
85             sysclockfreq = LSI_VALUE;
86             break;
87         }
88         case RCC_SYSCLKSOURCE_STATUS_PLLCLK:
89         {
90             /* 获取PLL的输入时钟源 */
91             if(RCC->PLLCFGR&0x01)       // HSE用作PLL的输入时钟
92             {
93                 if(RCC->PLLCFGR&0x02)   // HSE二分频后输入给PLL
94                 {
95                     pllclk = HSE_VALUE>>1;
96                 }
97                 else                    // HSE部分变频直接输出给PLL
98                 {
99                     pllclk = HSE_VALUE;
100                 }
101             }
102             else    // HSI用作PLL的输入时钟
103             {
104                 pllclk = HSI_VALUE;
105             }
106             prediv = (RCC->PLLCFGR>>8)&0x07;    // PLL的分频系数:PLLCFGR[10:8]
107             pllmul = (RCC->PLLCFGR>>16)&0x7F;   // PLL的倍频系数: PLLCFGR[22:16]
108             sysclockfreq = pllclk * (pllmul+1) / (prediv+1);
109 
110             break;
111         }
112         default:break;
113     }
114 
115     SystemClockFreq = sysclockfreq;
116 }
117 
update_ahb_clock(void)118 static void update_ahb_clock(void)
119 {
120     uint32_t tmpreg = RCC->CFGR;
121     uint8_t hpre = (tmpreg>>4)&0x0F;
122     if((hpre&0x08) == 0)   // 不分频
123         AHBClockFreq = SystemClockFreq;
124     else
125     {
126         hpre = (hpre&0x07) + 1;
127         AHBClockFreq = SystemClockFreq>>hpre;
128     }
129 }
130 
update_apb1_clock(void)131 static void update_apb1_clock(void)
132 {
133     uint32_t tmpreg = RCC->CFGR;
134     uint8_t ppre1 = (tmpreg>>8)&0x0F;
135     if((ppre1&0x04) == 0)   // 不分频
136         APB1ClockFreq = AHBClockFreq;
137     else
138     {
139         ppre1 = (ppre1&0x03) + 1;
140         APB1ClockFreq = AHBClockFreq>>ppre1;
141     }
142 }
143 
update_apb2_clock(void)144 static void update_apb2_clock(void)
145 {
146     uint32_t tmpreg = RCC->CFGR;
147     uint8_t ppre2 = (tmpreg>>11)&0x0F;
148     if((ppre2&0x04) == 0)   // 不分频
149         APB2ClockFreq = AHBClockFreq;
150     else
151     {
152         ppre2 = (ppre2&0x03) + 1;
153         APB2ClockFreq = AHBClockFreq>>ppre2;
154     }
155 }
156 
HAL_GetSysClockFreq(void)157 uint32_t HAL_GetSysClockFreq(void)
158 {
159     return SystemClockFreq;
160 }
161 
HAL_Get_AHB_Clock(void)162 uint32_t HAL_Get_AHB_Clock(void)
163 {
164     return AHBClockFreq;
165 }
166 
HAL_Get_APB1_Clock(void)167 uint32_t HAL_Get_APB1_Clock(void)
168 {
169     return APB1ClockFreq;
170 }
171 
HAL_Get_APB2_Clock(void)172 uint32_t HAL_Get_APB2_Clock(void)
173 {
174     return APB2ClockFreq;
175 }
176 
177