• Join
  • Sign In with my.TI Login
Texas Instruments
  • Products
  • Applications
  • Tools & Software
  • Support & Community
  • Sample & Buy
  • About TI
Sample & Purchase Cart Sample & Purchase Cart
  • Search
  • Advanced
TI E2E™ Community
  • Support Forums
  • Blogs
  • Groups
  • Videos
  • 简体中文
  • More ...
TI Home » TI E2E Community » Support Forums » Microcontrollers » MSP430™ Microcontrollers » MSP430 Ultra-Low Power 16-bit Microcontroller Forum » Mysterious: TAIE getting enabled somehow
Share
MSP430™ Microcontrollers
  • Forum
  • Announcements
  • E2E Wiki
Options
  • Subscribe via RSS
MSP430 Resources
  • MSP430 Product Folder
  • MSP-EXP430G2 - MSP430 LaunchPad Value Line Development kit
  • MSP430 Getting Started Guide
  • MSP430 Microcontroller Projects
  • More Resources >
  • Forums

    Mysterious: TAIE getting enabled somehow

    This question is not answered
    Asa Cannell
    Posted by Asa Cannell
    on Apr 16 2012 11:14 AM
    Prodigy160 points

    Setup is:

    MSP430F1101A

    Internal DCO at wakeup then switch to external 4.096MHz crystal.

    AQ430 C compiler/IDE

    MSP-FET430UIF

    This processor keeps getting locked up. I've added all kinds of pin wiggles to watch whats happening, because it doesnt happen while connected to the debugger. As far as I can tell, it appears that a Timer A interrupt sometimes starts to repeatedly occur, and since originally there was no TimerA ISR, the code jumps to FFFF, executes the nonsense opode (actually the reset vector address) and goes off into la-la land.... The mystery is that as far as I can tell by breaking in the simulator and my own analysis of the code, I never enable TAIE. Note: there is now a Timer A ISR, but only for debuggin this problem. It is not normally there and as far as I can tell should not need to be there since I never enable TAIE.

    To prove this, I added interrupt handler functions for every vector, and when any of them are activated (interrupt occurs), I wiggle a pin as many times as that vector. So if vector 8 occurs, I wiggle a pin 8 times so I can tell. Since it appeared Timer A interrupt was occuring, I added another debug feature that leaves the pin high if TAIE is enabled. And it is. How can this be?

    The way this processor is used is:

    Initial power on.

    Setup hardware in a typical way, go to sleep LPM4.

    Get awoken every 1000ms by a port 1 interrupt, switch oscillators, use timer A capture to measure something (without interrupt), go back to sleep.

    The code is (not including cstart.asm):

    // --------------
    // Include Files
    // --------------

    #include <msp430x11X1.h>

    // ---------------------
    // Function Prototypes
    // ---------------------

    void main( void );
    void init_hardware( void );
    void check_cha_frequency( void );
    void check_chb_frequency( void );
    void isr(void);
    unsigned char vect;

    // ------------
    // Definitions
    // ------------

    // To make the program easier to understand.
    #define TRUE     1
    #define FALSE     0

    // For Time Delay Loops
    #define HS_OSC_DELAY   0xFF
    #define INTERRUPT_DELAY_TIME  100

    // Define Window Limits
    #define SMCLK_FREQ    4096000
    #define SMCLK_FREQ_ERROR   40   // Allowable deviation.
    #define MAX_BAD_COUNTS   100   // Used for filtering bad counts.
    #define CHA_HIGH_LIMIT    ( SMCLK_FREQ / 4000 ) + SMCLK_FREQ_ERROR
    #define CHA_LOW_LIMIT     ( SMCLK_FREQ / 4000 ) - SMCLK_FREQ_ERROR
    #define CHB_HIGH_LIMIT   ( SMCLK_FREQ / 4000 ) + SMCLK_FREQ_ERROR
    #define CHB_LOW_LIMIT   ( SMCLK_FREQ / 4150 ) - SMCLK_FREQ_ERROR

    // Inputs
    #define HV_ACTIVE    BIT3
    #define CHA_HV_DETECT   BIT2
    #define CHB_HV_DETECT   BIT1
    #define CHA_AND_CHB    ( BIT1+BIT2 )

    // Outputs
    #define CHA_HV_GOOD    BIT2
    #define CHB_HV_GOOD    BIT1
    #define TEST_OUT    BIT0

    // -------------
    // Define Enums
    // -------------

    // ----------------------
    // Structure Definitions
    // ----------------------

    // ------------------
    // Global Variables
    // ------------------

    // ----------------
    // Local Variables
    // ----------------

    // Channel A Related Variables
    unsigned char ucChAError;
    unsigned int uiChAFrequency;
    unsigned int uiPrevChAFrequency;
    unsigned int uiCurrentChAFrequency;
    unsigned char ucChAHVPresentFlag;

    // Channel B Related Variables
    unsigned char ucChBError;
    unsigned int uiChBFrequency;
    unsigned int uiPrevChBFrequency;
    unsigned int uiCurrentChBFrequency;
    unsigned char ucChBHVPresentFlag;

    // Diagnostics Related Variables
    unsigned int ucNumberWdResets = 0;

    // Store Version Number
    unsigned int uiVersionNumber = 101; // Can only be seen with a debugger.

    void main( void )
      { 
      init_hardware();
     
      while( TRUE )
        {
        WDTCTL = WDT_ARST_1000;     // Set Watchdog Timer interval.
        
     // So we can  tell that a watchdog reset occured.
        if(( IFG1 & WDTIFG ) == WDTIFG )
          {
          // Set the flag.
          ucNumberWdResets = 0xFF;
           P1OUT &= ~BIT0;
      P1OUT |= BIT0;
      P1OUT &= ~BIT0;
      IFG1 &= ~WDTIFG;
          }
       
        // Start monitoring the frequency for channels A and B.
        check_cha_frequency();  // CHA_HV_GOOD HIGH = LOW, HV OK.

        // -----------------
        // ENTER SLEEP MODE
        // -----------------
       
        // If HV_ACTIVE input is low, SLEEEEEPPPP.....  
        if(( P1IN & HV_ACTIVE ) == 0 )
          {
          P2OUT |= CHA_HV_GOOD;  // Set output high so we are in a known state.
          P2OUT |= CHB_HV_GOOD;  // Set output high so we are in a known state.
          _DINT();     // Momentarily disable interrupts.
          P1IE |= HV_ACTIVE;  // Enable HV_ACTIVE interrupts (disabled in ISR).
          P1IFG = 0;    // Clear HV interrupt flag.
          _EINT();     // Re-enable interrupts
          LPM4;      // Enter LPM4.     
          }
        }
      }
      
     
    void init_hardware( void )
      {
      unsigned int i;
     
      WDTCTL = WDTPW + WDTHOLD;             // Stop WDT
      BCSCTL1 |= ( XTS+XT2OFF+DIVA_3 );  // ACLK = LFXT1 = HF XTAL ACKL / 8.
      BCSCTL2 |= ( SELS+SELM_2 );   // Switch SMCLK, MCLK to HS Crystal.
     
      // If there is a problem with the HS Oscillator we will hang up here.
      do
        {
        IFG1 &= ~OFIFG;                     // Clear OSC Fault flag
        for( i = HS_OSC_DELAY; i>0; i-- ); // Time for flag to set
        }   
      while (( IFG1 & OFIFG ) != 0 );       // OSC Fault flag still set?
     
      // Setup Port 1 Inputs
      P1SEL |= CHA_HV_DETECT;    // Setup CCR1 - Capture mode.    
      P1SEL |= CHB_HV_DETECT;    // Setup CCR0 - Capture mode.
     
      P1DIR |= BIT0;      // Make unused I/O pins outputs.
      P1OUT &= ~BIT0;      // And set unused I/O pins Low.
     
      P1IES = 0;       // Interrupt on Rising Edge
      P1IE |= HV_ACTIVE;     // Enable HV_ACTIVE interrupts.
      P1IFG = 0;       // Clear HV_ACTIVE interrupt flag.

      // Setup Capture Compare Rregisters
      TACTL = ( TASSEL_2+MC1+TACLR );  // SMCLK - Clear TAR, Continuous Up mode.      
      TACCTL0 = ( CM_2+SCS+CAP );   // Falling edge, capture mode.
      TACCTL1 = ( CM_2+SCS+CAP );   // Falling edge, capture mode.
     
      // Setup Port 2 outputs
      P2DIR |= 0x3F;      // Set P2.0 - P2.6 to outputs.
      P2OUT = 0x06;       // Start CH A and CH B Good lines high.
     
      // Initialize global variables.
      ucChAError = 0; 
      uiChAFrequency = 0;
      uiPrevChAFrequency = 0;
      uiCurrentChAFrequency = 0;
      ucChAHVPresentFlag = FALSE;
     
      ucChBError = 0;
      uiChBFrequency = 0;
      uiPrevChBFrequency = 0;
      uiCurrentChBFrequency = 0;
      ucChBHVPresentFlag = FALSE;
      IE1 |= WDTIE;                         // Enable WDT interrupt
     
      //---------------------------
      // Get ready. Get set. Go!!!
      // --------------------------
     
      _EINT();                              // Enable interrupts
      }  
                          
    void check_cha_frequency( void )
      {
      unsigned int i, n;
     
      // See if electrical stimulation is being produced on Channel A.
     
      // This loop is so that we can get a specified number of errors in a row
      // before concluding that the frequency is off.
     
      ucChAError = 0;
      for( i=0; i<MAX_BAD_COUNTS; i++ )
        {
        TACCTL1 &= ~CCIFG;      // Clear the CCR1 interrupt flag.
        n=0;         // Intialize delay loop counter.
        while( TRUE )
          {
          // This loop is so that we don't get hung up forever waiting for an
          // interrupt to occur. If it has not occured after n times through the
          // loop we just return.
         
          if(( TACCTL1 & CCIFG ) == CCIFG )  // CCR1 Interruptflag set?
            {
            uiCurrentChAFrequency = TACCR1;  // Yes, Save the TAR count.
            uiChAFrequency = uiCurrentChAFrequency - uiPrevChAFrequency;
           
            // Is the TAR count within prescribed limits?
            if(( uiChAFrequency < CHA_LOW_LIMIT ) || ( uiChAFrequency > CHA_HIGH_LIMIT ))
              {
              ucChAError++;      // Out of limits. Increment the error count.
              }
            uiPrevChAFrequency =  TACCR1;  // Read current TAR for next iteration.
            break;
            }
          else
            {
            n++;        // Increment delay loop counter.
            if( n > INTERRUPT_DELAY_TIME )
              {
        // Set output high because no frequency was detected.
         P2OUT |= CHA_HV_GOOD;
              return;       // Bail out.
              }
            }
          }   
        }
            
      // Evaluate results of frequency test for Channel A
      if( ucChAError < MAX_BAD_COUNTS )
        {
        P2OUT &= ~CHA_HV_GOOD;     // Set output LOW because frequency is within limits.
        }
      else 
        {
        P2OUT |= CHA_HV_GOOD;     // Set output high because frequency is out of bounds.
        }
      }

    interrupt[ PORT1_VECTOR ] void hv_active_int( void )
      {
      unsigned int i;

      // Wake up if HV Active goes high. We should be running off the DCO
      // Clock at first.
      LPM4_EXIT;             // Resume normal operation. 
      WDTCTL = WDT_ARST_1000;       // Start Watchdog Timer interval
       
      // Switch to HS Osillator.
      BCSCTL1 |= ( XTS+XT2OFF+DIVA_3 );  // ACLK = LFXT1 = HF XTAL ACKL / 8.
      BCSCTL2 |= ( SELS+SELM_2 );   // Switch SMCLK, MCLK to HS Crystal.
     
      // Wait for HS Oscillator to stablize. 
      do
        {  
        IFG1 &= ~OFIFG;      // Clear OSC Fault flag
        for( i = HS_OSC_DELAY; i>0; i-- ); // Time for flag to set
        }   
      while (( IFG1 & OFIFG ) != 0 );       // OSC Fault flag still set?
     
      P1IFG = 0;       // Clear interrupt flag.
      }
     

    void isr(void)
    {
     unsigned char count;
     P1DIR |= BIT0;
     for(count = 0; count < vect; count++)
     {
      P1OUT &= ~BIT0;
      P1OUT |= BIT0;
      P1OUT &= ~BIT0;
     }
     if(TACTL |= 0x0002)
     {
      P1OUT &= ~BIT0;
      P1OUT |= BIT0;
     }
    }
    /*
    interrupt [0] void int0(void)
    {
    isr();
    }
    */
    interrupt [2] void int1(void)
    {
    vect = 1;
    isr();
    }

    interrupt [6] void int3(void)
    {
    vect = 3;
    isr();
    }

    interrupt [8] void int4(void)
    {
    vect = 4;
    isr();
    }

    interrupt [10] void int5(void)
    {
    vect = 5;
    isr();
    }

    interrupt [12] void int6(void)
    {
    vect = 6;
    isr();
    }

    interrupt [14] void int7(void)
    {
    vect = 7;
    isr();
    }

    interrupt [16] void int8(void)
    {
    vect = 8;
    isr();
    }

    interrupt [18] void int9(void)
    {
    vect = 9;
    isr();
    }

    interrupt [20] void int10(void)
    {
    vect = 10;
    isr();
    }

    interrupt [22] void int11(void)
    {
    vect = 11;
    isr();
    }

    interrupt [24] void int12(void)
    {
    vect = 12;
    isr();
    }

    interrupt [26] void int13(void)
    {
    vect = 13;
    isr();
    }

    interrupt [28] void int14(void)
    {
    vect = 14;
    isr();
    }

    Report Abuse
    • Reply
    You have posted to a forum that requires a moderator to approve posts before they are publicly available.
    All Replies
    • Jens-Michael Gross
      Posted by Jens-Michael Gross
      on Apr 16 2012 13:06 PM
      Guru141810 points

      Asa Cannell
        IE1 |= WDTIE;                         // Enable WDT interrupt

      You don't seem to have an ISR for the WDT initially. Well, now you have (even if this is just a dummy one). But since it now should be covered, it shouldn't execute nonsense that might set the timer IE bit.
      On second glance, you don't configure the WDT for delay mode, so this is as don't care anyway.

      The MSP has only 128 bytes ram. With all those global variables you have, and the stack space needed for the ISR, maybe you're experiencing a stack overflow. But then, your code shouldn't use that much ram (I didn't count)

      I don't see any other code that might cause a stack overflow, an array-out-of-bounds access or anything else that could cause this. So sorry, I don't know what happens.

      _____________________________________
      Before posting bug reports or ask for help, do at least quick scan over this article. It applies to any kind of problem reporting. On any forum. And/or look here.
      If you cannot discuss your problem in the public, feel free to start a private conversation: click on my name and then 'start conversation'. But please do so only if you really cannot do it in a public thread, as I usually read all threads. And I prefer to answer where others can profit from it (or contribute to it) too.

      Report Abuse
      • Reply
      You have posted to a forum that requires a moderator to approve posts before they are publicly available.
    • TonyKao
      Posted by TonyKao
      on Apr 16 2012 13:15 PM
      Genius3770 points

      I think you made a typo here:

       if(TACTL |= 0x0002)
       {
        P1OUT &= ~BIT0;
        P1OUT |= BIT0;
       }

      The condition, since it's an assignment, will always be true, and it will set the TAIE bit in TACTL.

      Tony

      Report Abuse
      • Reply
      You have posted to a forum that requires a moderator to approve posts before they are publicly available.
    • Asa Cannell
      Posted by Asa Cannell
      on Apr 16 2012 13:16 PM
      Prodigy160 points

      Thanks for trying!

       

      Hmm...yes I dont put the WDT in timer mode, yet I still disable WDTIE...thats unnecssary isnt it. Maybe that has unintended consequences? On the other hand, I do now have ISR's that would catch the timer WDT vector, even if it somehow happened, and I don't see evidence of it at the moment, only the Timer A vector. So maybe thats a dead end.

      Is there a way to detect a stack overflow without using the debugger?

      Is there any possibility that interrupts are nesting and actually occuring multiple times inside the PORT1_VECTOR ISR? (the only one that is in the original code).

      AQ430 says I am using 20 bytes of ram in the release version of the code (none of my debug ISRs and with another copy of the check_a_frequency function called check_b)

      HMMMM.....

      If I can start isolating this...assuming that TAIE is actually getting set somewhere, maybe I could search the hex dump of the code for a word that would set TAIE, even if its not meant to...in other words if the cpu starts going off into the nether world and executing rom bytes willy nilly, maybe I can figure out which rom byte ends up inadvertantly disassembling to TAIE = 1 (or equivalent), and work backwards from there?

       

       

      Report Abuse
      • Reply
      You have posted to a forum that requires a moderator to approve posts before they are publicly available.
    • Asa Cannell
      Posted by Asa Cannell
      on Apr 16 2012 13:22 PM
      Prodigy160 points

      TonyKao

      I think you made a typo here:

       if(TACTL |= 0x0002)
       {
        P1OUT &= ~BIT0;
        P1OUT |= BIT0;
       }

      The condition, since it's an assignment, will always be true, and it will set the TAIE bit in TACTL.

      Tony

       Whoops! Thanks. I changed it to:

       if(TACTL & 0x0002)
       {
        P1OUT &= ~BIT0;
        P1OUT |= BIT0;
       }

       Luckily that bad code shouldnt have even been reached unless an invalid ISR occured..

      So now with the code changed, it still experiences a Timer A ISR infinite loop, but its not indicating that TAIE is set anymore...WTF?? How could this be?

       

       

      Report Abuse
      • Reply
      You have posted to a forum that requires a moderator to approve posts before they are publicly available.
    • Jens-Michael Gross
      Posted by Jens-Michael Gross
      on Apr 16 2012 13:25 PM
      Guru141810 points

      Asa Cannell
      yet I still disable WDTIE

      No, you enable it :) However, thsi bit is a don't care in watchdog mode, since a watchdog timeout will always trigger a reset :)

      And TonyKao got it right. Your if statement condition iside the dummy ISR is actually an assignment and sets the WDTIE bit. A self-fulfilling prophecy :)

      The IF must read

      if (TACTL & 0x0002)...

      _____________________________________
      Before posting bug reports or ask for help, do at least quick scan over this article. It applies to any kind of problem reporting. On any forum. And/or look here.
      If you cannot discuss your problem in the public, feel free to start a private conversation: click on my name and then 'start conversation'. But please do so only if you really cannot do it in a public thread, as I usually read all threads. And I prefer to answer where others can profit from it (or contribute to it) too.

      Report Abuse
      • Reply
      You have posted to a forum that requires a moderator to approve posts before they are publicly available.
    • TonyKao
      Posted by TonyKao
      on Apr 16 2012 13:46 PM
      Genius3770 points

      Asa Cannell

      So now with the code changed, it still experiences a Timer A ISR infinite loop, but its not indicating that TAIE is set anymore...WTF?? How could this be?

      Hi Asa, I don't see anywhere in your code a #pragma directive telling the linker where to find your ISR. You should do something like this:

      #pragma vector=SOME_INTERRUPT_VECTOR

      __interrupt void myISR(void) {

      \\ some code

      }

      Otherwise the MSP430 would keep on trying to fetch from the uninitialized interrupt vector, resulting in undefined behaviour.

      A different approach would be to use a pointer to assign the right function to the interrupt vector, or even better, to use a C++ class (gasp!) to model the entire interrupt vector space, but that's another story for another day...

      Tony

      Report Abuse
      • Reply
      You have posted to a forum that requires a moderator to approve posts before they are publicly available.
    • Jens-Michael Gross
      Posted by Jens-Michael Gross
      on Apr 17 2012 09:23 AM
      Guru141810 points

      TonyKao
      Hi Asa, I don't see anywhere in your code a #pragma directive telling the linker where to find your ISR. You should do something like this:
      #pragma vector=SOME_INTERRUPT_VECTOR

      This is specific to IAR/CCS. The compiler used by Asa uses the 'interrupt[vector]' notation instead. So the ISR is properly registered.

      _____________________________________
      Before posting bug reports or ask for help, do at least quick scan over this article. It applies to any kind of problem reporting. On any forum. And/or look here.
      If you cannot discuss your problem in the public, feel free to start a private conversation: click on my name and then 'start conversation'. But please do so only if you really cannot do it in a public thread, as I usually read all threads. And I prefer to answer where others can profit from it (or contribute to it) too.

      Report Abuse
      • Reply
      You have posted to a forum that requires a moderator to approve posts before they are publicly available.
    TI E2E™ Community
    • Support Forums
    • Blogs
    • Videos
    • Groups
    • Site Support & Feedback
    • Settings
    TI E2E™ Community Groups
    • TI University Program
    • Make the Switch
    • Microcontroller Projects
    • Motor Drive & Control
    Other Communities
    • Deyisupport
    • Designsomething.org
    • beagleboard.org
    • TI on Element 14
    • TI on TechXchangeSM
    Other Technical & Support Resources
    • WEBENCH® Design Center
    • Product Information Centers
    • Technical Documents
    • TI Design Network
    • TI Technical Articles
    • TI Training

    All content and materials on this site are provided "as is". TI and its respective suppliers and providers of content make no representations about the suitability of these materials for any purpose and disclaim all warranties and conditions with regard to these materials, including but not limited to all implied warranties and conditions of merchantability, fitness for a particular purpose, title and non-infringement of any third party intellectual property right. TI and its respective suppliers and providers of content make no representations about the suitability of these materials for any purpose and disclaim all warranties and conditions with respect to these materials. No license, either express or implied, by estoppel or otherwise, is granted by TI. Use of the information on this site may require a license from a third party, or a license from TI.

    Content on this site may contain or be subject to specific guidelines or limitations on use. All postings and use of the content on this site are subject to the Terms of Use of the site; third parties using this content agree to abide by any limitations or guidelines and to comply with the Terms of Use of this site. TI, its suppliers and providers of content reserve the right to make corrections, deletions, modifications, enhancements, improvements and other changes to the content and materials, its products, programs and services at any time or to move or discontinue any content, products, programs, or services without notice.

    Follow Us Texas Instruments on Facebook Texas Instruments on Twitter Texas Instruments on LinkedIn Texas Instruments on Google+
    TI Worldwide | Contact Us | my.TI Login | Site Map | Corporate Citizenship | mobile m.ti.com (Mobile Version)

    TI is a global semiconductor design and manufacturing company. Innovate with 100,000+ analog ICs and
    embedded processors, along with software, tools and the industry’s largest sales/support staff.

    © Copyright 1995-2013 Texas Instruments Incorporated. All rights reserved.
    Trademarks | Privacy Policy | Terms of Use