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.

How to make LCD timeout on MSP430?

Other Parts Discussed in Thread: MSP430FG4618

Dear TI Community:

I am new to the MSP430 and am currently using the MSP430FG4618/F2013 experimenter’s board for a project. I am using the Capacitive Toucphad demo as a baseline for a few modifications (contained in the zip folder slac129a).

I am trying to modify the FG4618 host_comms.c code so that the LCD will timeout after 15 sec and go back to sleep.

I have looked at a few examples of how to setup TimerA. Here is a snippet of FG4618 host_comms.c where I made modifications to try to accomplish this:

void main(void)
{
    WDTCTL = WDTPW | WDTHOLD;               /* Stop watchdog */

    configure_uart_usci0();
    configure_i2c_usci0();
    init_lcd();
   
    _EINT();
   
   
    for (;;)
    {
#if 1
        /* Normal operation */
        LPM0;
       
    //Start timer: ACLK, divide by 8, continuous mode, clear
    TACTL = TASSEL_1 | ID_3 | MC_2 | TACLR;    //Set timer for 16 sec period (close enough to 15 sec)
 
        LCDdec(xxx, 3);
#else
        /* Checking out the host interface */
        UCA0TXBUF = xxx++;
        {
          long int i;
          for (i = 0;  i < 10000;  i++)
              _NOP();
        }
#endif
    }
}

#pragma vector = TIMERA0_VECTOR
__interrupt void timera0_interrupt(void)
{
  LPM0_EXIT;
}

·        

·       However I am having trouble testing and debugging what I have written. I put a breakpoint at start of the interrupt, but never get there. I must be doing something fundamentally wrong.

CoCould you please point me to some good examples that parallel what I’m trying to accomplish? How should I approach testing/debugging an interrupt? Any suggestions or tips are much appreciated. Thank you.

 

 

t



  • Anne Thomas said:
           LPM0;      
        //Start timer: ACLK, divide by 8, continuous mode, clear
    TACTL = TASSEL_1 | ID_3 | MC_2 | TACLR;    //Set timer for 16 sec period (close enough to 15 sec)

    Looks like you enter LMP0 before you configure the timer for the wakeup interrupt. It's like going to sleep before enabling the alarm and then wondering why you overslept - with the difference that the MSP will not wake up on its own ever again.

  • Thank you for your reply. Actually, I was trying to post a simplified version of my code, but in the process I made an error and placed LPM0 before the timer configuration. Sorry. Here is my actual code. I have the timer configured before entering LPM0. I am still having trouble reaching the interrupt. Thank you for your help.

     

    void main(void)
    {
      uint16_t* flashPtrForRead;
      flashPtrForRead = (uint16_t*)0x01800;
     
      int timer_count = 0;
      int sum = 0;
     
      WDTCTL = WDTPW | WDTHOLD;               /* Stop watchdog */

        configure_uart_usci0();
        configure_i2c_usci0();
        init_lcd();
       
        _EINT();
       
        //Start timer: ACLK, divide by 8, continuous mode, clear
        TACTL = TASSEL_1 | ID_3 | MC_2 | TACLR;  
       
        for (;;)
        {
    #if 1
            /* Normal operation */
            valueFromFlash = ReadFromInfoMem(flashPtrForRead);  //read from flash
            LCDdec(valueFromFlash, 3);  //display value retrieved from flash
            writeToInfoMem(valueToLCD); //write value to flash
            _EINT();    //enable interrupts
            LPM0;      
            LCDdec(valueToLCD, 3);  //display most recent value
    #else
            /* Checking out the host interface */
            UCA0TXBUF = valueToLCD++;
            {
              long int i;
              for (i = 0;  i < 10000;  i++)
                  _NOP();
            }
    #endif
        }
    }

    #pragma vector = TIMERA0_VECTOR
    __interrupt void timera0_interrupt(void)
    {
      LPM0_EXIT;
    }

  • Anne Thomas said:
    I am still having trouble reaching the interrupt

    No wonder. In this code, you configure the timer, yet you never enable any interrupt. Also, TIMERA0_VECTOR is reserved for the CCR0 capture/compare unit. Only if you configure this unit and set the CCIE bit to allow interrupts from this unit, you'll get an interrupt to this vector.

    All other TimerA CCRx interrupts as well as the timer overflow interrupt are directed to the TIMERA1_VECTOR, and enabled by setting the CCIE bit in the CCRx units (except CCR0) or the TAIE bit in TACTL

    You're using cont mdoe (MC_2), which runs the timer from 0 to 65535 and then overflowing to 0 again, triggering the TAIE interrupt (setting the TAIFG bit). If TAIE is set, TIMERA1_VECTOR (check the compiler manual for the correct name, as this is different for different MSPs, especially those with more than one TimerA) is called after each 65536 timer ticks.

    Note that (other than for the CCR0 interrupt), you'll have to reset the interrupt source inside the ISR. THis can be done by manually clearing the TAIFG bit, or reading the TAIV vector register (which tells you the highest priority interrupt cause amongst the different CCRx units and at the same time clears this units IFG bit). If you fail to clear the IFG bit that caused the interrupt, you'll enter the very same ISR instantly over and over again right after exiting it (effectively bringing main and all lower-priority interrupts to a halt)

  • Thank you for your reply. I made the corrections you mentioned - enabling interrrupts and setting the CCIE bit - shortly after my last posting.I can tell as I step through the code that I am now able to enter and exit the interrupt. However, I have one (or more) other problem with this code. I appreciate your patience.

    I am using F2013 touchpad.c from the "Capacitive Touchpad" demo project in conjunction with modifications to FG4618 host_comms.c. I am trying to get the LCD to timeout after approx. 15 sec. and enter LPM.

    I have configured Timer_A0 to get this approx. timing.I have _ENT() included after the calls to read/write because interrupts are disabled within the the read/write functions.

    Here is what happens as I step through the 4618 code as I use the debugger. I am able to step through each instruction with anticipated results until I get to "LPM0". As I step through this instruction, the debugger "hangs" for about 15 sec. then moves to the next line of code - clrLCD(). The LCD is cleared when I step through this instruction and the cursor moves back to the start of for(;;).

    I did a full test by downloading and running the original F2013 touchpad code to the F2013 experimenter's board. AsI traced the "4" on touchpad, I was able to see the numbers change, but at no point (say after approx. 15 sec) does the LCD clear.

    As I said above, I want the LCD to continue processing values sent via I2C from F2013 until 15 sec. have passed, at which point I want the LCD to clear and enter LPM0. The LCD should remain in this state until the code is run again. So I expect to see the interrupt just once and not start the timer again.

    Of course, I am doing something fundamentally wrong. But what? Can you please provide some guidance.

    Thank you.

     

    void main(void)
    {

        uint16_t* flashPtrForRead;
        flashPtrForRead = (uint16_t*)0x01800;
       
        WDTCTL = WDTPW | WDTHOLD;           /* Stop watchdog */
       
        configure_uart_usci0();
        configure_i2c_usci0();
        FLL_CTL0 = XCAP14PF;        // Configure load caps (14pF)
        PortsInit();            // Initialize ports
        init_lcd();
       
        _EINT();
        our
        //Start timer: ACLK, divide by 8, continuous mode, clear
        TACTL = TASSEL_1 | ID_3 | MC_2 | TACLR ;
        TACCTL0 = CCIE;    // Enable interrupts on Compare 0
       
        for (;;)
        {
    #if 1
            /* Normal operation */
              valueFromFlash = ReadFromInfoMem(flashPtrForRead);  //read from flash
              LCDdec(valueFromFlash, 3);  //display value retrieved from flash
              _EINT();    //enable interrupts
              writeToInfoMem(valueToLCD); //write value to flash
              LCDdec(valueToLCD, 3);    
              _EINT();    //enable interrupts
              LPM0;
     //         clrLCD();
           //   LPM0;
    #else
            /* Checking out the host interface */
            UCA0TXBUF = valueToLCD++;
            {
              long int i;
              for (i = 0;  i < 10000;  i++)
                  _NOP();
            }
    #endif
        }
    }

    #pragma vector = USCIAB0TX_VECTOR
    __interrupt void USCIAB0TX_ISR(void)
    {
        valueToLCD =
        UCA0TXBUF = UCB0RXBUF;
    }

    #pragma vector = USCIAB0RX_VECTOR
    __interrupt void USCIAB0RX_ISR(void)
    {
        UCB0STAT &= ~(UCSTPIFG | UCSTTIFG);
        LPM0_EXIT;
    }

    #pragma vector = TIMERA0_VECTOR
    __interrupt void timera0_interrupt(void)
    {
       LPM0_EXIT; 
       clrLCD();
    }

  • I was working more with the code that I posted above yesterday.

    I notice that if I comment out all references to LPM0, I never enter the interrupt as I step through or run the code. Why is this the case? What is it that I am missing in my understanding of LMP and interrupts?

    Here is the sample code again, minus LPM0. Thank you for your help.

    void main(void)
    {

        uint16_t* flashPtrForRead;
        flashPtrForRead = (uint16_t*)0x01800;
       
        WDTCTL = WDTPW | WDTHOLD;           /* Stop watchdog */
       
        configure_uart_usci0();
        configure_i2c_usci0();
        FLL_CTL0 = XCAP14PF;        // Configure load caps (14pF)
        PortsInit();            // Initialize ports
        init_lcd();
       
        _EINT();
        //LPM0;
       
        //Start timer: ACLK, divide by 8, continuous mode, clear
        TACTL = TASSEL_1 | ID_3 | MC_2 | TACLR ;
        TACCTL0 = CCIE;    // Enable interrupts on Compare 0
       
        for (;;)
        {
    #if 1
            /* Normal operation */
              //LPM0;
              valueFromFlash = ReadFromInfoMem(flashPtrForRead);  //read from flash
              LCDdec(valueFromFlash, 3);  //display value retrieved from flash
              _EINT();    //enable interrupts
              writeToInfoMem(valueToLCD); //write value to flash
              LCDdec(valueToLCD, 3);    
              _EINT();    //enable interrupts
              //LPM0;
     //         clrLCD();
              //LPM0;
    #else
            /* Checking out the host interface */
            UCA0TXBUF = valueToLCD++;
            {
              long int i;
              for (i = 0;  i < 10000;  i++)
                  _NOP();
            }
    #endif
        }
    }

    #pragma vector = USCIAB0TX_VECTOR
    __interrupt void USCIAB0TX_ISR(void)
    {
        valueToLCD =
        UCA0TXBUF = UCB0RXBUF;
    }

    #pragma vector = USCIAB0RX_VECTOR
    __interrupt void USCIAB0RX_ISR(void)
    {
        UCB0STAT &= ~(UCSTPIFG | UCSTTIFG);
        LPM0_EXIT;
    }

    #pragma vector = TIMERA0_VECTOR
    __interrupt void timera0_interrupt(void)
    {
       //LPM0_EXIT; 
       clrLCD();
    }

  • Anne Thomas said:
    I never enter the interrupt as I step through or run the code

    Did you put a breakpoint into the timera0_interrupt ISR?

    If you do not enter LPM, you lose synchronisatio between the data receive and the display update.
    That means, the data is constantly updated, whether there was new data received or not. This immediately nullifies the clrLCD() on the timer timeout (maybe you'll see a flicker when the timer deactivates the LCD, but immediately after, the main loop activates it again, as the loop doesn't wait for new incoming data if LPM is not entered)

     

  • Thank you for your reply. In order to simplify the debugging, I removed all communication with the F2013 and am just incrementing the value to display to the LCD withing the for(;;) loop. And for testing purposes, I also removed all reference to LPM0. Now I never reach the breakpoint I placed inside the timera0_interrupt ISR, and the LCD display 0-999 over and over.

    Are you saying that LPM must be present for the data and the LCD to be synchronized? If so, where would I place LPM0 in the simplified code below? (I mentioned the "hanging" issue in my previous post.) Thank you for your help.

     

    void main(void)
    {
          int valueToLCD = 0;
    //    uint16_t* flashPtrForRead;
    //    flashPtrForRead = (uint16_t*)0x01800;

       
        WDTCTL = WDTPW | WDTHOLD;           /* Stop watchdog */
       
     //   configure_uart_usci0();
     //   configure_i2c_usci0();
        FLL_CTL0 = XCAP14PF;        // Configure load caps (14pF)
        PortsInit();            // Initialize ports
        init_lcd();
       
    //    valueFromFlash = ReadFromInfoMem(flashPtrForRead);  //read from flash
    //    LCDdec(valueFromFlash, 3);  //display value retrieved from flash       

        //LPM0;
       
        //Start timer: ACLK, divide by 8, continuous mode, clear
        TACTL = TASSEL_1 | ID_3 | MC_2 | TACLR ;
        TACCTL0 = CCIE;    // Enable interrupts on Compare 0
       
        _EINT();
        LPM0;
       
        for (;;)
        {
    #if 1
            /* Normal operation */
              //LPM0;
              //valueFromFlash = ReadFromInfoMem(flashPtrForRead);  //read from flash
              //LCDdec(valueFromFlash, 3);  //display value retrieved from flash
              //_EINT();    //enable interrupts
     //        writeToInfoMem(valueToLCD); //write value to flash
              LCDdec(valueToLCD, 3);
              ++valueToLCD;
              //_EINT();    //enable interrupts
              //LPM0;
              //clrLCD();
              //LPM0;
    #else
            /* Checking out the host interface */
            UCA0TXBUF = valueToLCD++;
            {
              long int i;
              for (i = 0;  i < 10000;  i++)
                  _NOP();
            }
    #endif
        }
    }

     

    #pragma vector = TIMERA1_VECTOR
    __interrupt void timera1_interrupt(void)
    {
       //LPM0_EXIT; 
       clrLCD();
    }

     

     

     

  • I think I finally got the code (see below) to do what I want - i.e., for the LCD to continuously display values communicated from the F2013 until 15 sec. have passed, at which point the LCD "times out" for several seconds. It took a while to understand how LPM and the ISR were behaving. If someone has a better approach for how to achieve this functionality, please let me know. Thank you.

     

    void main(void)
    {

        uint16_t* flashPtrForRead;
        flashPtrForRead = (uint16_t*)0x01800;

       
        WDTCTL = WDTPW | WDTHOLD;           /* Stop watchdog */
       
        configure_uart_usci0();
        configure_i2c_usci0();
       
        PortsInit();            // Initialize ports
        init_lcd();
       
        valueFromFlash = ReadFromInfoMem(flashPtrForRead);  //read from flash
        LCDdec(valueFromFlash, 3);  //display value retrieved from flash       
       
        //Start timer: ACLK, divide by 8, continuous mode, clear
        TACCR0 = 0xF000;    // upper limit of count for TAR ( ~15 sec)
        TACCTL0 = CCIE;    // Enable interrupts on Compare 0
        TACTL = TASSEL_1 | ID_3 | MC_2 | TACLR ;

        _EINT();
       
        for (;;)
        {
    #if 1
            /* Normal operation */
            _EINT();    //enable interrupts
            writeToInfoMem(valueToLCD); //write value to flash
            LCDdec(valueToLCD, 3);
            _EINT();    //enable interrupts  
         
            if (TAR == TACCR0)
            { 
              LPM0;
            }
     
    #else
            /* Checking out the host interface */
            UCA0TXBUF = valueToLCD++;
            {
              long int i;
              for (i = 0;  i < 100000;  i++)
                  _NOP();
            }
    #endif
        }
    }

    #pragma vector = USCIAB0TX_VECTOR
    __interrupt void USCIAB0TX_ISR(void)
    {
        valueToLCD =
        UCA0TXBUF = UCB0RXBUF;
    }

    #pragma vector = USCIAB0RX_VECTOR
    __interrupt void USCIAB0RX_ISR(void)
    {
        UCB0STAT &= ~(UCSTPIFG | UCSTTIFG);
        LPM0_EXIT;
    }

    #pragma vector = TIMERA0_VECTOR
    __interrupt void timera0_interrupt(void)
    {
      int i = 0;
      for (i = 0; i < 10000; ++i)
      {
           clrLCD();
      }
    }

  • In you r USCIAB0TX_ISR you assign UCB0RXBUF to UCA0TXBUF. This inplies that there actually Is a byte to move right now. And I don't see any synchronisation for the rest of the program logic too. Main doesn't know that actually a new byte arrived - it just tries to set the last received value over and over again.

    So if it works, it is fragile at best.

    Also, you make 10.000 calls to clr_LCD inside your timer ISR. During this time, no other interrupt is allowed. Everything stops. I don't think this really is what you wanted. What happens if the 10.000 calls are over? Then main will write the last received value again to the LCD, 'unblanking' it.
    In the meantime, the current consumption will likely be much higher than what you would expect ith the LCD just on all the time.

**Attention** This is a public forum