STM32時鐘體系、SetSysClock、PLL、時鐘源

来源:https://www.cnblogs.com/zqingyang/p/18304310
-Advertisement-
Play Games

簡要介紹了一、時鐘體系 1、參考手冊 2、時鐘源3種 3、時鐘樹 4.時鐘詳解 HSE時鐘 HSI時鐘 鎖相環時鐘 系統時鐘 HCLK時鐘 PCLK1時鐘 PCLK2時鐘 RTC時鐘 獨立看門狗時鐘: 12S時鐘: 乙太網PHY時鐘: USBPHY時鐘: MCO時鐘輸出 系統時鐘配置函數Setsys... ...


V1.0 2024年7月12日


目錄


一、時鐘體系

給單片機提供一個時鐘信號(一個非常穩定的頻率信號),使單片機各內部組件同步工作,並且在和外部設備通信時是也能達到同步。

動態調整運行頻率,就可以控制性能與功耗!

STM32 的時鐘系統由外部晶振、PLL(鎖相環)和內部 RC 振蕩器組成。時鐘系統主要提供了處理器時鐘,以及可選的外設時鐘和RTC模塊時鐘。

其作用包括:

  • 為處理器提供準確的時鐘信號,保證處理器、匯流排和外設的正確工作。
  • 通過 PLL 的倍頻功能,產生多種頻率的時鐘信號,滿足不同外設的時鐘需求。
  • 通過時鐘系統提供的時鐘分頻器、預分頻器等功能,進一步調整時鐘頻率,以適應不同的應用場景。

時鐘系統在 STM32 的系統中扮演著關鍵的角色,它的穩定性和精度對整個系統的性能影響很大。

1、參考手冊

STM32F4xx 中文參考手冊.pdf 第 106 頁

2、時鐘源3種

a.可以使用三種不同的時鐘源來驅動系統時鐘 (SYSCLK),CPU 運行的頻率為 168MHz:

HSI 振蕩器時鐘(16MHz),也就是高速內部時鐘,一般來說很少用,因為精度沒有外部高速時鐘那麼高。

HSE 振蕩器時鐘,也就是高速外部時鐘,GECM4 開發板 8MHz。

主 PLL (PLL) 時鐘

b.器件具有以下兩個次級時鐘源:

32 kHz 低速內部 RC (LSI RC),該 RC 用於驅動獨立看門狗,也可選擇提供給 RTC 用於停機/待機模式下的自動喚醒。

32.768 kHz 低速外部晶振(LSE 晶振),用於驅動 RTC 時鐘 (RTCCLK)對於每個時鐘源來說,在未使用時都可單獨打開或者關閉,以降低功耗。

3、時鐘樹

時鐘樹就是關註時鐘源和時鐘的流向,嵌入式系統中的模塊和外設工作都以時鐘為基準。有了時鐘樹,就有了時鐘域。嵌入式中除了內核,還有各個單元,每個單元工作在不同的時鐘頻率下,給每個單元提供不同的時鐘。

實際應用中根據需要配置外設的時鐘控制開關,選擇需要的時鐘頻率,並可關閉不用外設時鐘。

image

stm32對每個外設的時鐘都設置了開關,讓用戶可以精確地控制,關閉不需要的設備,達到節省供電的目的。如果不用的就完全關閉,儘可能降低晶元功耗,以下以GPIO作為舉例

  1. 降低功耗:STM32設計允許用戶精確控制各個外設的電源管理,包括時鐘的開關。當不使用某個外設時,通過關閉其時鐘可以顯著減少功耗。因此,GPIO的時鐘預設是關閉的,以節省電力。
  2. 激活功能:使能GPIO的時鐘是激活其功能的第一步。沒有時鐘,GPIO的寄存器無法讀寫,從而無法配置GPIO的工作模式(如輸入、輸出、上拉、下拉等)或讀取輸入狀態。
  3. 同步操作硬體時鐘為GPIO提供了必要的時序和同步信號,確保GPIO的操作與系統其他部分協調一致。這對於維持數據的穩定傳輸和處理非常重要。
  4. 支持高級功能:對於某些高級功能,如復用功能(GPIO復用為其他外設功能)、中斷功能等,可能還需要額外使能AFIO(Alternate Function Input Output)的時鐘。這是因為這些功能涉及到更複雜的內部信號路由和管理。

實際上,在這裡面還涉及到一個時鐘門控技術,而這又涉及到同步電路,我們都知道(預設你們都知道)在同步電路中總是有一個時鐘控制。這裡就不贅述了,回去翻翻一本叫《數字電子技術基礎》的書,可以找到答案。

4. 時鐘詳解

查看<<中文參考手冊 第六章, RCC寄存器>>

HSE時鐘

HSE:High Speed External Clock signal,即高速的外部時鐘。

來源:有源晶振(1-50M)、無源晶振(4-26M)

控制:RCC_CR 時鐘控制寄存器的位16:HSEON控制

HSI時鐘

HSI:Low Speed Internal Clock signal,即高速的內部時鐘。

來源:晶元內部,大小為16M,當HSE故障時,系統時鐘會自動切換到HSI,直到HSE啟動成功。

控制: RCC_CR 時鐘控制寄存器的位0:HSION控制

鎖相環時鐘

鎖相環時鐘:PLLCLK

來源:HSI、HSE。由PLLSRC位配置。(0HSI 1HSE)

HSE或者HSI先經過一個分頻因數M進行分頻,然後再經過一個倍頻因數N,然後再經過一個分頻因數P,最後成為鎖相環時鐘PLLCLK = (HSE/M) * N / P = 25/25 * 336 / 2 = 168M

控制: RCC_PLLCFGR :RCC PLL 配置寄存器

PLL48CK:USB_FS(USB全速介面)、RANG(隨機發發生器)、SDIO提供時鐘

image

HSI精度不高.

PLLM 分頻因數

PLLN 倍頻

PLLP分配

系統時鐘

縮寫:SYSCLK,最高為168M。

來源:HSI、HSE,PLLCLK。

控制: RCC_CFGR 時鐘配置寄存器的SW位( 一般配置為10 選擇PLL作為系統時鐘)

image

HCLK時鐘

HCLK:AHB高速匯流排時鐘,最高為168M。為AHB匯流排的外設提供時鐘、為Cortex系統定時器提供時鐘(SysTick, 一般會8分頻)、為內核提供時鐘(FCLK 自由運行時鐘)。

AHB為advanced high-performance bus。

來源:系統時鐘分頻得到。

控制: RCC_CFGR 時鐘配置寄存器的HPRE位

PCLK1時鐘

PCLK1:APB1低速匯流排時鐘,最高為42M,為APB1匯流排的外設提供時鐘。

來源:HCLK分頻得到,通常配置為4分頻

控制: RCC_CFGR 時鐘配置寄存器的PPRE1位

PCLK2時鐘

PCLK1:APB高速匯流排時鐘,最高為84M,為APB2匯流排的外設提供時鐘。

來源:HCLK分頻得到,通常配置為2分頻。

控制: RCC_CFGR 時鐘配置寄存器的PPRE2位

RTC時鐘

RTC:為晶元內部的RTC提供時鐘。

來源:HSE_RTC(HSE分頻得到)、LSE(外部32.768KHZ的晶體提供)、LSI(32KHZ)。

控制: RCC備份域控制寄存器RCC_BDCR:RTCSEL位控制

獨立看門狗時鐘:

IWDGCLK,由LSI提供

image

I2S時鐘:

由外部的引腳I2S_CKIN或者PLLI2SCLK提供。

乙太網PHY時鐘:

407沒有集成PHY,只能外接PHY晶元,比如LAN8720,那PHY時鐘就由外部的PHY晶元提供,大小為50M。

USB PHY時鐘:

407的USB沒有集成PHY,要想實現USB高速傳輸,只能外接PHY晶元,比如USB33000。那USB PHY時鐘就由外部的PHY晶元提供。

MCO時鐘輸出

MCO:把控制器的時鐘通過外部的引腳輸出,可以外外部的設備提供時鐘。MCO1為PA8,MCO2為PC9。

控制: RCC_CFGR 時鐘配置寄存器的MCOX的PREx位

image

系統時鐘配置函數SetSysClock()

打開彙編文件

image

找到時鐘初始化

image

image

設置系統時鐘

將下麵這一段拷貝出, 進行裁剪:

/**
  * @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)
{
#if defined (STM32F40_41xxx) || defined (STM32F427_437xx) || defined (STM32F429_439xx) || defined (STM32F401xx)
/******************************************************************************/
/*            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;

#if defined (STM32F40_41xxx) || defined (STM32F427_437xx) || defined (STM32F429_439xx)      
    /* PCLK2 = HCLK / 2*/
    RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;
    
    /* PCLK1 = HCLK / 4*/
    RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;
#endif /* STM32F40_41xxx || STM32F427_437x || STM32F429_439xx */

#if defined (STM32F401xx)
    /* PCLK2 = HCLK / 2*/
    RCC->CFGR |= RCC_CFGR_PPRE2_DIV1;
    
    /* PCLK1 = HCLK / 4*/
    RCC->CFGR |= RCC_CFGR_PPRE1_DIV2;
#endif /* STM32F401xx */
   
    /* 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)
    {
    }
   
#if defined (STM32F427_437xx) || defined (STM32F429_439xx)
    /* Enable the Over-drive to extend the clock frequency to 180 Mhz */
    PWR->CR |= PWR_CR_ODEN;
    while((PWR->CSR & PWR_CSR_ODRDY) == 0)
    {
    }
    PWR->CR |= PWR_CR_ODSWEN;
    while((PWR->CSR & PWR_CSR_ODSWRDY) == 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;
#endif /* STM32F427_437x || STM32F429_439xx  */

#if defined (STM32F40_41xxx)     
    /* 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;
#endif /* STM32F40_41xxx  */

#if defined (STM32F401xx)
    /* 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;
#endif /* STM32F401xx */

    /* 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 */
  }
#elif defined (STM32F411xE)
#if defined (USE_HSE_BYPASS) 
/******************************************************************************/
/*            PLL (clocked by HSE) used as System clock source                */
/******************************************************************************/
  __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
  
  /* Enable HSE and HSE BYPASS */
  RCC->CR |= ((uint32_t)RCC_CR_HSEON | RCC_CR_HSEBYP);
 
  /* 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_DIV1;
    
    /* PCLK1 = HCLK / 4*/
    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_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 */
  }
#else /* HSI will be used as PLL clock source */
  /* 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_DIV1;
  
  /* PCLK1 = HCLK / 4*/
  RCC->CFGR |= RCC_CFGR_PPRE1_DIV2;
  
  /* Configure the main PLL */
  RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) | (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_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);
  {
  }
#endif /* USE_HSE_BYPASS */  
#endif /* STM32F40_41xxx || STM32F427_437xx || STM32F429_439xx || STM32F401xx */  
}

啟動外部晶振, HSE高速的外部時鐘

image

image


配置預分頻器

RCC_CFGR

image

    /* HCLK = SYSCLK / 1 AHB高速匯流排的分配因數 1分頻*/
    RCC->CFGR |= RCC_CFGR_HPRE_DIV1; 
    /* PCLK2 = HCLK / 2 APB2匯流排的分頻因數 2分頻*/
    RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;    
    /* PCLK1 = HCLK / 4 APB1匯流排的分頻因數 4分頻*/
    RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;

image-20240711210830924

image

註釋掉系統預設的系統時鐘彙編代碼, 系統預設使用HSI 16 MHz, 我們可以自定義的配置系統時鐘函數

image
image

#include "bsp_clkconfig.h"

void User_SetSysClock(void)
{
  /******************************************************************************/
  /*            PLL (clocked by HSE) used as System clock source                */
  /******************************************************************************/
  __IO uint32_t StartUpCounter = 0, HSEStatus = 0;

  /* 複位RCC的所有寄存器 */
  RCC_DeInit();

  /* Enable HSE */
  /* 使能HSE 《中文參考手冊 6.3.1 RCC時鐘控制寄存器》 ((uint32_t)0x00010000) */
  RCC->CR |= ((uint32_t)RCC_CR_HSEON);

  /* Wait till HSE is ready and if Time out is reached exit */
  /* 等待HSE啟動穩定,如果超時則退出  由RCC_CR HSERDY控制*/
  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;
  }

  /* HSE 啟動成功 */
  if (HSEStatus == (uint32_t)0x01)
  {
    /* Select regulator voltage output Scale 1 mode */
    /* 選擇電壓調節器的模式為1  和電源控制器PWR有關 PWR_CR寄存器VOS位, 實現功耗平衡*/
    RCC->APB1ENR |= RCC_APB1ENR_PWREN;
    PWR->CR |= PWR_CR_VOS;

    /* HCLK = SYSCLK / 1 AHB高速匯流排的分頻因數*/
    RCC->CFGR |= RCC_CFGR_HPRE_DIV1;
    /* PCLK2 = HCLK / 2 APB2匯流排的分頻因數*/
    RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;
    /* PCLK1 = HCLK / 4 APB1匯流排的分頻因數*/
    RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;

    /**
     * Configure the main PLL
     * 配置主PLL
     * PLL_M分頻因數應該和外部時鐘HSE一致, 分頻後為1
     * 因此N為336 P為2(/2得到168M), Q是7(得到48Mhz)
     * RCC_PLLCFGR_PLLSRC_HSE 選擇鎖相環時鐘來源, 這裡選擇HSE 8M
     *
     * 可以設置N最大為432 《中文參考手冊 6.3.2 》, 可超頻到216M, 原168M
     */
    //    RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |
    //                   (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);

    RCC->PLLCFGR = 25 | (336 << 6) | (((2 >> 1) - 1) << 16) |
                   (RCC_PLLCFGR_PLLSRC_HSE) | (7 << 24);

    /* Enable the main PLL */
    /* 使能主PLL  因為使能後無法修改! */
    RCC->CR |= RCC_CR_PLLON;

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

    /* Configure Flash prefetch, Instruction cache, Data cache and wait state */
    /* 配置FLASH預取指(將指令提前準備好),指令緩存,數據緩存,等待周期(速度越快等待周期越長, 見中文參考手冊3.8.1)
     * 配置flash外設的acr寄存器
     */
    FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN | FLASH_ACR_DCEN | FLASH_ACR_LATENCY_5WS;

    /* Select the main PLL as system clock source */
    /* 選擇主PLL時鐘作為系統時鐘 */
    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 */
    /* 確保主PLL時鐘選為系統時鐘, 若設置成功, 系統會硬體置1 《中文參考手冊 6.3.3 》*/
    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 啟動失敗,在這裡添加啟動失敗的處理代碼 */
  }
}

若使用系統自帶的系統配置文件, 需要做HSE修改, 預設是25M

image

系統時鐘配置流程

二、PLL

2.1 概述

PLL(Phase Locked Loop): 為鎖相迴路或鎖相環,用來統一整合時鐘信號,使高頻器件正常工作,如記憶體的存取資料等。

PLL基於振蕩器中的反饋技術,許多電子設備要正常工作,通常需要外部的輸入信號與內部的振蕩信號同步。

一般的晶振由於工藝與成本原因,做不到很高的頻率,而在需要高頻應用時,由相應的器件VCO,實現轉成高頻,但並不穩定,故利用鎖相環路就可以實現穩定且高頻的時鐘信號。

2.2 基本組成

鎖相環路是一種反饋控制電路,簡稱鎖相環(PLL,Phase-Locked Loop)。鎖相環的特點是:利用外部輸入的參考信號控制環路內部振蕩信號的頻率和相位。因鎖相環可以實現輸出信號頻率對輸入信號頻率的自動跟蹤,所以鎖相環通常用於閉環跟蹤電路。

鎖相環在工作的過程中,當輸出信號的頻率與輸入信號的頻率相等時,輸出電壓與輸入電壓保持固定的相位差值,即輸出電壓與輸入電壓的相位被鎖住,這就是鎖相環名稱的由來。鎖相環通常由鑒相器(PD,Phase Detector)、環路濾波器(LF,Loop Filter)和壓控振蕩器(VCO,Voltage Controlled Oscillator)三部分組成。

鎖相環的工作原理是檢測輸入信號和輸出信號的相位差,並將檢測出的相位差信號通過鑒相器轉換成電壓信號輸出,經低通濾波器濾波後形成壓控振蕩器的控制電壓,對振蕩器輸出信號的頻率實施控制,再通過反饋通路把振蕩器輸出信號的頻率、相位反饋到鑒相器。

鎖相環在工作過程中,當輸出信號的頻率成比例地反映輸入信號的頻率時,輸出電壓與輸入電壓保持固定的相位差值,這樣輸出電壓與輸入電壓的相位就被鎖住了。

image

2.3 類比說明

我們剛開始學車的時候,在道路上開車,眼睛就好像一個鑒相器,負責發現車行駛的方向(反饋)和前方的路(輸入)是否有差別,把差別輸入大腦進行判斷,然後指揮雙手旋轉方向盤,旋轉方向盤的動作轉換成車的行駛方向,如下圖所示。

image

我們通過這麼一個閉環過程不斷地調節方向盤,保證車行駛在正道上。

2.3 相位差[拓展]

兩個頻率相同的交流電相位的差叫做相位差,或者叫做相差,又稱“相角差”、“相差”、“周相差”或“位相差”。兩個作周期變化的物理量的相之間的差值。它為正值時稱前者超前於後者,為負值時則滯後於後者。它為零或π的偶數倍時,兩物理量同相;為π的奇數倍時則稱反相

這兩個頻率相同的交流電,可以是兩個交流電流,可以是兩個交流電壓,可以是兩個交流電動勢,也可以是這三種量中的任何兩個。兩個同頻率正弦量的相位差就等於初相之差。是一個不隨時間變化的常數。也可以是一個元件上的電流與電壓的相位變化。任意一個正弦量y = Asin(wt+ j0)的相位為(wt+ j0),兩個同頻率正弦量的相位差(與時間t無關)。設第一個正弦量的初相為 j01,第二個正弦量的初相為 j02,則這兩個正弦量的相位差為j12 = j01 - j02。

image

2.4 PLL配置參數

image

不同的晶元,倍頻(頻率翻倍)公式是不一樣的,需要查詢晶元手冊!

三、SystemInit系統初始化函數

1.其實第一個執行的文件是彙編文件

  • 棧的初始化,提供函數調用的時候進行現場保護和現場恢復
  • 堆的初始化,為申請記憶體提供空間,調用malloc
  • 執行Reset_Handler,意思說上電覆位後執行的動作
  • 執行SystemInit函數
  • 跳轉到main函數

2.初始化Flash介面,更新PLL系統頻率

/**
  * @brief  Setup the microcontroller system
  *         Initialize the Embedded Flash Interface, the PLL and update the
  *         SystemFrequency variable.
  * @param  None
  * @retval None
  */
void SystemInit(void)
{
    ................
        /* Configure the System clock source, PLL Multiplier and Divider factors,
     AHB/APBx prescalers and Flash settings ----------------------------------*/
        SetSysClock();

    ................

}

3.調用SetSysClock函數設置PLL時鐘,然後進行分頻

/**
  * @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)
{
   .....................
       /* Configure the main PLL */
       RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |
       (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);
   .....................
}

system_stm32f4xx.c文件有以下倍頻(PLL_N)與分頻(PLL_M、PLL_P)因數:

/* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N */
#define PLL_M      8     //(記得修改為8)
/* USB OTG FS, SDIO and RNG Clock =  PLL_VCO / PLLQ */
#define PLL_Q      7

#if defined (STM32F40_41xxx)
#define PLL_N      336
/* SYSCLK = PLL_VCO / PLL_P */
#define PLL_P      2
#endif /* STM32F40_41xxx */

由於官方的代碼是使用外部高速晶振25MHz,GEC-M4開發板是使用外部高速晶振8MHz,所以PLL的倍頻因數要進行修改,只修改PLL_M為8

4.閱讀system_stm32f4xx.c文件的頭部註釋

 *=============================================================================
 *=============================================================================
 *                    Supported STM32F40xxx/41xxx devices
 *-----------------------------------------------------------------------------
 *        System Clock source                    | PLL (HSE)
 *-----------------------------------------------------------------------------
 *        SYSCLK(Hz)                             | 168000000
 *-----------------------------------------------------------------------------
 *        HCLK(Hz)                               | 168000000
 *-----------------------------------------------------------------------------
 *        AHB Prescaler                          | 1
 *-----------------------------------------------------------------------------
 *        APB1 Prescaler                         | 4
 *-----------------------------------------------------------------------------
 *        APB2 Prescaler                         | 2
 *-----------------------------------------------------------------------------
 *        HSE Frequency(Hz)                      | 25000000   粵嵌開發板外部晶振是8MHz,我們要將25MHz修改為8MHz
 *-----------------------------------------------------------------------------
 *        PLL_M                                  | 25
 *-----------------------------------------------------------------------------
 *        PLL_N                                  | 336
 *-----------------------------------------------------------------------------
 *        PLL_P                                  | 2
 *-----------------------------------------------------------------------------
 *        PLL_Q                                  | 7
 *-----------------------------------------------------------------------------
 *        PLLI2S_N                               | NA
 *-----------------------------------------------------------------------------
 *        PLLI2S_R                               | NA
 *-----------------------------------------------------------------------------
 *        I2S input clock                        | NA
 *-----------------------------------------------------------------------------
 *        VDD(V)                                 | 3.3
 *-----------------------------------------------------------------------------
 *        Main regulator output voltage          | Scale1 mode
 *-----------------------------------------------------------------------------
 *        Flash Latency(WS)                      | 5
 *-----------------------------------------------------------------------------
 *        Prefetch Buffer                        | ON
 *-----------------------------------------------------------------------------
 *        Instruction cache                      | ON
 *-----------------------------------------------------------------------------
 *        Data cache                             | ON
 *-----------------------------------------------------------------------------
 *        Require 48MHz for USB OTG FS,          | Disabled
 *        SDIO and RNG clock                     |
 *-----------------------------------------------------------------------------
 *=============================================================================

去掉stm32f4xx.h的只讀屬性

image

接著修改stm32f4xx.h以下內容,行127將外部晶振頻率值修改為8MHz。

#if !defined  (HSE_VALUE)
  #define HSE_VALUE    ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */
#endif /* HSE_VALUE */

最後按照PLL的運算公式,最終得到輸出頻率為168MHz。

image

#註意事項

1.在《STM32F4xx中文參考手冊》 P117頁,PLL_M、PLL_N、PLL_P,這三個參數都有一定的範圍限制,詳細如下:

2≤ PLL_M ≤63
192≤ PLL_N ≤432
PLL_P:2、4、6、8

四、時鐘源

在特殊的應用場景,為了達到最高的能效比,沒有必要使用到PLL,可將HSE、HSI作為系統時鐘源。例如,在智能手錶鎖屏的情況下,如果使用PLL配置過後輸出的頻率會造成過多的功耗,降低自身的續航能力;同時要維持計步與測量心率功能。因此,PLL在鎖屏下的應用場景並不合適,在保證功能實現的前提下,儘可能降低功耗,可以切換頻率更低的時鐘源提供給系統時鐘。

image

1.選擇PLL作為系統時鐘源

RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
RCC->CFGR |= RCC_CFGR_SW_PLL;

或

RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);      	

2.選擇HSI作為系統時鐘源

RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
RCC->CFGR |= RCC_CFGR_SW_HSI;

或

RCC_SYSCLKConfig(RCC_SYSCLKSource_HSI); 	

3.選擇HSE作為系統時鐘源

```c	              
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
RCC->CFGR |= RCC_CFGR_SW_HSE;

或

RCC_SYSCLKConfig(RCC_SYSCLKSource_HSE); 	
```

五、應用場景

調節 CPU 的運行頻率,來控制系統的性能與功耗。比較典型的例子就是說手機/筆記本電腦都有高性能模式、平衡模式、低性能模式。

image

image

六、寄存器邊界地址

詳見《STM32F4xx中文參考手冊》的P52 ~ P54頁,部分展示如下:

image

參考文章

  • 溫子祺筆記
  • 野火STM32庫開發實戰指南

本文來自博客園,作者:舟清颺,轉載請註明原文鏈接:https://www.cnblogs.com/zqingyang/p/18304310


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • WPF的按鈕提供了Template模板,可以通過修改Template模板中的內容對按鈕的樣式進行自定義。結合資源字典,可以將自定義資源在xaml視窗、自定義控制項或者整個App當中調用 ...
  • 在 Visual Studio 中,至少可以創建三種不同類型的類庫: 類庫(.NET Framework) 類庫(.NET 標準) 類庫 (.NET Core) 雖然第一種是我們多年來一直在使用的,但一直感到困惑的一個主要問題是何時使用 .NET Standard 和 .NET Core 類庫類型。 ...
  • 之前也分享過 Swashbuckle.AspNetCore 的使用,不過版本比較老了,本次演示用的示例版本為 .net core 8.0,從安裝使用開始,到根據命名空間分組顯示,十分的有用 ...
  • 1.簡單使用實例 1.1 添加log4net.dll的引用。 在NuGet程式包中搜索log4net並添加,此次我所用版本為2.0.17。如下圖: 1.2 添加配置文件 右鍵項目,添加新建項,搜索選擇應用程式配置文件,命名為log4net.config,步驟如下圖: 1.2.1 log4net.co ...
  • 最近在微軟商店,官方上架了新款Win11風格的WPF版UI框架【WPF Gallery Preview 1.0.0.0】,這款應用引入了前沿的Fluent Design UI設計,為用戶帶來全新的視覺體驗。 ...
  • 當你使用Edge等瀏覽器或系統軟體播放媒體時,Windows控制中心就會出現相應的媒體信息以及控制播放的功能,如圖。 SMTC (SystemMediaTransportControls) 是一個Windows App SDK (舊為UWP) 中提供的一個API,用於與系統媒體交互。接入SMTC的好 ...
  • 在C#中使用RabbitMQ做個簡單的發送郵件小項目 前言 好久沒有做項目了,這次做一個發送郵件的小項目。發郵件是一個比較耗時的操作,之前在我的個人博客裡面回覆評論和友鏈申請是會通過發送郵件來通知對方的,不過當時只是簡單的進行了非同步操作。 那麼這次來使用RabbitMQ去統一發送郵件,我的想法是通過 ...
  • 一個自定義WPF窗體的解決方案,借鑒了呂毅老師的WPF製作高性能的透明背景的異形視窗一文,併在此基礎上增加了滑鼠穿透的功能。可以使得透明窗體的滑鼠事件穿透到下層,在下層窗體中響應。 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...