久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 9255|回復: 1
打印 上一主題 下一主題
收起左側

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

[復制鏈接]
跳轉到指定樓層
樓主
ID:91350 發(fā)表于 2015-10-29 15:50 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
 

19集     STM32 時鐘

 


藍色方框為時鐘源:HSI RC、HSE OSC、PLL、LSE OSC、LSI RC

梯形紫色為選擇器:就像一個切換開關。

可以從兩步分析該時鐘圖:

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

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

 

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

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

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

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

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

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

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

 

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

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

SYSCLK可以選擇從HSI RC、PLL、HSE OSC取其中一個時鐘信號,而PLL則可以從HSI RC的二分頻、HSE OSC、HSE OSC 二分頻取得時鐘信號。

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

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

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

CSS可以通過軟件被激活,一旦其被激活,CSS將在HSE振蕩器啟動延遲后被使能,并在HSE時鐘關閉后關閉。

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

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

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

2、每個時鐘都可以獨立開啟或關閉,這樣可以關閉不需要的時鐘從而降低功耗。

從下圖可以看出,每次需要使用某個外設時都要開啟相應的外設時鐘。

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

 

三、RTCCLK(RTC時鐘)

RTCCLK可以選擇從HSE OSC的128分頻、LSE OSC、LSI RC中取時鐘信號。

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

 

四、IWDGCLK(看門狗時鐘)

看門口時鐘只能從 LSI RC中取得時鐘源。

 

五、MCO 輸出(PA8引腳)

STM32還可以對外輸出時鐘,時鐘源可以從SYSCLK、HSI、HSE、PLLCLK的二分頻取得信號。

 

六、重要的時鐘

SYSCLK系統(tǒng)時鐘

AHB總線時鐘(高速)

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

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

PLL時鐘:用于倍頻

 

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

 

typedef struct

{

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

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

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

  __IO uint32_t APB2RSTR;    // APB2線上所有外設復位寄存器

  __IO uint32_t APB1RSTR;    // APB1線上所有外設復位寄存器

  __IO uint32_t AHBENR;        // DMA、SDIO等時鐘使能

  __IO uint32_t APB2ENR;        // APB2線上所有外設時鐘使能

  __IO uint32_t APB1ENR;        // APB1線上所有外設時鐘使能

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

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

} RCC_TypeDef;

 

0x4002 1000 - 0x4002 13FF 復位和時鐘控制(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、時鐘使能配置:

      RCC_LSEConfig() 、RCC_HSEConfig()、

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

2、時鐘源相關配置:

      RCC_PLLConfig ()、 RCC_SYSCLKConfig() 、

     RCC_RTCCLKConfig() 

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

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

4、外設時鐘使能:

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

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

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

5.  其他外設時鐘配置:

     RCC_ADCCLKConfig ();  RCC_RTCCLKConfig();

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

     RCC_GetClocksFreq();

     RCC_GetSYSCLKSource();

     RCC_GetFlagStatus()

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

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

 

20集     SystemInit()

 

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

也就是說我們在寫mian函數(shù)時,不必去調(diào)用SystemInit()函數(shù)。

 

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

void SystemInit (void)

{

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

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

 

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

  // SYSCLK不分頻 7:4

  // APB1\APB2 不分頻 13:8

  // ADC預分頻 PCLK2 2分頻后作為ADC時鐘 15:14

  // MCO引腳不輸出時鐘 26:24

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

 

  // HSE振蕩器關閉 16

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

  // PLL關閉 24

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

 

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

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

 

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

  // 設置HSE不分頻 17

  // 設置PLL 2倍頻輸出 21:18

  // 設置USB預分頻 PLL時鐘1.5倍分頻作為USB時鐘 22

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

 

  // 設置LSI、LSE、HSI、HSE、PLL就緒中斷關閉 12:8

  // 清除LSI、LSE、HSI、HSE、PLL就緒中斷標志位 20:16

  // 清楚CSSF時鐘安全系統(tǒng)中斷標志位 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;

 

/* 要設置 72MHz 需要使用HSE外部時鐘 */

static void SetSysClockTo72(void)

{

  __IO uint32_t StartUpCounter = 0, HSEStatus = 0;

  // 開啟HSE時鐘 16

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

  // 在一定的時間內(nèi)等待 HSE 時鐘穩(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時鐘就緒

  }

  else

  {

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

  } 

  // 如果HSE時鐘就緒

  if (HSEStatus == (uint32_t)0x01)

  {

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

    FLASH->ACR |= FLASH_ACR_PRFTBE; 

    // 48MHz < SYSCLK <= 72MHz 設置兩個等待周期 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 */

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

    RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;    

    /* PCLK2 = HCLK */

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

    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;   

    /* PCLK1 = HCLK/2 */

    // 設置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));

    // 設置HSE作為PLL輸入時鐘 16

    // 設置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就緒標志位就緒 25

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

    {

    }   

    /* Select PLL as system clock source */

    // 清零操作

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

    // 設置PLL為SYSCLK時鐘源

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

  }

}

 

二、總結

    SystemInit():

        設置SYSCLK、APB1、APB2不分頻,MCO不輸出時鐘

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

        設置USB時鐘為PLL輸出時鐘的1.5倍

        關閉所有時鐘源的中斷、清除所有時鐘源的中斷標志位

    SetSysClockTo72():

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

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

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

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

 

三、注意

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

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ā)
ID:83257 發(fā)表于 2019-2-15 10:20 | 只看該作者
不錯,講得還蠻詳細的
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則

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

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

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 亚洲国产一 | 久久99精品久久久久久国产越南 | 国产精品一区二区三区四区 | 国产精品激情 | 欧美日韩精品免费观看 | 久草a√| 狠狠干2020| 婷婷久久网 | 免费在线观看一区二区 | 欧美亚洲视频在线观看 | 日韩中文字幕视频在线观看 | 成人av观看| 岛国毛片在线观看 | 欧美色性 | 国产91久久久久久 | www日韩欧美 | 超碰欧美 | 超碰最新在线 | 国产成人精品久久二区二区 | 国产精品中文字幕在线播放 | 免费观看一级毛片 | 国产三级一区二区三区 | 国产乱码精品一区二区三区中文 | 中文字幕影院 | 久久久精品高清 | 欧美综合视频 | 91久久北条麻妃一区二区三区 | 成年网站在线观看 | 97中文视频 | 日本午夜免费福利视频 | 欧美区在线观看 | 久久精品一二三影院 | 国产成人精品一区二区三区在线 | 亚洲另类春色偷拍在线观看 | 夜夜爽99久久国产综合精品女不卡 | 天天夜夜人人 | 一级免费毛片 | 久久久久国产 | 无码日韩精品一区二区免费 | 中国一级毛片免费 | 男女视频在线免费观看 |