观前提示:函数完整代码在文末,本文梳理了函数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->OscillatorTypeRCC_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->OscillatorTypeRCC_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->HSIStateRCC_OscInitStruct->HSICalibrationValue的值是否符合要求。IS_RCC_HSIIS_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状态非禁用,那么代码会执行以下操作:

  1. 启用内部高速时钟(HSI):调用__HAL_RCC_HSI_ENABLE()函数使HSI开始振荡。
  2. 获取起始时间:使用HAL_GetTick()函数获取当前的系统滴答计数值,并将其存储在tickstart变量中。
  3. 等待HSI就绪:通过循环等待,检查RCC_FLAG_HSIRDY标志位是否被置位(表示HSI已经就绪)。如果HSI未在超时时间内就绪,则返回HAL_TIMEOUT
  4. 调整HSI校准值:调用__HAL_RCC_HSI_CALIBRATIONVALUE_ADJUST()函数,根据RCC_OscInitStruct->HSICalibrationValue的值来调整HSI的校准值。

如果RCC_OscInitStruct->HSIState等于RCC_HSI_OFF,即HSI状态为禁用,那么代码会执行以下操作:

  1. 禁用内部高速时钟(HSI):调用__HAL_RCC_HSI_DISABLE()函数,将HSI停止振荡。
  2. 获取起始时间:使用HAL_GetTick()函数获取当前的系统滴答计数值,并将其存储在tickstart变量中。
  3. 等待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->OscillatorTypeRCC_OSCILLATORTYPE_LSI进行按位与操作,并将结果与RCC_OSCILLATORTYPE_LSI进行比较。如果结果等于RCC_OSCILLATORTYPE_LSI,则条件成立,表示LSI作为振荡器类型被启用。

接下来,代码会执行以下操作:

  1. 检查LSI状态参数:调用assert_param()宏来验证RCC_OscInitStruct->LSIState的值是否符合要求。
  2. 检查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在指定范围内完全稳定。
  3. 如果RCC_OscInitStruct->LSIState等于RCC_LSI_OFF,即LSI状态为禁用,那么执行以下操作:
    • 禁用内部低速时钟(LSI):调用__HAL_RCC_LSI_DISABLE()函数,将LSI停止振荡。
    • 获取起始时间:使用HAL_GetTick()函数获取当前的系统滴答计数值,并将其存储在tickstart变量中。
    • 等待LSI禁用完成:通过循环等待,检查RCC_FLAG_LSIRDY标志位是否被清除(表示LSI已经禁用)。如果LSI在超时时间内未禁用完成,则返回HAL_TIMEOUT

LSE Configuration

这段代码根据RCC_OscInitStruct->OscillatorType的值判断是否启用外部低速时钟(LSE)。

首先,代码通过按位与运算符将RCC_OscInitStruct->OscillatorTypeRCC_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();
}

如果之前启用了电源时钟(pwrclkchangedSET),则调用__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.PLL2MULRCC_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)的操作。让我们一行一行地进行解析:

  1. assert_param(IS_RCC_PLL(RCC_OscInitStruct->PLL.PLLState));
    这行代码使用宏assert_param()来验证RCC_OscInitStruct->PLL.PLLState的值是否符合要求。

  2. if ((RCC_OscInitStruct->PLL.PLLState) != RCC_PLL_NONE)
    如果RCC_OscInitStruct->PLL.PLLState不等于RCC_PLL_NONE,执行以下操作。

  3. if (__HAL_RCC_GET_SYSCLK_SOURCE() != RCC_SYSCLKSOURCE_STATUS_PLLCLK)
    检查PLL是否被用作系统时钟。如果PLL不是系统时钟源,执行以下操作。

  4. if ((RCC_OscInitStruct->PLL.PLLState) == RCC_PLL_ON)
    如果RCC_OscInitStruct->PLL.PLLState等于RCC_PLL_ON,执行以下操作。

  5. assert_param(IS_RCC_PLLSOURCE(RCC_OscInitStruct->PLL.PLLSource));
    验证RCC_OscInitStruct->PLL.PLLSource的值是否符合要求。

  6. assert_param(IS_RCC_PLL_MUL(RCC_OscInitStruct->PLL.PLLMUL));
    验证RCC_OscInitStruct->PLL.PLLMUL的值是否符合要求。

  7. __HAL_RCC_PLL_DISABLE();
    禁用主PLL。

  8. tickstart = HAL_GetTick();
    获取起始时间。

  9. while (__HAL_RCC_GET_FLAG(RCC_FLAG_PLLRDY) != RESET)
    等待PLL被禁用。

  10. 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;
        }
      }
    }
  }
  1. 首先,代码检查传入的RCC配置结构体中的PLLSource是否为RCC_PLLSOURCE_HSE。如果是,则进入if语句块。

  2. 在if语句块中,代码首先使用assert_param宏来验证传入的RCC配置结构体中的HSEPredivValue参数是否合法。

  3. 接下来,代码使用SET_BIT宏来设置RCC_CFGR2寄存器中的Prediv1Source位,该位用于选择PREDIV1的源。

  4. 然后,代码使用__HAL_RCC_HSE_PREDIV_CONFIG()函数配置PREDIV1的值。

  5. 接下来,代码使用HAL_RCC_PLL_CONFIG()函数配置主PLL的时钟源和乘法因子,并使用HAL_RCC_PLL_ENABLE()函数使能主PLL。

  6. 然后,代码使用HAL_GetTick()函数获取当前的系统滴答计数,并与tickstart变量比较,以检查是否超时。如果超时,则返回HAL_TIMEOUT。

  7. 如果传入的RCC配置结构体中的PLLSource不是RCC_PLLSOURCE_HSE,则禁用主PLL。

  8. 接下来,代码使用HAL_GetTick()函数获取当前的系统滴答计数,并与tickstart变量比较,以检查是否超时。如果超时,则返回HAL_TIMEOUT。

  9. 如果当前系统时钟源为PLL,并且传入的RCC配置结构体中的PLL的状态为RCC_PLL_OFF,则返回HAL_ERROR。

  10. 如果当前的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;
}