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)22void 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)64static 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)118static 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)131static 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)144static 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)157uint32_t HAL_GetSysClockFreq(void) 158 { 159 return SystemClockFreq; 160 } 161 HAL_Get_AHB_Clock(void)162uint32_t HAL_Get_AHB_Clock(void) 163 { 164 return AHBClockFreq; 165 } 166 HAL_Get_APB1_Clock(void)167uint32_t HAL_Get_APB1_Clock(void) 168 { 169 return APB1ClockFreq; 170 } 171 HAL_Get_APB2_Clock(void)172uint32_t HAL_Get_APB2_Clock(void) 173 { 174 return APB2ClockFreq; 175 } 176 177