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.
These days we've encountered a problem on timer0 B1 interrupt process. We're using IAR MSP430 7.20.1 as the development environment. And we're using ACLK from VLO 9.4KHz clock as the clock source of timer 0 B1 in LPM3 mode. We uses continuous mode, ID /8, TBSSEL ACLK and TBIE enabled in TB0CTL initialization and TBIDEX /2 in TB0EX0. So the timer B interrupt occurs every 3569.6s, about 59.5minute, we uses the time as about 1 hour. And we need the system keeps in LPM3 sleep mode until about 3 hours arrives and then it's waken up. So we implemented the interrupt as following:
static U_WORD timeoutCounter = 0U;
#pragma vector = TIMER0_B1_VECTOR
static __interrupt void timerBInt( void ) {
switch(TB0IV) {
case TB0IV_TBIFG:
timeoutCounter++;
break;
default:
break;
}
if(timeoutCounter >= 3) {
LPM3_EXIT;
}
}
void ctrlHostSupplyEnterSleepMode( void ) {
...
LPM3;
__no_operation();
drvDioCurMeasSetOn(HIGH);
...
}
But the system doesn't work as we expected. When the timeoutCounter arrives 3 in the 3rd timeout interrupt, it do invoked LMP3_EXIT, but the system is not waken up and break at the breakpoint on drvDioCurMeasSetOn(HIGH) line after LPM3 line in ctrlHostSupplyEnterSleepMode() function in debugger mode(We're sure LPM3 line already invoked and it's in LPM3 mode in the whole test. We tested with dozens of times and added breakpoints in other later lines to avoid there's maybe some code optimization problem to skipped the breakpoint.). So we started to track this issue. After debugging dozens times, we finally found if we remove the if(timeoutCounter >= 3) line and exactly let the interrupt of timerBInt() to invoke LPM3_EXIT before exit. The drvDioCurMeasSetOn(HIGH) line break occurs and the system is waken up. So that mean only the 1st interrupt to invoke LPM3_EXIT will wakeup the system. Code Modified like this:
#pragma vector = TIMER0_B1_VECTOR
static __interrupt void timerBInt( void ) {
switch(TB0IV) {
case TB0IV_TBIFG:
timeoutCounter++;
break;
default:
break;
}
LPM3_EXIT;
}
So we're confused with this because it’s really strange. So now I’d like to inform this issue to your side if anyone of you had met with similar issues like this and give us some suggestions. Thanks!
Hi Gong Qiqi,
I'll look into this and get back to you tomorrow.
Regards,
Evan
Hi Gong Qiqi,
Can you confirm that TB0IV_TBIFG is firing and that timeoutCounter is getting incremented? The only way I can explain the behavior you have described is that another timer interrupt is firing. If that isn't the issue please provide your timer configuration code so I can try to reproduce on my end.
Thanks,
Evan
Hi Evan,
Thank you for your reply. Yes, the TB0IV_TBIFG is firing and the timeoutCounter is getting incremented. Here I'll attach the code. I've tide up the code because the original code is too complicated. The code can also reproduce this issue:
#define _SYS_CTRL_C /* ==================================================================================== * INCLUDE FILES ==================================================================================== */ #include "msp430.h" #include "cdefs.h" #include "boardDef.h" /* ==================================================================================== * LOCAL DEFINITIONS ==================================================================================== */ #define DRV_INT_MASK_WAKEUP_AC 0x0020 #define DRV_INT_MASK_START_BUTTON 0x0040 /* RESERVED 0x0080*/ /* RESERVED 0x1000*/ /* RESERVED 0x2000*/ #define DRV_INT_MASK_SYS_TIME 0x4000U #define DRV_INT_MASK_GLOBAL_INT 0x8000U #define DRV_INT_MASK_SUPPLY_ALL 0x000FU #define DRV_INT_MASK_BOOT (DRV_INT_MASK_GLOBAL_INT | DRV_INT_MASK_SYS_TIME | DRV_INT_MASK_START_BUTTON) #define DRV_INT_MASK_LPM (DRV_INT_MASK_GLOBAL_INT | DRV_INT_MASK_WAKEUP_AC | DRV_INT_MASK_START_BUTTON) #define DRV_INT_MASK_ALL (DRV_INT_MASK_BOOT | DRV_INT_MASK_WAKEUP_AC) #define DRV_INT_START_FLAG P2IV_P2IFG5 #define DRV_INT_AC_FLAG P2IV_P2IFG7 #define DEFAULT_AUX_TIMEOUT 3U /* ==================================================================================== * LOCAL VARIABLES ==================================================================================== */ static U_WORD timeoutCounter = 0U; /* ==================================================================================== * LOCAL FUNCTION PROTOTYPES ==================================================================================== */ #pragma vector = TIMER0_B1_VECTOR static __interrupt void timerBInt( void ); static void initSystemTime(void); void drvIntEnable( U_WORD intFlags ) { U_BYTE ucb0ie, ucb1ie, ucb3ie; if( (intFlags & DRV_INT_MASK_START_BUTTON) == DRV_INT_MASK_START_BUTTON ) { P2IES |= P2_IN_START; /* set flag on transition from high to low */ P2IFG &= (U_BYTE)~P2_IN_START; P2IE |= P2_IN_START; } if( (intFlags & DRV_INT_MASK_WAKEUP_AC) == DRV_INT_MASK_WAKEUP_AC ) { P2IES &= (U_BYTE)~P2_IN_AC_WAKEUP; /* set flag on transition from low to high */ P2IFG &= (U_BYTE)~P2_IN_AC_WAKEUP; P2IE |= P2_IN_AC_WAKEUP; } /* global interrupt */ if( (intFlags & DRV_INT_MASK_GLOBAL_INT) == DRV_INT_MASK_GLOBAL_INT ) { /* workaround for errata USCI39 */ ucb0ie = UCB0IE; UCB0IE &= ~(UCSTTIE | UCNACKIE | UCSTPIE); ucb1ie = UCB1IE; UCB1IE &= ~(UCSTTIE | UCNACKIE | UCSTPIE); ucb3ie = UCB3IE; UCB3IE &= ~(UCSTTIE | UCNACKIE | UCSTPIE); __enable_interrupt(); UCB0IE = ucb0ie; UCB1IE = ucb1ie; UCB3IE = ucb3ie; } } void drvIntDisable( U_WORD intFlags ) { if( (intFlags & DRV_INT_MASK_START_BUTTON) == DRV_INT_MASK_START_BUTTON ) { P2IE &= (U_BYTE)~P2_IN_START; } if( (intFlags & DRV_INT_MASK_WAKEUP_AC) == DRV_INT_MASK_WAKEUP_AC ) { P2IE &= (U_BYTE)~P2_IN_AC_WAKEUP; } /* global interrupt */ if( (intFlags & DRV_INT_MASK_GLOBAL_INT) == DRV_INT_MASK_GLOBAL_INT ) { __disable_interrupt(); } } U_WORD drvIntGetEnabled( void ) { U_WORD intFlags = 0U; if( (P2IE & P2_IN_START) == P2_IN_START ) { intFlags |= DRV_INT_MASK_START_BUTTON; } if( (P2IE & P2_IN_AC_WAKEUP) == P2_IN_AC_WAKEUP ) { intFlags |= DRV_INT_MASK_WAKEUP_AC; } /* global interrupt */ if(__get_interrupt_state() != 0){ intFlags |= DRV_INT_MASK_GLOBAL_INT; } return intFlags; } void drvIntRestore( U_WORD intFlags ) { drvIntDisable(DRV_INT_MASK_ALL); drvIntEnable(intFlags); } void drvTimerBStartAux( void ) { timeoutCounter = 0U; TB0CTL = TBCLR; TB0CCR0 = 0U; TB0CCTL2 = 0U; TB0CCR2 = 0U; TB0R = 0U; TB0EX0 = TBIDEX_1; /* divide by 2 */ TB0CTL = MC__CONTINUOUS | ID__8 | TBSSEL__ACLK | TBIE; /* 293.75 Hz / (2*8) ~> 18,359375 Hz*/ } BOOL drvTimerBIsAuxExpired( void ) { if (timeoutCounter >= DEFAULT_AUX_TIMEOUT) { return TRUE; } else { return FALSE; } } void drvTimerBStop( void ) { TB0EX0 = 0U; TB0CTL = TBCLR; timeoutCounter = 0U; } int main (void) { WDTCTL = WDTPW + WDTHOLD; initSystemTime(); drvIntEnable(DRV_INT_MASK_BOOT); drvTimerBStartAux(); while( 1 ) { drvIntRestore(DRV_INT_MASK_LPM); LPM3; __no_operation(); drvIntRestore(DRV_INT_MASK_BOOT); } } static void initSystemTime(void) { P11OUT |= BIT2; /* SMCLK output on Pin 11.2 */ P11SEL |= BIT2; /* MCLK = f_dcoclk = 4194304 Hz * f_dcoclk = D x (N+1) x (f_fllrefclk / n) * with D = 4 (FLLD__4) * N = 31 (FLLN) * f_fllrefclk = 32768 Hz * n = 1 (FLLREFDIV__1) * */ UCSCTL1 = DCORSEL_2; /* select DCO range of 0.75 MHz to 7.68 MHz */ UCSCTL2 = FLLD__4 | 31; /* CLOCKDIV 4, FLLN 31 */ UCSCTL3 = SELREF__REFOCLK | FLLREFDIV__1; /* select 32768 ref clk, divide by 1 */ /* source SMCLK from DCOCLKDIV, MCLK from DCO, ACLK from VLO (9.4Hz typical) */ UCSCTL4 = SELS__DCOCLKDIV | SELM__DCOCLK | SELA__VLOCLK; UCSCTL5 = DIVM__1 | DIVA__32 | DIVS__1 ; do { UCSCTL7 &= (U_BYTE)~(XT2OFFG | XT1LFOFFG | DCOFFG); SFRIFG1 &= (U_BYTE)~OFIFG; for ( U_BYTE i = 80; i > 0; i--) { __no_operation(); } } while ((UCSCTL7 & DCOFFG) == DCOFFG); } /***************************************************************************** * timerBInt - interrupt handler for timer b * * Aux interrupt is 3569.6s, about 59.5 minutes. * The VLO frequency may range from 6..14 kHz, while its typical frequency * is 9.4 kHz. Additionally, a temperature drift of 0.5 % / deg C and a * supply voltage drift of 4% / V may apply. * ****************************************************************************/ static __interrupt void timerBInt( void ) { switch(TB0IV) { case TB0IV_TBIFG: timeoutCounter++; break; default: break; } if(timeoutCounter >= DEFAULT_AUX_TIMEOUT) { LPM3_EXIT; } }
#ifndef UTILS_CDEFS_H_ #define UTILS_CDEFS_H_ /* ==================================================================================== * GLOBAL DEFINITIONS ==================================================================================== */ #define TRUE ((BOOL)(1==1)) /* Boolean true */ #define FALSE ((BOOL)(0==1)) /* Boolean false */ #define OK ( 0 ) /* regular return value */ #define ERROR ( -1 ) #ifndef NULL #define NULL ((void *) 0) #endif typedef enum { DISABLE = 0U, ENABLE = 1U, } EnableState; typedef enum { HIGH = 1, LOW = 0, } PinLevel; #define BYTE_ERR 0xFF #define WORD_ERR 0xFFFF #define WORD_MAX 0x7FFF /* ==================================================================================== * GLOBAL TYPES ==================================================================================== */ typedef signed char BOOL ; /* 1 bit boolean */ typedef signed char STATUS; typedef signed char BYTE ; /* 8 bit signed integer data type */ typedef signed short WORD ; /* 16 bit signed integer data type */ typedef signed long DWORD ; /* 32 bit signed integer data type */ typedef unsigned char U_BYTE ; /* 8 bit unsigned integer data type */ typedef unsigned short U_WORD ; /* 16 bit unsigned integer data type*/ typedef unsigned long U_DWORD ; /* 32 bit unsigned integer data type*/ typedef float FLOAT ; /* 32 bit floating point value */ typedef double DOUBLE ; /* 64 bit floating point value */ /* pointer definitions used for test compatibility */ #ifndef pREG8 #define pREG8 U_BYTE* #endif #ifndef pREG16 #define pREG16 U_WORD* #endif #endif
#ifndef UTILS_BOARDDEF_H_ #define UTILS_BOARDDEF_H_ /* ================================================================= * GLOBAL INCLUDES ================================================================= */ #include "msp430.h" /* ================================================================= * GLOBAL TYPES ================================================================= */ /* ================================================================= * GLOBAL DEFINITIONS ================================================================= */ /* ================================================================= * PIN DEFINITIONS ================================================================= */ #define P2_OUT_NOT_USED (BIT4 | BIT6) #define P2_OUT_D_ACT (BIT0) #define P2_IN_FAN_SPEED (BIT1) #define P2_IN_BAT1_SOURCE_HIGH (BIT2) #define P2_IN_BAT2_SOURCE_HIGH (BIT3) #define P2_IN_START (BIT5) #define P2_IN_AC_WAKEUP (BIT7) #endif /* UTILS_BOARDDEF_H_ */
Hi Gong Qiqi,
Apologies it is going to be more challenging than I thought to reproduce your code since I'm working with slightly different hardware.
In the meantime, can you try something for me. Can you place a trap in the ISR (see below) to confirm all the surrounding code is working as expected?
static __interrupt void timerBInt( void ) {
switch(TB0IV) {
case TB0IV_TBIFG:
timeoutCounter++;
break;
default:
break;
}
if(timeoutCounter >= DEFAULT_AUX_TIMEOUT) {
while(1);
//LPM3_EXIT;
}
}
Thanks,
Evan
I put together an even simpler version of your code to test on my end. I wasn't able to reproduce your problem. When ii==3, the device exits LPM3 and lands on the while(1) in the main().
Can you run this code on your end and see if you have the same behavior?
#include <msp430.h> unsigned int ii = 0; int main(void) { WDTCTL = WDTPW + WDTHOLD; // Stop WDT UCSCTL1 = DCORSEL_2; /* select DCO range of 0.75 MHz to 7.68 MHz */ UCSCTL2 = FLLD__4 | 31; /* CLOCKDIV 4, FLLN 31 */ UCSCTL3 = SELREF__REFOCLK | FLLREFDIV__1; /* select 32768 ref clk, divide by 1 */ /* source SMCLK from DCOCLKDIV, MCLK from DCO, ACLK from VLO (9.4Hz typical) */ UCSCTL4 = SELS__DCOCLKDIV | SELM__DCOCLK | SELA__VLOCLK; //UCSCTL5 = DIVM__1 | DIVA__32 | DIVS__1 ; UCSCTL5 = DIVM__1 | DIVA__2 | DIVS__1 ; do { UCSCTL7 &= ~(XT2OFFG | XT1LFOFFG | DCOFFG); SFRIFG1 &= ~OFIFG; int i; for ( i = 80; i > 0; i--) { __no_operation(); } } while ((UCSCTL7 & DCOFFG) == DCOFFG); P5DIR |= BIT1; // P1.0 output TB0CTL = TBCLR; TB0CCR0 = 0U; TB0CCTL2 = 0U; TB0CCR2 = 0U; TB0R = 0U; TB0EX0 = TBIDEX_1; /* divide by 2 */ //TB0CTL = MC__CONTINUOUS | ID__8 | TBSSEL__ACLK | TBIE; /* 293.75 Hz / (2*8) ~> 18,359375 Hz*/ TB0CTL = MC__CONTINUOUS | ID__1 | TBSSEL__ACLK | TBIE; __bis_SR_register(GIE); LPM3; __no_operation(); while(1); // recovered from LPM } // Timer B0 interrupt service routine #pragma vector=TIMER0_B1_VECTOR __interrupt void TIMER0_B1_VECTOR_ISR (void) { switch(__even_in_range(TBIV,TB0IV_TB0IFG)){ case TB0IV_TB0CCR1: while(1); break; case TB0IV_TB0CCR2: while(1); break; case TB0IV_TB0CCR3: while(1); break; case TB0IV_TB0CCR4: while(1); break; case TB0IV_TB0CCR5: while(1); break; case TB0IV_TB0CCR6: while(1); break; case TB0IV_TB0IFG : ii++; P5OUT ^= BIT1; break; default: while(1); break; } if (ii == 3) { LPM3_EXIT; } }
The code is rather convoluted so it is not apparent to me how timeoutCounter gets reset after waking up from LPM3. I only see it being cleared in the timer start and stop code. Without being reset, it would be greater than 3 and cause a wakeup most every interrupt.
I would structure this a bit differently with the timer ISR just incrementing the counter and exiting LPM3. The foreground code would look at the counter and decide what to do: go back to sleep, or reset the counter and execute the time out tasks.
Hi Evan,
I've tested with the code you provided. The behavior is just as same as my code as I described previously. You can see some detail debug information here:
If it's OK on your side, is it possible the issue is caused by IAR or my debugger? I'm using IAR MSP430 7.20.1 and the debugger is TI MSP430 USB-Debug-Interface MSP-FET430UIF.
And also I added the remaining include files' code in my previous reply.
Best regards,
Gong Qiqi
Hi David,
Thank you for your concerning on it!
In fact, the code I showed is not the original code. I tided up the code and removed all the unnecessary files and lines. So this code is just to reproduce this issue. To make things simple, you can also try with Evan's code. I've reproduced this issue on his code.
Thanks a lot!
Qiqi
Hi Gong Qiqi,
Could you try my example in CCS and see if it has the same behavior?
Thanks,
Evan
Hi Evan,
I've tried your code in CCS and the same behavior occurred. And it seems it will occur in the case that we pause the running program in LPM3 mode in debug. If there're any pause operations after the 1st timer 0 B1 ISR had occurred, this issue will occur.
Thanks,
Gong Qiqi
Hi Gong Qiqi,
Thanks for the follow-up. I'm also able to create some bad behavior in the example code I gave you by repeatedly pausing and resuming the debugger during the operation of the program. I don't understand the root cause exactly, but the debugger is invasive and can create unexpected behavior.
Regards,
Evan
**Attention** This is a public forum