RTC on MSP430 microcontroller with 32.768kHz crystal and low power

low-powermicrocontrollermsp430rtc

I need to set timer to interrupt every second. I'm using 32.768kHz external crystal with MSP430G2553 MCU. The setup should consume < 10μA.

I tried this code but it consumed 80-90 μA.
What am I doing wrong?

Why is consumption too high?

int main(void) {
  WDTCTL = WDTPW | WDTHOLD;

  BCSCTL1 |= DIVA_3;    // divide by 8
  BCSCTL3 |= XCAP_3;

  //set timer
  TA1CCTL0 = CM_0 + CCIS_0 + OUTMOD_0 + CCIE;
  TA1CCR0 = 1020;
  TA1CTL = TASSEL_1 + ID_2 + MC_1;

  LPM3;
}

//interupt every 1000ms
#pragma vector=TIMER1_A0_VECTOR
__interrupt void TIMER1_A0_ISR(void)
{
}

Best Answer

Could be a number of reasons : is the crystal oscillator working? I don't see your program setting port 2 up to enable it.

Here is an example "Blinky" program whose current consumption has been measured under 1 uA (with no LED!). A more complex version implementing a 1970's style LED digital watch runs on the 2553, again under 1 uA (display off!) in under a kilobyte.

It's not in C but I think it's pretty easy to read, and you may find settings you need in the Init_Clock or Start_Delay procedures.

with Interfaces;                   use Interfaces;
with CPU;
with timer_X;

procedure Blinky_xtal is

-- This example demonstrates a very small Ada application built
-- using gcc-msp intrinsic functions (for delay, manipulating interrupts).
-- New in Blinky_xtal: a 32768Hz crystal oscillator

    use CPU.wdt;
    use CPU.port1_r;

    LED : Boolean renames p1out_bits(0);

begin
    -- Initialise registers

    wdtctl := wdtpw or wdthold;
    p1dir  := unsigned_8(CPU.cpu.bit0 or CPU.cpu.bit5);
    p1sel  := unsigned_8(CPU.cpu.bit5);
    timer_X.Init_Clock;
    timer_X.Start_Delay_MS(128);
    loop
       LED := True;
       timer_X.Wait;
       LED := False;
       timer_X.Wait;
    end loop;
end Blinky_xtal; 

It uses a package "Timer_X" to handle the low level details of setting the oscillator and timer : the package spec is

with CPU;

package timer_X is

    procedure Start_Delay_MS(MS : Natural);
    procedure Init_Clock;
    procedure Wait;
    pragma Inline_Always(Wait);

private

    procedure Handler;
    pragma Machine_Attribute (Entity => Handler,
                              Attribute_Name => "interrupt",
                              Info => CPU.vectors.timera0_vector);
end timer_X;

and the package body (implementation) is

with CPU;
with System.GCC_Builtins;
with Interfaces;                   use Interfaces;

package body timer_X is

use CPU.ta2;
use CPU.bc2;
use CPU.port1_r;

    procedure Handler is
    begin  
       -- clear Low Power Mode in status reg copy on stack; loaded on RETI
       System.GCC_Builtins.bic_status_register_on_exit(CPU.cpu.lpm3);
    end;

    procedure Init_Clock is
    begin
        -- MCLK is 1 MHz DCO
        dcoctl  := 0;  -- slowest setting during setup
        -- ClkCtrl 1    Calibration     XT2off  XTS DIVA    
        bcsctl1 := CPU.calibration.calbc1_1mhz or xt2off or diva_3;
        dcoctl  := CPU.calibration.caldco_1mhz;

        -- set MClk to 1 MHz.
        -- ClkCtrl 2    SELMx   DIVMx   SELS    DIVSx   DCOR
        --      0=DCO   0=div1  0=dco   3=div8  0=int
        bcsctl2 := selm_0 or divm_0 ;

        -- ClkCtrl 3    XT2Sx   LFXT1Sx XCAPx   XT2OF   LFXT1OF
        --                              1=6pf   fault   fault
        bcsctl3 := xcap_2;

        -- Connect oscillator pins from oscillator to crystal!
        -- p2.7 select oscillator, dir=out, p2.6 select osc (dir=in)
        p2dir  := unsigned_8(CPU.cpu.bit7);
        p2sel  := unsigned_8(CPU.cpu.bit6 or CPU.cpu.bit7);

        -- clear interrupt fault flag 
        CPU.cpu.ifg1_bits(1) := FALSE;

    System.GCC_Builtins.bic_status_register(CPU.cpu.oscoff);

        -- and enable interrupts!
        System.GCC_Builtins.eint;
    end;

    procedure Start_Delay_MS(MS : Natural) is
    begin
        -- set Timer A to interrupt in MS ms

        -- Control  TASSEL  IDx     MCx     TACLR   TAIE    TAIFG
        --          2=SMCLK 2=div4  1=ccr   clear   int+    no flag
        ta0ctl := tassel_1 or id_2 or mc_1 or taclr; -- or taie; 
        -- Capture-Compare Register
        ccr0   := Unsigned_16(MS-1);
        -- Capture-Compare Control
        --  CMx CCISx   SCS SCCI    CAP OUTMOD  CCIE    CCI OUT COV CCIFG
        --  0=nocap 0   0   0   0=comp  0   1=int           
        cctl0   := ccie;
    end;

    procedure Wait is
    begin
       -- enter LPM3.
       System.GCC_Builtins.bis_status_register(CPU.cpu.lpm3);
    end;

end timer_X;
Related Topic