MSP430 Timer A not responding right

msp430

I need some help with an MSP430F2272. I'm working on an assignment for class where I'm supposed to make a function generator. I put the code I've written so far below. Most individual parts of the code work fine, except one thing: The TimerA which is supposed to be controlling the frequency of the output isn't triggering properly. After I start the program, the debugger gets as far as P1DIR = 0x00 in main() before going into the TimerA0 ISR. The problem is immediately after the ISR is done, it jumps back to P1DIR = 0x00, then goes into the ISR again. The Timer counter is only at 0x0005 and the compare register holds 0x0064, so it shouldn't be triggering, but it keeps doing so. If I could get that to stop, I'm pretty sure the rest of the program works exactly how I want it to. Can anyone help?

#include <msp430.h>
#include "msp430x22x2.h"

/* P4 - Digital Input
 * P2 - DAC Output
 * P3 - ADC Input
 *
 */

char sine[50] = {0x80,0x90,0xA0,0xB0,0xBE,0xCC,0xD9,0xE4,0xED,0xF5,0xFA,0xFE,0xFF,0xFF,0xFC,0xF8,0xF1,0xE8,0xDE,0xD2,0xC5,0xB7,0xA8,0x98,0x88,0x77,0x67,0x57,0x48,0x3A,0x2D,0x21,0x17,0x0E,0x07,0x03,0x00,0x00,0x01,0x05,0x0A,0x12,0x1B,0x26,0x33,0x41,0x4F,0x5F,0x6F,0x7F};
char squr[50] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
char trgl[50] = {0x00,0x0A,0x15,0x20,0x2A,0x35,0x40,0x4A,0x55,0x60,0x6A,0x75,0x80,0x8A,0x95,0xA0,0xAA,0xB5,0xC0,0xCA,0xD5,0xE0,0xEA,0xF5,0xFF,0xFF,0xF5,0xEA,0xE0,0xD5,0xCA,0xC0,0xB5,0xAA,0xA0,0x95,0x8A,0x80,0x75,0x6A,0x60,0x55,0x4A,0x40,0x35,0x2A,0x20,0x15,0x0A,0x00};
char swth[50] = {0x00,0x05,0x0A,0x0F,0x14,0x1A,0x1F,0x24,0x29,0x2F,0x34,0x39,0x3E,0x43,0x49,0x4E,0x53,0x58,0x5E,0x63,0x68,0x6D,0x72,0x78,0x7D,0x82,0x87,0x8D,0x92,0x97,0x9C,0xA1,0xA7,0xAC,0xB1,0xB6,0xBC,0xC1,0xC6,0xCB,0xD0,0xD6,0xDB,0xE0,0xE5,0xEB,0xF0,0xF5,0xFA,0xFF};
    int i = 0;
    int wave_sel = 0;
    char dout = 0x00;

void dac_write(char data){
    int output = 0x0000;
    char temp;
    signed char x;

    P2SEL &= 0xF8; //select digital I/0
    P2DIR |= 0x07; //set directon register P2.0 - P2.2
    P2OUT &= 0xF8; // clear data, clock, and enable
    P2OUT |= 0x04; // set enable high

    temp = data; // format data
    data = data >> 4;
    data &= 0x0F;
    data |= 0xF0;
    output = data;
    output <<= 8;
    data = temp;
    data <<= 4;
    data &= 0xF0;
    output |= data;

    P2OUT &= 0xFB; //set enable low
    for (x = 15; x > -1; x--){  //send out 16 bits of data
        P2OUT |= (output >> x) & 0x01;
        P2OUT |= 0x02;
        P2OUT &= 0xFD;
        P2OUT &= 0xFE;
    }
    P2OUT |= 0x04; // set enable high
}

int main(void) {
WDTCTL = WDTPW + WDTHOLD;   // Stop watchdog timer
TACCTL0 = CCIE;
TACTL = TASSEL_2 + MC_1 + ID_3; //CLK(1MHz) /8
TACCR0 = 100; //25-100 Hz 250-10Hz
TACCR1 = 0xFFFF;
TACCR2 = 0xFFFF;
_BIS_SR(LPM0_bits + GIE);

    P1DIR   = 0x00;
    P2DIR   = 0xFF; //DAC Ouptut
    P3DIR   = 0x00; //ADC Input
    P4DIR   = 0x00; //Digital Input
    P3SEL  |= BIT6 + BIT7;

    ADC10CTL0  = SREF_0 + ADC10SHT_3 + MSC + ADC10ON + ADC10IE;
    ADC10CTL1  = INCH_7 + ADC10DIV_3 + CONSEQ_1;
    ADC10AE0  |= 0xC0; //Turn on ADC of 3.6 and 3.7
    ADC10DTC1  = 2;

    double amp = 0;
    double freq = 0;
    unsigned int ADC[2];

    for(;;)
    {
        wave_sel =P4IN;

        ADC10CTL0 &= ~ENC;
        while (ADC10CTL1 & BUSY);
        ADC10SA = (unsigned int)ADC;
        ADC10CTL0 |= ENC + ADC10SC;

        freq = (double)ADC[0]/1023;
        amp  = (double)ADC[1]/1023;    

        TACCR0 = 25 + (freq*225);
        dout *= amp;
        dac_write(dout);
    }
}

#pragma vector=TIMER0_A1_VECTOR
__interrupt void Timer_A1(void)
{}

#pragma vector=TIMER0_A0_VECTOR
__interrupt void Timer_A0(void)
{
    if (wave_sel == 0)
    {
        dout = sine[i];
    }else if (wave_sel == 1)
    {
        dout = squr[i];
    }else if (wave_sel == 2)
    {
        dout = trgl[i];
    }else if (wave_sel == 3)
    {
        dout = swth[i];
    }
    if (i<49){
        i += 1;
    }else{
        i = 0;
    }
}

Best Answer

On the MSP430, timers are hardware modules and are running whenever the clock they are connected to is running. You are running on SMCLOCK (TACTL = TASSEL_2), which is probably the same as the CPU clock (MCLOCK). Depending of your debugger options, Mclock may or may not be running between breakpoints. If it is running, the program will enter the ISR after each breakpoints, because they pause the CPU for a longer time than the counter period. When the CPU resume operation, he will immediately serve all the interrupts that go raised during the pause.

Also, even if Mclock is not running all the time, I am not sure that the number of clock cycles will be the same with and without the debugger. On top of that, the timer will continue to run while you enter the ISR and before you reach the next breakpoint, so the current counter value (TAR) will not be accurate. If you can, try to debug the timer using another way, like UART.