淺談msp430f5529入門(2)——時鐘配置、例程分析

        前天寫了關於DCO,FLL的一些問題,而其他的如XT1,XT2和1xx系列幾乎沒有區別,而且相比比較簡單,就不另外討論了。現在總結一下55系列的時鐘配置,我以TI官網提供的例程爲例子進行分析,只要肯折騰,收穫是不會少的。而且我發現了例程裏的註釋有錯誤,可能會給大家帶來學習時的困擾,我在下文會指出。

        有人可能會問TI的例程怎麼找,我在這裏也說一下。在TI官網搜索需要的芯片,在結果的右邊會有該芯片的資料,點進去後找到“工具和軟件”,點它之後再軟件的培訓內容裏可以找到例程下載,就是名字裏有examples的zip。

        呵呵,可能已經有人這麼嘗試過了,但F5529的這裏並沒有例程。不過這並不表明TI沒有提供5529的例程。另闢蹊徑吧騷年,我估摸着一個系列的例程都是通用的,於是就再搜了一遍5526,結果就在那裏找到了55xx的例程,也就是我下面要分析的例程。

例程下載鏈接


-----------------------------------可以開宰了------------------------------------


        包裏有關時鐘配置的例程一共有9個,其實弄好前面幾個,後面只是大同小異而已。


        (1)首先,第一個,最簡單的一個,因爲它根本就沒有配置時鐘尷尬......不過,它還是很有用,因爲它給我們呈現了單片機上電後的時鐘狀況。

//   ACLK = REFO = 32.768kHz, MCLK = SMCLK = Default 1MHz
#include <msp430.h>

int main(void)
{
  volatile unsigned int i;

  WDTCTL = WDTPW+WDTHOLD;                   // Stop WDT
  P1DIR |= BIT1;                            // P1.1 output

  P1DIR |= BIT0;                            // ACLK set out to pins
  P1SEL |= BIT0;                            
  P2DIR |= BIT2;                            // SMCLK set out to pins
  P2SEL |= BIT2;                            
  P7DIR |= BIT7;                            // MCLK set out to pins
  P7SEL |= BIT7;                              

  while(1)
  {
    P1OUT ^= BIT1;
    __delay_cycles(60000);                  // Delay
  }
}

        博主我剛開始學時就很糾結這PUC後的默認時鐘狀況:

After a PUC, the UCS module default configuration is:
• XT1 in LF mode is selected as the oscillator source for XT1CLK. XT1CLK is selected for ACLK.
• DCOCLKDIV is selected for MCLK.
• DCOCLKDIV is selected for SMCLK.
• FLL operation is enabled and XT1CLK is selected as the FLL reference clock, FLLREFCLK.
• On devices that have XIN and XOUT shared with general-purpose I/O, XIN and XOUT pins are set to
general-purpose I/Os and XT1 remains disabled until the I/O ports are configured for XT1 operation. If
XIN and XOUT are not shared with general-purpose I/O, XT1 is enabled.
• When available, XT2IN and XT2OUT pins are set to general-purpose I/Os and XT2 is disabled.


        剛上電後,說是ACLK和FLL默認以XT1爲源,但你又不打開XT1,那問題糾結了我很久,用示波器測試測得ACLK是大約327668Hz,但使用手冊後面有說這兩個時鐘在XT1LF失效後會轉向REFOCLK,它是內部的32768Hz的時鐘(那時我還沒看- -||)。

        真相就是這麼一回事:

        這是我用CCS仿真調試時暫停截的圖,圖示程序已經執行到while(1)裏了,打開寄存器窗口看到XT1LFOFFG和DCOFFG置1了。前者被置位就是因爲ACLK和FLL處於默認狀態一直在向XT1取源,而XT1被禁止失效所以XT1LFOFFG被置位了,而程序還能跑就是因爲XT1LF失效時它們兩個時鐘暫時向REFOCLK取源。後者爲什麼也置1了呢?它沒有向XT1取源啊。呵呵,上一章說過,默認狀態的DCO由FLL穩定,而FLL的時鐘源XT1出問題所以DCOFFG就置1了。

        因此,即使大家不需要調整單片機的時鐘,在程序的開頭也請先配置一下時鐘,養成這個習慣,至少把XT1打開,因爲XT1比REFOCLK穩定多了。


        (2)第二個例程,很值得去折騰,它設置了FLL來穩定DCO到8MHz。噢不!是16MHz.

//   ACLK = REFO = 32kHz, MCLK = SMCLK = 8MHz
#include <msp430.h>

int main(void)
{
  volatile unsigned int i;

  WDTCTL = WDTPW+WDTHOLD;                   // Stop WDT
  P1DIR |= BIT1;                            // P1.1 output

  P1DIR |= BIT0;                            // ACLK set out to pins
  P1SEL |= BIT0;                            
  P2DIR |= BIT2;                            // SMCLK set out to pins
  P2SEL |= BIT2;                            
  P7DIR |= BIT7;                            // MCLK set out to pins
  P7SEL |= BIT7;           

  UCSCTL3 = SELREF_2;                       // Set DCO FLL reference = REFO
  UCSCTL4 |= SELA_2;                        // Set ACLK = REFO
  UCSCTL0 = 0x0000;                         // Set lowest possible DCOx, MODx

  // Loop until XT1,XT2 & DCO stabilizes - In this case only DCO has to stabilize
  do
  {
    UCSCTL7 &= ~(XT2OFFG + XT1LFOFFG + DCOFFG);
                                            // Clear XT2,XT1,DCO fault flags
    SFRIFG1 &= ~OFIFG;                      // Clear fault flags
  }while (SFRIFG1&OFIFG);                   // Test oscillator fault flag
	
  __bis_SR_register(SCG0);                  // Disable the FLL control loop
  UCSCTL1 = DCORSEL_5;                      // Select DCO range 16MHz operation
  UCSCTL2 |= 249;                           // Set DCO Multiplier for 8MHz
                                            // (N + 1) * FLLRef = Fdco
                                            // (249 + 1) * 32768 = 8MHz
  __bic_SR_register(SCG0);                  // Enable the FLL control loop

  // Worst-case settling time for the DCO when the DCO range bits have been
  // changed is n x 32 x 32 x f_MCLK / f_FLL_reference. See UCS chapter in 5xx
  // UG for optimization.
  // 32 x 32 x 8 MHz / 32,768 Hz = 250000 = MCLK cycles for DCO to settle
  __delay_cycles(250000);
	
  while(1)
  {
    P1OUT ^= BIT0;                          // Toggle P1.0
    __delay_cycles(600000);                 // Delay
  }
}


        18和19行,將這兩個時鐘的時鐘源取爲了REFO,這樣,就沒有任何時鐘在向XT1請求時鐘源,DCO也沒有問題,故而下面的do{}while語句能通過。這個語句就是檢測時鐘有沒有問題,如果晶體正在起振,還沒有達到工作狀態,會在這個循環裏等待晶體起振完畢。XT2OFFG,XT1LFOFFG,DCOFFG,OFIFG都必須由軟件清零。另外,POR後,OFIFG是被置位了的。

        比如我把UCSCTL4 |= SELA_2;註釋掉,這樣,ACLK也會向REFO申請時鐘源,但程序運行下來就並不一樣了。

        它會卡在這個循環裏出不去,和上面(1)的情況一樣,ACLK的寄存器裏的默認值還是在向XT1申請時鐘源,XT1不幹活,XT1LFOFFG就置位了。


        20行那裏其實可以不配置,因爲默認就已經是0x0000,而FLL會自動調整UCSCTL0。


        這個程序的精髓就在於30-35這4行(啊咧?4行?),這是配置FLL的標準流程,在調整有關FLL的寄存器前,無比要先禁止FLL,不然可能會產生不可預料的結果。

        上一章說到,用FLL穩定DCO,只要設置好FLL的時鐘,再就是配置DCORSEL和FLLN就好了。利用公式:

      ·fDCOCLK= D × (N + 1) × (fFLLREFCLK÷ n)
        ·fDCOCLKDIV= (N + 1) × (fFLLREFCLK÷ n)

        就可以計算出所需的值,納尼?這和註釋裏的不一樣?呵呵,是的,真的是註釋錯了。程序裏(249 + 1) * 32768 = 8MHz計算的是fDCOCLKDIV!而不是註釋裏寫的fDCOCLK!而註釋裏的那條看起來像公式的根本就不是個東西!

        那爲什麼我測出來的真的是它說的大約8MHz呢?呵呵,因爲它說錯了,SMCLK並沒有使用DCOCLK,它還是默認地使用了DCOCLKDIV,所以那條式子計算出來的的的確確是SMCLK的頻率,但因爲它錯了兩次,1.(N + 1) * FLLRef = Fdco.2.SMCLK使用DCOCLK。所以就被它繞回來了。沒想到堂堂TI的例程,也會出錯。被我這菜鳥抓到了。


        爲了揭穿TI的真面目,我把19行改爲了

	UCSCTL4 &= ~SELS_4;						  //取消默認的SELS_4
	UCSCTL4 |= SELA_2 + SELS_3;               //設置SMCLK = DCO

        測了一下SMCLK,16.828MHz,是接近計算值,結論正確!所以大家在計算使用DCO時要注意DCODIV的存在,在我感覺,DCODIV更像是老大。


        而後我把目光盯向了DCORSEL,因爲看的資料一直在說只要把公式裏面4個量設置好就可以得到想要的DCO或DCODIV頻率。那還設置DCORSEL幹嘛?

        於是,我把UCSCTL1 = DCORSEL_5;註釋掉了,RCORSEL默認值是RCORSEL_2,再調試了一遍。

        發現DCOFFG被置位了,而SMCLK得頻率只有2.456MHz,不是計算值呀!

        DCORSEL的作用是設定DCO的頻率範圍,詳見datasheet裏的下面這表:

        可以看到,DCORSEL = 2時,DCO最大最大也就7.38MHz,沒有達到我們要的16點多MHz。

        也就是說,就算是使用FLL來穩定DCO,DCO大概的範圍即DCORSEL還是需要設置的!

        於是,我有把DCORSEL = 3,調了一次

        DCOOFFG還是被置位了,SMCLK頻率只有4.654MHz,看錶,DCORSLE = 3時DCO最大是14.0,還沒有達到計算值。

        在把DCORSEL設置爲4之後,一切都正常了,5,6,7都試過沒問題,計算值16.384MHz包含在這些範圍裏面。所以結論是正確的!還是那句話:就算是使用FLL來穩定DCO,DCO大概的範圍即DCORSEL還是需要設置的!這個範圍只需要包含目標值就行。


        (3)例程2終於被我折騰完了,後面的例程不過是換了下時鐘源換了下頻率,已經沒多少研究的價值,不過這些是我都看了一遍之後的結論。

        在例程3和4裏,還是設置FLL,不過是3裏面換了下數值,do{}while放下面而已,還是使用DCODIV,註釋還是錯的......


        4裏面啓用了XT1,用了這3句代碼:

  P5SEL |= BIT4+BIT5;                       // Port select XT1
  UCSCTL6 &= ~(XT1OFF);                     // XT1 On
  UCSCTL6 |= XCAP_3;                        // Internal load cap

        打開XIN和XOUT

        置0XT1OFF

        老實說電容我不知道怎麼選,不過這裏選了12pf,那就12pf吧。其實上電後XCAP裏的值默認就是XCAP_3,所以這裏可以不配置

        啓用了XT1別忘了要等它起振:

  // Loop until XT1 fault flag is cleared
  do
  {
    UCSCTL7 &= ~XT1LFOFFG;                  // Clear XT1 fault flags
  }while (UCSCTL7&XT1LFOFFG);               // Test XT1 fault flag

        其他的沒什麼了,說一下XT1的牛逼,這裏ACLK和SMCLK的計算值分別是

ACLK = 32768Hz, SMCLK = 2457600Hz。

        我測出來的是

ACLK = 32767.5Hz, SMCLK = 2457560Hz。

        非常高的精密度,而且非常穩定,數值就沒有變化過。相比起使用REFO時的頻率總是會有百分之零點幾到一點幾的誤差而且會有波動,當然是XT1更勝一籌。


        (4)好了,寫了這麼多,能分享的就是這些了,關於時鐘這一塊,就到此結束吧。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章