diff --git "a/Documents/01_\347\263\273\347\273\237\346\227\266\351\222\237\345\210\235\345\247\213\345\214\226.md" "b/Documents/01_\347\263\273\347\273\237\346\227\266\351\222\237\345\210\235\345\247\213\345\214\226.md" new file mode 100644 index 0000000000000000000000000000000000000000..b7d8bd8e6678486708f4624812f680cac5799fd9 --- /dev/null +++ "b/Documents/01_\347\263\273\347\273\237\346\227\266\351\222\237\345\210\235\345\247\213\345\214\226.md" @@ -0,0 +1,164 @@ +--- +title: 系统时钟初始化 +categories: [ch32v307, peripheral] +tags: [risc-v] +date: 2022-10-24 20:24:00 +author: 唐国林 +--- + +## 系统启动流程 + +```mermaid + +flowchart LR + A(startup.s) --> B(SystemInit) --> C(SetSysClock)--> D(SetSysClockTo72_HSE) +``` + +## RCC_TypeDef + +复位和时钟控制结构体定义在 ch32v30x.h 文件的第 533 行。每个寄存器每一位的作用详见[应用手册](../CH32FV2x_V3xRM.PDF)第 3.4 节 + +```c ch32v30x.h +typedef struct +{ + __IO uint32_t CTLR; // 时钟控制寄存器 + __IO uint32_t CFGR0; // 时钟配置寄存器0 + __IO uint32_t INTR; // 时钟中断寄存器 + __IO uint32_t APB2PRSTR; // APB2外设复位寄存器 + __IO uint32_t APB1PRSTR; // APB1外设复位寄存器 + __IO uint32_t AHBPCENR; // AHB外设时钟使能寄存器 + __IO uint32_t APB2PCENR; // APB2外设时钟全能寄存器 + __IO uint32_t APB1PCENR; // APB1外设时钟使能寄存器 + __IO uint32_t BDCTLR; // 后备域控制寄存器 + __IO uint32_t RSTSCKR; // 控制/状态寄存器 + + __IO uint32_t AHBRSTR; // AHB外设复位寄存器 + __IO uint32_t CFGR2; // 时钟配置寄存器2 +} RCC_TypeDef; +``` + +## SystemInit + +```c system_ch32v307.c +void SystemInit (void) +{ + // 使能HSI振荡器,复位时该们已由硬件位1 + RCC->CTLR |= (uint32_t)0x00000001; + +#ifdef CH32V30x_D8C + // 选择内部时钟源为系统时钟,所有外设时钟不分频,不对外输出时钟 + RCC->CFGR0 &= (uint32_t)0xF8FF0000; +#else + RCC->CFGR0 &= (uint32_t)0xF0FF0000; +#endif + + // 关闭PLL时钟,关闭HSE振荡器,不旁路外部高速晶体 + RCC->CTLR &= (uint32_t)0xFEF6FFFF; + // 不旁路外部高速晶体 + RCC->CTLR &= (uint32_t)0xFFFBFFFF; + // HSI作为PLL的时钟源,PLL倍频后输出 + RCC->CFGR0 &= (uint32_t)0xFF80FFFF; + +#ifdef CH32V30x_D8C + // 关闭PLL3时钟,关闭PLL时钟,PLL时钟未锁定 + RCC->CTLR &= (uint32_t)0xEBFFFFFF; + // 清除时钟就绪中断标志 + RCC->INTR = 0x00FF0000; + RCC->CFGR2 = 0x00000000; +#else + RCC->INTR = 0x009F0000; +#endif + SetSysClock(); +} +``` + +## SetSysClockTo72_HE + +```c system_ch32v30x.c +static void SetSysClockTo72_HSE(void) +{ + __IO uint32_t StartUpCounter = 0, HSEStatus = 0; + // 使能HSE振荡器 + RCC->CTLR |= ((uint32_t)RCC_HSEON); + + // 循环等外部时钟就绪,外部时钟就绪超时也会退出 + do + { + HSEStatus = RCC->CTLR & RCC_HSERDY; + StartUpCounter++; + } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT)); + + if ((RCC->CTLR & RCC_HSERDY) != RESET) + { + HSEStatus = (uint32_t)0x01; + } + else + { + HSEStatus = (uint32_t)0x00; + } + + if (HSEStatus == (uint32_t)0x01) + { + /* HCLK = SYSCLK */ + RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1; + /* PCLK2 = HCLK */ + RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1; + /* PCLK1 = HCLK */ + RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2; + + /* PLL configuration: PLLCLK = HSE * 9 = 72 MHz */ + RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE | + RCC_PLLMULL)); + +#ifdef CH32V30x_D8 + RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL9); +#else + RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL9_EXTEN); +#endif + + /* Enable PLL */ + RCC->CTLR |= RCC_PLLON; + /* Wait till PLL is ready */ + while((RCC->CTLR & RCC_PLLRDY) == 0) + { + } + /* Select PLL as system clock source */ + RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW)); + RCC->CFGR0 |= (uint32_t)RCC_SW_PLL; + /* Wait till PLL is used as system clock source */ + while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08) + { + } + } + else + { + /* + * If HSE fails to start-up, the application will have wrong clock + * configuration. User can add here some code to deal with this error + */ + } +} +``` + +## 如何修改系统时钟 + +解注 system_ch32v30x.c 中 18 行开始的系统时钟频率定义 + +```c system_ch32v30x.c +//#define SYSCLK_FREQ_HSE HSE_VALUE +//#define SYSCLK_FREQ_48MHz_HSE 48000000 +//#define SYSCLK_FREQ_56MHz_HSE 56000000 +#define SYSCLK_FREQ_72MHz_HSE 72000000 +//#define SYSCLK_FREQ_96MHz_HSE 96000000 +//#define SYSCLK_FREQ_120MHz_HSE 120000000 +//#define SYSCLK_FREQ_144MHz_HSE 144000000 +//#define SYSCLK_FREQ_HSI HSI_VALUE +//#define SYSCLK_FREQ_48MHz_HSI 48000000 +//#define SYSCLK_FREQ_56MHz_HSI 56000000 +//#define SYSCLK_FREQ_72MHz_HSI 72000000 +//#define SYSCLK_FREQ_96MHz_HSI 96000000 +//#define SYSCLK_FREQ_120MHz_HSI 120000000 +//#define SYSCLK_FREQ_144MHz_HSI 144000000 +``` + +库文件是在外部晶振为 8M 的前提下进行配置的,如果外部晶振不是 8M 就需要对应调整分频倍频参数。