提交 eecd8b89 编写于 作者: tglingli's avatar tglingli

doc: 添加RCC配置说明

上级 b11a5b73
---
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 就需要对应调整分频倍频参数。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册