找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開始

搜索
查看: 9294|回復(fù): 1
打印 上一主題 下一主題
收起左側(cè)

學(xué)習(xí)筆記-STM32F10xx 時(shí)鐘系統(tǒng)及代碼分析

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:91350 發(fā)表于 2015-10-29 15:50 | 只看該作者 回帖獎(jiǎng)勵(lì) |倒序?yàn)g覽 |閱讀模式
 

19集     STM32 時(shí)鐘

 


藍(lán)色方框?yàn)闀r(shí)鐘源:HSI RC、HSE OSC、PLL、LSE OSC、LSI RC

梯形紫色為選擇器:就像一個(gè)切換開關(guān)。

可以從兩步分析該時(shí)鐘圖:

1、從SYSCLK開始看,由誰可以提供時(shí)鐘給SYSCLK,逐一分析。

2、從RTCCLK、IWDGCLK開始分析,由誰可以提供時(shí)鐘給RTCCLK\IWDGCLK。

 

一、時(shí)鐘源:內(nèi)部時(shí)鐘的精度都比較差(《STM32中文參考手冊(cè) V10》 ---- 57頁)

HSI RC: 高速內(nèi)部時(shí)鐘(約8M),當(dāng)被用作PLL時(shí)鐘的輸入時(shí),系統(tǒng)時(shí)鐘能得到的最大頻率為64MHz

HSE OSC: 高速外部時(shí)鐘,一般采用晶振(可選4~16M,一般選8M)

PLL: 鎖相環(huán)(2~16倍),用于倍頻時(shí)鐘,可選來源 HSI 二分頻、HSE、HSE二分頻。

PLL的設(shè)置必須在其激活前完成,一旦PLL被激活,這些參數(shù)都無法被改動(dòng),如果發(fā)現(xiàn)PLL的    設(shè)置無效,就可能在設(shè)置時(shí)PLL已經(jīng)完成激活,如果需要使用USB接口,PLL必須被設(shè)置為輸    出48MHz或者72MHz時(shí)鐘,用于提供48MHz的USBCLK時(shí)鐘。

LSE OSC: 低速外部時(shí)鐘,一般采用晶振(32.768KHz)用于提供RTC時(shí)鐘

LSI RC: 低速內(nèi)部時(shí)鐘(約40KHz),用于提供獨(dú)立看門口作為時(shí)鐘源

 

二、SYSCLK:(最重要的時(shí)鐘)

從上圖中可以看到,SYSCLK為最重要的時(shí)鐘,幾乎大部分的外設(shè)時(shí)鐘都是從SYSCLK得到時(shí)鐘信號(hào)。所以可以從SYSCLK開始分析。

SYSCLK可以選擇從HSI RC、PLL、HSE OSC取其中一個(gè)時(shí)鐘信號(hào),而PLL則可以從HSI RC的二分頻、HSE OSC、HSE OSC 二分頻取得時(shí)鐘信號(hào)。

系統(tǒng)復(fù)位后,HSI為默認(rèn)的系統(tǒng)時(shí)鐘來源。在做時(shí)鐘源切換時(shí),目標(biāo)時(shí)鐘源穩(wěn)定就緒后才會(huì)發(fā)生切換。

1、CSS 時(shí)鐘安全系統(tǒng):(當(dāng)系統(tǒng)運(yùn)行速度莫名其妙的下降、或者USB不工作,可以留意這里)

因STM32內(nèi)部時(shí)鐘是利用電容產(chǎn)生的時(shí)鐘,并不是太穩(wěn)定,所以一般項(xiàng)目中都會(huì)采用外部晶振通過HSE OSC提供穩(wěn)定的時(shí)鐘給系統(tǒng),當(dāng)外部晶振出現(xiàn)問題即HSE失效時(shí),CSS就會(huì)自動(dòng)將時(shí)鐘源切換至HSI RC。

CSS可以通過軟件被激活,一旦其被激活,CSS將在HSE振蕩器啟動(dòng)延遲后被使能,并在HSE時(shí)鐘關(guān)閉后關(guān)閉。

如果HSE時(shí)鐘發(fā)生故障,HSE振蕩器被自動(dòng)關(guān)閉,時(shí)鐘失效事件將被送到高級(jí)定時(shí)器(TIM1和TIM8)的剎車輸入端,并產(chǎn)生時(shí)鐘安全中斷CSSI,允許軟件完成營(yíng)救操作。此CSSI中斷連接到Cortex-M3的NMI中斷。

一旦CSS被激活,并且HSE時(shí)鐘出現(xiàn)故障,CSS中斷就產(chǎn)生,并且NMI也自動(dòng)產(chǎn)生。NMI將不斷執(zhí)行,直到CSS中斷掛起位被清除。因此,在NMI的處理程序中必須通過設(shè)置時(shí)鐘中斷寄存器(RCC_CIR)里的CSSC位來清除CSS中斷。

如果HSE振蕩器被直接或間接地作為系統(tǒng)時(shí)鐘,時(shí)鐘故障將導(dǎo)致系統(tǒng)時(shí)鐘自動(dòng)切換到HSI振蕩器,同時(shí)外部HSE振蕩器被關(guān)閉。在時(shí)鐘失效時(shí),如果HSE振蕩器時(shí)鐘是用做系統(tǒng)時(shí)鐘的PLL的輸入時(shí)鐘,PLL也將關(guān)閉。(問題來了,那么USBCLK是不是也就失效了吧?

2、每個(gè)時(shí)鐘都可以獨(dú)立開啟或關(guān)閉,這樣可以關(guān)閉不需要的時(shí)鐘從而降低功耗。

從下圖可以看出,每次需要使用某個(gè)外設(shè)時(shí)都要開啟相應(yīng)的外設(shè)時(shí)鐘。

(參考STM32中文參考手冊(cè) V10 56頁)

 

三、RTCCLK(RTC時(shí)鐘)

RTCCLK可以選擇從HSE OSC的128分頻、LSE OSC、LSI RC中取時(shí)鐘信號(hào)。

這里沒有CSS,那如果采用HSE的時(shí)鐘信號(hào)而其又失效,豈不是RTC也就失效了?

 

四、IWDGCLK(看門狗時(shí)鐘)

看門口時(shí)鐘只能從 LSI RC中取得時(shí)鐘源。

 

五、MCO 輸出(PA8引腳)

STM32還可以對(duì)外輸出時(shí)鐘,時(shí)鐘源可以從SYSCLK、HSI、HSE、PLLCLK的二分頻取得信號(hào)。

 

六、重要的時(shí)鐘

SYSCLK系統(tǒng)時(shí)鐘

AHB總線時(shí)鐘(高速)

APB1總線時(shí)鐘(低速):速度最高36MHz 連接低速外設(shè)

APB2總線時(shí)鐘(高速):速度最高72MHz 連接高速外設(shè)

PLL時(shí)鐘:用于倍頻

 

七、寄存器相關(guān)(具體參閱 《STM32中文參考手冊(cè) V10》 60~75頁)

 

typedef struct

{

  __IO uint32_t CR;            // HSI、HSE、CSS、PLL等的使能和就緒標(biāo)志位

  __IO uint32_t CFGR;        // PLL等的時(shí)鐘源選擇、分頻系數(shù)設(shè)定

  __IO uint32_t CIR;            // 清除、使能時(shí)鐘就緒中斷

  __IO uint32_t APB2RSTR;    // APB2線上所有外設(shè)復(fù)位寄存器

  __IO uint32_t APB1RSTR;    // APB1線上所有外設(shè)復(fù)位寄存器

  __IO uint32_t AHBENR;        // DMA、SDIO等時(shí)鐘使能

  __IO uint32_t APB2ENR;        // APB2線上所有外設(shè)時(shí)鐘使能

  __IO uint32_t APB1ENR;        // APB1線上所有外設(shè)時(shí)鐘使能

  __IO uint32_t BDCR;        // 備份域控制寄存器

  __IO uint32_t CSR;            // 控制狀態(tài)寄存器

} RCC_TypeDef;

 

0x4002 1000 - 0x4002 13FF 復(fù)位和時(shí)鐘控制(RCC)

#define PERIPH_BASE           ((uint32_t)0x40000000)

#define AHBPERIPH_BASE       (PERIPH_BASE + 0x20000)

#define RCC_BASE              (AHBPERIPH_BASE + 0x1000)

#define RCC                       ((RCC_TypeDef *) RCC_BASE)

 

八、庫函數(shù)類型(system_stm32f10x.c -- SystemInit() 函數(shù)中通過直接配置寄存器配置,并未采用庫函數(shù))

1、時(shí)鐘使能配置:

      RCC_LSEConfig() 、RCC_HSEConfig()、

      RCC_HSICmd() 、 RCC_LSICmd() 、 RCC_PLLCmd() …

2、時(shí)鐘源相關(guān)配置:

      RCC_PLLConfig ()、 RCC_SYSCLKConfig() 、

     RCC_RTCCLKConfig() 

3、分頻系數(shù)選擇配置:

      RCC_HCLKConfig() 、 RCC_PCLK1Config() 、 RCC_PCLK2Config()…

4、外設(shè)時(shí)鐘使能:

      RCC_APB1PeriphClockCmd():  //APB1線上外設(shè)時(shí)鐘使能

     RCC_APB2PeriphClockCmd();  //APB2線上外設(shè)時(shí)鐘使能

     RCC_AHBPeriphClockCmd();   //AHB線上外設(shè)時(shí)鐘使能

5.  其他外設(shè)時(shí)鐘配置:

     RCC_ADCCLKConfig ();  RCC_RTCCLKConfig();

6、狀態(tài)參數(shù)獲取參數(shù):

     RCC_GetClocksFreq();

     RCC_GetSYSCLKSource();

     RCC_GetFlagStatus()

7、RCC中斷相關(guān)函數(shù) :

     RCC_ITConfig() 、 RCC_GetITStatus() 、 RCC_ClearITPendingBit()…

 

20集     SystemInit()

 

SystemInit()函數(shù)在 startup_stm32f10x_hd.s 文件里面先于main函數(shù)調(diào)用。

也就是說我們?cè)趯憁ian函數(shù)時(shí),不必去調(diào)用SystemInit()函數(shù)。

 

一、代碼分析 (需要參考 《STM32中文參考手冊(cè) V10.pdf、《STM32F10xxx閃存編程參考手冊(cè).pdf》)

void SystemInit (void)

{

  // 開啟HSI內(nèi)部8MHz高速時(shí)鐘 1

  RCC->CR |= (uint32_t)0x00000001;       

 

  // 設(shè)置HSI做為系統(tǒng)時(shí)鐘 1:0

  // SYSCLK不分頻 7:4

  // APB1\APB2 不分頻 13:8

  // ADC預(yù)分頻 PCLK2 2分頻后作為ADC時(shí)鐘 15:14

  // MCO引腳不輸出時(shí)鐘 26:24

  RCC->CFGR &= (uint32_t)0xF8FF0000;   

 

  // HSE振蕩器關(guān)閉 16

  // CSS時(shí)鐘監(jiān)視關(guān)閉 19

  // PLL關(guān)閉 24

  RCC->CR &= (uint32_t)0xFEF6FFFF;

 

  // 設(shè)置外部4-16MHz振蕩器沒有旁路 18

  RCC->CR &= (uint32_t)0xFFFBFFFF;

 

  // 設(shè)置HSI振蕩器時(shí)鐘經(jīng)2分頻后作為PLL輸入時(shí)鐘 16

  // 設(shè)置HSE不分頻 17

  // 設(shè)置PLL 2倍頻輸出 21:18

  // 設(shè)置USB預(yù)分頻 PLL時(shí)鐘1.5倍分頻作為USB時(shí)鐘 22

  RCC->CFGR &= (uint32_t)0xFF80FFFF;

 

  // 設(shè)置LSI、LSE、HSI、HSE、PLL就緒中斷關(guān)閉 12:8

  // 清除LSI、LSE、HSI、HSE、PLL就緒中斷標(biāo)志位 20:16

  // 清楚CSSF時(shí)鐘安全系統(tǒng)中斷標(biāo)志位 23

  RCC->CIR = 0x009F0000;

 

  /* Configure the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers */

  /* Configure the Flash Latency cycles and enable prefetch buffer */

  SetSysClock();

 

#ifdef VECT_TAB_SRAM

  SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */

#else

  SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH.*/

#endif

}

 

#define SYSCLK_FREQ_72MHz  72000000

static void SetSysClock(void)

{

#ifdef SYSCLK_FREQ_HSE

  SetSysClockToHSE();

#elif defined SYSCLK_FREQ_24MHz

  SetSysClockTo24();

#elif defined SYSCLK_FREQ_36MHz

  SetSysClockTo36();

#elif defined SYSCLK_FREQ_48MHz

  SetSysClockTo48();

#elif defined SYSCLK_FREQ_56MHz

  SetSysClockTo56(); 

#elif defined SYSCLK_FREQ_72MHz        // <--- 該宏被定義

  SetSysClockTo72();                // <--- 該函數(shù)被調(diào)用

#endif

}

 

#define  RCC_CR_HSEON         ((uint32_t)0x00010000)

#define  RCC_CR_HSERDY        ((uint32_t)0x00020000)

#define HSE_STARTUP_TIMEOUT   ((uint16_t)0x0500)

 

#define  FLASH_ACR_PRFTBE                     ((uint8_t)0x10)

#define  FLASH_ACR_LATENCY                   ((uint8_t)0x03)

#define  FLASH_ACR_LATENCY_2                 ((uint8_t)0x02)

#define  RCC_CFGR_HPRE_DIV1                  ((uint32_t)0x00000000)

#define  RCC_CFGR_PPRE2_DIV1                 ((uint32_t)0x00000000)

#define  RCC_CFGR_PPRE1_DIV2                 ((uint32_t)0x00000400)

#define  RCC_CFGR_PLLSRC                     ((uint32_t)0x00010000)

#define  RCC_CFGR_PLLXTPRE                   ((uint32_t)0x00020000) 

#define  RCC_CFGR_PLLMULL                    ((uint32_t)0x003C0000)

#define  RCC_CFGR_PLLSRC_HSE                 ((uint32_t)0x00010000)

#define  RCC_CFGR_PLLMULL9                   ((uint32_t)0x001C0000)

#define  RCC_CR_PLLON                        ((uint32_t)0x01000000)

#define  RCC_CR_PLLRDY                       ((uint32_t)0x02000000)

#define  RCC_CFGR_SW                         ((uint32_t)0x00000003)

#define  RCC_CFGR_SW_PLL                     ((uint32_t)0x00000002)

#define  RCC_CFGR_SWS                        ((uint32_t)0x0000000C)

 

typedef enum {RESET = 0, SET = !RESET} FlagStatus, ITStatus;

 

/* 要設(shè)置 72MHz 需要使用HSE外部時(shí)鐘 */

static void SetSysClockTo72(void)

{

  __IO uint32_t StartUpCounter = 0, HSEStatus = 0;

  // 開啟HSE時(shí)鐘 16

  RCC->CR |= ((uint32_t)RCC_CR_HSEON);

  // 在一定的時(shí)間內(nèi)等待 HSE 時(shí)鐘穩(wěn)定

  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;        // HSE時(shí)鐘就緒

  }

  else

  {

    HSEStatus = (uint32_t)0x00;        // HSE時(shí)鐘未就緒

  } 

  // 如果HSE時(shí)鐘就緒

  if (HSEStatus == (uint32_t)0x01)

  {

    // 啟用預(yù)取緩沖區(qū) 4

    FLASH->ACR |= FLASH_ACR_PRFTBE; 

    // 48MHz < SYSCLK <= 72MHz 設(shè)置兩個(gè)等待周期 2:0

    FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);

    FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;   

    /*** SYSCLK -> HCLK -> PLCK1\PCLK2 */

    /* HCLK = SYSCLK */

    // 設(shè)置AHB分頻系數(shù)為 1 即不分頻,等于SYSCLK的頻率 即72MHz

    RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;    

    /* PCLK2 = HCLK */

    // 設(shè)置APB2分頻系數(shù)為 1 即不分頻,等于HCLK的頻率 即72MHz

    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;   

    /* PCLK1 = HCLK/2 */

    // 設(shè)置APB1分頻系數(shù)為 2 即二分頻,等于HCLK/2的頻率 即36MHz

    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;

    /*  PLL configuration: PLLCLK = HSE * 9 = 72 MHz */

    // 這里主要是清零操作 21:16

    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL));

    // 設(shè)置HSE作為PLL輸入時(shí)鐘 16

    // 設(shè)置PLL 9 倍頻輸出 (HSE為8M晶振輸入:SYSCLK = 8MHz * 9 = 72MHz)

    RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);

    /* Enable PLL */

    // 開啟PLL

    RCC->CR |= RCC_CR_PLLON;

    /* Wait till PLL is ready */

    // 等待PLL就緒標(biāo)志位就緒 25

    while((RCC->CR & RCC_CR_PLLRDY) == 0)

    {

    }   

    /* Select PLL as system clock source */

    // 清零操作

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

    // 設(shè)置PLL為SYSCLK時(shí)鐘源

    RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;   

    /* Wait till PLL is used as system clock source */

    while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)

    {

    }

  }

  else    // HSE未就緒

  { /* If HSE fails to start-up, the application will have wrong clock

         configuration. User can add here some code to deal with this error */

  }

}

 

二、總結(jié)

    SystemInit():

        設(shè)置SYSCLK、APB1、APB2不分頻,MCO不輸出時(shí)鐘

        SYSCLK由PLL提供時(shí)鐘、PLL則由HSI經(jīng)2分頻后提供時(shí)鐘

        設(shè)置USB時(shí)鐘為PLL輸出時(shí)鐘的1.5倍

        關(guān)閉所有時(shí)鐘源的中斷、清除所有時(shí)鐘源的中斷標(biāo)志位

    SetSysClockTo72():

        該函數(shù)首先是開啟HSE時(shí)鐘,然后在一定的時(shí)間等待其穩(wěn)定。

        穩(wěn)定之后,設(shè)置FLASH開啟預(yù)取緩沖區(qū)、設(shè)置兩個(gè)等待周期。

        接著設(shè)置AHB、APB2、APB1分配系數(shù)來配置HCLK、PCLK2、PCLK1的時(shí)鐘頻率。

        再設(shè)置HSE作為PLL時(shí)鐘源,并設(shè)置PLL為9倍頻,再開啟PLL,等待PLL就緒。

 

三、注意

SystemCoreClock 在實(shí)際寫代碼中可以通過這個(gè)變量來獲得當(dāng)前所設(shè)置的系統(tǒng)時(shí)鐘頻率值

system_stm32f10x.h:

extern uint32_t SystemCoreClock;

system_stm32f10x.c:

#if defined (STM32F10X_LD_VL) || (defined STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)

/* #define SYSCLK_FREQ_HSE    HSE_VALUE */

 #define SYSCLK_FREQ_24MHz  24000000

#else

/* #define SYSCLK_FREQ_HSE    HSE_VALUE */

/* #define SYSCLK_FREQ_24MHz  24000000 */

/* #define SYSCLK_FREQ_36MHz  36000000 */

/* #define SYSCLK_FREQ_48MHz  48000000 */

/* #define SYSCLK_FREQ_56MHz  56000000 */

#define SYSCLK_FREQ_72MHz  72000000

#endif

 

#ifdef SYSCLK_FREQ_HSE

  uint32_t SystemCoreClock         = SYSCLK_FREQ_HSE;  

#elif defined SYSCLK_FREQ_24MHz

  uint32_t SystemCoreClock         = SYSCLK_FREQ_24MHz;

#elif defined SYSCLK_FREQ_36MHz

  uint32_t SystemCoreClock         = SYSCLK_FREQ_36MHz;

#elif defined SYSCLK_FREQ_48MHz

  uint32_t SystemCoreClock         = SYSCLK_FREQ_48MHz;

#elif defined SYSCLK_FREQ_56MHz

  uint32_t SystemCoreClock         = SYSCLK_FREQ_56MHz;

#elif defined SYSCLK_FREQ_72MHz

  uint32_t SystemCoreClock         = SYSCLK_FREQ_72MHz;

#else /*!< HSI Selected as System Clock source */

  uint32_t SystemCoreClock         = HSI_VALUE;       

#endif   

 


分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏1 分享淘帖 頂 踩
回復(fù)

使用道具 舉報(bào)

沙發(fā)
ID:83257 發(fā)表于 2019-2-15 10:20 | 只看該作者
不錯(cuò),講得還蠻詳細(xì)的
回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

手機(jī)版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表