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.

MSP430F2618: Problem with WDT/UART after enabling interrupt and implementing LPM0

Part Number: MSP430F2618


Hello All,

I am working on the BSL project which was working fine until I went ahead to implement LPM0 and enabled receiving UART Chars through ISR instead of reading the RX buffer when RXIFG is set.

My project uses UCA0 for UART and WDT Timer Interval for time outs. When it was working, there were no interrupt routines enabled and would look for IFG2 & UCA0RXIFG to receive from UCA0RXBUF directly. I implemented LPM0 and it changed the receive mechanism and now I receive in the __interrupt void usart0_rx(void) after enabling IE2 |= UCA0RXIE; It would help me wake-up from the LPM0 as it generates an interrupt. In my initialization sequence I disable watchdog timer interrupt using IE1  &= ~WDTIE; and then clear the watchdog interval timer flag. 

My UART receive seems to be working fine when I send .txt file and not use timeout while receiving characters. However, when I transfer my firmware through Xmodem the program breaks at the very first byte i think and goes to _c_int00_noargs_noexit(). 


__interrupt void usart0_rx(void) puts received characters in my rx_buf ring buffer and i use following functions to read characters from the ring buffer. One of GetCharTmo() uses time out.  

extern "C"
__interrupt void usart0_rx(void)
{
    char ch;
    ch = UCA0RXBUF;                     // get the character we have read

    if(!rx_buf.put(ch))
    {

    }
    else
    {

    }

    __bic_SR_register_on_exit(LPM0_bits);
}


int main(int argc, char* argv[])
{

....

// Serial port initialization

    UCA0CTL1 = UCSSEL1 + UCSWRST;                                           // **Initialize USCI state machine**
    IE2 &= ~UCA0RXIE;                                                       // Disable USCI_A0 RX interrupt
    UCA0BR0 = 0x15; //0xAD; //0x11;                                         //  16mhz/57600 =  //10mhz/9600 = 1041.667 = 0x0411 -> divisor for 9600 baud
    UCA0BR1 = 0x01; //0x00; //0x04;                                         //  277.78 = 0x115 //10mhz/57600 = 173.111 = 0x00AD -> divisor for 57600 baud
    UCA0MCTL = UCBRS2 + UCBRS0;                                             //Modulation UCBRSx = 5  rounding error
    UCA0CTL1 &= ~UCSWRST;                                                   //**Initialize USCI state machine**
    P3SEL |= BIT4 + BIT5;                                                   // P3.4,5 = USCI_A0 TXD/RXD
    P3SEL |= BIT0;
    P3DIR &= ~BIT0;

    // Watchdog timer initialization - we put the watchdog timer into interval mode
    // Change WDT+ to interval timer mode, ACLK, clock/8192 interval

    IE1  &= ~WDTIE;                                                         // disable the watchdog timer interupt - we don't use
    IFG1 &= ~WDTIFG;                                                        // clear the watchdog interval timer flag
    WDTCTL = WDTPW + WDTCNTCL + WDTTMSEL + WDTIS0;                          // Change WDT+ to interval timer mode

    // initialize variables
    //P3OUT |= 0x08;

    IE2 |= UCA0RXIE;                                                        // Enable USCI_A0 RX interrupt
    __bis_SR_register(GIE);                                                 //Enable the global interrupts, currently the rx interrupts from the Mac and hso

...

 while(1)
    {
        __bis_SR_register(LPM0_bits+GIE);
...
/* reading from ring buffer to char cmd[256] here */


        ProcessCommand(cmd);    // pass the command to the command processor
    }
}

void TimerSpin()
{
    static int TIMER_TICK_COUNT = 2;
    static int secCounter = TIMER_TICK_COUNT;

    if( (IFG1 & WDTIFG) && --secCounter )
    {
        secCounter = TIMER_TICK_COUNT;
        IFG1 &= ~WDTIFG;
        // count down any times that are active
        if( getCharTimer != 0 ) getCharTimer--;
    }
    return;
}

int16_t GetChar()
{
    char ch;

    while (!rx_buf.get(ch))
    {
        TimerSpin();
    }
    return ch;
}

int16_t GetCharTmo(uint16_t tmo)
{
    char ch;

    getCharTimer = tmo;

    while (!rx_buf.get(ch))
    {
        TimerSpin();

        if( getCharTimer == 0 )
            return -1;
    }
    return ch;
}





Note: When in LPM0 my program waits to receive a character. As soon as it receives a character it wakes up from the low power mode and disables LPM0 in receive Interrupt routine and then waits for firmware in normal mode. 

Pausing the debug mode gives me below stack. 

I do not know what is happening that causes my program to break. Can not print anything on the terminal when i start receiving through Xmodem. Breaks when I start sending the firmware image. I think has to do with interrupt. Any debugging help would be appreciated.  

  • Hello Rishit,

    Can you post your USCI initialization, LPM entry, and ISR? I'm slightly confused since your interrupt definition refers to USART, a peripheral which does not exist on the MSP430F2618. Referring to the wrong interrupt vector could trap the CPU.

    Regards,
    Ryan
  • Thanks for quick reply. I have updated the code in question above. Hope that helps. Its USCI, I am just naming the ISR as USART.

    ProcessCommand() waits for the correct command and uses Xmodem() to receive the firmware. Xmodem() uses the getCharTmo() amd nreaks when receives the first char.

    ProcessCommand() -> Xmodem() -> getCharTmo()

  • What interrupt vector address does usart0_rx refer to? I'll assume your baud rate settings are correct from your SMCLK setup but I would have gone with numbers from Section 15.3.13.

    Regards,
    Ryan
  • ISR23.

    Please see the attached file to Interrupt vector.

    I will update and try baudrate from the section you mentioned. However, the USCI setup, except USART_ISR and IE2 |= UCA0RXIE, was working before I implemented LPM0. I was able to transfer firmware file through UART (USCI) before. 

    xfervect.asm

  • By no means is the USCI setup incorrect, it just may be possible to improve. The interval timer interrupt vector is ISR26, in watchdog mode it is ISR31.  Can you use the debugger's memory window to make sure that 0FFEEh points to a valid address for the RX ISR?

    Regards,
    Ryan

  • Ryan,

    By mistake i clicked on Resolve my issue tab. Do i have to create another question?

    To answer your question, 0x0FFEE has the address 0x3128. 0x3128 address has a string something like this "$../xfervect.asm:34:44$, ISR23" . In my vector table file xfervect.asm, ISR23 is on line 34. So i think it points to the right address for RX ISR.

    By looking closely, I found that When I send the first character PC jumps to the Vector Table and look for address 0x314c. Which is right after the address of ISR31() ox3148. Xfervector section is located at 0x3100-0x3150. but continue debugging step by step, PC tries to jump at 0x314c and find no symbol there and breaks.
    Adding to that, When i send the character from the terminal and a put a break point inside RX Interrupt routine it never gets to the breakpoint . It breaks even before getting into RX Interrupt Vector. Which i assume is related to what i am talking about whan i say PC is jumping at the address 0x314c and not finding anything there and crashing inturn.

    Any ideas??? Where can i look hard???

    Thanks for helping out.

    Regards,
    Rishit

  • Rishit,

    Another post is not required, we will continue to service your questions through this thread. You seem to be on the right trail and there appears to be something incorrect about the xfervect.asm file that is not allowing the correct ISR to be entered after the RX IFG is set. I'm not familiar with this assembly solution and therefore do not have a direct answer at the moment.

    Regards,
    Ryan
  • Ryan,

    Thanks for the reply. 

    More Information, I tried to do the whole thing different way. Instead of keeping the UCA0RXIE set, I am clearing it once I wake up from the LPM0. Hoping that it would work as it did when I did not implement the LPM0 (there were no interrupt events when it was working). That way once I wake up from the LPM0 and clear the UCA0RXIE bit there wont be any interrupt event and I can read directly from the buffer once the UCA0RXIFG is set. Again, With this settings now, It reads the text file using GetChar() but when it starts to read the firmware file using GetCharTmo(uint16_t tmo) it shows the same behavior as it did when I kept the interrupts events for RX on. (maybe some mixeup with WDT and RX IRs)

    According to the user manual, when UCARX0IE is not set there shouldn't be any interrupt event when RX interrupt flag is set. However, it still has the interrupt event and jumps to vector table when the interrupt flag is set (I am sure I am not setting UCA0RXIE anywhere else). 

    I do not find anything that talks about 'once UCA0RXIE is set it can not be changed on the fly'. Please correct me if i am wrong. 

    I really need to get this thing going with LPM0. 

    Thanks for the reply.

    Regards,

    Rishit

    EDIT1: I think it works with interrupt events disabled on the fly. I am verifying it. Please wait for me to get back. 

  • I take all of I wrote in my last reply back. I am able to disable the interrupt event on the fly now. But the original problem remains. I am implementing a makeshift solution to lower the power for a brief moment for now. But i need to get LPM0 working when Interrupt events are on.

    Thanks Ryan for the patience.

    Regards,
    Rishit

**Attention** This is a public forum