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.

Help w/ ADC on MSP430G2553

Other Parts Discussed in Thread: DRV8850, DRV8850EVM

I had a DRV8850 EVM module and had modified the code for my application. Basically this turns on and turns the motor CW for ~400ms, then changes the direction to CCW for ~400ms. I left the pot control in to be able to vary the motor speed.

I just built up my prototype based on the DRV8850EVM but I swapped some pins in order to get a better board layout. The changed pins are:

  • IN1H was P2.5, now P2.3
  • IN1L was P2.1, now P2.4
  • IN2H was P2.4, now P2.1
  • IN2L was P2.2, also P2.2
  • SPD_REF was P1.0, now P1.5

The _v2 program is the original program that works on the EVM and the _Proto is the version I modified for the prototype board. When I debug the code it looks like the ADC is always returning 0 yet if I measure the voltage on the pot pin I can see different voltages.

Hopefully I've just missed something silly in the code!

Thanks in Advance!!

George

#include "msp430g2553.h"


// Port 1 output definitions
#define STATUS_LED		BIT7				// P1.7

// Port 2 output definitions

#define IN1H			BIT5				// P2.5
#define IN1L			BIT1				// P2.1
#define IN2H			BIT4				// P2.4
#define IN2L			BIT2				// P2.2

// Port 1 REN definitions (set unused to REN)
#define UNUSED			BIT4 | BIT 3		// P1.4 and P1.3 are unused

//
#define SPEED_REF		BIT0				// P1.0 is ADC read location

// Port 2 inputs
#define DIR				BIT7				// P2.7 is direction

// TIMER defines
// use 8
#define DUTY_CYCLE_TIMER_MAX 127	// max timer count value  -- total is 256 for up/down
#define DEADTIME		1			// software deadtime loop
									// set to 0 to use internal deadtime
#define MIN_DC 4					// sets the minimum duty cycle threshold to spin the motor
									// 1 - 50%
									// 2 - 25%
									// 3 - 12.5%
									// 4 - 6.25%
									// 5 - 3.125%
#define MAX_DC 5					// sets the maximum duty cycle threshold to spin the motor
									// 1 - 50%
									// 2 - 75%
									// 3 - 87.5%
									// 4 - 93.75%
									// 5 - 96.875%
#define DC_TOLERANCE	1			// Masked ADC value must change by DC_TOLERANCE + 1 before an update will occur
									// Value to change is ((DC_TOLERANCE + 1) * Vcc)/1024/8) Volts

// direction
#define FORWARD			0

#define ALL_LOW			0x00
#define ALL_HIGH		0xFF

volatile unsigned int LEDcounter=0;			// Initialize LED timing counter
unsigned int loop_counter;
unsigned int Direction, PriorDirection;
signed int DutyCycle, PriorDutyCycle;

unsigned int delayloop1;
unsigned int delayloop2;


/// SUBROUTINES
// this routine is a simple method of using duty cycle
// it is calculating the duty cycle by using the DUTY_CYCLE_TIMER_MAX number as
// a multiple of the number of bits (the number of bits is 6 (64 bins), and the
// the multiple is MULT_FACTOR)
// by using a multiple of the number of bits, the duty cycle is a math calculation
// OUTMOD0 is static, uses state of BIT2 to set low or high
// OUTMOD2 is toggle/reset  -- use on low side
// OUTMOD6 is toggle/set    -- use on high side

 void UpdateSpeed(unsigned int dc)
{
// calculate the next high side and low side values, then set them to minimize time
	 // the truth table for using this section is shown below
	 // Dir/Speed		IN1L	IN1H	IN2L	IN2H
	 // 0				H		L		H		L
	 // FWD < 100%		PWM		PMW		H		L
	 // FWD - 100%		L		H		H		L
	 // REV < 100%		H		L		PWM		PWM
	 // REV - 100%		H		L		L		H

// set up for slow decay mode

// Stop and reset the timers
//		TA1CCTL1 &= ~CCIE;	// disable the interrupt
		TA1CTL  |=  TACLR;	// CLR the timer;
		if (dc < (DUTY_CYCLE_TIMER_MAX >> MIN_DC)) // do not start spinning until 12.5%
		{
			// clear IN1H and IN2H
			// set IN1L and IN2L high to stop motor
			TA1CCTL1 = OUTMOD_0 | BIT2;
			TA1CCTL2 = OUTMOD_0;
			P2SEL = BIT5 | BIT4 | BIT2 | BIT1;
		}
		else if (dc < DUTY_CYCLE_TIMER_MAX - (DUTY_CYCLE_TIMER_MAX >> MAX_DC))     // use this up to 88%
		{
			// enable interrupts
//			TACTL |= TAIE;
			TA1CCR1 = DUTY_CYCLE_TIMER_MAX - dc;
			TA1CCR2 = DUTY_CYCLE_TIMER_MAX + DEADTIME - dc;
//			TA1CCTL1 |= CCIE;
			// clear IN1H and IN2H
			// set IN1L and IN2L high to stop motor
			P2SEL = BIT2 | BIT1;
			TA1CCTL1 = OUTMOD_2;
			TA1CCTL2 = OUTMOD_6;
			// need to set bits to clear based on direction
			if (Direction == FORWARD)
			{
				P2SEL = BIT5 | BIT1;		// PWM IN1 and
				P2OUT = BIT2;				// SET IN2L high
			}
			else
			{
				P2SEL = BIT4 | BIT2;		// PWM IN2 and
				P2OUT = BIT1;				// SET IN1L high
			}

			// restart the timer
			TA1CTL   =  TASSEL_2 | ID_0 | MC_3 | TACLR;  // Timer Clock = SMCLK;

		}
		else  // 100%
		{
			TA1CCTL1 = OUTMOD_0 | BIT2;
			TA1CCTL2 = OUTMOD_0 | BIT2;
			if (Direction == 0)
			{
				P2SEL = BIT5 | BIT2;		// Set IN1H and IN2L high
				P2OUT &= ~(BIT4 | BIT1);	// Set IN1L and IN2H low
			}
			else
			{
				P2SEL = BIT4 | BIT1;		// Set IN2H and IN1L high
				P2OUT &= ~(BIT5 | BIT2);	// Set IN1H and IN2L low
			}
		}
}


// MAIN Routine





int main(void)
{
  WDTCTL = WDTPW + WDTHOLD;             	// Stop watchdog timer

// Initialization -- First set all GPIO as inputs with pulldown

  P1REN  = BIT7 + BIT6 + BIT5 + BIT4 + BIT3 + BIT2 + BIT1 + BIT0;
  P2REN  = BIT7 + BIT6 + BIT5 + BIT4 + BIT3 + BIT2 + BIT1 + BIT0;
  P3REN  = BIT7 + BIT6 + BIT5 + BIT4 + BIT3 + BIT2 + BIT1 + BIT0;

  P1OUT  = ALL_LOW;
  P2OUT  = ALL_LOW;
  P3OUT  = ALL_LOW;

// Now re-configure Port Directions and Peripherals as required
  P1DIR = STATUS_LED;			// Set Port 1 GPIO to output on P1.7
  P1REN &= ~STATUS_LED;			// Disable Resistor

// must clear P2.7 prior to using it as an input
  P2SEL = ALL_LOW;

// Now re-configure Port Directions and Peripherals as required
  P2DIR = IN1H | IN1L | IN2H | IN2L;			// Set Port 1 GPIO to output on P1.1 and P1.2
  P2REN &= ~(IN1H | IN1L | IN2H | IN2L);		// Disable resistors
//

// Configure ADC10 to supply reference voltage and read value of voltage divider on P1.0

  ADC10CTL0 |= ADC10SHT_2 + ADC10ON + ADC10IE;    // VR+ = Vcc, VR- =AVSS, 16x sample and conversion, enable ADC and ADC interrupt
  ADC10AE0 |= INCH_0;						// Enable ADC input on A0

//  BCSCTL3 =  LFXT1S_3;						// Register value that must be set to allow TAI functionality on XIN pin

// Timer count value needs to be load only once
  TA1CCR0 = DUTY_CYCLE_TIMER_MAX;				// set time
  TA1CCTL1 |= OUTMOD_2;							// set mode to toggle/set
  TA1CCTL2 |= OUTMOD_6;							// set mode to toggle/reset

// delay for some time prior to speeding the clock, approximately 250ms per outer loop
  for (delayloop2 = 2; delayloop2 > 0; delayloop2 --)
  {
	  for (delayloop1 = 20000; delayloop1 > 0; delayloop1--)
      {__no_operation();
	  }
  }


// Set the DCO to calibrated 12MHz, be sure to have MCLK/2 and SMCLK/2 set prior to these commands.
  BCSCTL2  |= DIVM_1 | DIVS_1;				// MCLK is DCO/2, SMCLK is DCO/2
  DCOCTL	= ALL_LOW;						// clear the DCO then read the values

  BCSCTL1 	= CALBC1_12MHZ;
  DCOCTL	= CALDCO_12MHZ;					// Now set clock frequency at 6MHz



//// End of initialization

// Main Body of Code
  _BIS_SR(GIE);								// Global interrupt enable

// set values to force compare
  PriorDirection = 12000;
  PriorDutyCycle = 12000;


// initial setup of direction to avoid time delay
  Direction = ((P2IN & DIR) >> 7);	// read direction if 0 -- forward else reverse
  if (Direction != PriorDirection)
  	{
	  UpdateSpeed(0);					// stop the motor first then restart in new direction
										//Set Direction
	  PriorDirection = Direction;
  	}

// end of setup, beginning of main loop
		TA1CCTL1 = OUTMOD_0 | BIT2;
		TA1CCTL2 = OUTMOD_0 | BIT2;
//		UpdateSpeed(DutyCycle);  //Check Speed Wheel once before looping

  for (;;)
    {
	  //UpdateSpeed(0);  //Stop motor before changing Direction
	  Direction = 0;
		ADC10CTL0 |= ENC + ADC10SC;		// Read Speed value from ADC -- Sampling and conversion start
		UpdateSpeed(DutyCycle);  //Check Speed Wheel
		// Delay for 30ms per outer loop or 420ms
		for (delayloop2 = 14; delayloop2 > 0; delayloop2 --)
		{
		  for (delayloop1 = 24000; delayloop1 > 0; delayloop1--)
		  {__no_operation();
		  }
		}

		//UpdateSpeed(0);  //Stop motor before changing Direction
		Direction =1;
		ADC10CTL0 |= ENC + ADC10SC;		// Read Speed value from ADC -- Sampling and conversion start
		UpdateSpeed(DutyCycle);  //Check Speed Wheel

		// Delay for 30ms per outer loop or 420ms
		for (delayloop2 = 14; delayloop2 > 0; delayloop2 --)
		{
		  for (delayloop1 = 24000; delayloop1 > 0; delayloop1--)
		  {__no_operation();
		  }
		}

    }
}

///////////////////////////////// Interrupt service routines ////////////////////////

// ADC10 interrupt service routine
#pragma vector=ADC10_VECTOR
__interrupt void ADC10_ISR(void)
{
	  DutyCycle = (ADC10MEM & 0x3f8) >> 3;	// discard the last 3 bits ~25mV/bit and
	  	  	  	  	  	  	  	  	  	  	// shift right one to match 511 max
	  P1OUT ^= STATUS_LED;           		// Toggle LED
}



#pragma vector=PORT1_VECTOR, PORT2_VECTOR, USCIAB0TX_VECTOR, USCIAB0RX_VECTOR, \
		TIMER0_A1_VECTOR, TIMER0_A0_VECTOR, WDT_VECTOR, COMPARATORA_VECTOR, \
		TIMER1_A1_VECTOR, TIMER1_A0_VECTOR, NMI_VECTOR
__interrupt void Trap_ISR(void)
{
	  // this is a trap ISR - check for the interrupt cause here by
	  // checking the interrupt flags, if necessary also clear the interrupt
	  // flag
}

#include "msp430g2553.h"


// Port 1 output definitions
#define STATUS_LED		BIT7				// P1.7

// Port 2 output definitions

#define IN1H			BIT3				// P2.3
#define IN1L			BIT4				// P2.4
#define IN2H			BIT1				// P2.1
#define IN2L			BIT2				// P2.2

// Port 1 REN definitions (set unused to REN)
#define UNUSED			BIT4 | BIT 3		// P1.4 and P1.3 are unused

//
#define SPEED_REF		BIT5				// P1.5 is ADC read location

// Port 2 inputs
#define DIR				BIT7				// P2.7 is direction

// TIMER defines
// use 8
#define DUTY_CYCLE_TIMER_MAX 127	// max timer count value  -- total is 256 for up/down
#define DEADTIME		1			// software deadtime loop
									// set to 0 to use internal deadtime
#define MIN_DC 4					// sets the minimum duty cycle threshold to spin the motor
									// 1 - 50%
									// 2 - 25%
									// 3 - 12.5%
									// 4 - 6.25%
									// 5 - 3.125%
#define MAX_DC 5					// sets the maximum duty cycle threshold to spin the motor
									// 1 - 50%
									// 2 - 75%
									// 3 - 87.5%
									// 4 - 93.75%
									// 5 - 96.875%
#define DC_TOLERANCE	1			// Masked ADC value must change by DC_TOLERANCE + 1 before an update will occur
									// Value to change is ((DC_TOLERANCE + 1) * Vcc)/1024/8) Volts

// direction
#define FORWARD			0

#define ALL_LOW			0x00
#define ALL_HIGH		0xFF

volatile unsigned int LEDcounter=0;			// Initialize LED timing counter
unsigned int loop_counter;
unsigned int Direction, PriorDirection;
signed int DutyCycle, PriorDutyCycle;

unsigned int delayloop1;
unsigned int delayloop2;


/// SUBROUTINES
// this routine is a simple method of using duty cycle
// it is calculating the duty cycle by using the DUTY_CYCLE_TIMER_MAX number as
// a multiple of the number of bits (the number of bits is 6 (64 bins), and the
// the multiple is MULT_FACTOR)
// by using a multiple of the number of bits, the duty cycle is a math calculation
// OUTMOD0 is static, uses state of BIT2 to set low or high
// OUTMOD2 is toggle/reset  -- use on low side
// OUTMOD6 is toggle/set    -- use on high side

 void UpdateSpeed(unsigned int dc)
{
// calculate the next high side and low side values, then set them to minimize time
	 // the truth table for using this section is shown below
	 // Dir/Speed		IN1L	IN1H	IN2L	IN2H
	 // 0				H		L		H		L
	 // FWD < 100%		PWM		PMW		H		L
	 // FWD - 100%		L		H		H		L
	 // REV < 100%		H		L		PWM		PWM
	 // REV - 100%		H		L		L		H

// set up for slow decay mode

// Stop and reset the timers
//		TA1CCTL1 &= ~CCIE;	// disable the interrupt
		TA1CTL  |=  TACLR;	// CLR the timer;
		if (dc < (DUTY_CYCLE_TIMER_MAX >> MIN_DC)) // do not start spinning until 12.5%
		{
			// clear IN1H and IN2H
			// set IN1L and IN2L high to stop motor
			TA1CCTL1 = OUTMOD_0 | BIT2;
			TA1CCTL2 = OUTMOD_0;
			P2SEL = BIT3 | BIT4 | BIT2 | BIT1;
		}
		else if (dc < DUTY_CYCLE_TIMER_MAX - (DUTY_CYCLE_TIMER_MAX >> MAX_DC))     // use this up to 88%
		{
			// enable interrupts
//			TACTL |= TAIE;
			TA1CCR1 = DUTY_CYCLE_TIMER_MAX - dc;
			TA1CCR2 = DUTY_CYCLE_TIMER_MAX + DEADTIME - dc;
//			TA1CCTL1 |= CCIE;
			// clear IN1H and IN2H
			// set IN1L and IN2L high to stop motor
			P2SEL = BIT4 | BIT2;
			TA1CCTL1 = OUTMOD_2;
			TA1CCTL2 = OUTMOD_6;
			// need to set bits to clear based on direction
			if (Direction == FORWARD)
			{
				P2SEL = BIT3 | BIT4;		// PWM IN1 and
				P2OUT = BIT2;				// SET IN2L high
			}
			else
			{
				P2SEL = BIT1 | BIT2;		// PWM IN2 and
				P2OUT = BIT4;				// SET IN1L high
			}

			// restart the timer
			TA1CTL   =  TASSEL_2 | ID_0 | MC_3 | TACLR;  // Timer Clock = SMCLK;

		}
		else  // 100%
		{
			TA1CCTL1 = OUTMOD_0 | BIT2;
			TA1CCTL2 = OUTMOD_0 | BIT2;
			if (Direction == 0)
			{
				P2SEL = BIT3 | BIT2;		// Set IN1H and IN2L high
				P2OUT &= ~(BIT4 | BIT1);	// Set IN1L and IN2H low
			}
			else
			{
				P2SEL = BIT1 | BIT4;		// Set IN2H and IN1L high
				P2OUT &= ~(BIT3 | BIT2);	// Set IN1H and IN2L low
			}
		}
}


// MAIN Routine





int main(void)
{
  WDTCTL = WDTPW + WDTHOLD;             	// Stop watchdog timer

// Initialization -- First set all GPIO as inputs with pulldown

  P1REN  = BIT7 + BIT6 + BIT5 + BIT4 + BIT3 + BIT2 + BIT1 + BIT0;
  P2REN  = BIT7 + BIT6 + BIT5 + BIT4 + BIT3 + BIT2 + BIT1 + BIT0;
  P3REN  = BIT7 + BIT6 + BIT5 + BIT4 + BIT3 + BIT2 + BIT1 + BIT0;

  P1OUT  = ALL_LOW;
  P2OUT  = ALL_LOW;
  P3OUT  = ALL_LOW;

// Now re-configure Port Directions and Peripherals as required
  P1DIR = STATUS_LED;			// Set Port 1 GPIO to output on P1.7
  P1REN &= ~STATUS_LED;			// Disable Resistor

// must clear P2.7 prior to using it as an input
  P2SEL = ALL_LOW;

// Now re-configure Port Directions and Peripherals as required
  P2DIR = IN1H | IN1L | IN2H | IN2L;			// Set Port 1 GPIO to output on P1.1 and P1.2
  P2REN &= ~(IN1H | IN1L | IN2H | IN2L);		// Disable resistors
//

// Configure ADC10 to supply reference voltage and read value of voltage divider on P1.5

  ADC10CTL0 |= ADC10SHT_2 + ADC10ON + ADC10IE;    // VR+ = Vcc, VR- =AVSS, 16x sample and conversion, enable ADC and ADC interrupt
  ADC10AE0 |= INCH_5;						// Enable ADC input on A5

//  BCSCTL3 =  LFXT1S_3;						// Register value that must be set to allow TAI functionality on XIN pin

// Timer count value needs to be load only once
  TA1CCR0 = DUTY_CYCLE_TIMER_MAX;				// set time
  TA1CCTL1 |= OUTMOD_2;							// set mode to toggle/set
  TA1CCTL2 |= OUTMOD_6;							// set mode to toggle/reset

// delay for some time prior to speeding the clock, approximately 250ms per outer loop
  for (delayloop2 = 2; delayloop2 > 0; delayloop2 --)
  {
	  for (delayloop1 = 20000; delayloop1 > 0; delayloop1--)
      {__no_operation();
	  }
  }


// Set the DCO to calibrated 12MHz, be sure to have MCLK/2 and SMCLK/2 set prior to these commands.
  BCSCTL2  |= DIVM_1 | DIVS_1;				// MCLK is DCO/2, SMCLK is DCO/2
  DCOCTL	= ALL_LOW;						// clear the DCO then read the values

  BCSCTL1 	= CALBC1_12MHZ;
  DCOCTL	= CALDCO_12MHZ;					// Now set clock frequency at 6MHz



//// End of initialization

// Main Body of Code
  _BIS_SR(GIE);								// Global interrupt enable

// set values to force compare
  PriorDirection = 12000;
  PriorDutyCycle = 12000;


// initial setup of direction to avoid time delay
  Direction = ((P2IN & DIR) >> 7);	// read direction if 0 -- forward else reverse
  if (Direction != PriorDirection)
  	{
	  UpdateSpeed(0);					// stop the motor first then restart in new direction
										//Set Direction
	  PriorDirection = Direction;
  	}

// end of setup, beginning of main loop
		TA1CCTL1 = OUTMOD_0 | BIT2;
		TA1CCTL2 = OUTMOD_0 | BIT2;
//		UpdateSpeed(DutyCycle);  //Check Speed Wheel once before looping

  for (;;)
    {
	  //UpdateSpeed(0);  //Stop motor before changing Direction
	  Direction = 0;
		ADC10CTL0 |= ENC + ADC10SC;		// Read Speed value from ADC -- Sampling and conversion start
		UpdateSpeed(DutyCycle);  //Check Speed Wheel
		// Delay for 30ms per outer loop or 420ms
		for (delayloop2 = 14; delayloop2 > 0; delayloop2 --)
		{
		  for (delayloop1 = 24000; delayloop1 > 0; delayloop1--)
		  {__no_operation();
		  }
		}

		//UpdateSpeed(0);  //Stop motor before changing Direction
		Direction = 1;
		ADC10CTL0 |= ENC + ADC10SC;		// Read Speed value from ADC -- Sampling and conversion start
		UpdateSpeed(DutyCycle);  //Check Speed Wheel

		// Delay for 30ms per outer loop or 420ms
		for (delayloop2 = 14; delayloop2 > 0; delayloop2 --)
		{
		  for (delayloop1 = 24000; delayloop1 > 0; delayloop1--)
		  {__no_operation();
		  }
		}

    }
}

///////////////////////////////// Interrupt service routines ////////////////////////

// ADC10 interrupt service routine
#pragma vector=ADC10_VECTOR
__interrupt void ADC10_ISR(void)
{
	  DutyCycle = (ADC10MEM & 0x3f8) >> 3;	// discard the last 3 bits ~25mV/bit and
	  	  	  	  	  	  	  	  	  	  	// shift right one to match 511 max
	  P1OUT ^= STATUS_LED;           		// Toggle LED
}



#pragma vector=PORT1_VECTOR, PORT2_VECTOR, USCIAB0TX_VECTOR, USCIAB0RX_VECTOR, \
		TIMER0_A1_VECTOR, TIMER0_A0_VECTOR, WDT_VECTOR, COMPARATORA_VECTOR, \
		TIMER1_A1_VECTOR, TIMER1_A0_VECTOR, NMI_VECTOR
__interrupt void Trap_ISR(void)
{
	  // this is a trap ISR - check for the interrupt cause here by
	  // checking the interrupt flags, if necessary also clear the interrupt
	  // flag
}

**Attention** This is a public forum