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.

MSP430F5310: Device watchdogs after exiting LPM3

Part Number: MSP430F5310

Hi there,

I am trying to run a fairly simple piece of code to pulse an IO every 100mS and then go into LPM3.

But every time I run it, a watchdog reset occurs.. The code is attached..

has anybody any suggestions as to what I may be doing wrong here? I am tearing my hair out :-(

test code.c
static volatile uint8_t kick_watchdog = 0;

/**
Brief: 	kernel timer isr, uses timer0 a0,
@param[in]
@param[in]
@return
*/
void __attribute__((interrupt)) hal_timer0_a0_isr(void)
{	
	_bic_SR_register_on_exit(0xF0);
	
	if (kick_watchdog)
	{
		WDTCTL = WDTPW + WDTSSEL0 + WDTCNTCL + WDTIS__32K;  // password, aclk, clear counter, /32768
		kick_watchdog = 0;
	}	
}

/**
Brief: 	Delay in microseconds. Times are approx.
@param[in] 	uint16_t delay - in microseconds
@param[in] 	none
@return		none
*/
void __attribute__((optimize("O0"))) hal_delay_us(uint16_t delay_us)
{
	uint8_t i;

	for(;delay_us;delay_us--)
	{
		i = 2;
		while(!i--)
		{
			__asm volatile(" nop\n");
			__asm volatile(" nop\n");
			__asm volatile(" nop\n");
		}
	}		
}


/**
Brief: main entry point into code

		Clock setup:
		- 	MCLK is the master clock and runs at 24mHZ
			MCLK is sourced from the DCOCLK 
		  	The DCOCLK runs at 24mHz from the FLL
		  	VCORE the core voltage must be set to its highest level, level 3
		- 	SMCLK is Sub Master clock and runs at 12Mhz 
			This clock is used as the source clock for the UART and ... 
			The SMCLK is sourced from the DCOCLK with a /2 divider i.e. 24Mhz/2 = 12Mhz
		- 	ACLK is the auxcillary clock and runs at 32768Hz
			and is used as a source clock for low power timers such as timer A0.
			ACLK is sourced from XT1CLK. XT1CLK is an external 32768Hz Crystal connected to 
			P5.4 and P5.5. 
			This allows timers to run in low power modes

*/
void hal_init(void)
{
	// -------------------------------------
	// Set up MCLK, DCOCLK = 24Mhz
	// Core voltage must be set to highest level to support 24Mhz
	// Vcore will be set to level3, but core voltage can only be changed one level at a time (see errata)
	// so we will iterate from level 1 to 3 until level 3 reached
	for (uint8_t level = 1; level <= 3; level++)
	{		
		PMMCTL0_H = PMMPW_H;												// Open PMM registers for write by writing the password
		SVSMHCTL = SVSHE | SVSHRVL0 * level | SVMHE | SVSMHRRL0 * level;	// Set SVS/SVM high side new level												
		SVSMLCTL = SVSLE | SVMLE | SVSMLRRL0 * level;						// Set SVM low side to new level 

		while ((PMMIFG & SVSMLDLYIFG) == 0); 								// Wait till SVM is settled
		PMMIFG &= ~(SVMLVLRIFG | SVMLIFG); 									// Clear already set flags		
		PMMCTL0_L = PMMCOREV0 * level;	   									// Set VCore to new level

		// Wait till new level reached	
		if ((PMMIFG & SVMLIFG))												
			while ((PMMIFG & SVMLVLRIFG) == 0);
				
		SVSMLCTL = SVSLE | SVSLRVL0 * level | SVMLE | SVSMLRRL0 * level; 		// Set SVS/SVM low side to new level
		PMMCTL0_H = 0x00;												 		// Lock PMM registers for write access
	}
	
	__bis_SR_register(SCG0);        // Disable the FLL control loop
	UCSCTL4 = SELM__DCOCLK;			// Select the MCLK source, MCLK = DCOCLK
	UCSCTL0 = 0x0000;           	// Set lowest possible DCOx, MODx	        
	UCSCTL1 = DCORSEL_7;            // Select DCO range 50MHz operation    		

	// Set DCO Multiplier for 24MHz
	// (N + 1) * FLLRef = Fdco
	// (731 + 1) * 32768 = 24MHz
	// Set FLL Div = fDCOCLK/2
	// Enable the FLL control loop		
	UCSCTL2 = FLLD_0 | 731;               																																								
	__bic_SR_register(SCG0);                		
		
	// 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 25 MHz / 32,768 Hz ~ 750k MCLK cycles for DCO to settle
	// this delay is about 85mS far in excess of the ~35mS that is required
	for (uint32_t delay = 0; delay < 100000; delay++);

	// -------------------------------------
	// Set up SMCLK, DCOCLK/2 = 12Mhz
	// Select the SMCLK source, SMCLK = DCOCLK/2								
	UCSCTL4 |= SELS__DCOCLK;		
	UCSCTL5 = DIVS__2;											

	// -------------------------------------
	// Setup ACLK - 32Khz XT1
	// Select the ACLK source, ACLK = XT1CLK
	// Select XT1 Mode on P5.4 & P5.5
	UCSCTL4 |= SELA__XT1CLK;		
	P5SEL |= BV(4) | BV(5);

	// Wait for the XTAL to stabilize, and fault flags to clear	
	// clear DCO, XT2 & XT1 oscillator fault flags. If these bits are set, the OFIFG flag is also set.
	while ((SFRIFG1 & OFIFG))
	{				
		UCSCTL7 &= ~(XT2OFFG | XT1LFOFFG | DCOFFG);
		SFRIFG1 &= ~OFIFG; 		
	}

	// reduce drive strength to XT1, set to max by default
	UCSCTL6 &= ~(XT1DRIVE_3);	

	// -------------------------------------
	// GPIO setup
	// PORT 1 GPIO
	P1SEL = 0b00000000;					// set pin mode, 0=gpio 1=alt 
	P1DIR = 0b11000001;					// set direction, 0=input 1=output
	P1REN = 0b00001110; 				// Pullup or pulldown resistor enabled, 0=pull disabled 1=pull enabled 
	P1OUT = 0b00001110; 				// Set IO state for output 0=low 1=high, or, set pull resistor mode fot input 0=pulldown 1=pullup
	
	// PORT 5 GPIO
	P5SEL = 0b00110000;					// set pin mode, 0=gpio 1=alt 
	P5DIR = 0b11001111;					// set direction, 0=input 1=output
	P5REN = 0b00000000; 				// Pullup or pulldown resistor enabled, 0=pull disabled 1=pull enabled 
	P5OUT = 0b00000011; 				// Set IO state for output 0=low 1=high, or, set pull resistor mode fot input 0=pulldown 1=pullup

	// led on, for short time to indicate power up
	P5OUT &= ~0x02;
	for (uint8_t i = 250; i > 0; i--)	
		hal_delay_us(1000);
	P5OUT |= 0x02; 

	// Enable the watchdog
	WDTCTL = WDTPW + WDTSSEL0 + WDTCNTCL + WDTIS__32K;  // password, aclk, clear counter, /32768

	// Setup and start timer0 a0, interrupt every 100mS
	TA0CCTL0 = CCIE; 					// CCR0 interrupt enabled
	TA0CCR0 = 3277;						// CCR0 is loaded with 3277, aclk=32Khz => 1/32Khz = ~30.5uS + 3277 = ~100ms
	TA0CTL = TASSEL_1 | MC_1 | TACLR; 	// ACLK, upmode, clear TAR	

	// enable interrupts 
	_enable_interrupts();

	// into main loop
	while (1)
	{
		// set watchdog flag, picked up in ISR
		kick_watchdog = 1;		

		// Pulse output
		P1OUT |= 0x01;
		hal_delay_us(5);
		P1OUT &= ~0x01;
		hal_delay_us(2);

		// into low power mode, wake in 100ms
		__bis_SR_register(LPM3_bits + GIE); 
		__no_operation();	
	}	
}

  • I don't see where you disable the watchdog. This should be done as soon as possible because it comes out of reset with a very short interval. If you don't do that then it could easily fire while you are initializing the hardware. (Changing SMCLK could reduce the amount of time available as well.)

  • Hi David, 

    thanks for getting back to me.. 

    The watchdog is stopped in the startup code (not included) before main code execution.. 

    I wonder could the problem be related to the fact I am running the DCOCLK/MCLK at 24mHz and then going into LPM3? 

    Regards

    Trevor

  • > void __attribute__((interrupt)) hal_timer0_a0_isr(void)

    I think this needs to be something like [Ref msp430 GCC UG (SLAU646F) Sec 5.1.1]

    > void __attribute__((interrupt(TIMER0_A0_VECTOR))) hal_timer0_a0_isr(void)

  • Hi Bruce, 

    The interrupt fires fine, in fact the code works as expected for a few seconds before resetting.. 

    Thanks

    Trevor

  • Just to add a bit more information... 

    1) The reset condition also seems to be voltage dependent, if I run the code with the MCU VDD at 3.3V all is good, but if I do the same test with the MCU VDD at 2.9V, the MCU resets with a watchdog. 

    2) If I go into the LPM0 instead of LPM3 all is good (LPM0 is not an option in my application as the current consumption is too high)

    3) If delay for an extra ~20uS before going into LPM3 on each iteration of the main loop all is good.

    Any comments/suggestions as what I could try to resolve this issue would be much appreciated? 

    Regards

    Trevor

  • When I run this code on an F5529 (Mitto v7.3.2.154) it never calls the timer ISR, and it resets after roughly a second.

    When I make the indicated change it runs forever (OK, I got bored after a few minutes).

    I'm not sure what we're doing differently (beyond the obvious).

**Attention** This is a public forum