国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

stm32 hal庫(kù) RCC初始化函數(shù)SystemClock_Config()梳理分析、初步細(xì)致學(xué)習(xí)(一)

這篇具有很好參考價(jià)值的文章主要介紹了stm32 hal庫(kù) RCC初始化函數(shù)SystemClock_Config()梳理分析、初步細(xì)致學(xué)習(xí)(一)。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

目錄

一、PLL主時(shí)鐘初始化

1.1 時(shí)鐘使能

?1.2 配置好主時(shí)鐘配置結(jié)構(gòu)體

1.3 將配置好的值寫入到對(duì)應(yīng)的寄存器、初始化PLL主時(shí)鐘;

1.3.1 __HAL_RCC_HSE_CONFIG(RCC_OscInitStruct->HSEState)分析:?

1.3.2 給PLL相關(guān)寄存器賦值:

二、外設(shè)時(shí)鐘初始化

2.1等待周期的驗(yàn)證和寫入;

2.2 HCLK配置

2.3 SYSCLK配置、時(shí)鐘源選擇

2.3.1? PLL時(shí)鐘就緒檢測(cè)和__HAL_RCC_GET_FLAG(RCC_FLAG_PLLRDY)宏定義的分析

2.3.2 系統(tǒng)時(shí)鐘源選擇

2.4PCLK1和PCLK2配置

2.5 更新hal庫(kù)參數(shù)

三、總結(jié)


本人使用的單片機(jī)stm32f407vg,代碼來源stm32CubeMx。

時(shí)鐘配置如下

systemclock_config,stm32,學(xué)習(xí)

?主函數(shù)調(diào)用SystemClock_Config();,這也是RCC初始化函數(shù);

void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Configure the main internal regulator output voltage 
  */
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
  /** Initializes the CPU, AHB and APB busses clocks 
  */
  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 = 25;
  RCC_OscInitStruct.PLL.PLLN = 144;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 4;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB busses clocks 
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}

一、PLL主時(shí)鐘初始化

1.1 時(shí)鐘使能

__HAL_RCC_PWR_CLK_ENABLE();

#define __HAL_RCC_PWR_CLK_ENABLE() ? ? do { \
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??__IO uint32_t tmpreg = 0x00U; \
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? SET_BIT(RCC->APB1ENR, RCC_APB1ENR_PWREN);\
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /* Delay after an RCC peripheral clock enabling */ \
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??tmpreg = READ_BIT(RCC->APB1ENR, RCC_APB1ENR_PWREN);\
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? UNUSED(tmpreg); \
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??} while(0U)

#define SET_BIT(REG, BIT) ? ? ((REG) |= (BIT))

?#define READ_BIT(REG, BIT) ? ?((REG) & (BIT))

#define RCC_APB1ENR_PWREN_Pos ? ? ? ? ? ? ?(28U) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
#define RCC_APB1ENR_PWREN_Msk ? ? ? ? ? ? ?(0x1UL<<RCC_APB1ENR_PWREN_Pos)?
#define RCC_APB1ENR_PWREN ? ? ? ? ? ? ? ? ?RCC_APB1ENR_PWREN_Msk ? ?

systemclock_config,stm32,學(xué)習(xí)

把0x1左移28位,即使能電源接口時(shí)鐘;

__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

這個(gè)函數(shù)是調(diào)壓器輸出電壓級(jí)別選擇,選擇級(jí)別1模式(默認(rèn)的模式),暫時(shí)不了解有什么作用;

?1.2 配置好主時(shí)鐘配置結(jié)構(gòu)體

systemclock_config,stm32,學(xué)習(xí)

?32的時(shí)鐘樹,暫時(shí)用到這些;

?RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
?RCC_OscInitStruct.HSEState = RCC_HSE_ON;

#define RCC_OSCILLATORTYPE_NONE ? ? ? ? ? ?0x00000000U
#define RCC_OSCILLATORTYPE_HSE ? ? ? ? ? ? 0x00000001U
#define RCC_OSCILLATORTYPE_HSI ? ? ? ? ? ? 0x00000002U
#define RCC_OSCILLATORTYPE_LSE ? ? ? ? ? ? 0x00000004U
#define RCC_OSCILLATORTYPE_LSI ? ? ? ? ? ? 0x00000008U

#define RCC_HSE_OFF ? ? ? ? ? ? ? ? ? ? ?0x00000000U
#define RCC_HSE_ON ? ? ? ? ? ? ? ? ? ? ? RCC_CR_HSEON
#define RCC_HSE_BYPASS ? ? ? ? ? ? ? ((uint32_t)(RCC_CR_HSEBYP | RCC_CR_HSEON))

分別是配置時(shí)鐘源為(HSE\HSI\LSE\LSI); 選擇HSE時(shí)鐘狀態(tài)(使能、關(guān)閉、旁路)

? RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
? RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
? RCC_OscInitStruct.PLL.PLLM = 25;
? RCC_OscInitStruct.PLL.PLLN = 144;
? RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
? RCC_OscInitStruct.PLL.PLLQ = 4;

#define RCC_PLL_NONE ? ? ? ? ? ? ? ? ? ? ?((uint8_t)0x00)
#define RCC_PLL_OFF ? ? ? ? ? ? ? ? ? ? ? ((uint8_t)0x01)
#define RCC_PLL_ON ? ? ? ? ? ? ? ? ? ? ? ?((uint8_t)0x02)

#define RCC_PLLSOURCE_HSI ? ? ? ? ? ? ? ?RCC_PLLCFGR_PLLSRC_HSI
#define RCC_PLLSOURCE_HSE ? ? ? ? ? ? ? ?RCC_PLLCFGR_PLLSRC_HSE

#define RCC_PLLCFGR_PLLSRC_HSE_Pos ? ? ? ? (22U) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
#define RCC_PLLCFGR_PLLSRC_HSE_Msk? ?

?????????????????????????????????????????????????????????????????(0x1UL <<RCC_PLLCFGR_PLLSRC_HSE_Pos)?
#define RCC_PLLCFGR_PLLSRC_HSE ? ? ? ? ? ? RCC_PLLCFGR_PLLSRC_HSE_Msk

?#define RCC_PLLP_DIV2 ? ? ? ? ? ? ? ? ?0x00000002U
#define RCC_PLLP_DIV4 ? ? ? ? ? ? ? ? ?0x00000004U
#define RCC_PLLP_DIV6 ? ? ? ? ? ? ? ? ?0x00000006U
#define RCC_PLLP_DIV8 ? ? ? ? ? ? ? ? ?0x00000008U

分別為PLL時(shí)鐘(使能、關(guān)閉);PLL時(shí)鐘源選擇(HSE\HSI);PLL M\N\P,Q分頻器賦值;

1.3 將配置好的值寫入到對(duì)應(yīng)的寄存器、初始化PLL主時(shí)鐘;

? if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
? {
? ? Error_Handler();
? }

調(diào)用這個(gè)函數(shù)進(jìn)行賦值,并通過返回值判斷是否初始化成功;

代碼很長(zhǎng),只留下HSE和PLL配置部分;

__weak HAL_StatusTypeDef HAL_RCC_OscConfig(RCC_OscInitTypeDef  *RCC_OscInitStruct)
{
  uint32_t tickstart, 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 HSE will not disabled */
    if((__HAL_RCC_GET_SYSCLK_SOURCE() == RCC_CFGR_SWS_HSE) ||\
      ((__HAL_RCC_GET_SYSCLK_SOURCE() == RCC_CFGR_SWS_PLL) && ((RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) == RCC_PLLCFGR_PLLSRC_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 bypassed or disabled */
        while(__HAL_RCC_GET_FLAG(RCC_FLAG_HSERDY) != RESET)
        {
          if((HAL_GetTick() - tickstart ) > HSE_TIMEOUT_VALUE)
          {
            return HAL_TIMEOUT;
          }
        }
      }
    }
  }
/*-------------------------------- 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_CFGR_SWS_PLL)
    {
      if((RCC_OscInitStruct->PLL.PLLState) == RCC_PLL_ON)
      {
        /* Check the parameters */
        assert_param(IS_RCC_PLLSOURCE(RCC_OscInitStruct->PLL.PLLSource));
        assert_param(IS_RCC_PLLM_VALUE(RCC_OscInitStruct->PLL.PLLM));
        assert_param(IS_RCC_PLLN_VALUE(RCC_OscInitStruct->PLL.PLLN));
        assert_param(IS_RCC_PLLP_VALUE(RCC_OscInitStruct->PLL.PLLP));
        assert_param(IS_RCC_PLLQ_VALUE(RCC_OscInitStruct->PLL.PLLQ));

        /* Disable the main PLL. */
        __HAL_RCC_PLL_DISABLE();

        /* 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;
          }
        }

        /* Configure the main PLL clock source, multiplication and division factors. */
        WRITE_REG(RCC->PLLCFGR, (RCC_OscInitStruct->PLL.PLLSource                                            | \
                                 RCC_OscInitStruct->PLL.PLLM                                                 | \
                                 (RCC_OscInitStruct->PLL.PLLN << RCC_PLLCFGR_PLLN_Pos)             | \
                                 (((RCC_OscInitStruct->PLL.PLLP >> 1U) - 1U) << RCC_PLLCFGR_PLLP_Pos) | \
                                 (RCC_OscInitStruct->PLL.PLLQ << RCC_PLLCFGR_PLLQ_Pos)));
        /* 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 ready */
        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_PLLCFGR_PLLSRC) != RCC_OscInitStruct->PLL.PLLSource) ||
           (READ_BIT(pll_config, RCC_PLLCFGR_PLLM) != RCC_OscInitStruct->PLL.PLLM) ||
           (READ_BIT(pll_config, RCC_PLLCFGR_PLLN) != RCC_OscInitStruct->PLL.PLLN) ||
           (READ_BIT(pll_config, RCC_PLLCFGR_PLLP) != RCC_OscInitStruct->PLL.PLLP) ||
           (READ_BIT(pll_config, RCC_PLLCFGR_PLLQ) != RCC_OscInitStruct->PLL.PLLQ))
        {
          return HAL_ERROR;
        }
      }
    }
  }
  return HAL_OK;
}

首先是很長(zhǎng)一堆判斷是否出錯(cuò)的語句,不用管;

1.3.1 __HAL_RCC_HSE_CONFIG(RCC_OscInitStruct->HSEState)分析:?

? ? ? /* Set the new HSE configuration ---------------------------------------*/
? ? ? __HAL_RCC_HSE_CONFIG(RCC_OscInitStruct->HSEState);?


而函數(shù)本身如下

#define __HAL_RCC_HSE_CONFIG(__STATE__) ? ? ? ? ? ? ? ? ? ? ? ? \
? ? ? ? ? ? ? ? ? ? do { if ((__STATE__) == RCC_HSE_ON) ?

????????????????????????? ? ????????? SET_BIT(RCC->CR, RCC_CR_HSEON); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
? ? ? ? ? ? ? ? ? ? ???????else if ((__STATE__) == RCC_HSE_BYPASS) ? \
? ? ? ? ? ? ? ? ? ? ???????{? ? ? ? ?SET_BIT(RCC->CR, RCC_CR_HSEBYP); ? ? ? ?\
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?SET_BIT(RCC->CR, RCC_CR_HSEON); ?? } ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \??????????????????????else ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\
? ? ? ? ? ? ? ? ? ? ????? { ? ? ? ? ??CLEAR_BIT(RCC->CR, RCC_CR_HSEON); ? ? ? \
? ? ? ? ? ? ? ? ? ? ? ? ???????????????CLEAR_BIT(RCC->CR, RCC_CR_HSEBYP); ?} ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??????? ? } while(0U)

簡(jiǎn)單看就是判斷HSE使能還是旁路。然后給RCC_CR對(duì)應(yīng)位賦值;

SET_BIT(RCC->CR, RCC_CR_HSEON); ?

#define SET_BIT(REG, BIT) ? ? ((REG) |= (BIT))

之前初始化的語句是:

RCC_OscInitStruct.HSEState = RCC_HSE_ON;

對(duì)應(yīng)的值如下

#define RCC_CR_HSEON_Pos ? ? ? ? ? ? ? ? ? (16U) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
#define RCC_CR_HSEON_Msk ? ? ? ? ? ? ? ? ? (0x1UL << RCC_CR_HSEON_Pos)? ? ? ? ??
#define RCC_CR_HSEON ? ? ? ? ? ? ? ? ? ? ? RCC_CR_HSEON_Msk ?

即1左移16位;

systemclock_config,stm32,學(xué)習(xí)

而,SET_BIT(RCC->CR, RCC_CR_HSEBYP);

#define RCC_CR_HSEBYP_Pos ? ? ? ? ? ? ? ? ?(18U) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
#define RCC_CR_HSEBYP_Msk ? ? ? ? ? ? ? ? ?(0x1UL << RCC_CR_HSEBYP_Pos)? ? ? ? ?
#define RCC_CR_HSEBYP ? ? ? ? ? ? ? ? ? ? ?RCC_CR_HSEBYP_Msk?

即1左移18位;

systemclock_config,stm32,學(xué)習(xí)

暫時(shí)沒用過HSE旁路,好像是不用晶振、用外部信號(hào)輸入代替晶振。

1.3.2 給PLL相關(guān)寄存器賦值:

先關(guān)閉PLL時(shí)鐘:

__HAL_RCC_PLL_DISABLE();

#define __HAL_RCC_PLL_DISABLE() (*(__IO uint32_t *) RCC_CR_PLLON_BB = DISABLE)

#define RCC_PLLON_BIT_NUMBER ? ? ? 0x18U
#define RCC_CR_PLLON_BB ? ? ? ? ? ?(PERIPH_BB_BASE + (RCC_CR_OFFSET * 32U) + (RCC_PLLON_BIT_NUMBER * 4U))
#define PERIPH_BB_BASE ? ? ? ?0x42000000UL
/* --- CR Register --- */
#define RCC_CR_OFFSET ? ? ? ? ? ? ?(RCC_OFFSET + 0x00U)

#define RCC_OFFSET ? ? ? ? ? ? ? ? (RCC_BASE - PERIPH_BASE)

簡(jiǎn)單點(diǎn)看就是在RCC_CR寄存器里。

0x18轉(zhuǎn)換為10進(jìn)制就是24,即bit24;

systemclock_config,stm32,學(xué)習(xí)

?賦0就是關(guān)閉PLL;使能PLL同理

主要賦值語句

WRITE_REG(RCC->PLLCFGR, (RCC_OscInitStruct->PLL.PLLSource | \
RCC_OscInitStruct->PLL.PLLM | \
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?(RCC_OscInitStruct->PLL.PLLN << RCC_PLLCFGR_PLLN_Pos) ? ? ? ? ? ? | \???????(((RCC_OscInitStruct->PLL.PLLP >> 1U) - 1U) << RCC_PLLCFGR_PLLP_Pos) | \
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?(RCC_OscInitStruct->PLL.PLLQ << RCC_PLLCFGR_PLLQ_Pos)));

#define WRITE_REG(REG, VAL) ? ((REG) = (VAL))

首先是RCC_PLLSOURCE_HSE之前寫結(jié)構(gòu)體如下:

RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;

#define RCC_PLLSOURCE_HSE ? ? ? ? ? ? ? ?RCC_PLLCFGR_PLLSRC_HSE

#define RCC_PLLCFGR_PLLSRC_HSE_Pos ? ? ? ? (22U) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??

#define RCC_PLLCFGR_PLLSRC_HSE_Msk ? ? ? ? (0x1UL << RCC_PLLCFGR_PLLSRC_HSE_Pos) /*!< 0x00400000 */
#define RCC_PLLCFGR_PLLSRC_HSE ? ? ? ? ? ? RCC_PLLCFGR_PLLSRC_HSE_Msk ?

即1左移22位,在RCC_PLLCFGR寄存器中作用選擇HSE;

systemclock_config,stm32,學(xué)習(xí)

?寄存器其他位和分頻器計(jì)算如下:

systemclock_config,stm32,學(xué)習(xí)

#define RCC_PLLCFGR_PLLN_Pos ? ? ? ? ? ? ? (6U)?

#define RCC_PLLP_DIV2 ? ? ? ? ? ? ? ? ?0x00000002U
#define RCC_PLLP_DIV4 ? ? ? ? ? ? ? ? ?0x00000004U
#define RCC_PLLP_DIV6 ? ? ? ? ? ? ? ? ?0x00000006U
#define RCC_PLLP_DIV8 ? ? ? ? ? ? ? ? ?0x00000008U

#define RCC_PLLCFGR_PLLP_Pos ? ? ? ? ? ? ? (16U)?

#define RCC_PLLCFGR_PLLQ_Pos ? ? ? ? ? ? ? (24U) ??

PLLM不移動(dòng),PLLN左移6位,PLLQ左移24

PLLP分頻的值右移1位、即除以2再減1,2~8分頻對(duì)應(yīng)00~11兩位,PLLP左移16位;

最后把各個(gè)數(shù)相或,數(shù)值寫到寄存器。

完畢后使能PLL時(shí)鐘。

這兒使用write,是因?yàn)椴僮鞯奈槐容^多,直接相與再寫入比較方便。

二、外設(shè)時(shí)鐘初始化

?systemclock_config,stm32,學(xué)習(xí)

時(shí)鐘樹如上,結(jié)構(gòu)體成員賦值如下:

RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2
;
? RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
? RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
? RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
? RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;

#define RCC_CLOCKTYPE_SYSCLK ? ? ? ? ? ? 0x00000001U
#define RCC_CLOCKTYPE_HCLK ? ? ? ? ? ? ? 0x00000002U
#define RCC_CLOCKTYPE_PCLK1 ? ? ? ? ? ? ?0x00000004U
#define RCC_CLOCKTYPE_PCLK2 ? ? ? ? ? ? ?0x00000008U

#define RCC_SYSCLKSOURCE_HSI ? ? ? ? ? ? RCC_CFGR_SW_HSI
#define RCC_SYSCLKSOURCE_HSE ? ? ? ? ? ? RCC_CFGR_SW_HSE
#define RCC_SYSCLKSOURCE_PLLCLK ? ? ? ? ?RCC_CFGR_SW_PLL

#define RCC_SYSCLK_DIV1 ? ? ? ? ? ? ? ? ?RCC_CFGR_HPRE_DIV1
#define RCC_SYSCLK_DIV2 ? ? ? ? ? ? ? ? ?RCC_CFGR_HPRE_DIV2

...
#define RCC_SYSCLK_DIV512 ? ? ? ? ? ? ? ?RCC_CFGR_HPRE_DIV512

#define RCC_HCLK_DIV1 ? ? ? ? ? ? ? ? ? ?RCC_CFGR_PPRE1_DIV1
#define RCC_HCLK_DIV2 ? ? ? ? ? ? ? ? ? ?RCC_CFGR_PPRE1_DIV2
...
#define RCC_HCLK_DIV16 ? ? ? ? ? ? ? ? ? RCC_CFGR_PPRE1_DIV16

分別是要使能的外設(shè)時(shí)鐘(HCLK\SYSCLK\PCLK1\PCLK2);

系統(tǒng)時(shí)鐘源選擇(HSI\HSE\PLLCLK);AHB分頻器,APB1分頻器,APB2分頻器。

將配置好的結(jié)構(gòu)體成員寫到對(duì)應(yīng)的寄存器內(nèi);

? if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
? {
? ? Error_Handler();
? }

調(diào)用這個(gè)函數(shù)并且判斷是否出錯(cuò);

函數(shù)主體如下:?

HAL_StatusTypeDef HAL_RCC_ClockConfig(RCC_ClkInitTypeDef  *RCC_ClkInitStruct, uint32_t FLatency)
{
  uint32_t tickstart;

  /* Check Null pointer */
  if(RCC_ClkInitStruct == NULL)
  {
    return HAL_ERROR;
  }

  /* Check the parameters */
  assert_param(IS_RCC_CLOCKTYPE(RCC_ClkInitStruct->ClockType));
  assert_param(IS_FLASH_LATENCY(FLatency));

  /* To correctly read data from FLASH memory, the number of wait states (LATENCY)
    must be correctly programmed according to the frequency of the CPU clock
    (HCLK) and the supply voltage of the device. */

  /* Increasing the number of wait states because of higher CPU frequency */
  if(FLatency > __HAL_FLASH_GET_LATENCY())
  {
    /* Program the new number of wait states to the LATENCY bits in the FLASH_ACR register */
    __HAL_FLASH_SET_LATENCY(FLatency);

    /* Check that the new number of wait states is taken into account to access the Flash
    memory by reading the FLASH_ACR register */
    if(__HAL_FLASH_GET_LATENCY() != FLatency)
    {
      return HAL_ERROR;
    }
  }

  /*-------------------------- HCLK Configuration --------------------------*/
  if(((RCC_ClkInitStruct->ClockType) & RCC_CLOCKTYPE_HCLK) == RCC_CLOCKTYPE_HCLK)
  {
    /* Set the highest APBx dividers in order to ensure that we do not go through
       a non-spec phase whatever we decrease or increase HCLK. */
    if(((RCC_ClkInitStruct->ClockType) & RCC_CLOCKTYPE_PCLK1) == RCC_CLOCKTYPE_PCLK1)
    {
      MODIFY_REG(RCC->CFGR, RCC_CFGR_PPRE1, RCC_HCLK_DIV16);
    }

    if(((RCC_ClkInitStruct->ClockType) & RCC_CLOCKTYPE_PCLK2) == RCC_CLOCKTYPE_PCLK2)
    {
      MODIFY_REG(RCC->CFGR, RCC_CFGR_PPRE2, (RCC_HCLK_DIV16 << 3));
    }

    assert_param(IS_RCC_HCLK(RCC_ClkInitStruct->AHBCLKDivider));
    MODIFY_REG(RCC->CFGR, RCC_CFGR_HPRE, RCC_ClkInitStruct->AHBCLKDivider);
  }

  /*------------------------- SYSCLK Configuration ---------------------------*/
  if(((RCC_ClkInitStruct->ClockType) & RCC_CLOCKTYPE_SYSCLK) == RCC_CLOCKTYPE_SYSCLK)
  {
    assert_param(IS_RCC_SYSCLKSOURCE(RCC_ClkInitStruct->SYSCLKSource));

    /* HSE is selected as System Clock Source */
    if(RCC_ClkInitStruct->SYSCLKSource == RCC_SYSCLKSOURCE_HSE)
    {
      /* Check the HSE ready flag */
      if(__HAL_RCC_GET_FLAG(RCC_FLAG_HSERDY) == RESET)
      {
        return HAL_ERROR;
      }
    }
    /* PLL is selected as System Clock Source */
    else if((RCC_ClkInitStruct->SYSCLKSource == RCC_SYSCLKSOURCE_PLLCLK)   ||
            (RCC_ClkInitStruct->SYSCLKSource == RCC_SYSCLKSOURCE_PLLRCLK))
    {
      /* Check the PLL ready flag */
      if(__HAL_RCC_GET_FLAG(RCC_FLAG_PLLRDY) == RESET)
      {
        return HAL_ERROR;
      }
    }
    /* HSI is selected as System Clock Source */
    else
    {
      /* Check the HSI ready flag */
      if(__HAL_RCC_GET_FLAG(RCC_FLAG_HSIRDY) == RESET)
      {
        return HAL_ERROR;
      }
    }

    __HAL_RCC_SYSCLK_CONFIG(RCC_ClkInitStruct->SYSCLKSource);

    /* Get Start Tick */
    tickstart = HAL_GetTick();

    while (__HAL_RCC_GET_SYSCLK_SOURCE() != (RCC_ClkInitStruct->SYSCLKSource << RCC_CFGR_SWS_Pos))
    {
      if ((HAL_GetTick() - tickstart) > CLOCKSWITCH_TIMEOUT_VALUE)
      {
        return HAL_TIMEOUT;
      }
    }
  }

  /* Decreasing the number of wait states because of lower CPU frequency */
  if(FLatency < __HAL_FLASH_GET_LATENCY())
  {
     /* Program the new number of wait states to the LATENCY bits in the FLASH_ACR register */
    __HAL_FLASH_SET_LATENCY(FLatency);

    /* Check that the new number of wait states is taken into account to access the Flash
    memory by reading the FLASH_ACR register */
    if(__HAL_FLASH_GET_LATENCY() != FLatency)
    {
      return HAL_ERROR;
    }
  }

  /*-------------------------- PCLK1 Configuration ---------------------------*/
  if(((RCC_ClkInitStruct->ClockType) & RCC_CLOCKTYPE_PCLK1) == RCC_CLOCKTYPE_PCLK1)
  {
    assert_param(IS_RCC_PCLK(RCC_ClkInitStruct->APB1CLKDivider));
    MODIFY_REG(RCC->CFGR, RCC_CFGR_PPRE1, RCC_ClkInitStruct->APB1CLKDivider);
  }

  /*-------------------------- PCLK2 Configuration ---------------------------*/
  if(((RCC_ClkInitStruct->ClockType) & RCC_CLOCKTYPE_PCLK2) == RCC_CLOCKTYPE_PCLK2)
  {
    assert_param(IS_RCC_PCLK(RCC_ClkInitStruct->APB2CLKDivider));
    MODIFY_REG(RCC->CFGR, RCC_CFGR_PPRE2, ((RCC_ClkInitStruct->APB2CLKDivider) << 3U));
  }

  /* Update the SystemCoreClock global variable */
  SystemCoreClock = HAL_RCC_GetSysClockFreq() >> AHBPrescTable[(RCC->CFGR & RCC_CFGR_HPRE)>> RCC_CFGR_HPRE_Pos];

  /* Configure the source of time base considering new system clocks settings */
  HAL_InitTick (uwTickPrio);

  return HAL_OK;
}

2.1等待周期的驗(yàn)證和寫入;

? if(FLatency > __HAL_FLASH_GET_LATENCY())
? {
? ? /* Program the new number of wait states to the LATENCY bits in the FLASH_ACR register */
? ? __HAL_FLASH_SET_LATENCY(FLatency);

? ? /* Check that the new number of wait states is taken into account to access the Flash
? ? memory by reading the FLASH_ACR register */
? ? if(__HAL_FLASH_GET_LATENCY() != FLatency)
? ? {
? ? ? return HAL_ERROR;
? ? }
? }

初步看是判斷等待周期的,

#define FLASH_LATENCY_2 ? ? ? ? ? ? ? ?FLASH_ACR_LATENCY_2WS ?

???????????????????????????????????????????????????????????????? /*!< FLASH Two Latency cycles ? ? ?*/

#define FLASH_ACR_LATENCY_2WS ? ? ? ? ?0x00000002U ??

#define __HAL_FLASH_GET_LATENCY() ? ? (READ_BIT((FLASH->ACR), FLASH_ACR_LATENCY))

systemclock_config,stm32,學(xué)習(xí)

?#define __HAL_FLASH_SET_LATENCY(__LATENCY__) (*(__IO uint8_t *)ACR_BYTE0_ADDRESS = (uint8_t)(__LATENCY__))

#define ACR_BYTE0_ADDRESS ? ? ? ? ? 0x40023C00U?

我們主要操作RCC_CFGR寄存器,所以在切換時(shí)鐘源時(shí)要插入1、2個(gè)等待周期。

所以做法是調(diào)用函數(shù)__HAL_FLASH_GET_LATENCY()

讀取FLASH_ACR寄存器LATENCY位。當(dāng)?shù)却芷谛∮?時(shí)要進(jìn)行處理。

方法就是給LATENCY地址寫值,寫的值就是FLASH_LATENCY_2。

至于為什么沒有用很多基地址組合,因?yàn)镕LASH下的寄存器很重要,能自主讀寫的很少。

systemclock_config,stm32,學(xué)習(xí)

2.2 HCLK配置

? /*-------------------------- HCLK Configuration --------------------------*/
? if(((RCC_ClkInitStruct->ClockType) & RCC_CLOCKTYPE_HCLK) == RCC_CLOCKTYPE_HCLK)
? {
? ? /* Set the highest APBx dividers in order to ensure that we do not go through
? ? ? ?a non-spec phase whatever we decrease or increase HCLK. */
? ? if(((RCC_ClkInitStruct->ClockType) & RCC_CLOCKTYPE_PCLK1) == RCC_CLOCKTYPE_PCLK1)
? ? {
? ? ? MODIFY_REG(RCC->CFGR, RCC_CFGR_PPRE1, RCC_HCLK_DIV16);
? ? }

? ? if(((RCC_ClkInitStruct->ClockType) & RCC_CLOCKTYPE_PCLK2) == RCC_CLOCKTYPE_PCLK2)
? ? {
? ? ? MODIFY_REG(RCC->CFGR, RCC_CFGR_PPRE2, (RCC_HCLK_DIV16 << 3));
? ? }

? ? assert_param(IS_RCC_HCLK(RCC_ClkInitStruct->AHBCLKDivider));
? ?MODIFY_REG(RCC->CFGR, RCC_CFGR_HPRE, RCC_ClkInitStruct->AHBCLKDivider);
? }

之前結(jié)構(gòu)體HCLK和其他三個(gè)相或,所以這兒的if判斷都要進(jìn)入里面;

后面兩個(gè)if語句都是判斷欲開啟的外設(shè)時(shí)鐘有沒有PCLK1、PCLK2,都有,然后賦值16分頻,具體的后面詳解;

這部分主要是

MODIFY_REG(RCC->CFGR, RCC_CFGR_HPRE, RCC_ClkInitStruct->AHBCLKDivider);

#define MODIFY_REG(REG, CLEARMASK, SETMASK) ?WRITE_REG((REG), (((READ_REG(REG)) & (~(CLEARMASK))) | (SETMASK)))

這兒括號(hào)很多,一開始看錯(cuò)了,看成前面的寄存器和后面一堆相與,怎么也不對(duì),其實(shí)是寄存器和中間那部分相與,再和后面那部分相或;這個(gè)宏定義作用是給這個(gè)寄存器寫數(shù)值,后面一堆按位運(yùn)算的作用是只寫給想修改的位,其他的保持不變。

READ_REG(REG)就是讀RCC_CFGR寄存器的值;

#define RCC_CFGR_HPRE_Pos ? ? ? ? ? ? ? ? ?(4U) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
#define RCC_CFGR_HPRE_Msk ? ? ? ? ? ? ? ? ?(0xFUL << RCC_CFGR_HPRE_Pos) ? ? ? ?

????????????????????????????????????????????????????????????????????????????????/*!< 0x000000F0 */
#define RCC_CFGR_HPRE ? ? ? ? ? ? ? ? ? ? ?RCC_CFGR_HPRE_Msk ?

RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;

#define RCC_SYSCLK_DIV1 ? ? ? ? ? ? ? ? ?RCC_CFGR_HPRE_DIV1

#define RCC_CFGR_HPRE_DIV1 ? ? ? ? ? ? ? ? 0x00000000U? ? ? ? ? ? ? ? ? ? ? ? ?
#define RCC_CFGR_HPRE_DIV2 ? ? ? ? ? ? ? ? 0x00000080U? ? ? ? ? ? ? ? ? ? ? ?
#define RCC_CFGR_HPRE_DIV4 ? ? ? ? ? ? ? ? 0x00000090U? ? ? ? ? ? ? ? ? ? ? ??
#define RCC_CFGR_HPRE_DIV8 ? ? ? ? ? ? ? ? 0x000000A0U? ? ? ? ? ? ? ? ? ? ??
...? ? ? ? ? ? ? ? ? ? ?
#define RCC_CFGR_HPRE_DIV512 ? ? ? ? ? ? ? 0x000000F0U?

這個(gè)宏定義的邏輯就是寄存器本來的值和(0x000000f0取反)也就是0xffffff0f相與,得到的值是bit[5:8]清零,其他位不變,這個(gè)值再和分頻的值相或,0的位置變?yōu)橄雽懭氲闹怠?/strong>

systemclock_config,stm32,學(xué)習(xí)

2.3 SYSCLK配置、時(shí)鐘源選擇

if(((RCC_ClkInitStruct->ClockType) & RCC_CLOCKTYPE_SYSCLK) == RCC_CLOCKTYPE_SYSCLK)
? {
? ? assert_param(IS_RCC_SYSCLKSOURCE(RCC_ClkInitStruct->SYSCLKSource));


? ? /* PLL is selected as System Clock Source */
? ? else if((RCC_ClkInitStruct->SYSCLKSource == RCC_SYSCLKSOURCE_PLLCLK) ? ||
? ? ? ? ? ? (RCC_ClkInitStruct->SYSCLKSource == RCC_SYSCLKSOURCE_PLLRCLK))
? ? {
? ? ? /* Check the PLL ready flag */
? ? ? if(__HAL_RCC_GET_FLAG(RCC_FLAG_PLLRDY) == RESET)
? ? ? {
? ? ? ? return HAL_ERROR;
? ? ? }
? ? }

? ? __HAL_RCC_SYSCLK_CONFIG(RCC_ClkInitStruct->SYSCLKSource);

? ? /* Get Start Tick */
? ? tickstart = HAL_GetTick();

? ? while (__HAL_RCC_GET_SYSCLK_SOURCE() != (RCC_ClkInitStruct->SYSCLKSource << RCC_CFGR_SWS_Pos))
? ? {
? ? ? if ((HAL_GetTick() - tickstart) > CLOCKSWITCH_TIMEOUT_VALUE)
? ? ? {
? ? ? ? return HAL_TIMEOUT;
? ? ? }
? ? }
? }

? /* Decreasing the number of wait states because of lower CPU frequency */
? if(FLatency < __HAL_FLASH_GET_LATENCY())
? {
? ? ?/* Program the new number of wait states to the LATENCY bits in the FLASH_ACR register */
? ? __HAL_FLASH_SET_LATENCY(FLatency);

? ? /* Check that the new number of wait states is taken into account to access the Flash
? ? memory by reading the FLASH_ACR register */
? ? if(__HAL_FLASH_GET_LATENCY() != FLatency)
? ? {
? ? ? return HAL_ERROR;
? ? }
? }

代碼很長(zhǎng),去掉一部分HSE、HSI作為時(shí)鐘源的代碼原理和PLL的一致。

2.3.1? PLL時(shí)鐘就緒檢測(cè)和__HAL_RCC_GET_FLAG(RCC_FLAG_PLLRDY)宏定義的分析

首先是時(shí)鐘就緒標(biāo)志位的檢測(cè),就比如我要PLL作為主時(shí)鐘的時(shí)鐘源。那么在開啟主時(shí)鐘之前必須要保證PLL是打開的,軟件通過CR寄存器下PLLRDY判斷。

systemclock_config,stm32,學(xué)習(xí)

?通過函數(shù)? ? ?

if(__HAL_RCC_GET_FLAG(RCC_FLAG_PLLRDY) == RESET)
? ? ? {
? ? ? ? return HAL_ERROR;
? ? ? }

#define __HAL_RCC_GET_FLAG(__FLAG__) (((((((__FLAG__) >> 5U) == 1U)? RCC->CR :((((__FLAG__) >> 5U) == 2U) ? RCC->BDCR :((((__FLAG__) >> 5U) == 3U)? RCC->CSR :RCC->CIR))) & (1U << ((__FLAG__) & RCC_FLAG_MASK)))!= 0U)? 1U : 0U)
這個(gè)宏定義很長(zhǎng),下面是__FLAG__可以選的值

/* Flags in the CR register */
#define RCC_FLAG_HSIRDY ? ? ? ? ? ? ? ? ?((uint8_t)0x21)
#define RCC_FLAG_HSERDY ? ? ? ? ? ? ? ? ?((uint8_t)0x31)
#define RCC_FLAG_PLLRDY ? ? ? ? ? ? ? ? ?((uint8_t)0x39)
#define RCC_FLAG_PLLI2SRDY ? ? ? ? ? ? ? ((uint8_t)0x3B)

/* Flags in the BDCR register */
#define RCC_FLAG_LSERDY ? ? ? ? ? ? ? ? ?((uint8_t)0x41)

/* Flags in the CSR register */
#define RCC_FLAG_LSIRDY ? ? ? ? ? ? ? ? ?((uint8_t)0x61)
#define RCC_FLAG_BORRST ? ? ? ? ? ? ? ? ?((uint8_t)0x79)
#define RCC_FLAG_PINRST ? ? ? ? ? ? ? ? ?((uint8_t)0x7A)
#define RCC_FLAG_PORRST ? ? ? ? ? ? ? ? ?((uint8_t)0x7B)
#define RCC_FLAG_SFTRST ? ? ? ? ? ? ? ? ?((uint8_t)0x7C)
#define RCC_FLAG_IWDGRST ? ? ? ? ? ? ? ? ((uint8_t)0x7D)
#define RCC_FLAG_WWDGRST ? ? ? ? ? ? ? ? ((uint8_t)0x7E)
#define RCC_FLAG_LPWRRST ? ? ? ? ? ? ? ? ((uint8_t)0x7F)

#define RCC_FLAG_MASK ?((uint8_t)0x1FU)

將宏定義拆開來看:

if((((((__FLAG__) >> 5U) == 1U)? RCC->CR :((((__FLAG__) >> 5U) == 2U) ? RCC->BDCR :((((__FLAG__) >> 5U) == 3U)? RCC->CSR :RCC->CIR))) & (1U << ((__FLAG__) & RCC_FLAG_MASK)))!= 0U)? ?return 1;

else? ? ? ?return 0;

把((__FLAG__) >> 5U) 看成 b;就是

if(b == 1)

{

? ? ? ? if(RCC_CR & (1U << ((__FLAG__) & RCC_FLAG_MASK)) != 0u)

? ? ? ? ????????return 1;

? ? ? ? else

? ? ? ? ? ? ? ? return 0;

}

else if (b == 2)

{

????????

? ? ? ? if(RCC_BDCR & (1U << ((__FLAG__) & RCC_FLAG_MASK)) != 0u)

? ? ? ? ????????return 1;

? ? ? ? else

? ? ? ? ? ? ? ? return 0;

}

...

#define RCC_FLAG_PLLRDY ? ? ? ? ? ? ? ? ?((uint8_t)0x39)

對(duì)于PLL標(biāo)準(zhǔn)位,0x39右移5位等于1,0x39和0x1f相與,也就是取后5位,得到0x19;1左移0x19位是1左移25位,也就是PLLRDY位,其他位都是0。再和RCC_CR相與,就是取第25位是0,還是1.

當(dāng)是1時(shí),也就是PLL開啟時(shí)得到的結(jié)果不等于0;當(dāng)未硬件置一時(shí),0和1相與也是0,得到的結(jié)果就是0;

2.3.2 系統(tǒng)時(shí)鐘源選擇

__HAL_RCC_SYSCLK_CONFIG(RCC_ClkInitStruct->SYSCLKSource);

#define __HAL_RCC_SYSCLK_CONFIG(__RCC_SYSCLKSOURCE__) MODIFY_REG(RCC->CFGR, RCC_CFGR_SW, (__RCC_SYSCLKSOURCE__))
?

#define RCC_CFGR_SW_Pos ? ? ? ? ? ? ? ? ? ?(0U) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
#define RCC_CFGR_SW_Msk ? ? ? ? ? ? ? ? ? ?(0x3UL << RCC_CFGR_SW_Pos) ? ? ? ? ?

#define RCC_CFGR_SW ? ? ? ? ? ? ? ? ? ? ? ?RCC_CFGR_SW_Msk ?????????/*!< 0x00000003 */

#define RCC_SYSCLKSOURCE_PLLCLK ? ? ? ? ?RCC_CFGR_SW_PLL

#define RCC_CFGR_SW_HSI ? ? ? ? ? ? ? ? ? ?0x00000000U? ? ? ? ? ? ? ? ? ? ? ? ?
#define RCC_CFGR_SW_HSE ? ? ? ? ? ? ? ? ? ?0x00000001U? ? ? ? ? ? ? ? ? ? ? ? ?
#define RCC_CFGR_SW_PLL ? ? ? ? ? ? ? ? ? ?0x00000002U? ? ? ? ? ? ? ? ? ? ? ? ?
函數(shù)邏輯和之前一樣,給最后兩位賦值,其他位保持不變。

systemclock_config,stm32,學(xué)習(xí)

? if(FLatency < __HAL_FLASH_GET_LATENCY())
? {
? ? ?/* Program the new number of wait states to the LATENCY bits in the FLASH_ACR register */
? ? __HAL_FLASH_SET_LATENCY(FLatency);

? ? /* Check that the new number of wait states is taken into account to access the Flash
? ? memory by reading the FLASH_ACR register */
? ? if(__HAL_FLASH_GET_LATENCY() != FLatency)
? ? {
? ? ? return HAL_ERROR;
? ? }
? }

這部分是減少等待周期;大于2時(shí),寫入到FLASH_ACR_LATENCY,和之前一樣。

2.4PCLK1和PCLK2配置

?/*-------------------------- PCLK1 Configuration ---------------------------*/
? if(((RCC_ClkInitStruct->ClockType) & RCC_CLOCKTYPE_PCLK1) == RCC_CLOCKTYPE_PCLK1)
? {
? ? assert_param(IS_RCC_PCLK(RCC_ClkInitStruct->APB1CLKDivider));
MODIFY_REG(RCC->CFGR, RCC_CFGR_PPRE1, RCC_ClkInitStruct->APB1CLKDivider);
? }

? /*-------------------------- PCLK2 Configuration ---------------------------*/
? if(((RCC_ClkInitStruct->ClockType) & RCC_CLOCKTYPE_PCLK2) == RCC_CLOCKTYPE_PCLK2)
? {
? ? assert_param(IS_RCC_PCLK(RCC_ClkInitStruct->APB2CLKDivider));
? ? MODIFY_REG(RCC->CFGR, RCC_CFGR_PPRE2,

????????????????????????????????????????????????????????((RCC_ClkInitStruct->APB2CLKDivider) << 3U));
? }

RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;

#define RCC_CFGR_PPRE1_Pos ? ? ? ? ? ? ? ? (10U) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
#define RCC_CFGR_PPRE1_Msk ? ? ? ? ? ? ? ? (0x7UL << RCC_CFGR_PPRE1_Pos) ? ? ?

?????????????????????????????????????????????????????????????????????????????????????????/*!< 0x00001C00 */
#define RCC_CFGR_PPRE1 ? ? ? ? ? ? ? ? ? ? RCC_CFGR_PPRE1_Msk?

#define RCC_CFGR_PPRE2_Pos ? ? ? ? ? ? ? ? (13U) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
#define RCC_CFGR_PPRE2_Msk ? ? ? ? ? ? ? ? (0x7UL << RCC_CFGR_PPRE2_Pos) ? ? ?

?????????????????????????????????????????????????????????????????????????????????????????/*!< 0x0000E000 */
#define RCC_CFGR_PPRE2 ? ? ? ? ? ? ? ? ? ? RCC_CFGR_PPRE2_Msk

#define RCC_HCLK_DIV1 ? ? ? ? ? ? ? ? ? ?RCC_CFGR_PPRE1_DIV1
#define RCC_HCLK_DIV2 ? ? ? ? ? ? ? ? ? ?RCC_CFGR_PPRE1_DIV2
...
#define RCC_HCLK_DIV16 ? ? ? ? ? ? ? ? ? RCC_CFGR_PPRE1_DIV16

#define RCC_CFGR_PPRE1_DIV1 ? ? ? ? ? ? ? ?0x00000000U? ? ? ? ? ? ? ? ? ? ? ??
#define RCC_CFGR_PPRE1_DIV2 ? ? ? ? ? ? ? ?0x00001000U? ? ? ? ? ? ? ? ? ? ? ??
...? ? ? ? ? ? ? ? ? ? ? ?
#define RCC_CFGR_PPRE1_DIV16 ? ? ? ? ? ? ? 0x00001C00U?

分別是給RCC_CFGR,bit[10:12]和bit[13:15]寫入數(shù)據(jù),數(shù)據(jù)內(nèi)容是分頻值。

對(duì)于PCLK2分頻值用到PPRE1的值,所以要左移三位。

在這兒可以直接用PPER2的分頻值,但不知道為什么沒有用;

#define RCC_CFGR_PPRE2_DIV1 ? ? ? ? ? ? ? ?0x00000000U? ? ? ? ? ? ? ? ? ? ? ?
#define RCC_CFGR_PPRE2_DIV2 ? ? ? ? ? ? ? ?0x00008000U? ? ? ? ? ? ? ? ? ? ? ?
...? ? ? ? ? ? ? ? ? ? ?
#define RCC_CFGR_PPRE2_DIV16 ? ? ? ? ? ? ? 0x0000E000U?

systemclock_config,stm32,學(xué)習(xí)

2.5 更新hal庫(kù)參數(shù)

? /* Update the SystemCoreClock global variable */
? SystemCoreClock = HAL_RCC_GetSysClockFreq() >> AHBPrescTable[(RCC->CFGR & RCC_CFGR_HPRE)>> RCC_CFGR_HPRE_Pos];

? /* Configure the source of time base considering new system clocks settings */
? HAL_InitTick (uwTickPrio);

翻譯下來的意思是:更新SystemCoreClock全局變量;

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 鑒于新的系統(tǒng)時(shí)鐘設(shè)置來配置時(shí)基。

這兒涉及到hal庫(kù),目前還不太懂,希望有大佬補(bǔ)充。

三、總結(jié)

時(shí)鐘的配置最核心的還是看懂時(shí)鐘樹,知道時(shí)鐘源怎么選,時(shí)鐘這個(gè)路怎么走的,到哪個(gè)外設(shè)。至于配置完全可以利用軟件的便利,節(jié)省大量的工作,對(duì)于函數(shù)的分析其實(shí)是筆者較真了。但是一點(diǎn)點(diǎn)梳理下來,還是學(xué)習(xí)到很多函數(shù)的寫法,宏定義的運(yùn)用。同時(shí),以后可能面對(duì)的時(shí)鐘配置遠(yuǎn)超過CubeMX軟件使用的復(fù)雜度,掌握配置時(shí)鐘整體的思路至關(guān)重要。

參考資料:stm32f4xx中文參考手冊(cè)文章來源地址http://www.zghlxwxcb.cn/news/detail-616752.html

到了這里,關(guān)于stm32 hal庫(kù) RCC初始化函數(shù)SystemClock_Config()梳理分析、初步細(xì)致學(xué)習(xí)(一)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • STM32 cubemx CAN
STM32 CAN初始化詳解

    STM32 cubemx CAN STM32 CAN初始化詳解

    接收用到的結(jié)構(gòu)體如下: CAN概念: ? ? ? ? 全稱Controller Area Network,是一種半雙工,異步通訊。 物理層: ? ? ? ? 閉環(huán):允許總線最長(zhǎng)40m,最高速1Mbps,規(guī)定總線兩端各有一個(gè)120Ω電阻,閉環(huán) ? ? ? ?開環(huán):最大傳輸距離1Km,最高速125Kbps,規(guī)定每根線串聯(lián)一個(gè)2.2kΩ的電阻,

    2024年02月13日
    瀏覽(29)
  • STM32的GPIO初始化配置-學(xué)習(xí)筆記

    STM32的GPIO初始化配置-學(xué)習(xí)筆記

    ? ? ? ? 由于剛開始沒有學(xué)懂GPIO的配置原理,導(dǎo)致后面學(xué)習(xí)其它外設(shè)的時(shí)候總是產(chǎn)生阻礙,因?yàn)槠渌庠O(shè)要使用前,大部分都要配置GPIO的初始化,因此這幾天重新學(xué)習(xí)了一遍GPIO的配置,記錄如下。 ? ? ? ? 首先我們要知道芯片上的引腳,并不是只有GPIO的功能,還能復(fù)用成

    2024年04月17日
    瀏覽(30)
  • STM32 串口的初始化(內(nèi)附詳細(xì)代碼)

    STM32 串口的初始化(內(nèi)附詳細(xì)代碼)

    首先我們先要根據(jù)原理圖來確認(rèn)我們用的串口接到了那個(gè)引腳 ?我這邊的串口1為例,接收端是PA10,發(fā)送端是PA9首先我們需要配置PA9和PA10. 把接受端配置成浮空輸入,完全靠引腳來判斷。把發(fā)送端配置成復(fù)用推挽模式,并打開GPIOA的時(shí)鐘和復(fù)用時(shí)鐘多的看代碼吧,我把注釋都寫

    2024年02月13日
    瀏覽(21)
  • STM32 GPIO設(shè)置(GPIO初始化)學(xué)習(xí)筆記

    STM32 GPIO設(shè)置(GPIO初始化)學(xué)習(xí)筆記

    GPIO 都知道是 通用輸入輸出接口 的意思就不詳細(xì)解釋 那么我們就直接進(jìn)入怎么設(shè)置GPIO接口: 這里我的編譯軟件是keil5,相信大家都應(yīng)該知道stm32有各種的工作模式上拉、下拉、推挽、開漏等等。如果想要了解具體的工作模式原理這里我推薦大家看:推挽 開漏 高阻 這都是誰

    2024年03月28日
    瀏覽(29)
  • STM32—TIM定時(shí)器初始化結(jié)構(gòu)體詳解

    STM32—TIM定時(shí)器初始化結(jié)構(gòu)體詳解

    ??注:高級(jí)控制定時(shí)器可以用到所有初始化結(jié)構(gòu)體,通用定時(shí)器不能使用 TIM_BDTRInitTypeDef 結(jié)構(gòu)體,基本定時(shí)器只能使用時(shí)基結(jié)構(gòu)體。 ?? 時(shí)基結(jié)構(gòu)體TIM_TimeBaseInitTypeDef用于定時(shí)器基礎(chǔ)參數(shù)設(shè)置,與TIM_TimeBaseInit函數(shù)配合使用完成配置。 (1) TIM_Prescaler:定時(shí)器預(yù)分頻器設(shè)置,

    2024年02月02日
    瀏覽(23)
  • STM32單片機(jī)同時(shí)初始化GPIOA和GPIOB

    要同時(shí)初始化STM32F1xx的GPIOA和GPIOB,您可以按照以下步驟進(jìn)行: 首先,在代碼中包含stm32f1xx.h頭文件 , 例如: 然后,使能GPIOA和GPIOB的時(shí)鐘 ,例如: 這將使能GPIOA和GPIOB的時(shí)鐘,以便進(jìn)行配置和使用。需要注意的是,STM32F103C8T6使用APB2總線驅(qū)動(dòng)GPIOA和GPIOB。 接下來,設(shè)置GPIOA和

    2024年02月14日
    瀏覽(139)
  • STM32/GD32學(xué)習(xí)指南-踩坑之(一)外部晶振配置,初始化失敗,不起振

    STM32/GD32學(xué)習(xí)指南-踩坑之(一)外部晶振配置,初始化失敗,不起振

    GD32使用外部有源晶振和無源晶振的問題,型號(hào)為GD32 F450 一、GD32配置使用外部晶振 1.使用外部無源晶振 找到startup_gd32f450_470.s匯編文件,找到SystemInit()函數(shù)跳轉(zhuǎn)進(jìn)去 在底部找到system_clock_config()函數(shù),再次跳轉(zhuǎn)進(jìn)去 選中宏定義:__SYSTEM_CLOCK_200M_PLL_IRC16M,跳轉(zhuǎn),如圖 將內(nèi)部時(shí)鐘

    2024年02月13日
    瀏覽(26)
  • STM32CubeMX v6.9.0 BUG:FLASH_LATENCY設(shè)置錯(cuò)誤導(dǎo)致初始化失敗

    STM32CubeMX v6.9.0 BUG:FLASH_LATENCY設(shè)置錯(cuò)誤導(dǎo)致初始化失敗

    今天在調(diào)試外設(shè)功能時(shí),發(fā)現(xiàn)設(shè)置了使用外部時(shí)鐘之后程序運(yùn)行異常,進(jìn)行追蹤調(diào)試并與先前可以正常運(yùn)行的項(xiàng)目進(jìn)行對(duì)比之后發(fā)現(xiàn)這個(gè)問題可能是由于新版本的STM32CubeMX配置生成代碼時(shí)的BUG引起的。 MCU: STM32H750VBT6 STM32CubeIDE: Version: 1.13.0 Build: 17399_20230707_0829 (UTC) STM32CubeMX: v

    2024年02月15日
    瀏覽(32)
  • 【STM32&RT-Thread零基礎(chǔ)入門】 5. 線程創(chuàng)建應(yīng)用(線程創(chuàng)建、刪除、初始化、脫離、啟動(dòng)、睡眠)

    【STM32&RT-Thread零基礎(chǔ)入門】 5. 線程創(chuàng)建應(yīng)用(線程創(chuàng)建、刪除、初始化、脫離、啟動(dòng)、睡眠)

    硬件:STM32F103ZET6、ST-LINK、usb轉(zhuǎn)串口工具、4個(gè)LED燈、1個(gè)蜂鳴器、4個(gè)1k電阻、2個(gè)按鍵、面包板、杜邦線 本章主要講線程的工作機(jī)制和管理方法,通過實(shí)例講解如何使用多線程完成多任務(wù)開發(fā)。 RT-Thread用線程控制塊來描述和管理一個(gè)線程,一個(gè)線程對(duì)應(yīng)一個(gè)線程控制塊。線程控

    2024年02月12日
    瀏覽(26)
  • 通用輸入輸出端口GPIO,及其初始化(HAL庫(kù))

    我在學(xué)習(xí)STM32時(shí)候呢,是直接先接觸的STM32CubeMX軟件,更著網(wǎng)上各種教程迷迷糊糊學(xué)了一大堆沒用的東西,于是先一步步來吧,我總結(jié)了很長(zhǎng)時(shí)間,希望對(duì)正在學(xué)習(xí)相關(guān)知識(shí)的朋友們有幫助。 可以先去看看STM32CubeMX如何配置:傳送門 讀完以上我寫的文章基本上是蒙的,因?yàn)槲?/p>

    2024年02月09日
    瀏覽(19)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包