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.

Problem with Breakpoint

Other Parts Discussed in Thread: MSP430G2553

I have a ISR that has a switch in it. I'm using it to different pieces of code run each time it enters the routine. Below I have a piece of the code.

#pragma vector=TIMER0_A0_VECTOR
__interrupt void Timer_A0 (void)
{
switch (estado){

case 0:
veces3 = 3;
veces412 = 2;
estado = 1;
TACCR0 += 160;
break;
case 1:
estado = 2;
P2OUT ^= BIT0;
TACCR0 += 320;
break;
case 2: {
estado = 3;
P2OUT ^= BIT0;
TACCR0 += 160;
break;
}
case 3: {
if(veces3 == 1000){
P2OUT ^= BIT2 + BIT4;
}
else if(veces3 == 0){
P2OUT ^= BIT3;
estado = 4;
break;
}
else{
P2OUT ^= BIT2 + BIT3 + BIT4;
}
veces3--;
TACCR0 += 80;
break;
}


...

The code has 14 "estados" but I did not pasted them all here. I'm using TIMER A to enter the ISR every time. 

Now, the code works perfectly when I put a lot of breakpoints in it... but when I disable them the code stops working. The variable inside the switch goes back to zero before going through every state. 

Any help, ideas why this is not working? Thanks in advance. 

  • Hi Diego,

    Make the variables inside the Switch as Global Variables and Check if it works........

    Regards,

    Saravanan

  • I think you should declare the variable as "volatile".

  • First of all thanks for your answers. 

    The variables were declared previously (not inside the switch), and I have declared them as volatile now and there is no change. I paste the whole code now if it helps: 

    #include <msp430g2553.h>

    #ifndef TIMER0_A1_VECTOR
    #define TIMER0_A1_VECTOR TIMERA1_VECTOR
    #define TIMER0_A0_VECTOR TIMERA0_VECTOR
    #endif

    #define TXD BIT1 // TXD on P1.1
    #define RXD BIT2 // RXD on P1.2
    //#define Bitime 13*4 // 0x0D
    #define LED0 BIT0 // LED0 on P1.0
    #define LED1 BIT6 // LED1 on P1.6

    volatile unsigned int estado;
    volatile unsigned int veces3;
    volatile unsigned int veces413;
    volatile unsigned int veces913;

    volatile unsigned int valorPixel;

    unsigned int cuenta;
    unsigned int actual;

    //unsigned int esp;
    //unsigned int value=0;
    //unsigned int vez1=0;

    void FaultRoutine(void);
    void ConfigWDT(void);
    void ConfigClocks(void);
    void ConfigPins(void);
    void ConfigADC10(void);
    void ConfigTimerA2(void);
    void Transmit(void);

    void ConfigADC10(void){
    ADC10CTL1 = INCH_5 + ADC10SSEL_3; // Channel 5, Elijo SMCLK
    ADC10CTL0 = SREF_1 + REFON + ADC10SHT_0 + ADC10ON + ADC10IE; //2.5V & Vss as reference
    ADC10AE0 |= BIT5; //P1.5 ADC option
    }

    void main(void) {
    ConfigWDT();
    ConfigClocks();
    ConfigPins();
    ConfigADC10();
    ConfigTimerA2();

    //__enable_interrupt();

    _BIS_SR(LPM0_bits + GIE); // Enter LPM0 w/ interrupt

    while(1){
    actual = TAR;
    }
    }

    void ConfigWDT(void){
    WDTCTL = WDTPW + WDTHOLD; // Stop WDT
    }

    void ConfigClocks(void){

    if (CALBC1_1MHZ ==0xFF || CALDCO_1MHZ == 0xFF) // If calibration data is erased
    FaultRoutine(); // run FaultRoutine()

    BCSCTL1 = CALBC1_1MHZ; // Set range
    DCOCTL = CALDCO_1MHZ; // Set DCO step + modulation
    BCSCTL3 |= LFXT1S_2; // LFXT1 = VLO
    IFG1 &= ~OFIFG; // Clear OSCFault flag
    BCSCTL2 = 0; // SMCLK = MCLK = DCO
    }

    void FaultRoutine(void){
    P1OUT = BIT0;
    while(1);
    }

    void ConfigPins(void){
    P1SEL |= TXD + RXD; // P1.1 & 2 TA0, rest GPIO
    P1DIR = ~(BIT5 + RXD); // P1.5 input, other outputs
    P1OUT = 0; // clear output pins
    //P2SEL = ~(BIT6 + BIT7); // P2.6 and 7 GPIO
    P2DIR |= 0x3F; // P2.0-5 outputs
    P2OUT = 0x02; // P2.1 = 1, resto = 0
    }

    void ConfigTimerA2(void){
    TACCTL0 = OUTMOD_4 + CCIE; // CCR0 toggle, interrupt enabled
    //TACCTL1 = OUTMOD_4 + CCIE; // CCR1 toggle, interrupt enabled
    //TACCTL2 = OUTMOD_4 + CCIE; // CCR2 toggle, interrupt enabled
    TACTL = TASSEL_2 + MC_2 + TAIE; // SMCLK, Contmode, int enabled

    //CCTL0 = OUT; // TXD Idle as Mark
    //TACTL = TASSEL_2 + MC_2 + ID_3; // SMCLK/8, continuous mode
    }

    /*
    // Function Transmits Character from TXByte
    void Transmit()
    {
    BitCnt = 0xA; // Load Bit counter, 8data + ST/SP
    while (CCR0 != TAR) // Prevent async capture
    CCR0 = TAR; // Current state of TA counter
    CCR0 += Bitime; // Some time till first bit
    TXByte |= 0x100; // Add mark stop bit to TXByte
    TXByte = TXByte << 1; // Add space start bit
    CCTL0 = CCIS0 + OUTMOD0 + CCIE; // TXD = mark = idle
    while ( CCTL0 & CCIE ); // Wait for TX completion
    }
    */

    // Timer A0 interrupt service routine
    #pragma vector=TIMER0_A0_VECTOR
    __interrupt void Timer_A0 (void)
    {
    switch (estado){

    case 0:
    veces3 = 3;
    veces413 = 2;
    estado = 1;
    TACCR0 += 160;
    break;
    case 1:
    estado = 2;
    P2OUT ^= BIT0;
    TACCR0 += 320;
    break;
    case 2: {
    estado = 3;
    P2OUT ^= BIT0;
    TACCR0 += 160;
    break;
    }
    case 3: {
    if(veces3 == 1001){
    P2OUT ^= BIT2 + BIT4;
    }
    else if(veces3 == 1){
    P2OUT ^= BIT3;
    estado = 4;
    }
    else{
    P2OUT ^= BIT2 + BIT3 + BIT4;
    }
    veces3--;
    TACCR0 += 80;
    break;
    }
    case 4: {
    if(veces413 == 0){
    estado = 14;
    }
    else{
    estado = 5;
    veces413--;
    veces913 = 4;
    }

    TACCR0 += 160;
    break;
    }
    case 5: {
    P2OUT ^= BIT3;
    estado = 6;
    TACCR0 += 160;
    break;
    }
    case 6: {
    P2OUT ^= BIT4;
    estado = 7;
    TACCR0 += 160;
    break;
    }
    case 7: {
    P2OUT ^= BIT3;
    estado = 8;
    TACCR0 += 160;
    break;
    }
    case 8: {
    P2OUT ^= BIT4;
    estado = 9;
    TACCR0 += 160;
    break;
    }
    case 9: {
    P2OUT ^= BIT5;
    estado = 10;
    TACCR0 += 10;
    veces913--;
    break;
    }
    case 10: {
    P2OUT ^= BIT1 + BIT4;
    estado = 11;
    TACCR0 += 10;
    break;
    }
    case 11: {
    P2OUT ^= BIT5;
    estado = 12;
    TACCR0 += 70;
    break;
    }
    case 12: {
    P2OUT ^= BIT1 + BIT4;
    estado = 13;
    TACCR0 += 50;
    break;
    }
    case 13: { //ADC y transmission
    ADC10CTL0 |= ENC + ADC10SC; // Sampling and conversion start
    __bis_SR_register(CPUOFF + GIE); // LPM0 with interrupts enabled
    valorPixel = ADC10MEM;

    if(veces913 == 0){
    estado = 4;
    }
    else{
    estado = 9;
    }
    TACCR0 += 20;
    break;
    }
    case 14: {
    estado = 0;
    TACCR0 += 160;
    break;
    }
    default: {
    estado = 0;
    TACCR0 += 160;
    break;
    }

    }

    /*
    CCR0 += Bitime; // Add Offset to CCR0
    if (CCTL0 & CCIS0) // TX on CCI0B?
    {
    if ( BitCnt == 0)
    {
    CCTL0 &= ~ CCIE ; // All bits TXed, disable interrupt
    }
    else
    {
    CCTL0 |= OUTMOD2; // TX Space
    if (TXByte & 0x01)
    CCTL0 &= ~ OUTMOD2; // TX Mark
    TXByte = TXByte >> 1;
    BitCnt --;
    }
    }
    */
    }

    // ADC10 interrupt service routine
    #pragma vector=ADC10_VECTOR
    __interrupt void ADC10_ISR (void)
    {
    __bic_SR_register_on_exit(CPUOFF); // Return to active mode
    }

    The problem is that sometimes the program gets into the TIMER_A ISR, just once, then it gets into the "case 0" piece of code and then it gets stuck in the loop of the main. Other times, it works perfectly fine and it gets through all the code.  However, when I take the breakpoints out, it never works correctly. 

    I thought maybe I'm leaving too little clock cycles between interrupts, is this possible?  Or maybe I have another mistake, I don't know. 

    Any ideas/suggestions?  Thank you all in advance. 

    PS. Also, CCS won't let me put breakpoints in some lines... why does this happen? Is there a problem with the code when this happens? 

  • I have been thinking and maybe it could be the "timer mode". I have set it up to Continuous mode, but I'm not sure about how this works. I have a question then: 

    Let's say TAR = 65000, and the code has to execute the line TACCR0 += 1000. 

    The next time the ISR will execute will be at 66000 - 65536 = 464 ? Or it will reset and start everything from zero? Because I think that the problem is in this line: when the timer gets to its end, everything gets reset (even the variables) and that's why it would start from zero again. 

    Thanks in advance  for your ideas and suggestions. 

    EDIT: More info: The 2nd 'if' (case 13) won't work correctly even in those times when the program manages to get there. It never gets in the 'if', even when the condition veces913 == 0 is true. This is exactly the line where I can't put the breakpoint.  I've tested this in another little program I'm making and it has the same problem... anyone has had the same problem? Thanks again and sorry if I'm asking to many questions.  

    EDIT2: Solved the issue with the if's... i think it was the 'else' what was causing problems. Instead, I programmed it with two separate if's and it worked. Very weird but true. I still have some problems though... the program is not working continuously, maybe it's because of the timer thing I mentioned before. The question persists: when the timer reaches its end, does everything get reseted?

  • Hi Diego,

    In continuous mode the Timer value resets  to zero when it hits 65535.In your case if TAR= 65000 and if the code has to execute the line TACCR0 += 1000 then it will will resets the Timer value to Zero.

    Regards,

    Saravanan 

  • Hi Saravanan,

    Correction. Timer Value is not reset to 0. The new value is 464. For all sums greater that 65535, carry is ignored.

    Thanks,

    Vivek

  • Diego Kaulen said:
    The next time the ISR will execute will be at 66000 - 65536 = 464 ?

    yes. Since the registers are unsigned ints for the compiler, 65000+1000 will result in 464 being written. And continuous mode is the right one to use.
    However, if after an interrupt, the ISR requires mroe than 1000 timer ticks to reprogram CCR0, this will delay the next interrupt by additional 65536 ticks. In the above example, if you do the add when the timer has already counted to 464, no interrupt will be trigered until the timer reaches 464 the next time.

    But you do other things: in state 13, you go into LPM inside teh ISR. That's a death sin. If (what's likely) the ADC ISR isn't triggered before another Tiemr interrupt happens, the timer ISR is entered a second time, on top of itself. And agian starts an ADC conversion and enter LPM, but the ADC interrupt will wake it up only once, so the device falls into eternal sleep. The ADC will continue and finish independently of the debugger. So if you have a beak during this loop of death, the ADC finishes before things get loose.

    Never go into LPM inside an ISR.

    You may set a helper indicator that is set by the ADC ISR and on the next tiemr interrupt you check it and eitehr advance the state or (if it isn't set yet)  stay in this 'loop state'. But don't enter LPM inside an ISR.
    The only application where I ever found it necessary to enter LPM inside an ISR was the thread scheduler ISR for preemptive multitasking, when all threads are blocked/sleeping. And even there I could have introduced an idle thread and enter LPM outside the ISR - but that would have been highly ineffective.

  • Thank you Jens-Michael. 

    About the mistake in state 13, would it be OK if I just eliminated the line "__bis_SR_register(CPUOFF + GIE);" ? Would the ADC10 work correctly without that line? 

    And also, I get the variables reseted before going through all the states... when debugging I get to state 2 and then every variable goes back to zero (even the "estado" variable), so it goes back to case 0.  Any ideas as to why is this happening?? 

  • Yes, teh ADC will work properly. However, the code will continue to execute after the ADC has been started, and won't wait for the result. You need to keep care for this (e.g. with an additional waiting state). The ADC ISR will be called as soon as the timer ISR exits. And will end LPM of main then.
    Of course (but I really want to discourage your to do it) you can simply wait for the ADC IFg bit to be set, then read the result, clear the bit and continue. But busy-waiting inside an ISR as almost as bad as going into LPM. But only almost :)

    About the rest, I guess I know what happens: a reset. A real one. You set TAIE in TACTL. That means when the timer rolls over from 65535 to 0, a TIMER0_A1_VECTOR interrupt is triggered. And you don't have an ISR for it, so the CPU jumps into the void, triggeringa reset. Which in turn resets your variables and restarts the program.

  • I erased the TAIE and it is working nice now. Thank you a lot guys. 

    I'll let you know if the ADC works correctly too. 

**Attention** This is a public forum