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.

MSP430G2553 launchpad using TimerA0, Timer A1, and ADC

Hi,

I am building a mini robot using the msp430 launchpad. The robot has an IR proximity sensor in front and it stops and backs up when it senses an object too close. Every thing was working fine until I thought it would be cool to put the sensor on a mini servo so it can sweep the area and see more objects. So now I am using timerA0 for the drive motors, timerA1 for the servo and the ADC for the sensor. 

The problem I am having is it seems timerA1 may somehow be interfering with the ADC. Both the servo and the drive motors work together until the sensor sees an object, then it never escapes the 'backup'code, and I don't even think the ADC interrupt is getting fired anymore. I think this results in some misunderstandings I have about the timers, such as whats the difference between TIMER1_A1_VECTOR and TIMER1_A0_VECTOR? Likewise for timerA0. I haven't been able to find documentation about it. 

Any help or tips on how to improve my code are much appreciated. Thanks!

#include <msp430.h>

#define AIN1 BIT4  //Input 1 for motor A, PORT 1
#define AIN2 BIT5  //Input 2 for motor A, PORT 1
#define BIN1 BIT4  //Input 1 for motor B, PORT 2
#define BIN2 BIT5  //Input 2 for motor B, PORT 2
#define stdby BIT2  //Stand by to release motor, PORT 2
#define MCU_CLOCK			1100000UL
#define PWM_FREQUENCY		50		// In Hertz, ideally 50Hz.

int pos = 0;
int timer = 0;

void GPIO_Setup()
{
	/*** GPIO Set-Up ***/
	P1DIR |= AIN1 | AIN2;			//Inputs for direction/mode control
	P1DIR |= BIT2 | BIT7;
	P1SEL |= BIT2;				//PWM for motor A
	P2DIR |= stdby | BIN1 | BIN2;				//Release motor by pulling high
	P2DIR |= BIT1;               // P2.1 = output
	P2SEL |= BIT1;               // P2.1 = TA1 output
}

void Timer0A_Setup()
{
	/*** Timer0_A Set-Up ***/
	TA0CTL |= TASSEL_2 | MC_1 | ID_3;
	TA0CCR0 |= 1000;
	TA0CCTL1 |= OUTMOD_7;
	TA0CCR1 |= 500;

}

void Timer1A_Setup()
{
	unsigned int PWM_Period		= (MCU_CLOCK / PWM_FREQUENCY);	// PWM Period
	unsigned int PWM_Duty		= 1000;
	TA1CCTL1 = OUTMOD_7 + CCIE;    // TACCR1 reset/set
    TA1CTL	= TASSEL_2 + MC_1;     // SMCLK, upmode
	TA1CCR0	= PWM_Period-1;        // PWM Period
	TA1CCR1	= PWM_Duty;            // TACCR1 PWM Duty Cycle

}

void ADC_Setup()
{
	ADC10CTL0 = SREF_1 + REFON + REF2_5V + ADC10SHT_2 + ADC10ON + ADC10IE; // ADC10ON, interrupt enabled
	__enable_interrupt();                     // Enable interrupts.
	  TACCR0 = 300;                              // Delay to allow Ref to settle
	ADC10CTL1 = INCH_0;                       // input P1.0 A0
	ADC10AE0 |= BIT0;                         // PA.0 ADC option select
}

void forward()
{

	//This just makes the motor go straight from the start
	TA0CCR1 = 500;
	//Set motor conditions CCW Motor A
	P1OUT &= ~AIN1;		//AIN1 LOW
	P1OUT |= AIN2;		//AIN2 HIGH

	//Set motor conditions CCW Motor B
	P2OUT &= ~BIN1;		//AIN1 LOW
	P2OUT |= BIN2;		//AIN2 HIGH
	//TA1CTL	= TASSEL_2 + MC_1;   	//For some reason this makes the ADC freak out. It stops sampling it appears
}

void backUp()
{
	//TA1CTL	= TASSEL_2 + MC_0;     // SMCLK, stop the timer
	//TA1CCR1 = 500;
	TA0CCR1 = 500;
	//Set motor conditions CW Motor A
	P2OUT = 0;
	P2OUT |= stdby;		//stdby low (OFF)
	P1OUT = 0;
	P1OUT &= ~AIN2;		//AIN1 LOW
	P1OUT |= AIN1;		//AIN2 HIGH
	P2OUT |= stdby;		//stdby low (ON)

	while(ADC10MEM > 415)
	{
		P1OUT |= BIT7;
		ADC10CTL0 |= ENC + ADC10SC;             // Sampling and conversion start
	    __bis_SR_register(CPUOFF + GIE);        // LPM0, ADC10_ISR will force exit

	    if(ADC10MEM < 200)   //I had ADC10CTL0 here for some reason (can't remember my reasoning)
	    	break;
	}
}

void shortBrake()
{

	TA0CCR1 = 0;			// The 'ON' cycle of the PWM waveform counts to 0, so essentially it never turns on
	__delay_cycles(1000);
}
int main(void)
{
  WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT

  GPIO_Setup();
  Timer0A_Setup();
  //Timer1A_Setup();

  forward();

   /****This turns motor ON/OFF ****/
   P2OUT |= stdby;		//stdby high (ON)
   //P2OUT &= ~stdby;		//stdby low (OFF)

   ADC_Setup();

   while(1)
   {
	   ADC10CTL0 |= ENC + ADC10SC;             // Sampling and conversion start
	   __bis_SR_register(CPUOFF + GIE);        // LPM0, ADC10_ISR will force exit
	   //Moving Algorithm
	   if(ADC10MEM > 415)			//This is a measure of how close an object is (its too close now, back up)
	   {
		  // P2OUT &= ~stdby;		//stdby low (OFF)
	   	   P1OUT |= BIT7;
	   	   shortBrake();
	   	   backUp();
	   }
	   else
	   {
		   //shortBrake();

		   P2OUT |= stdby;		//stdby low (ON)
		   forward();
		   P1OUT &= ~BIT7;
	   }

   }

}

// ADC10 interrupt service routine

#pragma vector=ADC10_VECTOR
__interrupt void ADC10_ISR(void)
{
  __bic_SR_register_on_exit(CPUOFF);        // Clear CPUOFF bit from 0(SR)
}


#pragma vector=TIMER1_A1_VECTOR    // Timer1 A1 interrupt service routine
__interrupt void Timer1_A1 (void)
{
	timer++;
	if(pos == 0 && timer == 50)
	{
		TA1CCR1 = 500;
		pos = !pos;
		timer = 0;
	}

	else if(pos == 1 && timer == 50)
	{
		TA1CCR1 = 4000;
		pos = !pos;
		timer = 0;
	}
	TA1CCTL1 &= ~CCIFG;
}

  • The most succinct description of A0 vs A1_VECTOR is SLAU144J sec 12.2.6, but I think you've already figured it out right.

    There are a number of commented lines, and I'm not quite sure which ones are required to trigger your symptom. Even so, I don't see anything obviously wrong.

    Here's a shot in the dark: Precede each of your ADC starts ("ADC10CTL0 |= ENC + ADC10SC;") with "__disable_interrupt();". You'll be turning GIE back on two lines below, so you won't stay disabled for very long.

    Hypothesis: The conversion takes (16+13=29) ADC10CLKs, but ADC10OSC runs at about 5MHz, so that's only about 6usec. With MCLK=~1MHz, that's only 6 CPU clocks, which is one or two instructions. If the Timer1 interrupt happens right then, it could add maybe 40 CPU clocks in between those two lines, and the ADC interrupt would come in before you go to sleep. Since your (only) wakeup source has already triggered, your program would then sleep forever.

    I can't say that this is what is happening to you, but it is possible, and I've seen stranger things. (It's also a pretty quick experiment.)
  • Sorry for the late response. Yes this indeed did fix the problem! Although I must admit I am still confused as to what the problem was and how this fixed it. 

**Attention** This is a public forum