This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

MSP430G2152 Watchdog interval timer variation issues (LPM3 with Watchdog as interval timer)

Other Parts Discussed in Thread: MSP430G2152

I have a simple circuit where an MSP430G2152 is used to control a transistor. The intent is to briefly cut the power to a device once per day (the reason is a long story so I won't get into it). I'm trying to get as close to once per day as possible using a minimum of parts to keep the cost low. So, no external crystal, RTC, etc.).


I built three replicates of the same circuit, and programmed them with the same program in order to look at the variation between the three.

My test code is as follows:

#include <msp430.h> 

//*****************************************************************************
//                            GLOBAL VARIABLES                                *
//*****************************************************************************
#define RED_BIT           BIT7
#define GREEN_BIT         BIT6
#define ENABLE_OUTPUT_BIT BIT0
#define THRESHOLD_0M      6646    // Estimated total counts for a 24 hour period
#define RESET_DURATION    95541   // ~2 sec off time
long    CYC_COUNTER = 0;

//*****************************************************************************
// Set up device for specific clock rate, power configuration, and outputs    *
// before enabling the watchdog timer.                                        *
//*****************************************************************************
int main(void) {
    // Stop the watchdog timer
    WDTCTL = WDTPW | WDTHOLD;
    // Setup the auxiliary clock (ACLK)
    // - DIVA_2 = /4 (~10.9s)
    BCSCTL1 = DIVA_2 | BCSCTL1;
    // Setup the master clock (MCLK):
    // - Run from DCOCLK (SELM_0)
    // - SMCLK from VLOCLK (SELS)
    BCSCTL2 = BCSCTL2 | SELM_0 | SELS;
    // - Set to use 12kHz VLOCLK since XTS = 0 (LFXT1S_2)
    BCSCTL3 = LFXT1S_2;
    // Setup the IO functions for the LED and output enable line
    P2SEL = P2SEL & (~RED_BIT) & (~GREEN_BIT);  // Select IO function for P2.6 and P2.7 (LEDs)
    P1SEL = P1SEL & (~ENABLE_OUTPUT_BIT);       // Select IO function for P1.0 (Power control)
    P2OUT = P2OUT | GREEN_BIT;                  // Pre-configure the output to turn on the GREEN LED
    P2DIR = P2DIR | RED_BIT | GREEN_BIT;	// Set Port 2 direction to output.
    P1OUT = P1OUT | ENABLE_OUTPUT_BIT;          // Turn on output enable
    P1DIR = P1DIR | ENABLE_OUTPUT_BIT;          // Set Port 1 direction to output.
    // Turn on the GREEN LED and turn off the RED LED
    P2OUT = P2OUT & (~RED_BIT) | GREEN_BIT;
    // Configure watchdog/interval timer (WDT):
    // - From ACLK (WDTSSEL)
    // - Interval timer (WDTTMSEL)
    // - ACLK/32768 (WDTIS0 and WDTIS1 UNSET)
    // - Counter cleared (WDTCNTCL)
    WDTCTL = WDTPW + WDTSSEL + WDTTMSEL + WDTCNTCL;
    // Set the interrupt configuration
    // - Enable WDTIFG interrupt for interval timer mode (WDTIE)
    IE1 = IE1 | WDTIE;
    // Configure power mode
    // - LPM3 = CPU, MCLK, SMCLK, DCO are disabled. DC generator disabled. ACLK is active.
    _BIS_SR(LPM3_bits + GIE);           // Original: Enter LPM3 with interrupts
	return 0;
}

//*****************************************************************************
// The watchdog timer controls the counter and the visual display indicating  *
// to the user the amount of time remaining in a power cycle. This routine    *
// is entered based on the WDT interrupt, disabled, the count checked and the *
// indication shown to the user and/or the power cycled, and then the watchdog*
// is re-enabled for another loop. This continues until power is removed. The *
// counter is volatile and resets upon power-up.                              *
//*****************************************************************************
#pragma vector=WDT_VECTOR
__interrupt void WatchdogTimer(void) {
	volatile long i = 0;
	volatile long j = 0;
	volatile int blink = 0;
	CYC_COUNTER++;

	// Reset the watchdog timer
	WDTCTL = WDTHOLD + WDTPW;

	// Enable the LEDs
	P2DIR = P2DIR | GREEN_BIT | RED_BIT;

	if (CYC_COUNTER >= THRESHOLD_0M) {
		// 0M (RESET EVENT)
		P2OUT = P2OUT & (~GREEN_BIT) | RED_BIT ;			// Turn on the RED LED and turn off the GREEN LED
		P1OUT = P1OUT & (~ENABLE_OUTPUT_BIT);				// Turn off the output.
		for (i = RESET_DURATION; i >= 0; i--) {}			           // Delay
		P1OUT = P1OUT | ENABLE_OUTPUT_BIT;				// Turn on the output.
		P2OUT = P2OUT | (~GREEN_BIT) | (~RED_BIT);			// Turn off all LEDs
		CYC_COUNTER = 0;						           // Reset the cycle counter
	}

// Turn off the LEDs P2DIR = P2DIR & (~GREEN_BIT) & (~RED_BIT); // Configure WDT to run as interval timer again, restarting the whole process WDTCTL = WDTPW + WDTSSEL + WDTCNTCL + WDTTMSEL; return; }

The results are dramatically different looking at the actual time between power-on and the output cut event (intended to be close to 24:00:00):

Board 1 - 22:33:44

Board 2 - 24:01:22 (this was the board used to determine the value of THRESHOLD_0M

Board 3 - 25:28:32

The variation seems to be directly tied to the watchdog interval timer.

My questions:

1. Is this much variation expected from controller to controller within the watchdog when used as an interval timer?

2. What can I do to limit this variation? I do not want to add more parts, so software solutions are ideal. I also cannot leave the part active all the time since power consumption is a consideration for my application, although I'm not sure that would address the underlying cause anyway.


As a test, I also ran the same code using LPM2, LPM1, and LPM0 and the results are very similar.

Thanks for reading. Any help would be appreciated.

  • Hello Ryan,

    The only way to get better accuracy is to use an LF Xtal here. In those LPMs without an Xtal, you are using the VLO which can vary wildly over temp, supply, and device/lot differences.

    regards,
    JH
  • vlo can be off by 20%, time it using 1% dco calibration and it gets a little better.

    I would try a on the fly calibration,
    you use dco for the wdt for four cycle (8sec) once every 30 minutes and when you get back you check vlo value in  T0AR
    do not div aclk during this as that  will give less rounding down error
    ~15KHz for 4seconds will fit in 64K timer, plus you can always check overflow flag.

    You will now know what value 8sec is, you calculate so you sleep for 29min and 52 seconds with vlo
    and then do next dco wdt calibration for 8sec again  = 30min total.

    But over a month or two it will still (probably) be off by hours,
    unless you press a button at for say 9:00am once every two weeks or some other outside reference.
    A 32K crystal cost 60cents and you will only be off a minute a year.

  • Ryan Smith46 said:
    ...I'm trying to get as close to once per day as possible using a minimum of parts to keep the cost low...

    Is 50/60Hz AC main available to your system?

    If so, you may be able to derive a 50/60Hz clock cheaply. Depends on where you are, the accumulative clock frequency error can be much smaller than that from a watch crystal. 

  • Alas, no. It is DC powered.

  • I thought that this may be where the discussion would naturally lead. I'm going to wire in a crystal to each and see how it goes before rev'ing the board. Not much cost, I agree, but for something that needed to be "about every 24 hours" I was hoping to get away without one. You live and you learn.
  • I did not mean the power source. I only want to get a 50/60Hz clock from the "AC main".
  • By "wiring" a crystal, I don't think it will work properly. The crystal won't get oscillated if the loading capacitors are not matched. Anyway, you can try it. Or, you can redesign the PCB and get manufactured within couple of days.

**Attention** This is a public forum