一、认识时钟树
二、配置系统时钟
三、总结
时钟(Clock)在数字电路和计算机系统中是一种周期性的信号,用于同步和协调系统中各个部分的操作。时钟信号在单片机中是非常重要的,它指导着各个组件的工作,确保它们在正确的时间执行相应的任务。时钟信号通常是一个方波信号,具有固定的周期和占空比。
时钟树(Clock Tree)是指在数字系统或芯片中,将一个主时钟信号分配和扩展到整个系统中各个模块和部分的一种层次结构。时钟树的目的是确保系统中所有的时钟域都能够按照规定的时序要求同步运行。时钟树通常包括以下关键元素:
主时钟源(Clock Source): 时钟树的起点通常是一个主时钟源,这可以是外部晶振、振荡器或其他时钟源。
时钟分频器(Clock Divider): 时钟分频器用于将主时钟信号分频,以产生其他模块或部分所需的时钟频率。这样可以根据需要调整时钟频率,使得不同的部分能够以不同的速度运行。
时钟缓冲器(Clock Buffer): 时钟缓冲器用于放大和驱动时钟信号,确保时钟信号能够准确地传播到系统中的各个部分。
时钟分配网络(Clock Distribution Network): 时钟分配网络将时钟信号传送到系统中的各个模块。这通常包括时钟线路、时钟树分支等。
时钟树的设计需要考虑时序要求、功耗、噪声和电磁兼容性等因素。精心设计的时钟树能够确保系统各个部分协同工作,提高系统的稳定性和性能。在数字集成电路中,时钟树的设计是一个复杂而关键的任务。
H、L、S、I、E代表了一些常见的缩写,通常与单片机或者数字电路中的时钟、速度和内外部资源有关。
含义:
H:high
L:low
S:speed
I:internal
E:external
分频器和倍频系数是在时钟系统中常见的概念,用于调整时钟信号的频率。让我们更详细地了解这两个概念:
分频器(Divider):
倍频系数(Multiplier):
在实际应用中,分频器和倍频系数的配置对于调整系统时钟至关重要,特别是在使用锁相环(PLL)等技术进行时钟调整时。在微控制器或数字系统中,通过配置分频器和倍频系数,可以灵活地适应不同的硬件要求,以满足外设的时钟需求,同时确保系统时钟的稳定性和准确性。
总的来说,分频器和倍频系数是时钟系统中的两个关键元素,通过它们的配置,可以实现对时钟频率的灵活调整,以满足不同应用场景的需求。
锁相环(Phase-Locked Loop,PLL)是一种控制系统,用于调整输出信号的频率和相位,使其与输入信号保持特定的关系。在PLL中,常用的表达式是F/M*N/P,其中:
F:
M:
N:
P:
这个表达式的含义是,通过调整M、N和P的值,可以控制输出频率F。下面是更详细的解释:
输入信号:
反馈:
输出频率:
具体来说,输出频率F可以通过以下公式计算:
F = F 输入 × M × N P F = \dfrac{F_{\text{输入}} \times M \times N}{P} F=PF输入×M×N
在实际应用中,通过调整M、N和P的值,可以实现对输出频率的精确控制。这种调整通常用于微控制器、射频电路、时钟产生器等应用中,以满足系统对不同频率的需求。
分频器是一种电路或模块,用于将输入的时钟信号分频,即减小其频率。这是在数字电路中常见的一种功能,它允许在系统中使用不同频率的时钟信号,以适应不同的模块和外设的工作需求。分频器通常通过使用可编程的分频系数,将输入时钟信号的频率降低到所需的水平。
以下是分频器的一些关键概念:
分频系数(Divider Ratio):
整数分频和分数分频:
分频器的应用:
分频器类型:
总体而言,分频器是数字电路中的重要组件,允许系统中的不同部分以不同的时钟频率运行,以满足不同模块的工作要求。在时钟系统设计中,分频器起到了关键的作用,有助于优化电路的性能和功耗。
这两个概念涉及到STM32微控制器的时钟管理和安全特性。让我们更详细地了解它们:
时钟安全系统(Clock Security System,CSS):
自由运行时钟(Free Running Clock,FCLK):
这两个特性都是STM32系列微控制器提供的一些高级时钟管理和安全功能,有助于提高系统的可靠性和稳定性。在使用这些特性时,建议仔细查阅相关的STM32芯片手册和参考资料,以确保正确配置和使用。
高速时钟源OSC(HSE、HSI):
锁相环PLL:
HAL_RCC_OscConfig()
配置时钟源,选择 HSE 或 HSI 以及其他相关配置。分频系数:
HAL_RCC_ClockConfig()
进行系统时钟、总线和外设时钟的配置。外设时钟使能:
__HAL_RCC_PPP_CLK_ENABLE()
使能外设的时钟。扩展外设时钟(RTC/ADC/USB):
HAL_RCCEx_PeriphCLKConfig()
扩展外设的时钟。内核时钟:
具体时钟频率设置:
低速时钟源OSC(LSI、LSE):
IWDG、RTC:
总体而言,上述步骤涵盖了从时钟源的选择、通过PLL调整时钟频率、配置各个时钟分频系数,到最终配置系统总线和外设时钟的过程。在具体的应用中,需要根据芯片手册和硬件设计的要求进行调整。
PLLXTPRE:
PLLSRC:
PLLMUL:
PLLCLK:
SYSCLK:
HAL_RCC_ClockConfig()
配置PLL、分频因子等,以设置SYSCLK的频率。HCLK:
HAL_RCC_ClockConfig()
设置HCLK的频率。Cortex系统时钟:
滴答定时器:
HAL_InitTick()
等函数进行配置。FCLK:
TIMXCLK:
PCLK:
HAL_RCC_ClockConfig()
配置APB1和APB2的分频因子。I2SCLK:
USBCLK:
RTCCLK:
RC-IWDGCLK:
MCO:
这些概念的详细理解有助于在STM32CubeMX或其他开发环境中正确配置时钟和时序。请根据具体的硬件和应用需求,在配置时钟时参考芯片手册和相关文档。
为了让 FSUSB 满足 48MHz 把 Main PLL 的倍频系数配置成X384 而不是X360这样系统时钟就超频了
首先,为了让 FSUSB 满足 48MHz,我们需要将 Main PLL 的倍频系数配置为 X384。以下是一个示例代码,以确保系统时钟的配置满足 USB 的需求。
在这里,我将使用 HAL 库的一些函数作为例子,实际的代码可能会因为使用的具体库和芯片型号而有所不同。以下是一个基本的流程:
#include "stm32f4xx_hal.h"
void SystemClock_Config(void);
void Error_Handler(void);
int main(void)
{
HAL_Init();
// 配置系统时钟
SystemClock_Config();
// 初始化USB外设(这里使用USB FS作为示例)
HAL_PCD_MspInit(&hpcd_USB_FS);
HAL_PCD_Init(&hpcd_USB_FS);
// 进行其他初始化和应用程序代码
while (1)
{
// 主循环
}
}
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
// 配置 HSE 为 8MHz 外部晶振
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 8; // 分频系数,原始频率 / 8 = 1MHz
RCC_OscInitStruct.PLL.PLLN = 384; // 倍频系数,1MHz * 384 = 384MHz
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; // 384MHz / 2 = 192MHz (SYSCLK)
RCC_OscInitStruct.PLL.PLLQ = 8; // 分频系数,384MHz / 8 = 48MHz (USB频率)
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_3) != HAL_OK)
{
Error_Handler();
}
// 更新系统时钟配置
SystemCoreClockUpdate();
}
void Error_Handler(void)
{
while (1)
{
// 处理错误
}
}
这个代码片段中,关键的部分是 RCC_OscInitStruct
和 RCC_ClkInitStruct
结构体的配置,特别是 PLL.PLLN
的值设置为 384,以满足 48MHz 的 USB 频率要求。这个例程假设使用的是 STM32Cube HAL 库,并在 main()
函数中调用了 HAL_Init()
。实际上,具体的配置可能需要根据你的硬件设计和使用的芯片型号进行调整。在编写代码时,请参考相关的芯片手册和硬件设计文档。
配置HSE_VALUE:
stm32xxxx_hal_conf.h
文件中,你需要设置 HSE_VALUE
宏定义,用于告诉HAL库外部晶振的频率。这是时钟系统的基础,确保HAL库能正确配置时钟。调用SystemInit()函数(可选):
SystemInit()
函数通常包含在启动文件中,用于执行一些基本的系统初始化。在这里,它可以执行一些硬件的初始化,例如设置向量表和启用FPU等。这一步通常是由编译器自动调用的,你只需确保启动文件正确。选择时钟源,配置PLL:
HAL_RCC_OscConfig()
函数配置时钟源和PLL。RCC_OscInitTypeDef
结构体,可以指定HSE或HSI作为时钟源,并配置PLL的倍频系数和分频系数。RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 8; // 时钟源分频
RCC_OscInitStruct.PLL.PLLN = 336; // PLL倍频
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; // PLL分频
RCC_OscInitStruct.PLL.PLLQ = 7; // USB OTG FS, SDIO and RNG分频
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
选择系统时钟源,配置总线分频器:
HAL_RCC_ClockConfig()
函数配置系统时钟和总线分频器。RCC_ClkInitTypeDef
结构体,可以选择PLL为系统时钟源,并配置AHB、APB1、APB2等分频系数。RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
{
Error_Handler();
}
配置扩展外设时钟(可选):
HAL_RCCEx_PeriphCLKConfig()
函数配置扩展外设时钟,如RTC、ADC、USB等。RCC_PeriphCLKInitTypeDef PeriphClkInitStruct;
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_USB | RCC_PERIPHCLK_RTC;
PeriphClkInitStruct.UsbClockSelection = RCC_USBCLKSOURCE_PLL;
PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSE;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
{
Error_Handler();
}
这些步骤涵盖了从外部晶振到PLL配置,再到系统时钟和总线分频的整个过程。确保在配置时钟时参考芯片手册和硬件设计文档,以确保满足具体硬件的要求。
在HAL库中,使能和失能外设时钟的方法通常使用了一些预定义的宏和函数。以下是对这两个操作的分析:
使能外设时钟:
__HAL_RCC_XXX_CLK_ENABLE()
的宏,其中 XXX
表示具体的外设(比如GPIOA、USART1等)。失能外设时钟:
__HAL_RCC_XXX_CLK_DISABLE()
的宏,其中 XXX
表示具体的外设。这些宏实际上是对底层寄存器的访问进行了封装,方便用户使用。例如,对于GPIOA的时钟使能:
__HAL_RCC_GPIOA_CLK_ENABLE(); // 使能 GPIOA 时钟
__HAL_RCC_GPIOA_CLK_DISABLE(); // 禁止 GPIOA 时钟
上述操作会调用底层的函数,具体实现会涉及到对相应寄存器的设置或清零。这些宏和函数的实现在HAL库的源代码中,用户一般无需直接关注底层实现,只需要正确使用这些宏即可。
这种封装提高了代码的可读性和可维护性,同时确保了对寄存器的操作是正确的。