打印
[STM32F4]

STM32F407ZG HAL库配置过程 时钟系统

[复制链接]
436|20
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
kqh11a|  楼主 | 2023-1-26 14:01 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
硬件设计时钟源构成

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

时钟源详细信息

使用特权

评论回复
沙发
kqh11a|  楼主 | 2023-1-26 14:04 | 只看该作者
PLL为锁相环倍频输出。STM32F4有两个PLL:

主PLL(PPL)由HSE或者HSI提供时钟信号,并具有两个不同的输出时钟。第一个输出PLLP用于生成高速的系统时钟(最高168MHz);第二个输出PLLQ用于生成USB OTG FS的时钟(48MHz)、随机数发生器的时钟和SDIO时钟。

使用特权

评论回复
板凳
kqh11a|  楼主 | 2023-1-26 14:07 | 只看该作者
专用PPL(PPLI2S)用于生成精准时钟,从而在I2S接口实现高品质音频性能
锁相环是一种利用反馈控制原理实现相位和频率同步的技术,作用是将电路输出的时钟与其外部的参考时钟保持同步。

使用特权

评论回复
地板
kqh11a|  楼主 | 2023-1-26 14:07 | 只看该作者
主PLL时钟输出PLLP的计算方法
主PLL时钟的时钟源需要先经过一个分频系数为M的分频器,然后经过倍频系数为N的倍频器,之后经过一个分频系数为P(输出PLLP)或者Q(输出PLLQ)的分频器分频后,生成最终的主PLL时钟。

其中FREQ为时钟源时钟频率。若时钟频率为8MHz,设置分频器M=8,倍频器倍频系数N=336,分频器分频系数P=2,那么主PPL生成的高速时钟PLLP为168MHz。

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

使用特权

评论回复
5
kqh11a|  楼主 | 2023-1-26 14:17 | 只看该作者
系统及外设时钟
看门狗时钟
看门狗时钟源只能是低速的LSI时钟。

使用特权

评论回复
6
kqh11a|  楼主 | 2023-1-26 14:19 | 只看该作者
RTC时钟源
RTC时钟源可以选择LSI、LSE以及HSE分频后的时钟。HSE分频系数为2~31。

使用特权

评论回复
7
kqh11a|  楼主 | 2023-1-26 15:31 | 只看该作者
STM32F4输出时钟MCO1、MCO2
MCO1是向芯片的PA8引脚输出时钟。它的时钟来源为HSI、LSE、HSE和PLL时钟。

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

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

使用特权

评论回复
8
kqh11a|  楼主 | 2023-1-26 15:32 | 只看该作者
系统时钟SYSCLK
SYSCLK有三个时钟来源HSI、HSE和PLL。在实际应用中,一般采用PLL作为SYSCLK时钟源。

使用特权

评论回复
9
kqh11a|  楼主 | 2023-1-26 15:33 | 只看该作者
以太网PTP时钟、AHB时钟、APB1低速时钟、APB2高速时钟
四个时钟的时钟源均为SYSCLK系统时钟。其中以太网PTP时钟使用系统时钟,AHB、APB1和APB2由SYSCLK分频而来。AHB最大时钟频率为168MHz,APB1最大时钟频率为42MHz,APB2最大时钟频率为84MHz。

使用特权

评论回复
10
kqh11a|  楼主 | 2023-1-26 15:42 | 只看该作者
I2S时钟源
I2S时钟源源于PLLI2S或者映射到I2S_CKIN引脚为外部时钟。处于音质考虑,I2S对时钟精度要求很高。

使用特权

评论回复
11
kqh11a|  楼主 | 2023-1-26 15:43 | 只看该作者
STM32F4内部以太网MAC时钟
USB OTG HS(60MHz)是中欧
由外部PHY提供。

使用特权

评论回复
12
kqh11a|  楼主 | 2023-1-26 15:44 | 只看该作者
Cortex系统定时器Systick时钟
Systick时钟源可以是AHB时钟HCLK或HCLK的8分频。

使用特权

评论回复
13
kqh11a|  楼主 | 2023-1-26 15:45 | 只看该作者
软件设计
系统启动后,程序会先执行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
}

使用特权

评论回复
14
kqh11a|  楼主 | 2023-1-26 15:50 | 只看该作者
SystemInit主要做了一下四个方面的工作:

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

使用特权

评论回复
15
kqh11a|  楼主 | 2023-1-26 15:51 | 只看该作者
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 预取
        }
}

使用特权

评论回复
16
kqh11a|  楼主 | 2023-1-26 15:52 | 只看该作者
Clock_Init的作用是进行时钟系统配置,不仅配置了PLL相关参数确定SYSCLK值,还配置了AHB、APB1和APB2的分频系数,也就是确定了HCLK、PCLK1和PCLK2的时钟。

使用特权

评论回复
17
kqh11a|  楼主 | 2023-1-26 15:53 | 只看该作者
使用HAL库配置STM32F407时钟系统的一般步骤:

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

使用特权

评论回复
18
kqh11a|  楼主 | 2023-1-26 15:54 | 只看该作者
步骤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;

使用特权

评论回复
19
kqh11a|  楼主 | 2023-1-26 16:03 | 只看该作者
对于这个结构体,前几个参数用来选择配置的振荡器类型。例如我们要开启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;

使用特权

评论回复
20
kqh11a|  楼主 | 2023-1-26 16:05 | 只看该作者
这个结构体是用来配置PLL时钟源以及相关分频倍频参数。

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

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

24

主题

499

帖子

0

粉丝