观前提示:函数完整代码在文末,本文梳理了函数HAL_RCC_OscConfig()的主要逻辑和实现方法
f105时钟树详解图
HAL_RCC_OscConfig()
函数介绍:
此函数是一个用于初始化RCC(Reset and Clock Control)振荡器(Oscillators,函数名中Osc为此单词缩写)的函数。它接受一个指向RCC_OscInitTypeDef结构体的指针,结构体的各成员分别包含了RCC振荡器的配置信息。
函数行数为442行,功能性上分为六个部分:
- HSE配置,外部高速时钟
- HSI配置,内部高速时钟
- LSE配置,外部低速时钟
- LSI配置,内部低速时钟
- PLL1配置,锁相环1
- PLL2配置,锁相环2
下文中我们将以功能为线索依次分析此函数
函数分析
HAL_StatusTypeDef HAL_RCC_OscConfig(RCC_OscInitTypeDef *RCC_OscInitStruct)
{
uint32_t tickstart;
uint32_t pll_config;
/* Check Null pointer */
if (RCC_OscInitStruct == NULL)
{
return HAL_ERROR;
}
/* Check the parameters */
assert_param(IS_RCC_OSCILLATORTYPE(RCC_OscInitStruct->OscillatorType));
首先,定义了两个局部变量tickstart和pll_config。
接下来,检查传入的指针RCC_OscInitStruct是否为空,如果为空,则返回HAL_ERROR。
然后,使用assert_param宏来检查RCC_OscInitStruct->OscillatorType参数是否合法。
HSE Configuration部分
if (((RCC_OscInitStruct->OscillatorType) & RCC_OSCILLATORTYPE_HSE) == RCC_OSCILLATORTYPE_HSE)
这行代码通过按位与运算符将RCC_OscInitStruct->OscillatorType
与RCC_OSCILLATORTYPE_HSE
进行按位与操作,并将结果与RCC_OSCILLATORTYPE_HSE
进行比较。如果结果等于RCC_OSCILLATORTYPE_HSE
,则条件成立。这个条件判断语句的目的是检查是否启用了外部高速时钟(HSE)作为振荡器类型。
/* Check the parameters */
assert_param(IS_RCC_HSE(RCC_OscInitStruct->HSEState));
这是一个断言语句,用于检查RCC_OscInitStruct->HSEState
的值是否符合要求。IS_RCC_HSE
是一个宏,用于验证RCC_OscInitStruct->HSEState
是否满足特定的条件。如果断言失败,则会触发断言错误。
if ((__HAL_RCC_GET_SYSCLK_SOURCE() == RCC_SYSCLKSOURCE_STATUS_HSE)
|| ((__HAL_RCC_GET_SYSCLK_SOURCE() == RCC_SYSCLKSOURCE_STATUS_PLLCLK) && (__HAL_RCC_GET_PLL_OSCSOURCE() == RCC_PLLSOURCE_HSE)))
这个条件判断语句检查系统时钟源是否为外部高速时钟(HSE),或者是由HSE驱动的PLL时钟源。如果条件成立,则意味着HSE在系统时钟或PLL时钟源中被使用,此时不允许将其禁用。
if ((__HAL_RCC_GET_FLAG(RCC_FLAG_HSERDY) != RESET) && (RCC_OscInitStruct->HSEState == RCC_HSE_OFF))
{
return HAL_ERROR;
}
这个条件判断语句检查HSE是否已经就绪,并且RCC_OscInitStruct->HSEState
的值为禁用状态(RCC_HSE_OFF
)。如果这两个条件都满足,函数将返回HAL_ERROR
。
__HAL_RCC_HSE_CONFIG(RCC_OscInitStruct->HSEState);
这行代码根据RCC_OscInitStruct->HSEState
的值配置HSE振荡器的状态。__HAL_RCC_HSE_CONFIG
是一个宏,用于设置HSE的状态。
/* Check the HSE State */
if (RCC_OscInitStruct->HSEState != RCC_HSE_OFF)
{
/* Get Start Tick */
tickstart = HAL_GetTick();
/* Wait till HSE is ready */
while (__HAL_RCC_GET_FLAG(RCC_FLAG_HSERDY) == RESET)
{
if ((HAL_GetTick() - tickstart) > HSE_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
}
这部分代码在HSE不是禁用状态时,等待HSE就绪。它使用__HAL_RCC_GET_FLAG
宏来检查HSE是否已经就绪。如果HSE在超时时间内仍未就绪,函数将返回HAL_TIMEOUT
。
else
{
/* Get Start Tick */
tickstart = HAL_GetTick();
/* Wait till HSE is disabled */
while (__HAL_RCC_GET_FLAG(RCC_FLAG_HSERDY) != RESET)
{
if ((HAL_GetTick() - tickstart) > HSE_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
}
这部分代码在HSE为禁用状态时,等待HSE被禁用。它使用__HAL_RCC_GET_FLAG
宏来检查HSE是否已经禁用。如果HSE在超时时间内仍未禁用,函数将返回HAL_TIMEOUT
。
HSI Configuration
if (((RCC_OscInitStruct->OscillatorType) & RCC_OSCILLATORTYPE_HSI) == RCC_OSCILLATORTYPE_HSI)
这行代码通过按位与运算符将RCC_OscInitStruct->OscillatorType
与RCC_OSCILLATORTYPE_HSI
进行按位与操作,并将结果与RCC_OSCILLATORTYPE_HSI
进行比较。如果结果等于RCC_OSCILLATORTYPE_HSI
,则条件成立。这个条件判断语句的目的是检查是否启用了内部高速时钟(HSI)作为振荡器类型。
/* Check the parameters */
assert_param(IS_RCC_HSI(RCC_OscInitStruct->HSIState));
assert_param(IS_RCC_CALIBRATION_VALUE(RCC_OscInitStruct->HSICalibrationValue));
这是两个断言语句,用于检查RCC_OscInitStruct->HSIState
和RCC_OscInitStruct->HSICalibrationValue
的值是否符合要求。IS_RCC_HSI
和IS_RCC_CALIBRATION_VALUE
是宏,用于验证相应的参数是否满足特定的条件。如果断言失败,则会触发断言错误。
/* Check if HSI is used as system clock or as PLL source when PLL is selected as system clock */
if ((__HAL_RCC_GET_SYSCLK_SOURCE() == RCC_SYSCLKSOURCE_STATUS_HSI)
|| ((__HAL_RCC_GET_SYSCLK_SOURCE() == RCC_SYSCLKSOURCE_STATUS_PLLCLK) && (__HAL_RCC_GET_PLL_OSCSOURCE() == RCC_PLLSOURCE_HSI_DIV2)))
这个条件判断语句检查系统时钟源是否为内部高速时钟(HSI),或者是由HSI驱动的PLL时钟源(当PLL被选为系统时钟)。如果条件成立,则意味着HSI被用作系统时钟或PLL时钟源。
/* When HSI is used as system clock it will not disabled */
if ((__HAL_RCC_GET_FLAG(RCC_FLAG_HSIRDY) != RESET) && (RCC_OscInitStruct->HSIState != RCC_HSI_ON))
{
return HAL_ERROR;
}
/* Otherwise, just the calibration is allowed */
else
{
/* Adjusts the Internal High Speed oscillator (HSI) calibration value.*/
__HAL_RCC_HSI_CALIBRATIONVALUE_ADJUST(RCC_OscInitStruct->HSICalibrationValue);
}
如果HSI被用作系统时钟,且RCC_OscInitStruct->HSIState
的值不等于RCC_HSI_ON
,则函数将返回HAL_ERROR
。否则,只允许进行校准操作,并调整内部高速时钟(HSI)的校准值。
/* Check the HSI State */
if (RCC_OscInitStruct->HSIState != RCC_HSI_OFF)
{
/* Enable the Internal High Speed oscillator (HSI). */
__HAL_RCC_HSI_ENABLE();
/* Get Start Tick */
tickstart = HAL_GetTick();
/* Wait till HSI is ready */
while (__HAL_RCC_GET_FLAG(RCC_FLAG_HSIRDY) == RESET)
{
if ((HAL_GetTick() - tickstart) > HSI_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
/* Adjusts the Internal High Speed oscillator (HSI) calibration value.*/
__HAL_RCC_HSI_CALIBRATIONVALUE_ADJUST(RCC_OscInitStruct->HSICalibrationValue);
}
else
{
/* Disable the Internal High Speed oscillator (HSI). */
__HAL_RCC_HSI_DISABLE();
/* Get Start Tick */
tickstart = HAL_GetTick();
/* Wait till HSI is disabled */
while (__HAL_RCC_GET_FLAG(RCC_FLAG_HSIRDY) != RESET)
{
if ((HAL_GetTick() - tickstart) > HSI_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
}
这段代码是根据RCC_OscInitStruct->HSIState
的值来启用或禁用内部高速时钟(HSI)。
如果RCC_OscInitStruct->HSIState
不等于RCC_HSI_OFF
,即HSI状态非禁用,那么代码会执行以下操作:
- 启用内部高速时钟(HSI):调用
__HAL_RCC_HSI_ENABLE()
函数使HSI开始振荡。 - 获取起始时间:使用
HAL_GetTick()
函数获取当前的系统滴答计数值,并将其存储在tickstart
变量中。 - 等待HSI就绪:通过循环等待,检查
RCC_FLAG_HSIRDY
标志位是否被置位(表示HSI已经就绪)。如果HSI未在超时时间内就绪,则返回HAL_TIMEOUT
。 - 调整HSI校准值:调用
__HAL_RCC_HSI_CALIBRATIONVALUE_ADJUST()
函数,根据RCC_OscInitStruct->HSICalibrationValue
的值来调整HSI的校准值。
如果RCC_OscInitStruct->HSIState
等于RCC_HSI_OFF
,即HSI状态为禁用,那么代码会执行以下操作:
- 禁用内部高速时钟(HSI):调用
__HAL_RCC_HSI_DISABLE()
函数,将HSI停止振荡。 - 获取起始时间:使用
HAL_GetTick()
函数获取当前的系统滴答计数值,并将其存储在tickstart
变量中。 - 等待HSI禁用完成:通过循环等待,检查
RCC_FLAG_HSIRDY
标志位是否被清除(表示HSI已经禁用)。如果HSI在超时时间内未禁用完成,则返回HAL_TIMEOUT
。
总结一下:这段代码根据RCC_OscInitStruct->HSIState
的值来控制HSI的启用和禁用,并在必要时等待HSI就绪或禁用完成。
LSI Configuration
if (((RCC_OscInitStruct->OscillatorType) & RCC_OSCILLATORTYPE_LSI) == RCC_OSCILLATORTYPE_LSI)
{
/* Check the parameters */
assert_param(IS_RCC_LSI(RCC_OscInitStruct->LSIState));
/* Check the LSI State */
if (RCC_OscInitStruct->LSIState != RCC_LSI_OFF)
{
/* Enable the Internal Low Speed oscillator (LSI). */
__HAL_RCC_LSI_ENABLE();
/* Get Start Tick */
tickstart = HAL_GetTick();
/* Wait till LSI is ready */
while (__HAL_RCC_GET_FLAG(RCC_FLAG_LSIRDY) == RESET)
{
if ((HAL_GetTick() - tickstart) > LSI_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
/* To have a fully stabilized clock in the specified range, a software delay of 1ms
should be added.*/
RCC_Delay(1);
}
else
{
/* Disable the Internal Low Speed oscillator (LSI). */
__HAL_RCC_LSI_DISABLE();
/* Get Start Tick */
tickstart = HAL_GetTick();
/* Wait till LSI is disabled */
while (__HAL_RCC_GET_FLAG(RCC_FLAG_LSIRDY) != RESET)
{
if ((HAL_GetTick() - tickstart) > LSI_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
}
}
这段代码根据RCC_OscInitStruct->OscillatorType
的值来判断是否启用内部低速时钟(LSI)。
首先,通过按位与运算符将RCC_OscInitStruct->OscillatorType
与RCC_OSCILLATORTYPE_LSI
进行按位与操作,并将结果与RCC_OSCILLATORTYPE_LSI
进行比较。如果结果等于RCC_OSCILLATORTYPE_LSI
,则条件成立,表示LSI作为振荡器类型被启用。
接下来,代码会执行以下操作:
- 检查LSI状态参数:调用
assert_param()
宏来验证RCC_OscInitStruct->LSIState
的值是否符合要求。 - 检查LSI状态:如果
RCC_OscInitStruct->LSIState
不等于RCC_LSI_OFF
,即LSI状态非禁用,那么执行以下操作:- 启用内部低速时钟(LSI):调用
__HAL_RCC_LSI_ENABLE()
函数使LSI开始振荡。 - 获取起始时间:使用
HAL_GetTick()
函数获取当前的系统滴答计数值,并将其存储在tickstart
变量中。 - 等待LSI就绪:通过循环等待,检查
RCC_FLAG_LSIRDY
标志位是否被置位(表示LSI已经就绪)。如果LSI未在超时时间内就绪,则返回HAL_TIMEOUT
。 - 添加1ms的软件延迟:调用
RCC_Delay()
函数添加1ms的延迟,以确保LSI在指定范围内完全稳定。
- 启用内部低速时钟(LSI):调用
- 如果
RCC_OscInitStruct->LSIState
等于RCC_LSI_OFF
,即LSI状态为禁用,那么执行以下操作:- 禁用内部低速时钟(LSI):调用
__HAL_RCC_LSI_DISABLE()
函数,将LSI停止振荡。 - 获取起始时间:使用
HAL_GetTick()
函数获取当前的系统滴答计数值,并将其存储在tickstart
变量中。 - 等待LSI禁用完成:通过循环等待,检查
RCC_FLAG_LSIRDY
标志位是否被清除(表示LSI已经禁用)。如果LSI在超时时间内未禁用完成,则返回HAL_TIMEOUT
。
- 禁用内部低速时钟(LSI):调用
LSE Configuration
这段代码根据RCC_OscInitStruct->OscillatorType
的值判断是否启用外部低速时钟(LSE)。
首先,代码通过按位与运算符将RCC_OscInitStruct->OscillatorType
与RCC_OSCILLATORTYPE_LSE
进行按位与操作,并将结果与RCC_OSCILLATORTYPE_LSE
进行比较。这样可以检查RCC_OscInitStruct->OscillatorType
是否包含LSE作为振荡器类型。
接下来,代码执行以下操作:
/* Check the parameters */
assert_param(IS_RCC_LSE(RCC_OscInitStruct->LSEState));
使用assert_param()
宏来验证RCC_OscInitStruct->LSEState
的值是否符合要求。这个宏通常用于参数验证,确保参数的有效性。
/* Update LSE configuration in Backup Domain control register */
/* Requires to enable write access to Backup Domain of necessary */
if (__HAL_RCC_PWR_IS_CLK_DISABLED())
{
__HAL_RCC_PWR_CLK_ENABLE();
pwrclkchanged = SET;
}
如果备份域的写访问被禁用(通过__HAL_RCC_PWR_IS_CLK_DISABLED()
函数检查),则执行以下操作:
- 启用电源时钟:调用
__HAL_RCC_PWR_CLK_ENABLE()
函数以启用电源时钟。 - 设置
pwrclkchanged
变量为SET
,表示电源时钟已更改。
if (HAL_IS_BIT_CLR(PWR->CR, PWR_CR_DBP))
{
/* Enable write access to Backup domain */
SET_BIT(PWR->CR, PWR_CR_DBP);
/* Wait for Backup domain Write protection disable */
tickstart = HAL_GetTick();
while (HAL_IS_BIT_CLR(PWR->CR, PWR_CR_DBP))
{
if ((HAL_GetTick() - tickstart) > RCC_DBP_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
}
如果备份域的写保护被启用(通过检查PWR->CR
寄存器的PWR_CR_DBP
位),则执行以下操作:
- 启用对备份域的写访问:通过设置
PWR_CR_DBP
位来启用对备份域的写访问。 - 等待备份域写保护禁用:通过循环等待,检查
PWR_CR_DBP
位是否被设置(表示备份域的写保护已禁用)。如果在超时时间内写保护未禁用完成,则返回HAL_TIMEOUT
。
_HAL_RCC_LSE_CONFIG(RCC_OscInitStruct->LSEState);
调用_HAL_RCC_LSE_CONFIG()
函数来配置LSE的状态,参数为RCC_OscInitStruct->LSEState
。这个函数用于设置LSE的使能状态。
/* Check the LSE State */
if (RCC_OscInitStruct->LSEState != RCC_LSE_OFF)
{
/* Get Start Tick */
tickstart = HAL_GetTick();
/* Wait till LSE is ready */
while (__HAL_RCC_GET_FLAG(RCC_FLAG_LSERDY) == RESET)
{
if ((HAL_GetTick() - tickstart) > RCC_LSE_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
}
else
{
/* Get Start Tick */
tickstart = HAL_GetTick();
/* Wait till LSE is disabled */
while (__HAL_RCC_GET_FLAG(RCC_FLAG_LSERDY) != RESET)
{
if ((HAL_GetTick() - tickstart) > RCC_LSE_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
}
根据RCC_OscInitStruct->LSEState
的值判断LSE的状态。如果LSE状态不是禁用(即不等于RCC_LSE_OFF
),则执行以下操作:
- 获取起始时间:使用
HAL_GetTick()
函数获取当前的系统滴答计数值,并将其存储在tickstart
变量中。 - 等待LSE就绪:通过循环等待,检查
RCC_FLAG_LSERDY
标志位是否被置位(表示LSE已经就绪)。如果LSE在超时时间内未就绪,则返回HAL_TIMEOUT
。
如果LSE状态为禁用(即等于RCC_LSE_OFF
),则执行以下操作:
- 获取起始时间:使用
HAL_GetTick()
函数获取当前的系统滴答计数值,并将其存储在tickstart
变量中。 - 等待LSE禁用完成:通过循环等待,检查
RCC_FLAG_LSERDY
标志位是否被清除(表示LSE已经禁用)。如果LSE在超时时间内未禁用完成,则返回HAL_TIMEOUT
。
/* Require to disable power clock if necessary */
if (pwrclkchanged == SET)
{
__HAL_RCC_PWR_CLK_DISABLE();
}
如果之前启用了电源时钟(pwrclkchanged
为SET
),则调用__HAL_RCC_PWR_CLK_DISABLE()
函数来禁用电源时钟。
PLL2 Configuration
这段代码用于配置和控制PLL2(Phase-Locked Loop 2)。
首先,代码执行以下操作:
/* Check the parameters */
assert_param(IS_RCC_PLL2(RCC_OscInitStruct->PLL2.PLL2State));
使用assert_param()
宏来验证RCC_OscInitStruct->PLL2.PLL2State
的值是否符合要求。这个宏通常用于参数验证,确保参数的有效性。
接下来,代码根据RCC_OscInitStruct->PLL2.PLL2State
的值执行不同的操作。
如果RCC_OscInitStruct->PLL2.PLL2State
不等于RCC_PLL2_NONE
,执行以下操作:
if ((__HAL_RCC_GET_PLL_OSCSOURCE() == RCC_PLLSOURCE_HSE) &&
(__HAL_RCC_GET_SYSCLK_SOURCE() == RCC_SYSCLKSOURCE_STATUS_PLLCLK) &&
((READ_BIT(RCC->CFGR2, RCC_CFGR2_PREDIV1SRC)) == RCC_CFGR2_PREDIV1SRC_PLL2))
{
return HAL_ERROR;
}
检查PLL2的时钟源是否为HSE,系统时钟源是否为PLLCLK,以及PREDIV1的源是否为PLL2。如果满足这些条件,返回HAL_ERROR
。这是因为当PLL2的时钟间接用作系统时钟时,这些设置是不允许修改的。
否则,执行以下操作:
if ((RCC_OscInitStruct->PLL2.PLL2State) == RCC_PLL2_ON)
{
/* Check the parameters */
assert_param(IS_RCC_PLL2_MUL(RCC_OscInitStruct->PLL2.PLL2MUL));
assert_param(IS_RCC_HSE_PREDIV2(RCC_OscInitStruct->PLL2.HSEPrediv2Value));
/* Prediv2 can be written only when the PLLI2S is disabled. */
/* Return an error only if new value is different from the programmed value */
if (HAL_IS_BIT_SET(RCC->CR, RCC_CR_PLL3ON) &&
(__HAL_RCC_HSE_GET_PREDIV2() != RCC_OscInitStruct->PLL2.HSEPrediv2Value))
{
return HAL_ERROR;
}
/* Disable the main PLL2. */
__HAL_RCC_PLL2_DISABLE();
/* Get Start Tick */
tickstart = HAL_GetTick();
/* Wait till PLL2 is disabled */
while (__HAL_RCC_GET_FLAG(RCC_FLAG_PLL2RDY) != RESET)
{
if ((HAL_GetTick() - tickstart) > PLL2_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
/* Configure the HSE prediv2 factor */
__HAL_RCC_HSE_PREDIV2_CONFIG(RCC_OscInitStruct->PLL2.HSEPrediv2Value);
/* Configure the main PLL2 multiplication factors. */
__HAL_RCC_PLL2_CONFIG(RCC_OscInitStruct->PLL2.PLL2MUL);
/* Enable the main PLL2. */
__HAL_RCC_PLL2_ENABLE();
/* Get Start Tick */
tickstart = HAL_GetTick();
/* Wait till PLL2 is ready */
while (__HAL_RCC_GET_FLAG(RCC_FLAG_PLL2RDY) == RESET)
{
if ((HAL_GetTick() - tickstart) > PLL2_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
}
else
{
/* Set PREDIV1 source to HSE */
CLEAR_BIT(RCC->CFGR2, RCC_CFGR2_PREDIV1SRC);
/* Disable the main PLL2. */
__HAL_RCC_PLL2_DISABLE();
/* Get Start Tick */
tickstart = HAL_GetTick();
/* Wait till PLL2 is disabled */
while (__HAL_RCC_GET_FLAG(RCC_FLAG_PLL2RDY) != RESET)
{
if ((HAL_GetTick() - tickstart) > PLL2_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
}
如果RCC_OscInitStruct->PLL2.PLL2State
等于RCC_PLL2_ON
,执行以下操作:
- 验证
RCC_OscInitStruct->PLL2.PLL2MUL
和RCC_OscInitStruct->PLL2.HSEPrediv2Value
的值是否符合要求。 - 检查是否需要禁用PLL3(PLL2的先导PLL)以便写入预分频器PREDIV2的值。只有当新值与已编程的值不同时,才返回
HAL_ERROR
。 - 禁用主PLL2。
- 等待PLL2被禁用。
- 配置HSE预分频器PREDIV2的值。
- 配置主PLL2的倍频因子。
- 启用主PLL2。
- 获取起始时间。
- 等待PLL2就绪。
- 如果超过超时时间,则返回
HAL_TIMEOUT
。
否则,如果RCC_OscInitStruct->PLL2.PLL2State
不等于RCC_PLL2_ON
,执行以下操作:
- 将PREDIV1的源设置为HSE。
- 禁用主PLL2。
- 获取起始时间。
- 等待PLL2被禁用。
- 如果超过超时时间,则返回
HAL_TIMEOUT
。
最后,代码结束了#endif
块,结束了对RCC_CR_PLL2ON
的条件编译。
PLLConfiguration
assert_param(IS_RCC_PLL(RCC_OscInitStruct->PLL.PLLState));
if ((RCC_OscInitStruct->PLL.PLLState) != RCC_PLL_NONE)
{
/* Check if the PLL is used as system clock or not */
if (__HAL_RCC_GET_SYSCLK_SOURCE() != RCC_SYSCLKSOURCE_STATUS_PLLCLK)
{
if ((RCC_OscInitStruct->PLL.PLLState) == RCC_PLL_ON)
{
/* Check the parameters */
assert_param(IS_RCC_PLLSOURCE(RCC_OscInitStruct->PLL.PLLSource));
assert_param(IS_RCC_PLL_MUL(RCC_OscInitStruct->PLL.PLLMUL));
/* Disable the main PLL. */
__HAL_RCC_PLL_DISABLE();
/* Get Start Tick */
tickstart = HAL_GetTick();
/* Wait till PLL is disabled */
while (__HAL_RCC_GET_FLAG(RCC_FLAG_PLLRDY) != RESET)
{
if ((HAL_GetTick() - tickstart) > PLL_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
这段代码是用于配置和控制主PLL(Phase-Locked Loop)的操作。让我们一行一行地进行解析:
-
assert_param(IS_RCC_PLL(RCC_OscInitStruct->PLL.PLLState));
这行代码使用宏assert_param()
来验证RCC_OscInitStruct->PLL.PLLState
的值是否符合要求。 -
if ((RCC_OscInitStruct->PLL.PLLState) != RCC_PLL_NONE)
如果RCC_OscInitStruct->PLL.PLLState
不等于RCC_PLL_NONE
,执行以下操作。 -
if (__HAL_RCC_GET_SYSCLK_SOURCE() != RCC_SYSCLKSOURCE_STATUS_PLLCLK)
检查PLL是否被用作系统时钟。如果PLL不是系统时钟源,执行以下操作。 -
if ((RCC_OscInitStruct->PLL.PLLState) == RCC_PLL_ON)
如果RCC_OscInitStruct->PLL.PLLState
等于RCC_PLL_ON
,执行以下操作。 -
assert_param(IS_RCC_PLLSOURCE(RCC_OscInitStruct->PLL.PLLSource));
验证RCC_OscInitStruct->PLL.PLLSource
的值是否符合要求。 -
assert_param(IS_RCC_PLL_MUL(RCC_OscInitStruct->PLL.PLLMUL));
验证RCC_OscInitStruct->PLL.PLLMUL
的值是否符合要求。 -
__HAL_RCC_PLL_DISABLE();
禁用主PLL。 -
tickstart = HAL_GetTick();
获取起始时间。 -
while (__HAL_RCC_GET_FLAG(RCC_FLAG_PLLRDY) != RESET)
等待PLL被禁用。 -
if ((HAL_GetTick() - tickstart) > PLL_TIMEOUT_VALUE)
如果超过超时时间,则返回HAL_TIMEOUT
。
if (RCC_OscInitStruct->PLL.PLLSource == RCC_PLLSOURCE_HSE)
{
/* Check the parameter */
assert_param(IS_RCC_HSE_PREDIV(RCC_OscInitStruct->HSEPredivValue));
#if defined(RCC_CFGR2_PREDIV1SRC)
assert_param(IS_RCC_PREDIV1_SOURCE(RCC_OscInitStruct->Prediv1Source));
/* Set PREDIV1 source */
SET_BIT(RCC->CFGR2, RCC_OscInitStruct->Prediv1Source);
#endif /* RCC_CFGR2_PREDIV1SRC */
/* Set PREDIV1 Value */
__HAL_RCC_HSE_PREDIV_CONFIG(RCC_OscInitStruct->HSEPredivValue);
}
/* Configure the main PLL clock source and multiplication factors. */
__HAL_RCC_PLL_CONFIG(RCC_OscInitStruct->PLL.PLLSource,
RCC_OscInitStruct->PLL.PLLMUL);
/* Enable the main PLL. */
__HAL_RCC_PLL_ENABLE();
/* Get Start Tick */
tickstart = HAL_GetTick();
/* Wait till PLL is ready */
while (__HAL_RCC_GET_FLAG(RCC_FLAG_PLLRDY) == RESET)
{
if ((HAL_GetTick() - tickstart) > PLL_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
}
else
{
/* Disable the main PLL. */
__HAL_RCC_PLL_DISABLE();
/* Get Start Tick */
tickstart = HAL_GetTick();
/* Wait till PLL is disabled */
while (__HAL_RCC_GET_FLAG(RCC_FLAG_PLLRDY) != RESET)
{
if ((HAL_GetTick() - tickstart) > PLL_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
}
}
else
{
/* Check if there is a request to disable the PLL used as System clock source */
if ((RCC_OscInitStruct->PLL.PLLState) == RCC_PLL_OFF)
{
return HAL_ERROR;
}
else
{
/* Do not return HAL_ERROR if request repeats the current configuration */
pll_config = RCC->CFGR;
if ((READ_BIT(pll_config, RCC_CFGR_PLLSRC) != RCC_OscInitStruct->PLL.PLLSource) ||
(READ_BIT(pll_config, RCC_CFGR_PLLMULL) != RCC_OscInitStruct->PLL.PLLMUL))
{
return HAL_ERROR;
}
}
}
}
-
首先,代码检查传入的RCC配置结构体中的PLLSource是否为RCC_PLLSOURCE_HSE。如果是,则进入if语句块。
-
在if语句块中,代码首先使用assert_param宏来验证传入的RCC配置结构体中的HSEPredivValue参数是否合法。
-
接下来,代码使用SET_BIT宏来设置RCC_CFGR2寄存器中的Prediv1Source位,该位用于选择PREDIV1的源。
-
然后,代码使用__HAL_RCC_HSE_PREDIV_CONFIG()函数配置PREDIV1的值。
-
接下来,代码使用HAL_RCC_PLL_CONFIG()函数配置主PLL的时钟源和乘法因子,并使用HAL_RCC_PLL_ENABLE()函数使能主PLL。
-
然后,代码使用HAL_GetTick()函数获取当前的系统滴答计数,并与tickstart变量比较,以检查是否超时。如果超时,则返回HAL_TIMEOUT。
-
如果传入的RCC配置结构体中的PLLSource不是RCC_PLLSOURCE_HSE,则禁用主PLL。
-
接下来,代码使用HAL_GetTick()函数获取当前的系统滴答计数,并与tickstart变量比较,以检查是否超时。如果超时,则返回HAL_TIMEOUT。
-
如果当前系统时钟源为PLL,并且传入的RCC配置结构体中的PLL的状态为RCC_PLL_OFF,则返回HAL_ERROR。
-
如果当前的PLL配置与传入的RCC配置结构体中的PLL配置不相同,则返回HAL_ERROR。
HAL_StatusTypeDef HAL_RCC_OscConfig(RCC_OscInitTypeDef *RCC_OscInitStruct)
{
uint32_t tickstart;
uint32_t pll_config;
/* Check Null pointer */
if (RCC_OscInitStruct == NULL)
{
return HAL_ERROR;
}
/* Check the parameters */
assert_param(IS_RCC_OSCILLATORTYPE(RCC_OscInitStruct->OscillatorType));
/*------------------------------- HSE Configuration ------------------------*/
if (((RCC_OscInitStruct->OscillatorType) & RCC_OSCILLATORTYPE_HSE) == RCC_OSCILLATORTYPE_HSE)
{
/* Check the parameters */
assert_param(IS_RCC_HSE(RCC_OscInitStruct->HSEState));
/* When the HSE is used as system clock or clock source for PLL in these cases it is not allowed to be disabled */
if ((__HAL_RCC_GET_SYSCLK_SOURCE() == RCC_SYSCLKSOURCE_STATUS_HSE)
|| ((__HAL_RCC_GET_SYSCLK_SOURCE() == RCC_SYSCLKSOURCE_STATUS_PLLCLK) && (__HAL_RCC_GET_PLL_OSCSOURCE() == RCC_PLLSOURCE_HSE)))
{
if ((__HAL_RCC_GET_FLAG(RCC_FLAG_HSERDY) != RESET) && (RCC_OscInitStruct->HSEState == RCC_HSE_OFF))
{
return HAL_ERROR;
}
}
else
{
/* Set the new HSE configuration ---------------------------------------*/
__HAL_RCC_HSE_CONFIG(RCC_OscInitStruct->HSEState);
/* Check the HSE State */
if (RCC_OscInitStruct->HSEState != RCC_HSE_OFF)
{
/* Get Start Tick */
tickstart = HAL_GetTick();
/* Wait till HSE is ready */
while (__HAL_RCC_GET_FLAG(RCC_FLAG_HSERDY) == RESET)
{
if ((HAL_GetTick() - tickstart) > HSE_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
}
else
{
/* Get Start Tick */
tickstart = HAL_GetTick();
/* Wait till HSE is disabled */
while (__HAL_RCC_GET_FLAG(RCC_FLAG_HSERDY) != RESET)
{
if ((HAL_GetTick() - tickstart) > HSE_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
}
}
}
/*----------------------------- HSI Configuration --------------------------*/
if (((RCC_OscInitStruct->OscillatorType) & RCC_OSCILLATORTYPE_HSI) == RCC_OSCILLATORTYPE_HSI)
{
/* Check the parameters */
assert_param(IS_RCC_HSI(RCC_OscInitStruct->HSIState));
assert_param(IS_RCC_CALIBRATION_VALUE(RCC_OscInitStruct->HSICalibrationValue));
/* Check if HSI is used as system clock or as PLL source when PLL is selected as system clock */
if ((__HAL_RCC_GET_SYSCLK_SOURCE() == RCC_SYSCLKSOURCE_STATUS_HSI)
|| ((__HAL_RCC_GET_SYSCLK_SOURCE() == RCC_SYSCLKSOURCE_STATUS_PLLCLK) && (__HAL_RCC_GET_PLL_OSCSOURCE() == RCC_PLLSOURCE_HSI_DIV2)))
{
/* When HSI is used as system clock it will not disabled */
if ((__HAL_RCC_GET_FLAG(RCC_FLAG_HSIRDY) != RESET) && (RCC_OscInitStruct->HSIState != RCC_HSI_ON))
{
return HAL_ERROR;
}
/* Otherwise, just the calibration is allowed */
else
{
/* Adjusts the Internal High Speed oscillator (HSI) calibration value.*/
__HAL_RCC_HSI_CALIBRATIONVALUE_ADJUST(RCC_OscInitStruct->HSICalibrationValue);
}
}
else
{
/* Check the HSI State */
if (RCC_OscInitStruct->HSIState != RCC_HSI_OFF)
{
/* Enable the Internal High Speed oscillator (HSI). */
__HAL_RCC_HSI_ENABLE();
/* Get Start Tick */
tickstart = HAL_GetTick();
/* Wait till HSI is ready */
while (__HAL_RCC_GET_FLAG(RCC_FLAG_HSIRDY) == RESET)
{
if ((HAL_GetTick() - tickstart) > HSI_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
/* Adjusts the Internal High Speed oscillator (HSI) calibration value.*/
__HAL_RCC_HSI_CALIBRATIONVALUE_ADJUST(RCC_OscInitStruct->HSICalibrationValue);
}
else
{
/* Disable the Internal High Speed oscillator (HSI). */
__HAL_RCC_HSI_DISABLE();
/* Get Start Tick */
tickstart = HAL_GetTick();
/* Wait till HSI is disabled */
while (__HAL_RCC_GET_FLAG(RCC_FLAG_HSIRDY) != RESET)
{
if ((HAL_GetTick() - tickstart) > HSI_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
}
}
}
/*------------------------------ LSI Configuration -------------------------*/
if (((RCC_OscInitStruct->OscillatorType) & RCC_OSCILLATORTYPE_LSI) == RCC_OSCILLATORTYPE_LSI)
{
/* Check the parameters */
assert_param(IS_RCC_LSI(RCC_OscInitStruct->LSIState));
/* Check the LSI State */
if (RCC_OscInitStruct->LSIState != RCC_LSI_OFF)
{
/* Enable the Internal Low Speed oscillator (LSI). */
__HAL_RCC_LSI_ENABLE();
/* Get Start Tick */
tickstart = HAL_GetTick();
/* Wait till LSI is ready */
while (__HAL_RCC_GET_FLAG(RCC_FLAG_LSIRDY) == RESET)
{
if ((HAL_GetTick() - tickstart) > LSI_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
/* To have a fully stabilized clock in the specified range, a software delay of 1ms
should be added.*/
RCC_Delay(1);
}
else
{
/* Disable the Internal Low Speed oscillator (LSI). */
__HAL_RCC_LSI_DISABLE();
/* Get Start Tick */
tickstart = HAL_GetTick();
/* Wait till LSI is disabled */
while (__HAL_RCC_GET_FLAG(RCC_FLAG_LSIRDY) != RESET)
{
if ((HAL_GetTick() - tickstart) > LSI_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
}
}
/*------------------------------ LSE Configuration -------------------------*/
if (((RCC_OscInitStruct->OscillatorType) & RCC_OSCILLATORTYPE_LSE) == RCC_OSCILLATORTYPE_LSE)
{
FlagStatus pwrclkchanged = RESET;
/* Check the parameters */
assert_param(IS_RCC_LSE(RCC_OscInitStruct->LSEState));
/* Update LSE configuration in Backup Domain control register */
/* Requires to enable write access to Backup Domain of necessary */
if (__HAL_RCC_PWR_IS_CLK_DISABLED())
{
__HAL_RCC_PWR_CLK_ENABLE();
pwrclkchanged = SET;
}
if (HAL_IS_BIT_CLR(PWR->CR, PWR_CR_DBP))
{
/* Enable write access to Backup domain */
SET_BIT(PWR->CR, PWR_CR_DBP);
/* Wait for Backup domain Write protection disable */
tickstart = HAL_GetTick();
while (HAL_IS_BIT_CLR(PWR->CR, PWR_CR_DBP))
{
if ((HAL_GetTick() - tickstart) > RCC_DBP_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
}
/* Set the new LSE configuration -----------------------------------------*/
__HAL_RCC_LSE_CONFIG(RCC_OscInitStruct->LSEState);
/* Check the LSE State */
if (RCC_OscInitStruct->LSEState != RCC_LSE_OFF)
{
/* Get Start Tick */
tickstart = HAL_GetTick();
/* Wait till LSE is ready */
while (__HAL_RCC_GET_FLAG(RCC_FLAG_LSERDY) == RESET)
{
if ((HAL_GetTick() - tickstart) > RCC_LSE_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
}
else
{
/* Get Start Tick */
tickstart = HAL_GetTick();
/* Wait till LSE is disabled */
while (__HAL_RCC_GET_FLAG(RCC_FLAG_LSERDY) != RESET)
{
if ((HAL_GetTick() - tickstart) > RCC_LSE_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
}
/* Require to disable power clock if necessary */
if (pwrclkchanged == SET)
{
__HAL_RCC_PWR_CLK_DISABLE();
}
}
#if defined(RCC_CR_PLL2ON)
/*-------------------------------- PLL2 Configuration -----------------------*/
/* Check the parameters */
assert_param(IS_RCC_PLL2(RCC_OscInitStruct->PLL2.PLL2State));
if ((RCC_OscInitStruct->PLL2.PLL2State) != RCC_PLL2_NONE)
{
/* This bit can not be cleared if the PLL2 clock is used indirectly as system
clock (i.e. it is used as PLL clock entry that is used as system clock). */
if ((__HAL_RCC_GET_PLL_OSCSOURCE() == RCC_PLLSOURCE_HSE) && \
(__HAL_RCC_GET_SYSCLK_SOURCE() == RCC_SYSCLKSOURCE_STATUS_PLLCLK) && \
((READ_BIT(RCC->CFGR2, RCC_CFGR2_PREDIV1SRC)) == RCC_CFGR2_PREDIV1SRC_PLL2))
{
return HAL_ERROR;
}
else
{
if ((RCC_OscInitStruct->PLL2.PLL2State) == RCC_PLL2_ON)
{
/* Check the parameters */
assert_param(IS_RCC_PLL2_MUL(RCC_OscInitStruct->PLL2.PLL2MUL));
assert_param(IS_RCC_HSE_PREDIV2(RCC_OscInitStruct->PLL2.HSEPrediv2Value));
/* Prediv2 can be written only when the PLLI2S is disabled. */
/* Return an error only if new value is different from the programmed value */
if (HAL_IS_BIT_SET(RCC->CR, RCC_CR_PLL3ON) && \
(__HAL_RCC_HSE_GET_PREDIV2() != RCC_OscInitStruct->PLL2.HSEPrediv2Value))
{
return HAL_ERROR;
}
/* Disable the main PLL2. */
__HAL_RCC_PLL2_DISABLE();
/* Get Start Tick */
tickstart = HAL_GetTick();
/* Wait till PLL2 is disabled */
while (__HAL_RCC_GET_FLAG(RCC_FLAG_PLL2RDY) != RESET)
{
if ((HAL_GetTick() - tickstart) > PLL2_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
/* Configure the HSE prediv2 factor --------------------------------*/
__HAL_RCC_HSE_PREDIV2_CONFIG(RCC_OscInitStruct->PLL2.HSEPrediv2Value);
/* Configure the main PLL2 multiplication factors. */
__HAL_RCC_PLL2_CONFIG(RCC_OscInitStruct->PLL2.PLL2MUL);
/* Enable the main PLL2. */
__HAL_RCC_PLL2_ENABLE();
/* Get Start Tick */
tickstart = HAL_GetTick();
/* Wait till PLL2 is ready */
while (__HAL_RCC_GET_FLAG(RCC_FLAG_PLL2RDY) == RESET)
{
if ((HAL_GetTick() - tickstart) > PLL2_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
}
else
{
/* Set PREDIV1 source to HSE */
CLEAR_BIT(RCC->CFGR2, RCC_CFGR2_PREDIV1SRC);
/* Disable the main PLL2. */
__HAL_RCC_PLL2_DISABLE();
/* Get Start Tick */
tickstart = HAL_GetTick();
/* Wait till PLL2 is disabled */
while (__HAL_RCC_GET_FLAG(RCC_FLAG_PLL2RDY) != RESET)
{
if ((HAL_GetTick() - tickstart) > PLL2_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
}
}
}
#endif /* RCC_CR_PLL2ON */
/*-------------------------------- PLL Configuration -----------------------*/
/* Check the parameters */
assert_param(IS_RCC_PLL(RCC_OscInitStruct->PLL.PLLState));
if ((RCC_OscInitStruct->PLL.PLLState) != RCC_PLL_NONE)
{
/* Check if the PLL is used as system clock or not */
if (__HAL_RCC_GET_SYSCLK_SOURCE() != RCC_SYSCLKSOURCE_STATUS_PLLCLK)
{
if ((RCC_OscInitStruct->PLL.PLLState) == RCC_PLL_ON)
{
/* Check the parameters */
assert_param(IS_RCC_PLLSOURCE(RCC_OscInitStruct->PLL.PLLSource));
assert_param(IS_RCC_PLL_MUL(RCC_OscInitStruct->PLL.PLLMUL));
/* Disable the main PLL. */
__HAL_RCC_PLL_DISABLE();
/* Get Start Tick */
tickstart = HAL_GetTick();
/* Wait till PLL is disabled */
while (__HAL_RCC_GET_FLAG(RCC_FLAG_PLLRDY) != RESET)
{
if ((HAL_GetTick() - tickstart) > PLL_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
/* Configure the HSE prediv factor --------------------------------*/
/* It can be written only when the PLL is disabled. Not used in PLL source is different than HSE */
if (RCC_OscInitStruct->PLL.PLLSource == RCC_PLLSOURCE_HSE)
{
/* Check the parameter */
assert_param(IS_RCC_HSE_PREDIV(RCC_OscInitStruct->HSEPredivValue));
#if defined(RCC_CFGR2_PREDIV1SRC)
assert_param(IS_RCC_PREDIV1_SOURCE(RCC_OscInitStruct->Prediv1Source));
/* Set PREDIV1 source */
SET_BIT(RCC->CFGR2, RCC_OscInitStruct->Prediv1Source);
#endif /* RCC_CFGR2_PREDIV1SRC */
/* Set PREDIV1 Value */
__HAL_RCC_HSE_PREDIV_CONFIG(RCC_OscInitStruct->HSEPredivValue);
}
/* Configure the main PLL clock source and multiplication factors. */
__HAL_RCC_PLL_CONFIG(RCC_OscInitStruct->PLL.PLLSource,
RCC_OscInitStruct->PLL.PLLMUL);
/* Enable the main PLL. */
__HAL_RCC_PLL_ENABLE();
/* Get Start Tick */
tickstart = HAL_GetTick();
/* Wait till PLL is ready */
while (__HAL_RCC_GET_FLAG(RCC_FLAG_PLLRDY) == RESET)
{
if ((HAL_GetTick() - tickstart) > PLL_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
}
else
{
/* Disable the main PLL. */
__HAL_RCC_PLL_DISABLE();
/* Get Start Tick */
tickstart = HAL_GetTick();
/* Wait till PLL is disabled */
while (__HAL_RCC_GET_FLAG(RCC_FLAG_PLLRDY) != RESET)
{
if ((HAL_GetTick() - tickstart) > PLL_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
}
}
else
{
/* Check if there is a request to disable the PLL used as System clock source */
if ((RCC_OscInitStruct->PLL.PLLState) == RCC_PLL_OFF)
{
return HAL_ERROR;
}
else
{
/* Do not return HAL_ERROR if request repeats the current configuration */
pll_config = RCC->CFGR;
if ((READ_BIT(pll_config, RCC_CFGR_PLLSRC) != RCC_OscInitStruct->PLL.PLLSource) ||
(READ_BIT(pll_config, RCC_CFGR_PLLMULL) != RCC_OscInitStruct->PLL.PLLMUL))
{
return HAL_ERROR;
}
}
}
}
return HAL_OK;
}
评论(0)
您还未登录,请登录后发表或查看评论