STM32F407标准库学习笔记-RCC
- rcc.h
typedef struct
{
uint32_t SYSCLK_Frequency; /*!< SYSCLK clock frequency expressed in Hz */
uint32_t HCLK_Frequency; /*!< HCLK clock frequency expressed in Hz */
uint32_t PCLK1_Frequency; /*!< PCLK1 clock frequency expressed in Hz */
uint32_t PCLK2_Frequency; /*!< PCLK2 clock frequency expressed in Hz */
}RCC_ClocksTypeDef;
时钟频率集合
之后有大量宏定义,主要用途有:
时钟源开关、时钟源选择、分/倍频系数、启动标志、中断标志、外设时钟使能
#define RCC_HSE_OFF ((uint8_t)0x00)
#define RCC_LSE_HIGHDRIVE_MODE ((uint8_t)0x01)
#define RCC_PLLSAIDivR_Div16 ((uint32_t)0x00030000)
#define RCC_PLLSource_HSE ((uint32_t)0x00400000)
#define RCC_SYSCLKSource_HSE ((uint32_t)0x00000001)
#define RCC_IT_HSIRDY ((uint8_t)0x04)
#define RCC_AHB1ClockGating_APB1Bridge ((uint32_t)0x00000001)
#define RCC_AHB1Periph_GPIOA ((uint32_t)0x00000001)
函数声明
void RCC_HSEConfig(uint8_t RCC_HSE);
...
- rcc.c
#define RCC_OFFSET (RCC_BASE - PERIPH_BASE)
/* --- CR Register ---*/
/* Alias word address of HSION bit */
#define CR_OFFSET (RCC_OFFSET + 0x00)
#define HSION_BitNumber 0x00
#define CR_HSION_BB (PERIPH_BB_BASE + (CR_OFFSET * 32) + (HSION_BitNumber * 4))
rcc寄存器中各位对应的位带区寄存器地址计算
- 内外时钟\PLL\CSS\MCO配置函数段
void RCC_DeInit(void)
直接使用HSI作为系统时钟;
HSE\PLL相关\CSS\MCO\中断关闭
各总线分频系数设为1
没有改动外设时钟、低速时钟源、RTC
void RCC_HSEConfig(uint8_t RCC_HSE)
{
/* Reset HSEON and HSEBYP bits before configuring the HSE ------------------*/
*(__IO uint8_t *) CR_BYTE3_ADDRESS = RCC_HSE_OFF;
/* Set the new HSE configuration -------------------------------------------*/
*(__IO uint8_t *) CR_BYTE3_ADDRESS = RCC_HSE;
}
HSE配置函数
用于 开 关 旁路 HSE时钟源;
执行中会先复位各位(关闭HSE);
同时会关闭CSS;
打开HSE后应等待HSERDY位置位,以确定HSE工作正常;
被通过PLL用作系统时钟时,HSE不可关闭,应先更换时钟源;
关闭HSE后,HSERDY会在6个时钟周期后复位清零。
ErrorStatus RCC_WaitForHSEStartUp(void)
{
__IO uint32_t startupcounter = 0;
ErrorStatus status = ERROR;
FlagStatus hsestatus = RESET;
/* Wait till HSE is ready and if Time out is reached exit */
do
{
hsestatus = RCC_GetFlagStatus(RCC_FLAG_HSERDY);
startupcounter++;
} while((startupcounter != HSE_STARTUP_TIMEOUT) && (hsestatus == RESET));
if (RCC_GetFlagStatus(RCC_FLAG_HSERDY) != RESET)
{
status = SUCCESS;
}
else
{
status = ERROR;
}
return (status);
}
等待HSE启动函数
借助 RCC_GetFlagStatus(RCC_FLAG_HSERDY); 函数与 do while 循环判断HSE启动状况
使用了标志位状态枚举变量
返回值是错误状态枚举变量
void RCC_AdjustHSICalibrationValue(uint8_t HSICalibrationValue)
HSI时钟矫正函数
可用于根据电压 温度来矫正HSI频率准确度
标准的读 复位 改 写
void RCC_PLLConfig(uint32_t RCC_PLLSource, uint32_t PLLM, uint32_t PLLN, uint32_t PLLP, uint32_t PLLQ)
{
RCC->PLLCFGR = PLLM | (PLLN << 6) | (((PLLP >> 1) -1) << 16) | (RCC_PLLSource) |
(PLLQ << 24);
}
PLL配置函数
选择PLL时钟源,设置一系列分频倍频系数
注意PLLP的计算方法,系数与写入值并非直接对应,需要变化。
推荐 时钟源/PLLM = 2Mhz (1~2M之间)
在PLL关闭时才能生效
void RCC_PLLCmd(FunctionalState NewState)
{
*(__IO uint32_t *) CR_PLLON_BB = (uint32_t)NewState;
}
PLL开关函数
开启PLL后应等待启动完成
后面还有许多模块的PLL时钟配置与开关,大同小异
void RCC_ClockSecuritySystemCmd(FunctionalState NewState)
开启CSS功能
如果HSE发生故障,会主动关闭HSE并且产生一个CSS中断
使得MCU运行紧急操作,并且该中断与M4内核中断相链接。
- 系统\各总线配置函数段
void RCC_SYSCLKConfig(uint32_t RCC_SYSCLKSource)
{
uint32_t tmpreg = 0;
tmpreg = RCC->CFGR;
/* Clear SW[1:0] bits */
tmpreg &= ~RCC_CFGR_SW;
/* Set SW[1:0] bits according to RCC_SYSCLKSource value */
tmpreg |= RCC_SYSCLKSource;
/* Store the new value */
RCC->CFGR = tmpreg;
}
选择sysclk时钟源
配置 RCC->CFGR 的 SW 位;
uint8_t RCC_GetSYSCLKSource(void)
{
return ((uint8_t)(RCC->CFGR & RCC_CFGR_SWS));
}
查询sysclk时钟源
返回 RCC->CFGR 的 SWS 位(bit2~3)
void RCC_HCLKConfig(uint32_t RCC_SYSCLK)
设置AHB总线分频系数,产生HCLK时钟
后面是设置APB总线频率的两个函数,雷同
void RCC_GetClocksFreq(RCC_ClocksTypeDef* RCC_Clocks)
查询 sysclk/hclk/pclk 频率
注意 右移一位=除以2 两位=除以4 ……
构造了一个数组来对应寄存器位值与右移位数
- 外设时钟配置函数段
一系列与I2S、RTC、低功耗、备份寄存器相关的始终设置
一系列总线外设的时钟开关、外设复位、低功耗时钟等 - 中断与标志位管理函数段
void RCC_ITConfig(uint8_t RCC_IT, FunctionalState NewState)
{
if (NewState != DISABLE)
{
/* Perform Byte access to RCC_CIR[14:8] bits to enable the selected interrupts */
*(__IO uint8_t *) CIR_BYTE2_ADDRESS |= RCC_IT;
}
else
{
/* Perform Byte access to RCC_CIR[14:8] bits to disable the selected interrupts */
*(__IO uint8_t *) CIR_BYTE2_ADDRESS &= (uint8_t)~RCC_IT;
}
}
使能特定RCC准备中断
FlagStatus RCC_GetFlagStatus(uint8_t RCC_FLAG)
可以用不同的位段包含不同的信息
比如后五位代表BIT位数
前面代表位于哪个寄存器
RCC_FLAG_HSERDY 0x31 0b110001 0b1=1=RCC_CR 0b10001=17=bit17
获取 RCC准备 标志位
void RCC_ClearFlag(void)
清除各种复位标志
ITStatus RCC_GetITStatus(uint8_t RCC_IT)
检查RCC中断标志位
void RCC_ClearITPendingBit(uint8_t RCC_IT)
复位RCC中断标志