STM32F072從零配置工程-自定義時鍾配置詳解


從自己的板子STM32F407入手,參考官方的SystemInit()函數:

       核心在SetSysClock()這個函數,官方默認是采用HSE(設定為8MHz)作為PLL鎖相環的輸入輸出168MHz的SYSCLK;

/**
  * @brief  Setup the microcontroller system
  *         Initialize the Embedded Flash Interface, the PLL and update the 
  *         SystemFrequency variable.
  * @param  None
  * @retval None
  */
void SystemInit(void)
{
  /* Reset the RCC clock configuration to the default reset state ------------*/
  /* Set HSION bit */
  RCC->CR |= (uint32_t)0x00000001;

  /* Reset CFGR register */
  RCC->CFGR = 0x00000000;

  /* Reset HSEON, CSSON and PLLON bits */
  RCC->CR &= (uint32_t)0xFEF6FFFF;

  /* Reset PLLCFGR register */
  RCC->PLLCFGR = 0x24003010;

  /* Reset HSEBYP bit */
  RCC->CR &= (uint32_t)0xFFFBFFFF;

  /* Disable all interrupts */
  RCC->CIR = 0x00000000;

  /* Configure the System clock source, PLL Multiplier and Divider factors, 
     AHB/APBx prescalers and Flash settings ----------------------------------*/
  SetSysClock();

}

 

這里大致分析一下官方默認的SetSysClock()配置:

由於我個人采用的是STM32F407型號的芯片,因此精簡一下函數;

總體思路的話:

        使能HSE;

        等待HSE初始化完畢,進行下一步設置;

        設置HCLK、PCLK1、PCLK2的分頻系數;

        配置PLL,使能PLL,等待PLL初始化完畢;

        選擇PLL作為SYSCLK,等待SYSCLK時鍾設置完畢;

/**
  * @brief  Configures the System clock source, PLL Multiplier and Divider factors, 
  *         AHB/APBx prescalers and Flash settings
  * @Note   This function should be called only once the RCC clock configuration  
  *         is reset to the default reset state (done in SystemInit() function).   
  * @param  None
  * @retval None
  */
static void SetSysClock(void)
{
/******************************************************************************/
/*            PLL (clocked by HSE) used as System clock source                */
/******************************************************************************/
  __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
  
  /* Enable HSE */
  RCC->CR |= ((uint32_t)RCC_CR_HSEON);
 
  /* Wait till HSE is ready and if Time out is reached exit */
  do
  {
    HSEStatus = RCC->CR & RCC_CR_HSERDY;
    StartUpCounter++;
  } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));

  if ((RCC->CR & RCC_CR_HSERDY) != RESET)
  {
    HSEStatus = (uint32_t)0x01;
  }
  else
  {
    HSEStatus = (uint32_t)0x00;
  }

  if (HSEStatus == (uint32_t)0x01)
  {
    /* Select regulator voltage output Scale 1 mode */
    RCC->APB1ENR |= RCC_APB1ENR_PWREN;
    PWR->CR |= PWR_CR_VOS;

    /* HCLK = SYSCLK / 1*/
    RCC->CFGR |= RCC_CFGR_HPRE_DIV1;

    /* PCLK2 = HCLK / 2*/
    RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;
    
    /* PCLK1 = HCLK / 4*/
    RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;

    /* PCLK2 = HCLK / 1*/
    RCC->CFGR |= RCC_CFGR_PPRE2_DIV1;
    
    /* PCLK1 = HCLK / 2*/
    RCC->CFGR |= RCC_CFGR_PPRE1_DIV2;

    /* Configure the main PLL */
    RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |
                   (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);

    /* Enable the main PLL */
    RCC->CR |= RCC_CR_PLLON;

    /* Wait till the main PLL is ready */
    while((RCC->CR & RCC_CR_PLLRDY) == 0)
    {
    }

    /* Configure Flash prefetch, Instruction cache, Data cache and wait state */
    FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS;

    /* Configure Flash prefetch, Instruction cache, Data cache and wait state */
    FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_2WS;

    /* Select the main PLL as system clock source */
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
    RCC->CFGR |= RCC_CFGR_SW_PLL;

    /* Wait till the main PLL is used as system clock source */
    while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);
    {
    }
  }
  else
  { /* If HSE fails to start-up, the application will have wrong clock
         configuration. User can add here some code to deal with this error */
  }
}

 

在官方的基礎上,直接設定HSE作為SYSCLK時鍾:

       初始化HSE;

       等待HSE初始化成功后再繼續;

       設置調壓器電壓輸出級別為1以便使器件在最大頻率工作;

       設置HCLK、PCLK1、PCLK2分頻系數;

       設置HSE作為系統時鍾;

void HSE_SetSysClock(void)
{
    __IO uint32_t HSEStartUpStatus = 0;
    

  /* 開啟HSE時鍾 */
  /* 此函數從stm32f0xx_rcc.c獲取,用於配置外部時鍾HSE:
   *   有三個配置:RCC_HSE_OFF關閉外部HSE時鍾
   *         RCC_HSE_ON開始外部HSE晶振
   *         RCC_HSE_Bypass開始HSE旁路設置
   */
   RCC_HSEConfig(RCC_HSE_ON);
    
  /* 等待HSE開啟設置成功,並獲取到時鍾配置狀態 */
    HSEStartUpStatus = RCC_WaitForHSEStartUp();
    
  /* 若時鍾配置成功 */
    if(HSEStartUpStatus == SUCCESS)
    {
        RCC->APB1ENR |= RCC_APB1ENR_PWREN;
        PWR->CR |= PWR_CR_VOS;
        
        RCC_HCLKConfig(RCC_SYSCLK_Div1);
        
        RCC_PCLK2Config(RCC_HCLK_Div1);
        
        RCC_PCLK1Config(RCC_HCLK_Div1);
        
     /* 將SYSCLK系統時鍾設置為HSE */
        RCC_SYSCLKConfig(RCC_SYSCLKSource_HSE);
        
     /* 等待SYSCLK系統時鍾設置成功 */
        while(RCC_GetSYSCLKSource() != 0x04)
        {
        }
    }else
    {
        while(1);
    }
}

 

 

使用HSI經過PLL配置系統時鍾:

       使能HSI時鍾;

       獲取HSI狀態並等待HSI穩定;

       設置調節器電壓輸出級別配置為1;

       設置HCLK、PCLK1/2分頻系數;

       設置PLL時鍾分頻系數;

       使能PLL並等待PLL穩定后配置PLL狀態;

       設置PLL作為SYSCLK時鍾並等待設置完成;

void HSI_SetSysClock(uint32_t m, uint32_t n, uint32_t p, uint32_t q)
{
    __IO uint32_t HSIStartUpStatus = 0;
    
    /* 去初始化RCC */
    RCC_DeInit();
    
    /* 使能HSI時鍾 */
    RCC_HSICmd(ENABLE);
    
    /* 從RCC的CR寄存器中獲取HSI配置狀態 */
    HSIStartUpStatus = RCC->CR & RCC_CR_HSIRDY;
    
    /* 若HSI配置成功 */
    if(HSIStartUpStatus == RCC_CR_HSIRDY)
    {

        /* 配置調節器電壓輸出級別為1 */
        RCC->APB1ENR |= RCC_APB1ENR_PWREN;
        PWR->CR |= PWR_CR_VOS;
        
        /* 配置SYSCLK到HCLK的分頻系數為1 */
        RCC_HCLKConfig(RCC_SYSCLK_Div1);
        
        /* 配置HCLK到PCLK1/2的分頻系數為2/4 */
        RCC_PCLK2Config(RCC_HCLK_Div2);
        
        RCC_PCLK1Config(RCC_HCLK_Div4);
        
        /* 配置PLL參數,選用HSI作為PLL參數,同時使能PLL */
        RCC_PLLConfig(RCC_PLLSource_HSI, m, n, p, q);
        
        RCC_PLLCmd(ENABLE);
        
        /* 等待PLL設置完成 */
        while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
        
        FLASH->ACR = FLASH_ACR_PRFTEN 
                     | FLASH_ACR_ICEN
                     | FLASH_ACR_DCEN
                     | FLASH_ACR_LATENCY_5WS;
        
        RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
        
        while(RCC_GetSYSCLKSource() != 0x08);
    }else
    {
        while(1);
    }
}

 

HAL時鍾配置分析:

與STM32標准外設庫不同,HAL庫來實現時鍾配置需要重新適應配置方式,但是本質的寄存器調動是類似不變的,且配置的過程也和STM32標准外設庫相似;

參考使用STMCube生成的代碼,時鍾樹如圖所示:

 

在STM32Cube中設置:

HSE設置為Crystal/Ceramic Resonator,Input Frequency設置為16MHz;

在工程中要配置的參數:

        第一個HSE_VALUE參數位於stm32f0xx_hal_conf.h中,此參數與在STMCube時鍾樹上定義的一致,需要手動設置為實際的參數值

        第二個HSE_VALUE參數位於system_stm32f0xx.c中,此參數默認為8MHz,可以通過用戶程序來提供和調整;

        第三個SystemCoreClock參數位於system_stm32f0xx.c中,其默認值也是8MHz,可以根據以下三種方式來更新:

    調用CMSIS函數SystemCoreClockUpdate()、

    調用HAL API函數HAL_RCC_GetHCLKFreq()、

    調用HAL_RCC_ClockConfig();

/**
  * @brief Adjust the value of External High Speed oscillator (HSE) used in your application.
  *        This value is used by the RCC HAL module to compute the system frequency
  *        (when HSE is used as system clock source, directly or through the PLL).  
  */
#if !defined  (HSE_VALUE) 
  #define HSE_VALUE    ((uint32_t)16000000) /*!< Value of the External oscillator in Hz */
#endif /* HSE_VALUE */

#if !defined  (HSE_VALUE) 
  #define HSE_VALUE    ((uint32_t)8000000) 
/*!< Default value of the External oscillator in Hz.
      This value can be provided and adapted by the user application. */
#endif /* HSE_VALUE */

/** @addtogroup STM32F0xx_System_Private_Variables
  * @{
  */
  /* This variable is updated in three ways:
      1) by calling CMSIS function SystemCoreClockUpdate()
      2) by calling HAL API function HAL_RCC_GetHCLKFreq()
      3) each time HAL_RCC_ClockConfig() is called to configure the system clock frequency
         Note: If you use this function to configure the system clock there is no need to call the 2 first functions listed above, since SystemCoreClock variable is updated automatically.
  */
uint32_t SystemCoreClock = 8000000;

 

實際的時鍾配置函數如下圖:

使用了三個參數來配置:

        RCC_OscInitStruct用來配置外部時鍾參數,這里設置晶振類型為HSE、設置HSE的狀態為開啟狀態、不使用PLL;

        RCC_ClkInitStruct用來配置系統時鍾內的參數(如Sys CLK、HCLK、PCLK1),這里設置要配置的時鍾類型為HCLK、SYSCLK、PCLK1,選擇HSE時鍾作為SYSCLK的時鍾源,並設置系統時鍾SYSCLK分頻系數為0、HCLK的分頻系數為4;

        PeriphClkInit用來配置外設時鍾的時鍾源,這里設置USART1/2的時鍾源為PCLK1;

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};

  /** 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_NONE;
  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_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSE;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
  {
    Error_Handler();
  }
  PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1|RCC_PERIPHCLK_USART2;
  PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK1;
  PeriphClkInit.Usart2ClockSelection = RCC_USART2CLKSOURCE_PCLK1;
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
  {
    Error_Handler();
  }
  
  HAL_SYSTICK_Config(SystemCoreClock / 1000);
  HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
  HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}

這里加入了對SysTick的時鍾配置,參考HAL庫本身的設置:

        HAL_SYSTICK_Config()用來配置使能和配置SysTick寄存器;

        HAL_SYSTICK_CLKSourceConfig()選擇AHB時鍾(或AHB時鍾除以8)作為SysTick時鍾源;

        HAL_NVIC_SetPriority()配置SysTick_IRQn的中斷優先級為0,默認為最高;

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM