新聞中心

Stm32時鐘分析

作者: 時間:2016-11-28 來源:網(wǎng)絡(luò) 收藏

最后:配置SW,以及SWS。表示啟用HIS作為系統(tǒng)時鐘。

到這一步,經(jīng)過分析得知,RCC->CFGR &= 0xF8FF0000;主要是用來配置ahb等各個分頻器的設(shè)置,以及將片內(nèi)時鐘作為系統(tǒng)內(nèi)部時鐘。

(6)關(guān)閉HSEON,CSSON,PLLON

RCC->CR &= 0xFEF6FFFF;

通過分析CR寄存器可以看出,該寄存器主要涉及三個時鐘PLL,CSS,HSE。

(7)復(fù)位HSEBYP.

RCC->CR &= 0xFFFBFFFF;這一步有什么作用呢?查詢數(shù)據(jù)手冊57頁可知,外部時鐘源HSE有兩種模式,HSEBYP設(shè)置為0時,是選擇外部晶體作為外部時鐘源這種時鐘更加精準(zhǔn),當(dāng)然也是和外部電路有關(guān)的。當(dāng)然因為第(6)步已經(jīng)設(shè)置了HSEON關(guān)閉了,所以這一步才可自由設(shè)置HSEBYP。

(8)復(fù)位PLLSRC,PLLXTPRE,PLLMUL and USBPRE

RCC->CFGR &= 0xFF80FFFF;

注意:在這一部中可能會有這樣的疑問:

RCC->CFGR &= 0xFF80FFFF;
PLLSRC=0 HSI振蕩器時鐘經(jīng)2分頻后作為PLL輸入時鐘
PLLXTPRE=0,HSE分頻器作為PLL輸入,HSE不分頻
這樣不沖突嗎?

答案是:以最后配置為準(zhǔn),就是最后一次配置會改變前一次的配置,所以說以最后一次配置為準(zhǔn)。

也就是說后文還有其他代碼對其進(jìn)行定義。那干嘛還要怎么重復(fù)配置呢?

有時候是有用的。比如你想讓stm32超頻一會,然后又恢復(fù)正常運行,這就有用了。

(9)關(guān)閉所有中斷

RCC->CIR = 0x00000000;

(10)配置向量表

#ifndef VECT_TAB_RAM

MY_NVIC_SetVectorTable(NVIC_VectTab_RAM,0x0);

#else

MY_NVIC_SetVectorTable(NVIC_VextTab_FLASH,0x0);

#endif

下面對該函數(shù)分析:

//函數(shù)功能:設(shè)置向量表偏移地址

//NVIC_VectTab:基址

//Offset:偏移量

void MY_NVIC_SetVectorTable(u32 NVIC_VectTab, u32 Offset)
{
//檢查參數(shù)合法性
assert_param(IS_NVIC_VECTTAB(NVIC_VectTab));
assert_param(IS_NVIC_OFFSET(Offset));
SCB->VTOR = NVIC_VectTab|(Offset & (u32)0x1FFFFF80);//設(shè)置NVIC的向量表偏移寄存器
//用于標(biāo)識向量表是在CODE區(qū)還是在RAM區(qū)
}
前面兩行是用來檢查參數(shù)合法性,這里不作分析。重點看第三行

配置這個向量表有什么用?相見cortexm3權(quán)威指南113頁向量表的解釋

這里

#define NVIC_VectTab_RAM((u32)0x20000000)

#define NVIC_VectTab_FLASH((u32)0x08000000)

Offset的值為0x0,為偏移地址,地址必須能被64 * 4 = 256整除,具體請看權(quán)威手冊113頁

SCB->VTOR = NVIC_VectTab|(Offset & (u32)0x1FFFFF80);//設(shè)置NVIC的向量表偏移寄存器的疑問如下:

SCB->VTOR = NVIC_VectTab|(Offset & (u32)0x1FFFFF80);//設(shè)置NVIC的向量表偏移寄存器。
既然是設(shè)置NVIC的向量表偏移量,為什么還要和NVIC_VectTab相或呢。只設(shè)置OFFSET不就可以了嗎,另外VTOR設(shè)置只有BIT【28:7】有作用啊,相或以后也放不下這么多位吧?

這個是基址。
那個7~28的,你能定義一個28位的數(shù)據(jù)出來嘛?

VTOR設(shè)置只有BIT【28:7】,你把(u32)0x1FFFFF80二進(jìn)制看看是不是【28:7】。
然后再看下面一段話:

在<<權(quán)威指南>>第一百零四頁,有這么一段話:
NVIC中有一個寄存器,稱為“向量表偏移量寄存器”(在地址0xE000_ED08處),通過修改它的值就能定位向量表。但必須注意的是:向量表的起始地址是有要求的:必須先求出系統(tǒng)中共有多少個向量,再把這個數(shù)字向上增大到是2的整次冪,而起始地址必須對齊到后者的邊界上。例如,如果一共有32個中斷,則共有32+16(系統(tǒng)異常)=48個向量,向上增大到2的整次冪后值為64,因此地址
地址必須能被64*4=256整除,從而合法的起始地址可以是:0x0, 0x100, 0x200等。
向量表偏移量寄存器,也就是SCB->VTOR.它的第29位,用來標(biāo)識向量表是在CODE區(qū)還是RAM區(qū),從而0X1,就是最高3位不去動,這好理解.但是低位,根據(jù)上面這段話的理解,STM32自己有60個中斷,加上CM3的16個,總共有76個中斷,擴(kuò)大到2的整次冪,那就是128,然后再乘以4,得到512,也就是0X200.根據(jù)這樣計算,合法的偏移地址應(yīng)該是0X0,0X200,0X400,0X600...因此,在此處應(yīng)該&0X1FFF FE00.才對.
以上是我的理解.實際上確是&0X1FFF FF80;這點,我也有疑問.

答案:cortex-m3權(quán)威指南上介紹bit28-7為向量表的起始地址。所以低7位沒有用到,所以&0X80,為的就是將低七位清零。但這里寫&0X1FFF FE00,也能達(dá)到清零的目的。至于地址必須是512的整數(shù)只要offset這個參數(shù)注意就可以了。

下面我們回到例說stm32這本書61頁的Stm32_Clock_Init()函數(shù):

經(jīng)過上面配置完畢后,下面開始配置外部時鐘。

Ministm32開發(fā)板目前的實都是采用高速外部時鐘作為時鐘源,在經(jīng)過MYRCC_Deinit()先將外部時鐘源關(guān)閉,然后在cfgr重新配置之后,下面就準(zhǔn)備開啟高速外部時鐘。

(11)RCC->CR |= 0x00010000;外部高速時鐘使能HSEON,前面說過以最后一次設(shè)置為準(zhǔn),所以自打這一步開始HSE作為了外部時鐘。

(12)等待外部時鐘是否就緒

While(!(RCC->CR>>17));(其實這一步的作用和while(RCC->CR&(u32)(1<<17));是一樣的,因為在MYRCC_Deinit()中的18位至31位全為0了,當(dāng)然在論壇中http://www.openedv.com/posts/list/1943.htm第23樓也承認(rèn)While(!(RCC->CR>>17)這樣寫有點輕率,23樓這樣寫道

對此,原子哥也說了寫成(RCC-CR>>17)&0X01比較合適,但我感覺RCC-CR>>17是不準(zhǔn)確的,比方說如果第十八位是1,那么右移17位后不管時鐘是否就緒,表達(dá)式“RCC-CR>>17”的結(jié)果始終為真,這樣while(!(RCC-CR>>17))不就沒有意義了嗎?所以寫成(RCC-CR>>17)&0X01才是最準(zhǔn)確的

)

(13)配置APB1/2=DIV2和AHB = DIV1

RCC->CFGR = 0x00000400;

(14)設(shè)置PLL分頻

PLL -=2;

RCC->CFGR = PLL <<18;

設(shè)置PLL 9倍頻

這里還涉及到了一個問題,如下

其實,這里今天林妹妹問了一個比較專業(yè)的問題,那就是PLL是一個u8的數(shù)據(jù)類型,為什么在這里可以右移18位呢?不是早超出了么?其實,我們看看匯編代碼就明白了,匯編代碼如下: 219: RCC->CFGR|=PLL<<18; //設(shè)置PLL值2~16 0x08000618 4608 MOV r0,r1 0x0800061A 6840 LDR r0,[r0,#0x04] 0x0800061C EA404084 ORR r0,r0,r4,LSL #18 0x08000620 6048 STR r0,[r1,#0x04]可以看到,這個移位操作,是在R0和R1里面進(jìn)行的,r0,r1均是32位的寄存器,所以,這里的移位操作并不會產(chǎn)生錯誤(結(jié)果是賦值給32位的寄存器:RCC->CFGR).

(15)FLASH->ACR |= 0x32 //flash 2個延時周期。FLASH->ACR|=0x32是為了使頻率匹配,

//具體見《STM32閃存編程》

(16)打開PLLON

RCC->CR|=0x01000000;

(17)等待PLL鎖定

while(!((RCC->CR>>25)&0x01));

(18)PLL作為系統(tǒng)時鐘

RCC->CFGR |= 0x00000002;

(19)等待PLL作為系統(tǒng)時鐘設(shè)置成功

Unsigned char Temp = 0;

While(Temp!=0x02)

{

Temp = RCC->CFGR>>2;

Temp &= 0x03;

}

其實這段代碼就是判斷SWS,等待系統(tǒng)時鐘成功轉(zhuǎn)為PLL時鐘。

結(jié)合上面的分析已經(jīng)明了STM32時鐘一個始終配置過程,主要流程圖如下:

其實個人感覺不用想mini32中自帶例程配置有一些沒有必要,所以自己改動了一些,發(fā)現(xiàn)在跑馬燈程序中也能運行,目前只在跑馬燈程序中試驗過:

第一步:

RCC->APB1RSTR = 0x00000000;//復(fù)位結(jié)束

RCC->APB2RSTR = 0x00000000;

第二步:

RCC->AHBENR = 0x00000014;//睡眠模式閃存和SRAM時鐘使能.其他關(guān)閉.

第三步:關(guān)閉所有外設(shè)時鐘

RCC->APB2ENR = 0x00000000; //外設(shè)時鐘關(guān)閉.

RCC->APB1ENR = 0x00000000;

為什么要這步因為在配置cfgr以及cr等寄存器時,一些外設(shè)時鐘要關(guān)閉。

第四步:

RCC->CR &= 0xFEF2FFFF;//該補的主要作用是開啟內(nèi)部HSION,且關(guān)閉HSE,CSS,PLLON

第五步:設(shè)置分頻寄存器,配置分頻,使能PLLSRC ON



關(guān)鍵詞: Stm32時鐘分

評論


技術(shù)專區(qū)

關(guān)閉