新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > STM32F10x芯片時鐘控制總結

        STM32F10x芯片時鐘控制總結

        作者: 時間:2016-11-11 來源:網絡 收藏

        1、介紹

        STM32F10x芯片的時鐘控制主要包括以下幾個方面知識:時鐘源的選擇(HSE、HIS、PLL)、系統時鐘頻率的配置、總線(AHB、APB2、APB1)時鐘的配置、總線(AHB、APB2、APB1)設備時鐘的使能/除能、總線(AHB、APB2、APB1)設備的復位。

        本文引用地址:http://www.104case.com/article/201611/316901.htm

        2、系統時鐘框圖

        STM32F10x可以用三種不同的時鐘源來驅動系統時鐘(SYSCLK):HSI振蕩器時鐘;HSE外部時鐘和PLL時鐘。他們之間的關系如附件所示(時鐘樹)。

        從時鐘樹中可以看出一下幾點:

        l系統時鐘的來源可以是HSI振蕩器時鐘、PLL時鐘、或者HSE時鐘;且系統總線時鐘最大值為72MHz,AHB和APB2總線最大頻率也是72MHz,APB1總線最大允許頻率是36MHz;而Cortex-M3核的自由運行時鐘是FCLK(來源于AHB總線);

        lstm32f10x芯片總共有四個時鐘源:HSE、LSE(外部時鐘信號);HIS、LSI(內部時鐘信號),芯片內的其他所有時鐘都是通過如上四個時鐘源分頻得來;

        lRTC的時鐘來源可以是HSE外部時鐘128分頻之后的時鐘、或者LSE外部時鐘(32.768kHz)或者內部LSI振蕩器時鐘;

        lIWDG的時鐘來源必須是內部LSI振蕩器時鐘;

        lMCO引腳的時鐘輸出源的來源有:PLL時鐘的2分頻、內部HIS時鐘、外部HSE時鐘以及系統時鐘。

        lPLL時鐘的來源可以是HIS振蕩器時鐘或者HSE外部提供的時鐘;

        lUSB外設是直接使用PLL輸出時鐘(如果使用USB外設,HSE和PLL時鐘都必須使能,且系統時鐘必須是48MHz或者72MHz);AHB總線的時鐘輸入源的是系統時鐘;APB1和APB2的時鐘來源是AHB;

        l始終安全系統(CSS)必須由HSE提供時鐘源;若CSS激活且HSE時鐘出現故障,則引發CSS中斷,同時產生NMI(NMI中斷是不可屏蔽的),NMI將被不斷執行,知道CSS中斷掛起位被清除;

        l定時器時鐘要么等于總線時鐘,要么等于總線時鐘頻率的兩倍,這取決于總線分頻系數的值是否為1;

        l當HIS被用于作為PLL時鐘輸入時,系統時鐘能得到的最大頻率是64MHz;

        lCortex-M3內核的自由運行時間是FCLK。

        3、時鐘寄存器描述

        l時鐘控制寄存器:RCC_CR

        l時鐘配置寄存器:RCC_CFGR

        l時鐘中斷寄存器:RCC_CIR

        lAPB2外設復位寄存器:RCC_APB2RSTR

        lAPB1外設復位寄存器:RCC_APB1RSTR

        lAHB外設時鐘使能寄存器:RCC_AHBENR

        lAPB2外設時鐘使能寄存器:RCC_APB2ENR

        lAPB1外設時鐘使能寄存器:RCC_APB1ENR

        l備份域控制寄存器:RCC_BDCR

        l控制/狀態寄存器:RCC_CSR

        4、時鐘控制主要按照以下五步進行控制

        l系統復位后,HSI振蕩器被選為系統時鐘;

        l調用RCC_DeInit()函數將外設RCC寄存器重置為缺省值;

        l選擇系統時鐘:

        ?若選擇HSE做系統時鐘:先調用RCC_HSEConfig()使能HSE,然后調用RCC_WaitForHSEStartUp()函數等待HSE起震,最后調用RCC_GetFlagStatus()函數獲取HSE晶振狀態,查看HIE晶振是否就緒;;

        ?若選擇HSI做系統時鐘:首先調用RCC_AdjustHSICalibrationValue()函數調整內部高速晶振校準值(也可以不用,使用系統預留值),然后調用RCC_HSICmd()函數使能HSI,最后調用RCC_GetFlagStatus()函數獲取HSI晶振狀態,查看HIS晶振是否就緒;

        ?若要使用PLL做系統時鐘,如前面兩步將HSE和HIS設定好之后,調用RCC_PLLConig()選擇PLL時鐘源并設定倍頻系數,最后調用RCC_PLLCmd()使能PLL,最后調用RCC_GetFlagStatus()函數獲取PLL晶振狀態,查看PLL是否就緒;。

        l最后,在以上時鐘配置就緒之后,調用RCC_SYSCLKConfig()函數選擇系統時鐘輸入源:HSE/HIS/PLL。

        至此,系統時鐘設定完成,可以調用RCC_GetSYSCLKSource()函數來獲取當前系統時鐘是使用的哪個時鐘(檢測設置是否成功):0x010:HIS;x040:HSE;x08:PLL。

        l然后是總線時鐘設置:設置AHB總線時鐘:調用RCC_HCLKConfig()函數;設置APB1總線時鐘:調用RCC_PCLK1Config()函數;設置APB2總線時鐘:調用RCC_PCLK2Config()函數。其中AHB總線時鐘來源于SYSCLK總線時鐘,APB1和APB2總線時鐘來源于AHB總線時鐘。注意:這三個時鐘的設置可以在系統時鐘、PLL、HSE、HIS啟動之前設置,也可以在他們之后設置,但習慣在PLL配置之前。

        l最后是根據應用需要配置各總線上的外圍設備,啟動/停用外圍設備的函數有:RCC_AHBPeriphClockCmd();RCC_APB2PeriphClockCmd();RCC_APB1PeriphClockCmd();復位總線上的設備函數:RCC_APB2PeriphResetCmd();RCC_APB1PeriphResetCmd();具體可以查看RCC固件庫。

        注意:使能外設時鐘的函數必須在調用外設初始化函數XXX_Init()函數之前,否則可能會導致對應外設初始化失敗,編譯器卻不會因此報錯。

        5、時鐘控制例子

        void SetSysClockToHSE(void)

        {

        ErrorStatus HSEStartUpStatus;

        RCC_DeInit();

        RCC_HSEConfig(RCC_HSE_ON);

        HSEStartUpStatus = RCC_WaitForHSEStartUp();

        if(SUCCESS == HSEStartUpStatus)

        {

        FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);

        FLASH_SetLatency(FLASH_Latency_0);

        RCC_HCLKConfig(RCC_SYSCLK_Div1);

        RCC_PCLK2Config(RCC_HCLK_Div1);

        RCC_PCLK1Config(RCC_HCLK_Div1);

        RCC_SYSCLKConfig(RCC_SYSCLKSource_HSE);

        while(0x04 != RCC_GetSYSCLKSource())

        {

        }

        }

        else

        {

        }

        }

        void SetSysClockTo20(void)

        {

        ErrorStatus HSEStartUpStatus;

        RCC_DeInit();

        RCC_HSEConfig(RCC_HSE_ON);

        HSEStartUpStatus = RCC_WaitForHSEStartUp();

        if(SUCCESS == HSEStartUpStatus)

        {

        FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);

        FLASH_SetLatency(FLASH_Latency_0);

        RCC_HCLKConfig(RCC_SYSCLK_Div1);

        RCC_PCLK2Config(RCC_HCLK_Div1);

        RCC_PCLK1Config(RCC_HCLK_Div1);

        RCC_PLLConfig(RCC_PLLSource_HSE_Div2,RCC_PLLMul_5);

        RCC_PLLCmd(ENABLE);

        while(RESET == RCC_GetFlagStatus(RCC_FLAG_PLLRDY))

        {

        }

        RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

        while(0x08 != RCC_GetSYSCLKSource())

        {

        }

        }

        else

        {

        }

        }

        void SetSysClockTo36(void)

        {

        ErrorStatus HSEStartUpStatus;

        RCC_DeInit();

        RCC_HSEConfig(RCC_HSE_ON);

        HSEStartUpStatus = RCC_WaitForHSEStartUp();

        if(SUCCESS == HSEStartUpStatus)

        {

        FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);

        FLASH_SetLatency(FLASH_Latency_1);

        RCC_HCLKConfig(RCC_SYSCLK_Div1);

        RCC_PCLK2Config(RCC_HCLK_Div1);

        RCC_PCLK1Config(RCC_HCLK_Div1);

        RCC_PLLConfig(RCC_PLLSource_HSE_Div2,RCC_PLLMul_9);

        RCC_PLLCmd(ENABLE);

        while(RESET == RCC_GetFlagStatus(RCC_FLAG_PLLRDY))

        {

        }

        RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

        while(0x08 != RCC_GetSYSCLKSource())

        {

        }

        }

        else

        {

        }

        }

        void SetSysClockTo48(void)

        {

        ErrorStatus HSEStartUpStatus;

        RCC_DeInit();

        RCC_HSEConfig(RCC_HSE_ON);

        HSEStartUpStatus = RCC_WaitForHSEStartUp();

        if(SUCCESS == HSEStartUpStatus)

        {

        FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);

        FLASH_SetLatency(FLASH_Latency_1);

        RCC_HCLKConfig(RCC_SYSCLK_Div1);

        RCC_PCLK2Config(RCC_HCLK_Div1);

        RCC_PCLK1Config(RCC_HCLK_Div2);

        RCC_PLLConfig(RCC_PLLSource_HSE_Div1,RCC_PLLMul_6);

        RCC_PLLCmd(ENABLE);

        while(RESET == RCC_GetFlagStatus(RCC_FLAG_PLLRDY))

        {

        }

        RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

        while(0x08 != RCC_GetSYSCLKSource())

        {

        }

        }

        else

        {

        }

        }

        void SetSysClockTo72(void)

        {

        ErrorStatus HSEStartUpStatus;

        RCC_DeInit();

        RCC_HSEConfig(RCC_HSE_ON);

        HSEStartUpStatus = RCC_WaitForHSEStartUp();

        if(SUCCESS == HSEStartUpStatus)

        {

        FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);

        FLASH_SetLatency(FLASH_Latency_2);

        RCC_HCLKConfig(RCC_SYSCLK_Div1);

        RCC_PCLK2Config(RCC_HCLK_Div1);

        RCC_PCLK1Config(RCC_HCLK_Div2);

        RCC_PLLConfig(RCC_PLLSource_HSE_Div1,RCC_PLLMul_9);

        RCC_PLLCmd(ENABLE);

        while(RESET == RCC_GetFlagStatus(RCC_FLAG_PLLRDY))

        {

        }

        RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

        while(0x08 != RCC_GetSYSCLKSource())

        {

        }

        }

        else

        {

        }

        }

        6、系統時鐘安全系統CSS

        在實際應用中,經常出現由于晶體振蕩器在運行中失去作用,造成微處理器的時鐘源丟失,從而出現死機的現象,導致系統出錯。為避免發聲這種嚴重錯誤,STM32F10X系列芯片提供了一個時鐘安全系統CCS機制。如下圖:

        時鐘安全系統被激活后,時鐘監控器將實時監控外部高速振蕩器;如果HSE時鐘發生故障,外部振蕩器自動被關閉,產生時鐘安全中斷,此中斷被連接到Cortex-M3的NVIC中斷;與此同時CSS將內部RC振蕩器(HSI)切換為STM32的系統時鐘源。

        注意:一旦CSS被激活,當HSE時鐘出現故障產生CSS中斷,同時自動產生NMI,NMI將不斷執行,直到CSS中斷掛起位被清除。因此在NMI的處理程序中,必須通過設置時鐘中斷寄存器RCC_CIR中的CSSC位(軟件置1清除)來清除CSS中斷。(其實RCC的其他各時鐘源的就緒中斷標志,也都需要通過軟件置1來清除,只是CSS是NMI中斷(不可屏蔽中斷),其他中斷需要設置相應位允許中斷,并要在NVIC中打開RCC的中斷通道)

        7、系統時鐘安全系統CSS應用

        啟動時鐘安全系統CCS:

        RCC_ClockSecuritySystemCmd(ENABLE);

        編寫NMI中斷處理函數:

        void NMI_Handler(void)

        {

        if(RESET != RCC_GetITStatus(RCC_IT_CSS))

        {/* HSE、PLL已經被禁止,但PLL設置未變*/

        ……/*客戶添加相應的系統保護代碼處理*/

        /*下面添加HSE恢復后的預設代碼*/

        RCC_HSEConfig(RCC_HSE_ON);

        RCC_ITConfig(RCC_IT_HSERDY,ENABLE);

        RCC_ITConfig(RCC_IT_PLLRDY,ENABLE);

        RCC_ClearITPendingBit(RCC_IT_CSS);

        /*至此一旦HSE時鐘恢復,將發生HSERDY中斷,在RCC中斷處理程序中,可以將系統時鐘設置到以前的狀態*/

        }

        }

        編寫RCC中斷處理函數:

        void RCC_IRQHandler(void)

        {

        if(RESET != RCC_GetITStatus(RCC_IT_HSERDY))

        {

        /*添加相應處理*/

        RCC_ClearITPendingBit(RCC_IT_HSERDY);

        }

        if(RESET != RCC_GetITStatus(RCC_IT_PLLRDY))

        {

        /*添加相應處理*/

        RCC_ClearITPendingBit(RCC_IT_PLLRDY);

        }

        }

        8、輸出芯片內部時鐘

        STM32F10x芯片支持將內部時鐘通過PA.8輸出,但是必須注意GPIO輸出管腳最大響應頻率為50MHz,如果超過這個頻率,輸出的波形將會失真。應用實例如下:

        首先配置端口PA.8

        GPIO_InitTypeDef GPIO_InitStructure;

        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;

        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

        GPIO_Init(GPIOA,&GPIO_InitStructure);

        然后調用函數RCC_MCOConfig(RCC_MCO)選擇要輸出的內部時鐘:RCC_MCO可以是:

        RCC_MCO_NoClock——無時鐘輸出

        RCC_MCO_SYSCLK——輸出系統時鐘

        RCC_MCO_HSI——輸出內部高速8MHz的RC振蕩器時鐘

        RCC_MCO_HSE——輸出外部時鐘信號

        RCC_MCO_PLLCLK_Div2——輸出PLL倍頻后的二分頻時鐘



        關鍵詞: STM32F10x時鐘控

        評論


        技術專區

        關閉
        主站蜘蛛池模板: 绥江县| 靖江市| 伊宁市| 汉源县| 板桥市| 盐边县| 顺平县| 仙游县| 甘谷县| 锡林郭勒盟| 高清| 龙江县| 北安市| 延庆县| 丰城市| 德兴市| 珠海市| 姚安县| 九龙坡区| 万宁市| 东乌珠穆沁旗| 盐津县| 辰溪县| 东阳市| 墨玉县| 藁城市| 临沭县| 临猗县| 长汀县| 沅陵县| 石屏县| 固安县| 汤原县| 株洲县| 那曲县| 泸定县| 广昌县| 齐齐哈尔市| 甘洛县| 孟津县| 赣榆县|