IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> [HAL] STM32F407ZG HAL库配置过程 时钟系统 -> 正文阅读

[嵌入式][HAL] STM32F407ZG HAL库配置过程 时钟系统

硬件设计

时钟源构成

STM32中有5个最重要的时钟源,分别为HSIHSELSILSE和PLL。其中PLL实际分为两个时钟源,分别为主PLL和专用PLL。五种时钟源有一下两种分类方式:

分类方法\类别高速时钟源/外部时钟源低速时钟源/内部时钟源
时钟频率HSI HSE PLLLSI LSE
来源HSE LSEHSI LSI PLL

时钟源详细信息

名称频率功能
LSI低速内部时钟32kHz左右独立看门狗、自动唤醒单元
LSE低速外部时钟32.768kHzRTC时钟源
HSI高速内部时钟16MHz直接作为系统时钟、PPL输入
HSE高速外部时钟4MHz~26MHz直接作为系统时钟、PPL输入

PLL为锁相环倍频输出。STM32F4有两个PLL:

  1. 主PLL(PPL)由HSE或者HSI提供时钟信号,并具有两个不同的输出时钟。第一个输出PLLP用于生成高速的系统时钟(最高168MHz);第二个输出PLLQ用于生成USB OTG FS的时钟(48MHz)、随机数发生器的时钟和SDIO时钟。
  2. 专用PPL(PPLI2S)用于生成精准时钟,从而在I2S接口实现高品质音频性能

锁相环是一种利用反馈控制原理实现相位和频率同步的技术,作用是将电路输出的时钟与其外部的参考时钟保持同步。

主PLL时钟输出PLLP的计算方法

主PLL时钟的时钟源需要先经过一个分频系数为M的分频器,然后经过倍频系数为N的倍频器,之后经过一个分频系数为P(输出PLLP)或者Q(输出PLLQ)的分频器分频后,生成最终的主PLL时钟。
P L L = F R E Q ? N P ? Q PLL=\frac{FREQ*N}{P*Q} PLL=P?QFREQ?N?
其中FREQ为时钟源时钟频率。若时钟频率为8MHz,设置分频器M=8,倍频器倍频系数N=336,分频器分频系数P=2,那么主PPL生成的高速时钟PLLP为168MHz。

若选择HSE作为PLL时钟源,SYSCLK时钟源为PLL,那么SYSCLK时钟为168MHz。

系统及外设时钟

看门狗时钟

看门狗时钟源只能是低速的LSI时钟。

RTC时钟源

RTC时钟源可以选择LSI、LSE以及HSE分频后的时钟。HSE分频系数为2~31。

STM32F4输出时钟MCO1、MCO2

MCO1是向芯片的PA8引脚输出时钟。它的时钟来源为HSI、LSE、HSE和PLL时钟。

MCO2是向芯片的PC9引脚输出时钟。它的时钟来源为HSE、PLL、SYSCLK以及PLLI2S时钟。

MCO输出时钟频率最大不超过100MHz。

系统时钟SYSCLK

SYSCLK有三个时钟来源HSI、HSE和PLL。在实际应用中,一般采用PLL作为SYSCLK时钟源。

以太网PTP时钟、AHB时钟、APB1低速时钟、APB2高速时钟

四个时钟的时钟源均为SYSCLK系统时钟。其中以太网PTP时钟使用系统时钟,AHB、APB1和APB2由SYSCLK分频而来。AHB最大时钟频率为168MHz,APB1最大时钟频率为42MHz,APB2最大时钟频率为84MHz。

I2S时钟源

I2S时钟源源于PLLI2S或者映射到I2S_CKIN引脚为外部时钟。处于音质考虑,I2S对时钟精度要求很高。

STM32F4内部以太网MAC时钟

USB OTG HS(60MHz)是中欧

由外部PHY提供。

Cortex系统定时器Systick时钟

Systick时钟源可以是AHB时钟HCLK或HCLK的8分频。

软件设计

系统启动后,程序会先执行HAL库定义的SystemInit函数:

void SystemInit(void)
{
 /* FPU settings ------------------------------------------------------------*/
 #if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
    SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2)); /* set CP10 and CP11 Full Access */
 #endif
 /* Reset the RCC clock configuration to the default reset state ------------*/
 /* Set HSION bit */
 RCC->CR |= (uint32_t)0x00000001;
 /* Reset CFGR register */
 RCC->CFGR = 0x00000000;
 /* Reset HSEON, CSSON and PLLON bits */
 RCC->CR &= (uint32_t)0xFEF6FFFF;
 /* Reset PLLCFGR register */
 RCC->PLLCFGR = 0x24003010;
 /* Reset HSEBYP bit */
 RCC->CR &= (uint32_t)0xFFFBFFFF;
 /* Disable all interrupts */
 RCC->CIR = 0x00000000;
#if defined (DATA_IN_ExtSRAM) || defined (DATA_IN_ExtSDRAM)
 SystemInit_ExtMemCtl(); 
#endif /* DATA_IN_ExtSRAM || DATA_IN_ExtSDRAM */
 /* Configure the Vector Table location add offset address ------------------*/
#ifdef VECT_TAB_SRAM
 SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal 
SRAM */
#else
 SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in 
Internal FLASH */
#endif
}

SystemInit主要做了一下四个方面的工作:

  1. FPU(浮点运算单元)设置
  2. 复位RCC时钟,配置为默认复位值(默认开启了HSI)
  3. 外部储存器配置
  4. 中断向量表地址配置

SystemInit函数并没有进行时钟的配置,因此需要自行编写时钟初始化函数Clock_Init:

void Clock_Init(uint32_t plln, uint32_t pllm, uint32_t pllp, uint32_t pllq)
{
    HAL_StatusTypeDef ret = HAL_OK;
    RCC_OscInitTypeDef RCC_OscConfig;
    RCC_ClkInitTypeDef RCC_ClkConfig;
    
    __HAL_RCC_PWR_CLK_ENABLE();  // Enable clock of power
    __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
    RCC_OscConfig.OscillatorType = RCC_OSCILLATORTYPE_HSE;  // Set HSE as clock source
    RCC_OscConfig.HSEState = RCC_HSE_ON;  // Enable HSE
    RCC_OscConfig.PLL.PLLState = RCC_PLL_ON;  // Enable PLL
    RCC_OscConfig.PLL.PLLSource = RCC_PLLSOURCE_HSE;  // Set HSE as source of PLL
    RCC_OscConfig.PLL.PLLM = pllm;  // Set M as pllm, which in range 2 to 63
    RCC_OscConfig.PLL.PLLN = plln;  // Set N as plln, which in range 64 to 432
    RCC_OscConfig.PLL.PLLP = pllp;  // Set P as pllp, which in 2, 4, 6 and 8
    RCC_OscConfig.PLL.PLLQ = pllq;  // Set Q as pllq, which in range 2 to 15
    ret = HAL_RCC_OscConfig(&RCC_OscConfig);  // Config RCC
    if(ret != HAL_OK) while(1);  // Error
    // Config PLL as system clock source and config HCLK, PCLK1 and PCLK2
    RCC_ClkConfig.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
    RCC_ClkConfig.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;  // Config PLL as system clock source
    RCC_ClkConfig.AHBCLKDivider = RCC_SYSCLK_DIV1;  // AHB Divider 1
    RCC_ClkConfig.APB1CLKDivider = RCC_HCLK_DIV4;  // APB1 Divider 4
    RCC_ClkCOnfig.APB2CLKDivider = RCC_HCLK_DIV2;  // APB2 Divider 2
    ret=HAL_RCC_ClockConfig(&RCC_ClkInitStructure,FLASH_LATENCY_5);  // Config RCC Clock
	if(ret != HAL_OK) while(1);  // Error
    //  STM32F405x/407x/415x/417x Z 版本的器件支持预取功能
    if (HAL_GetREVID() == 0x1001)
	{
		__HAL_FLASH_PREFETCH_BUFFER_ENABLE(); //使能 flash 预取
	}
}

Clock_Init的作用是进行时钟系统配置,不仅配置了PLL相关参数确定SYSCLK值,还配置了AHB、APB1和APB2的分频系数,也就是确定了HCLK、PCLK1和PCLK2的时钟。

使用HAL库配置STM32F407时钟系统的一般步骤:

  1. 使能PWR时钟:调用函数__HAL_RCC_PWR_CLK_ENABLE();
  2. 设置调压器输出电压级别:调用函数__HAL_PWR_VOLTAGESCALING_CONFIG();
  3. 选择是否开始Over-Driver功能:调用函数__HAL_PWREx_EnableOverDrive();
  4. 配置时钟源相关参数:嗲用函数__HAL_RCC_OscConfig();
  5. 配置系统时钟源以及AHB、APB1和APB2的分频系数:调用函数HAL_RCC_ClockConfig()。

步骤4和步骤5是时钟系统配置的关键步骤。对于步骤4,我们嗲调用HAL_RCC_OscCOnfig()函数进行时钟的配置。该函数在stm32f4xx_hal_rcc.h中声明,在stm32f4xx_hal_rcc.c中定义。其只有一个入口参数,为结构体RCC_OscInitTypeDef类型指针,其定义为:

typedef struct
{
 uint32_t OscillatorType; //需要选择配置的振荡器类型
 uint32_t HSEState; //HSE 状态
 uint32_t LSEState; //LSE 状态
 uint32_t HSIState; //HIS 状态
 uint32_t HSICalibrationValue; //HIS 校准值
 uint32_t LSIState; //LSI 状态 
 RCC_PLLInitTypeDef PLL; //PLL 配置
}RCC_OscInitTypeDef;

对于这个结构体,前几个参数用来选择配置的振荡器类型。例如我们要开启HSE,那么我们会设置OscillatorType成员的值为RCC_OSCILLATORTYPE_HSE,然后配置HSEState的值为RCC_HSE_ON来开启HSE。对于时钟源HSI、LSI和LSE配置方法类似。这个结构体中另一个重要的成员为RCC_PLLInitTypeDef PLL,它的作用是配置PLL相关参数,其定义为:

typedef struct
{
    uint32_t PLLState; //PLL 状态
 	uint32_t PLLSource; //PLL 时钟源
	uint32_t PLLM; //PLL 分频系数 M
 	uint32_t PLLN; //PLL 倍频系数 N
 	uint32_t PLLP; //PLL 分频系数 P
 	uint32_t PLLQ; //PLL 分频系数 Q
}RCC_PLLInitTypeDef;

这个结构体是用来配置PLL时钟源以及相关分频倍频参数。

在配置好RCC_OscInitTypeDef结构体后,可以通过HAL_RCC_OscConfig()函数初始化时钟系统。而设置好PLL的时钟频率后,需要使用HAL_RCC_ClockConfig()函数来配置时钟频率。这个函数有两个入口参数:第一个入口参数为RCC_ClkInitTypeDef结构体指针类型参数,用来设置SYSCLK时钟源以及AHB、APB1和APB2的分频系数;第二个参数FLatency用于配置FLASH延迟。

RCC_ClkInitTypeDef结构体中有如下几个参数:ClockType、SYSCLKSource、AHBCLKDivider、APB1CLKDivider和APB2CLKDivider,分别为时钟类型、SYSCLK时钟源、AHB分频系数、APB1分频系数以及APB2分频系数。

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-11-16 18:59:57  更:2021-11-16 19:00:42 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 8:57:58-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码