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.

Debounce program using RTC timer

Other Parts Discussed in Thread: MSP430FR4133

Hello everybody. I am having trouble with a debounce pushbutton program.
   Briefly,I want my program tot work like this: when I press the button the port ISR will be diabled, the RTC timer will be enabled, the RTC timer routine will count
2 ticks after which the RTC timer will be disabled and the port ISR will be enabled again. During the 2 RTC timer ticks any activation of the pushbutton from the debounce
should be discarded because the port ISR is disabled. My problem is that during the 2 RTC ticks the MSP430 remembers the button activation and the port ISR is
executed after the 2 RTC ticks. I don't know why and how the MSP430 takes into considerations the activation of the button if the port ISR is disabled. So, instead of
disabling the port ISR during the 2 ticks, it just delays the execution of the ISR with 2 ticks.
  Expected behaviour: I push button, wait 2 ticks, the LED turns ON ans stays ON.
  Actual behaviour: I push button, LED turns ON, wait 2 ticks, LED turns OFF.

I am using MSP430FR4133.

Here is the code

//Enable Timer rtc with Pushbutton ISR


#include <msp430.h>

int counter_timer = 0;
int counter_port = 0;

int main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer



P1DIR |= BIT0;
P1OUT &= ~BIT0;

P4DIR |= BIT0; // Set P4.0 to output direction  \\pin 4.0 e Ledu verde
P2DIR &= ~BIT6; //Set P2.6 to input direction

P4OUT &= ~BIT0; // set P4.0 to 0 (LED OFF)

P2REN |= 0x40; // Resistor for P2.6  //  0x40 = 01000000 in binar, adica bitul6
P2OUT |= 0x40; // Resistor pulls up

P2IES |= 0x40; // High to low transition for P1.2

P2IE |= BIT6; // P2.6 interrupt enabled

P2IFG &= ~BIT6; // P2.6 IFG cleared


// Configure clock  as SMCLK = 1MHz
       __bis_SR_register(SCG0);                        // disable FLL
       CSCTL3 |= SELREF__REFOCLK;                      // Set REFO as FLL reference source
       CSCTL0 = 0;                                     // clear DCO and MOD registers
       CSCTL1 &= ~(DCORSEL_7);                         // Clear DCO frequency select bits first
       CSCTL1 |= DCORSEL_2;                            // Set DCO = 4MHz
       CSCTL2 = FLLD_1 + 60;                           // DCODIV = 2MHz
       __delay_cycles(3);
       __bic_SR_register(SCG0);                        // enable FLL
       while(CSCTL7 & (FLLUNLOCK0 | FLLUNLOCK1));      // Poll until FLL is locked

       CSCTL4 |= SELMS__DCOCLKDIV | SELA__REFOCLK;     // set default REFO(~32768Hz) as ACLK source, ACLK = 32768Hz
                                                       // default DCODIV as MCLK and SMCLK source
       CSCTL5 |= DIVM__1 | DIVS__2;                    // SMCLK = 1MHz, MCLK = 2MHz



       // Initialize RTC
                 RTCMOD = 400;
                 RTCCTL = RTCSS__SMCLK | RTCSR | RTCPS__1000 ;    //sursa clock-ului e SMCLK=1MHz | reload shadow register |SMCLK se divide cu 1000|interrupt enable
                 P2IE |= BIT6;  // P2.6 interrupt enabled




PM5CTL0 &= ~LOCKLPM5;

                    __no_operation();

                    __bis_SR_register(GIE);




       while(1)
       {
           if(counter_port == 1)         //if the button is pressed once
           {
               RTCCTL |= RTCIE;                            // RTC timer interrupt enable
               P2IE &= ~BIT6;                               // disable P2.6 interrupt

               if(counter_timer == 2)        // after 2 RTC timer ticks pass
               {
                   P1OUT ^= BIT0;                               // red led on
                   counter_timer = 0;                           //reset timer counter
                   counter_port = 0;                            //reset button counter
                   RTCCTL &= ~RTCIE;                            //RTC timer interrupt disable
                   P2IE |= BIT6;                                // P2.6 interrupt enabled
               }


           }


       }


}


// *************************INTERRUPT ROUTINES************************************************************************
        // Timer A0 interrupt service routine
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector = RTC_VECTOR
__interrupt void RTC_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(RTC_VECTOR))) RTC_ISR (void)
#else
#error Compiler not supported!
#endif
{

                counter_timer++;

                RTCIV = RTCIV_RTCIF ;



}




// Port 2 interrupt service routine

#pragma vector = PORT2_VECTOR
__interrupt void PORT2_ISR(void)
{


    counter_port++;

      P2IFG &= ~0x40; // Clear interrupt flag for P2.6



}

  • It sounds like you should clear the P2IFG bit just before you (re-)enable the P2IE:


    RTCCTL &= ~RTCIE; //RTC timer interrupt disable
    P2IFG &= ~BIT6; // Clear possible stale P2.6 status <---
    P2IE |= BIT6; // P2.6 interrupt enabled

    This is actually not a bad general practice, e.g. at startup -- just before you enable any interrupt, clear any stale status. (Full disclosure: There are a few cases where you don't want to do this, but they're rare.)

  • Hi Bruce. Unfortunately, that didn't work. The debounce problem is still there.

  • Can you post your updated code?
  • Sure. Here it is. I just want tot mention that the debounce effect(the led is on and after 2 ticks is off again) doesn't happen all the time but in 1 out of 6-7 cases.

    //Enable Timer rtc with Pushbutton ISR
    
    
    #include <msp430.h>
    
    int counter_timer = 0;
    int counter_port = 0;
    
    int main(void)
    {
    WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
    
    
    
    P1DIR |= BIT0;
    P1OUT &= ~BIT0;
    
    P4DIR |= BIT0; // Set P4.0 to output direction  \\pin 4.0 e Ledu verde
    P2DIR &= ~BIT6; //Set P2.6 to input direction
    
    P4OUT &= ~BIT0; // set P4.0 to 0 (LED OFF)
    
    P2REN |= 0x40; // Resistor for P2.6  //  0x40 = 01000000 in binar, adica bitul6
    P2OUT |= 0x40; // Resistor pulls up
    
    P2IES |= 0x40; // High to low transition for P1.2
    
    P2IE |= BIT6; // P2.6 interrupt enabled
    
    P2IFG &= ~BIT6; // P2.6 IFG cleared
    
    
    // Configure clock  as SMCLK = 1MHz
           __bis_SR_register(SCG0);                        // disable FLL
           CSCTL3 |= SELREF__REFOCLK;                      // Set REFO as FLL reference source
           CSCTL0 = 0;                                     // clear DCO and MOD registers
           CSCTL1 &= ~(DCORSEL_7);                         // Clear DCO frequency select bits first
           CSCTL1 |= DCORSEL_2;                            // Set DCO = 4MHz
           CSCTL2 = FLLD_1 + 60;                           // DCODIV = 2MHz
           __delay_cycles(3);
           __bic_SR_register(SCG0);                        // enable FLL
           while(CSCTL7 & (FLLUNLOCK0 | FLLUNLOCK1));      // Poll until FLL is locked
    
           CSCTL4 |= SELMS__DCOCLKDIV | SELA__REFOCLK;     // set default REFO(~32768Hz) as ACLK source, ACLK = 32768Hz
                                                           // default DCODIV as MCLK and SMCLK source
           CSCTL5 |= DIVM__1 | DIVS__2;                    // SMCLK = 1MHz, MCLK = 2MHz
    
    
    
           // Initialize RTC
                     RTCMOD = 400;
                     RTCCTL = RTCSS__SMCLK | RTCSR | RTCPS__1000 ;    //sursa clock-ului e SMCLK=1MHz | reload shadow register |SMCLK se divide cu 1000|interrupt enable
                     P2IE |= BIT6;  // P2.6 interrupt enabled
    
    
    
    
    PM5CTL0 &= ~LOCKLPM5;
    
                        __no_operation();
    
                        __bis_SR_register(GIE);
    
    
    
    
           while(1)
           {
               if(counter_port == 1)         //if the button is pressed once
               {
                   RTCCTL |= RTCIE;                            // RTC timer interrupt enable
                   P2IE &= ~BIT6;                               // disable P2.6 interrupt
    
                   if(counter_timer == 2)        // after 2 RTC timer ticks pass
                   {
                       P1OUT ^= BIT0;                               // red led on
                       counter_timer = 0;                           //reset timer counter
                       counter_port = 0;                            //reset button counter
                       RTCCTL &= ~RTCIE;                            //RTC timer interrupt disable
                       P2IFG &= ~BIT6;                              // Clear possible stale P2.6 status <---
                       P2IE |= BIT6;                                // P2.6 interrupt enabled
                   }
    
    
               }
    
    
           }
    
    
    }
    
    
    // *************************INTERRUPT ROUTINES************************************************************************
            // Timer A0 interrupt service routine
    #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
    #pragma vector = RTC_VECTOR
    __interrupt void RTC_ISR(void)
    #elif defined(__GNUC__)
    void __attribute__ ((interrupt(RTC_VECTOR))) RTC_ISR (void)
    #else
    #error Compiler not supported!
    #endif
    {
    
                    counter_timer++;
    
                    RTCIV = RTCIV_RTCIF ;
    
    
    
    }
    
    
    
    
    // Port 2 interrupt service routine
    
    #pragma vector = PORT2_VECTOR
    __interrupt void PORT2_ISR(void)
    {
    
    
        counter_port++;
    
          P2IFG &= ~0x40; // Clear interrupt flag for P2.6
    
    
    
    }
    

  • There's a similar case with the RTCIFG: You should clear the IFG before you start waiting for the RTC:
    RTCIV = RTCIV_RTCIF ; // clear stale IFG <---
    RTCCTL |= RTCIE;
    Without this, it is possible for your "2 ticks" to be nearly 0 ticks -- if the IFG is already set and the RTC is about to trigger again. As a result, (sometimes) the switch is still bouncing when your timer wait is completed. By doing this you guarantee a delay of at least one cycle (400ms).

    Unsolicited:
    (1) You should move the initial P2IFG/P2IE (in that order) settings below the clearing of LOCKLPM5 (see also SLAU445G sec 7.3.1).
    (2) There are a number of races here, which probably aren't causing trouble now but will eventually:
    (a) The "counter_port == 1" test should be "counter_port >= 1", in case the switch bounces very fast.
    (b) The counter_timer test should also be ">=", though you're much less likely to trip over that one.
    (c) After the timeout, you should clear the counters after clearing RTCIE (and before setting P2IE), in case one more interrupt sneaks in in between and throws counter_timer off.
  •   THANK YOU!!!! You were right. Clearing the flag for RTCIV solved my problem. I can't thank you enough. I have been trying to create a  debounce code for months.

      Thanks, Bruce! You are on my Christmas list!

**Attention** This is a public forum