【VLO】如何使用MSP430内部频率VLO以及如何校正频率

1、需求定义

有时候为了节省成本,会尽量减少外部器件的花费,MSP430有一个内部 12KHz 的 VLO 频率,虽然有较大温飘和压飘,通过校正也是可以满足需求的。

2、什么是 VLO

 Very-Low-Power Low-FrequencyOscillator (VLO),也就是超低功耗低频振荡器;

 输出频率:标称 12KHz,3V 下最小 4KHz,最大 20KHz;

 功耗: 2.2V 下最大只有 0.7uA,比32K768的手表晶振 1.5uA 还低很多,这已经是 LPM3 模式下功耗最低的时钟源了;

 用途:可以用作 MSP430 的 ACLK,MCLK,SMCLK 时钟源;

3、如何使用 VLO

//******************************************************************************
//  Description; Pulse P1.0 with a 1/100 active duty cycle using software.
//  Ultra-low frequency ~ 1.5kHz, ultra-low power active mode demonstrated.
//  ACLK = VL0, MCLK = VLO/8 ~1.5kHz, SMCLK = n/a
//
//                MSP430G2xx1
//             -----------------
//         /|\|              XIN|-
//          | |                 |
//          --|RST          XOUT|-
//            |                 |
//            |             P1.0|-->LED
//
//******************************************************************************

#include <msp430.h>

int main(void)
{
  volatile unsigned int i;                                   
  WDTCTL = WDTPW + WDTHOLD; 
  BCSCTL3 |= LFXT1S_2;                      // 选择时钟源:LFXT1 = VLO
  IFG1 &= ~OFIFG;                              // Clear OSCFault flag
  __bis_SR_register(SCG1 + SCG0);    
  BCSCTL2 |= SELM_3 + DIVM_3;       // 8分频:MCLK = LFXT1/8
  P1DIR = 0xFF;                            
  P1OUT = 0;                              
  P2DIR = 0xFF;                             
  P2OUT = 0;                               

  for (;;)
  {
    P1OUT |= 0x01;        
    for (i = 10; i > 0; i--);                
    P1OUT &= ~0x01;                    
    for (i = 1000; i > 0; i--);  
  }

}

4、如何校正 VLO 频率

VLO 非常适合做低功耗下的待机时钟,但是不同环境频率偏差太大,在TI的应用支持中就有一种方法来校准 VLO。

VLO 本身的输出频率并不能被改变,称作校准不是很确切。我们大部分情况下使用 VLO 低频时钟只是为了将单片机从低功耗模式下唤醒,也就是需要实用它产生一个从0到几十赫兹的唤醒信号。既然不能动时钟源,那我们就想办法改变定时器的计数来获得我们想要的唤醒信号。

在 msp430G2XXX 中还有一个时钟叫 DCO,主要用于时钟倍频。TI 为 msp430G2XXX 单片机提供了至少一个用于校准 DCO 的数据存放在 FLASH 中。

这个经过校准的最小 DCO 频率为 1MHz,我们可以通过书橱在一个或 X 个 VLO 周期内的 DCO 振荡次数 Y,这样 f(VLO)=f(DCO)*X/Y。知道 VLO 的频率之后,设置好定时器便可以获得我们需要的唤醒中断信号。并且这个唤醒信号的精度不依赖于VLO(当然温度和电压不能变化)。

实际应用可以隔一段时间重新校准一次 VLO,确保在温度变化时,唤醒信号的精度不随 VLO偏移。

TI 官网提供了较为完整的实例:

头文件 #include "VLO_Library.h":

#ifndef VLO_Library
#define VLO_Library
extern int  TI_measureVLO( void );
extern unsigned int TI_8MHz_Counts_Per_VLO_Clock;

#endif

校正源码:

;*******************************************************************************
;   L. Westlund
;   Texas Instruments Inc.
;   March 2006
;   Built with IAR Embedded Workbench Version: 3.40A
;*******************************************************************************

#include  <msp430x20x2.h>


            MODULE  VLO_Library
            ;Variables
            PUBLIC  TI_8MHz_Counts_Per_VLO_Clock
            ;Functions
            PUBLIC  TI_measureVLO
            RSEG      DATA16_I
TI_8MHz_Counts_Per_VLO_Clock  DS 2

#ifdef TACCTL2_                             ; For non-Timer_A2 devices
  #define TACCTLX  TACCTL2
  #define TACCRX TACCR2
#else
  #define TACCTLX TACCTL0
  #define TACCRX TACCR0
#endif
            RSEG    CODE                    ; Code is relocatable
;-------------------------------------------------------------------------------
TI_measureVLO
;           returns: r12
;           -An int representing the number of 8MHz clock pulses in one VLO cycle
;           -This value is identical to the number put into TI_8MHz_Counts_Per_VLO_Clock
;-------------------------------------------------------------------------------
            mov.b   &BCSCTL1,     r15       ; preserve previous settings
            mov.b   &DCOCTL,      r14
            push.b  &BCSCTL2
            push.b  &BCSCTL3
            push.b  &P2SEL
            bic.b   #0xC0,        &P2SEL    ; clear P2SEL bits to avoid XTAL interference.
            mov.b   &CALBC1_1MHZ, &BCSCTL1  ; Set range
            mov.b   &CALDCO_1MHZ, &DCOCTL   ; Set DCO step + modulation
            mov.w   #CM_1+CCIS_1+CAP,&TACCTLX ; CAP, ACLK
            mov.w   #TASSEL_2+MC_2+TACLR, &TACTL; SMCLK, cont-mode, clear
            mov.b   #LFXT1S_2,    &BCSCTL3  ; ACLK = VLO
            clr.b   &BCSCTL2
            bis.b   #DIVA_3,      &BCSCTL1  ; ACLK=VLO/8
            bic.w   #CCIFG,       &TACCTLX  ; Clear capture flag
edge_one    bit.w   #CCIFG,       &TACCTLX  ; Test capture flag to skip first signal
            jz      edge_one
            bic.w   #CCIFG,       &TACCTLX  ; Clear capture flag
edge_two    bit.w   #CCIFG,       &TACCTLX  ; Test capture flag to skip second signal
            jz      edge_two                ;
            mov.w   &TACCRX,      r13       ; save hardware captured value
            bic.w   #CCIFG,       &TACCTLX  ; Clear capture flag
edge_three  bit.w   #CCIFG,       &TACCTLX  ; Test capture flag to capture a good clock
            jz      edge_three              ;
            bic.w   #MC_3,        &TACTL    ; stop timer
            mov.w   &TACCRX,      r12
            sub.w   r13,          r12
            mov.w   r12,          &TI_8MHz_Counts_Per_VLO_Clock
            mov.b   r15,          &BCSCTL1
            mov.b   r14,          &DCOCTL
            pop.b   &P2SEL
            pop.b   &BCSCTL3
            pop.b   &BCSCTL2
            ret

            END

应用实例:

//******************************************************************************

//  Description: This example toggles P1.0 on approximately a 1 second interval
//  The DCO is set to 8MHz to demonstrate that clock settings are preserved
//  across the function call.
//  ACLK = VLO, MCLK = SMCLK = 8MHz
//
//               MSP430F2012
//             -----------------
//         /|\|              XIN|-
//          | |                 |
//          --|RST          XOUT|-
//            |                 |
//            |       P1.4/SMCLK|-->SMCLK = 8MHz
//            |        P1.0/ACLK|-->LED 1 second interrupt
//
//******************************************************************************

#include  <msp430x20x2.h>
#include "VLO_Library.h"

int dco_delta;
int result;

void main(void)
{
  volatile unsigned int i;
  WDTCTL = WDTPW +WDTHOLD;                  // Stop Watchdog Timer
  P1DIR |= 0x11;                            // P1.0,1,4 outputs
  P1SEL |= 0x10;                            // P1.4 = SMCLK

  BCSCTL3 |= LFXT1S_2;                      // ACLK = VLO
  BCSCTL1 = CALBC1_8MHZ;                    // 8MHz cal value
  DCOCTL = CALDCO_8MHZ;                     // 8MHz cal value
  dco_delta = TI_measureVLO();              // dco delta = number of
                                            // 1MHz cycles in 8 ACLK cycles
  TACCTL0 = CCIE;                           // CCR0 interrupt enabled
  TACCR0 = (8000000 / dco_delta);           //
  TACTL = TASSEL_1 + MC_1;                  // ACLK, upmode
  P1OUT = 0x01;
  _BIS_SR(LPM3_bits + GIE);                 // Enter LPM3 w/ interrupt
}

// Timer A0 interrupt service routine
#pragma vector=TIMERA0_VECTOR
__interrupt void Timer_A (void)
{
  P1OUT ^= 0x01;                            // Toggle P1.0

}


猜你喜欢

转载自blog.csdn.net/liwei16611/article/details/80469386
今日推荐