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.

MSP-EXP430FR4133: ISR Code isn't executing - can't figure out why

Part Number: MSP-EXP430FR4133

Hello, I am trying to leverage the Launchpad's OutofBox demo source to prove out some functionality and get some experience on the platform. I'm running into a problem where the TimerA0 ISR code doesn't seem to be executing and I am struggling to figure out why. Can someone please take a look and educate me? I feel like this is something very trivial that I just can't seem to spot. 

One thing that is confusing me is that if I uncomment the printf() statements in the ISR, the code executes as expected. I am using the two LEDs in question here as a state-machine detection debug to find out if they are ever getting called. I am trying to post only the relevant code snippets, but can provide more if appropriate. 

#pragma vector = TIMER0_A0_VECTOR
__interrupt void TIMER0_A0_ISR (void)
{
    // Both button S1 & S2 held down
    if (!(P1IN & BIT2) && !(P2IN & BIT6))
    {
        holdCount++;
        isrcount++;
        if (holdCount == 40)
        {
            // Stop Timer A0
            Timer_A_stop(TIMER_A0_BASE);

            // Change mode
     //       printf("Mode switch detected\n");
            if (*mode == 0)
            {
  // this part works
 //           printf("Switching to ADCRAW mode\n");
                (*mode) = ADCRAW_MODE;
                P1OUT |= BIT0; // Turn LED1 On
                P4OUT &= ~BIT0; // Turn LED2 Off

            }
            else if (*mode == ADCRAW_MODE)
            {
// this part doesn't - this code only executes with the printf() statements uncommented, but then it functions normally     
//           printf("Switching to LINEARFLOW mode\n");

                P1OUT &= ~BIT0; // Turn LED1 Off
                P4OUT |= BIT0; // Turn LED2 On

                (*mode) = LINEARFLOW_MODE;
            }
            else if (*mode == LINEARFLOW_MODE)
            {
   //             printf("Switching to GPHFLOW mode\n");
                P1OUT |= BIT0; // Turn LED1 On
                P4OUT |= BIT0; // Turn LED2 On

                (*mode) = GPHFLOW_MODE;
            }
            else if (*mode == GPHFLOW_MODE)
            {
     //           printf("Switching to ADCRAW mode\n");
                P1OUT |= BIT0; // Turn LED1 On
                P4OUT &= ~BIT0; // Turn LED2 Off

                (*mode) = ADCRAW_MODE;
            }

            __bic_SR_register_on_exit(LPM3_bits);                // exit LPM3
        }
    }

    // Button S1 released
    if (P1IN & BIT2)
    {
        *S1buttonDebounce = 0;                                   // Clear button debounce
        P1OUT &= ~BIT0;
    }

    // Button S2 released
    if (P2IN & BIT6)
    {
        *S2buttonDebounce = 0;                                   // Clear button debounce
        P4OUT &= ~BIT0;
    }

    // Both button S1 & S2 released
    if ((P1IN & BIT2) && (P2IN & BIT6))
    {
        // Stop timer A0
        Timer_A_stop(TIMER_A0_BASE);
        __bic_SR_register_on_exit(LPM3_bits);    // exit LPM3
    }
}
int main(void)
{
	//WDTCTL = WDTPW | WDTHOLD;	// stop watchdog timer
    WDT_A_hold(__MSP430_BASEADDRESS_WDT_A__);     // Stop WDT

    /*
     * Launchpad Demo includes this code to wake up from low power mode
     */
    // Check if a wakeup from LPMx.5
        if (SYSRSTIV == SYSRSTIV_LPM5WU)
        {
            Init_GPIO();
            __enable_interrupt();

            switch(*mode)
            {
                case ADCRAW_MODE:
                    break;
                case LINEARFLOW_MODE:
                    break;
                case GPHFLOW_MODE:
                    break;
            }
        }
        else    // Else must be first time boot, run Inits
        {

            /*
             * Init Routines before we do anything interesting
             */
                Init_GPIO();
                Init_Clock();
                Init_RTC();
                Init_LCD();
                GPIO_clearInterrupt(GPIO_PORT_P1, GPIO_PIN2);
                GPIO_clearInterrupt(GPIO_PORT_P2, GPIO_PIN6);
                *S1buttonDebounce = *S2buttonDebounce = *mode = 0;
                __enable_interrupt();

                RTC_setModulo(RTC_BASE, 8191);
                RTC_enableInterrupt(RTC_BASE, RTC_OVERFLOW_INTERRUPT);
                RTC_start(RTC_BASE, RTC_CLOCKSOURCE_XT1CLK);

                displayScrollText("FLOW DEMO"); // Boot message - Uppercase Chars Only

        }

    /*
     * Main Loop
     */
  
    while(1)
    {
  
        switch(*mode)
        {
        case ADCRAW_MODE:
            displayScrollText("ADC RAW MODE SELECTED");
            clearLCD();
            // Call ADC Init & Start
            break;
        case LINEARFLOW_MODE:
            displayScrollText("LINEAR FLOW MODE SELECTED");
            clearLCD();
            break;
        case GPHFLOW_MODE:
            displayScrollText("GPH NOT IMPLEMENTED");
            clearLCD();
            break;

        default:       // Must be first boot
            displayScrollText("HOLD S1 AND S2 TO SWITCH MODES");
            clearLCD();
            break;
        }

        __bis_SR_register(LPM3_bits | GIE); // Enter LPM3
        __no_operation();
    }


}// End of main()

  • Hello Dave,

    am not sure where your printf() is coming from. If it's your own one and based on something like putchar() sent to stdio implemented straight forward to the back channel UART without interrupt involvement; then it shall work. IF you use a printf() implementation that is more elegant/feature rich and does things interrupt driven in background  ==> then all is clear, it can't work.

    While inside the isr() all other interrupts are disabled and putting a complex communication function inside an isr() blocks the whole thing.

    Three ways out:

    - use printf() only from outside and communicate to the message generation via tokens/flags  -or-

    - use a simple stupid printf() implementation that does not require any interrupts. But don't call this one printf() it might be misleading..

    - as third solution, allow nesting of interrupts; this however can get tricky if you nest into interrupts of same type.

    I wish you some happy coding

           Johann

  • Hi Johann, I think you misunderstood my post. The printf() function is the default build in CCS MSP430 projects, nothing special here and the printf() actually seems to execute normally. My confusion is that portions of code immediately following the printf() statements (see the comments in snippets above) only seem to execute when the printf() statements are not commented out. 

  • Hi Dave,

    just for clarification.

    If the printf is included in the code, you can see the LED switch ON of OFF, right? If the printf is not included you cannot see any LED activity.

    Is that understanding correct?

    If that is the case, how you check the LEDs activity if printf is not included in the code? just visually. Have you tried to check with the scope to see if there is any activity (very short pulses?).

    It may be that the printf acts as a delay and this gives enough time to be able to see the LED.

    Let me now.

    Regards

    Kostas

  • Hi Dave,

    Thanks for your patience. I got notified that my 'FR4133 board arrived. I will be soon able to X-check what went wrong. Am working currently from home and do not have all EVMs in place that's why....

    Johann

     

  • Hi Johann,

    I scrapped that code and wrote my own and have moved on. I decided not to worry about debounce for the moment as it's not important to my end application, only for proof of concept. I believe the issue was something related to timer enable flags, but I haven't gone back to double check. If you determine what the issue was, I would certainly like to understand it for future reference. 

    For what it's worth, I found that example code very difficult to follow, particularly the debounce logic as there are very few comments explaining the flow. 

  • Hi Dave,

    I loaded the "OutOfBox" demo, adapted the code to be similar yours, added some defines to close the open references and ran it.

    The first thing I turned off was the RTC interrupt by setting RTCCTL.RTCIE=0 in the register window ...since the RTC interrupt came up again and again.

    ... and... You are right... same here in the "struct" param the ..._TAIE was never set, neither TA0CCTL0.CCIE therefor no ISR.  Setting the flags manually leads to the expected reaction.

    By the way you showed me an even funnier thing.... : I had a look on how the function "void Inc_RTC()" in "StopWatchMode.c" was implemented... It uses an modulo division instead of a compare. Please do not code like this, and do not take this as a good example; Even though it is mathematically correct it is not the way to save power.  It looks like we had an "abstract programmer" at work here.

    Dave, sorry for that inconvenience...  

         Johann

    PS: I might come back again here and tell you the clock difference on that "Inc_RTC();"

  • Hello again Dave,

    I have some results checking out the function "Inc_RTC()"  ...and was a bit surprised. I also provided an alternative implementation below "LpInc_RTC()" which is more energy conservative.

    Here the results for the performance check:

    Case name …before func(); …after func(); Inc_RTC();[clks] LpInc_RTC();[clks]
    no carry 00:00:00.00 00:00:00.01 189 13
    cSec carry 00:00:00.99 00:00:01.00 379 28
    Sec carry 00:00:59.99 00:01:00.00 569 40
    Min carry 00:59:59.99 01:00:00.00 751 52
    Hrs carry 99:59:59.99 00:00:00.00 752 50

    The original Function "Inc_RTC();" as in the demo.

    // Increment Real Time Counter
    void Inc_RTC()
    {
        // Clock increment logic
        // Handles maximum 100 hours, then wraps over to 00:00:00
        (*Centiseconds)++;
        (*Centiseconds) %= 100;
        if ((*Centiseconds) == 0)
        {
            (*Seconds)++;
            (*Seconds) %= 60;
            if ((*Seconds) == 0)
            {
                (*Minutes)++;
                (*Minutes) %= 60;
                if ((*Minutes) == 0)
                {
                    ++(*Hours);
                    (*Hours) %= 100;
                }
            }
        }
    }

    Below the low power implementation "LpInc_RTC();"  that is more energy conservative ( the variable names are altered too)

    void LpInc_RTC()
    {
      if ((*LpCSec)<99) (*LpCSec)++;
      else {
        (*LpCSec)=0;
        if ((*LpSec)<59) (*LpSec)++;
        else {
          (*LpSec)=0;
          if ((*LpMin)<59) (*LpMin)++;
          else {
            (*LpMin)=0;
            if ((*LpHrs)<99) (*LpHrs)++;
            else (*LpHrs)=0;
          }
        }
      }
    }

    I also checked some other SW techniques used in that demo (some of them are unusual too); I suppose there will be an update of that demo in future. Time will tell.

    Happy coding

         Johann

     

**Attention** This is a public forum