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.

MSP430FR5969 using a timer A0 to trigger ADC12

Hello,

 i have been trying to trigger an adc12 repeat sequence of channels conversion from timer A0 . The timer runs of an 32 kHz external crystal oscillator and i desire the ADC to sample at 4 kHz. i take 7 samples from the first signal and 1 of the second signal and 7 from the first and finaly one of the 3rd.

and i sent the sample to the PC via RN 42  bluetooth. 

when I wanted to try my program, I generate a sine wave and I Sampled this signal, after I sent the samples to the PC via Bluetooth.when I try to plot what I received I found a sine signal but does not have the same frequency of the transmitted signal.

here is my code.

can some one tell me where is the problem.

#include <msp430.h> 
#include "tt.h"
/*
 * main.c
 */
unsigned int ADC_cha1_value;
unsigned int ADC_cha2_value;
unsigned int ADC_cha3_value;
void main(void) {
	WDTCTL = WDTPW | WDTHOLD;	// Stop watchdog timer
	P1OUT &= ~BIT0;                           // Clear LED to start
	P4OUT &= ~BIT6;                           // Clear LED to start
	P1DIR |= BIT0;                            // P1.0 output
	P4DIR |= BIT6;
	P1REN |= 0x02;                            // enable P1.1 (Pushbutton S2)
	P1DIR &= ~0x02;                           // enable read port P1.1 (Pushbutton S2)
	PJSEL0 = BIT4 | BIT5;                     // For XT1
	
        clk_init();                               // programation de l'hrologe 8M pour uart et 32768KH pour ADC
	USART0_Init();                            // initialisation uart0 pour 115200
	USART1_Init();                            // initialisation uart0 pour 115200 (PIN rx=2.6 et tx=2.5)
	//adc12_alimentation_test();

	P1SEL1 |= BIT3 + BIT4 + BIT5 ;            // Configure P1.3 P1.4 P1.5 for ADC
	P1SEL0 |= BIT3 + BIT4 + BIT5 ;

	// Disable the GPIO power-on default high-impedance mode to activate
	// previously configured port settings
	PM5CTL0 &= ~LOCKLPM5;

	ADC12CTL0 = ADC12SHT0_0 | ADC12SHT1_0 | ADC12ON;        // Sampling time, S&H=4, ADC12 on
	// Use TA0.1 to trigger, and repeated-single-channel
	ADC12CTL1 = ADC12SHP | ADC12SHS_1 | ADC12CONSEQ_3;
	// A2 ADC input select; Vref+ = VREF


	while(REFCTL0 & REFGENBUSY);              // If ref generator busy, WAIT
	REFCTL0 |= REFVSEL_2|REFON;               // Select internal ref = 2.5V
	// Internal Reference ON
	while(!(REFCTL0 & REFGENRDY));            // Wait for reference generator
	ADC12MCTL0  = ADC12INCH_3 ;
	ADC12MCTL1  = ADC12INCH_3 ;
	ADC12MCTL2  = ADC12INCH_3 ;
	ADC12MCTL3  = ADC12INCH_3 ;
	ADC12MCTL4  = ADC12INCH_3 ;
	ADC12MCTL5  = ADC12INCH_3 ;
	ADC12MCTL6  = ADC12INCH_3 ;
	ADC12MCTL7  = ADC12INCH_4 ;
	ADC12MCTL8  = ADC12INCH_3 ;
	ADC12MCTL9  = ADC12INCH_3 ;
	ADC12MCTL10 = ADC12INCH_3 ;
	ADC12MCTL11 = ADC12INCH_3 ;
	ADC12MCTL12 = ADC12INCH_3 ;
	ADC12MCTL13 = ADC12INCH_3 ;
	ADC12MCTL14 = ADC12INCH_3 ;
	ADC12MCTL15 = ADC12INCH_5 ;
	ADC12IER0 |= ADC12IE0 |ADC12IE1 |ADC12IE2 |ADC12IE3 |ADC12IE4 |ADC12IE5 |ADC12IE6 |ADC12IE7 |ADC12IE8 |ADC12IE9 |ADC12IE10 |ADC12IE11 |ADC12IE12 |ADC12IE13 |ADC12IE14 |ADC12IE15 ;                    // Enable ADC interrupt

	// Configure Timer0_A3 to periodically trigger the ADC12
	TA0CCR0 = 8;                              // PWM Period  on a 32768 / 4000 ~~ 8
	TA0CCTL1 = OUTMOD_3;                      // TACCR1 set/reset
	TA0CCR1 = 8;                              // TACCR1 PWM Duty Cycle on a 32768 / 4000 ~~ 8
	TA0CTL = TASSEL__ACLK | MC__UP | TACLR;           // ACLK, up mode ACLK = 32768 hz
	ADC12CTL0 |= ADC12ENC | ADC12SC;          // Start sampling/conversion
	while (1){

		P1OUT |= BIT0;
		if( (P1IN & BIT1) == 0){      // Push BUTTON down when bit 1 == 0
			P1OUT |= BIT0;            // Set green LED on when button down
			
				// envoie des données
				__bis_SR_register(GIE);       // Enter LPM3, enable interrupts

			}

		}
		else {
		
			P1OUT |= BIT0;            // Set green LED on
			for (i=1; i<30000; i=i+1) {}        //Delay
			P1OUT &= ~BIT0;           // Set green LED off
			for (i=1; i<30000; i=i+1) {}        //Delay

		}
	}
}
// ADC12 interrupt service routine
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=ADC12_VECTOR
__interrupt void ADC12ISR (void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(ADC12_VECTOR))) ADC12ISR (void)
#else
#error Compiler not supported!
#endif
{
	switch(ADC12IV)
	{
	case ADC12IV_NONE:        break;        // Vector  0:  No interrupt
	case ADC12IV_ADC12OVIFG:  break;        // Vector  2:  ADC12MEMx Overflow
	case ADC12IV_ADC12TOVIFG: break;        // Vector  4:  Conversion time overflow
	case ADC12IV_ADC12HIIFG:  break;        // Vector  6:  ADC12BHI
	case ADC12IV_ADC12LOIFG:  break;        // Vector  8:  ADC12BLO
	case ADC12IV_ADC12INIFG:  break;        // Vector 10:  ADC12BIN
	case ADC12IV_ADC12IFG0:                 // Vector 12:  ADC12MEM0 Interrupt
		ADC_cha1_value = ADC12MEM0;
		process_phono( ADC_cha1_value );
		break;
	case ADC12IV_ADC12IFG1:
		ADC_cha1_value = ADC12MEM1;
		process_phono( ADC_cha1_value );
		break;        // Vector 14:  ADC12MEM1
	case ADC12IV_ADC12IFG2:
		ADC_cha1_value = ADC12MEM2;
		process_phono( ADC_cha1_value );
		break;        // Vector 16:  ADC12MEM2
	case ADC12IV_ADC12IFG3:
		ADC_cha1_value = ADC12MEM3;
		process_phono( ADC_cha1_value );
		break;        // Vector 18:  ADC12MEM3
	case ADC12IV_ADC12IFG4:
		ADC_cha1_value = ADC12MEM4;
		process_phono( ADC_cha1_value );
		break;        // Vector 20:  ADC12MEM4
	case ADC12IV_ADC12IFG5:
		ADC_cha1_value = ADC12MEM5;
		process_phono( ADC_cha1_value );
		break;        // Vector 22:  ADC12MEM5
	case ADC12IV_ADC12IFG6:
		ADC_cha1_value = ADC12MEM6;
		process_phono( ADC_cha1_value );
		break;        // Vector 24:  ADC12MEM6
	case ADC12IV_ADC12IFG7:
		ADC_cha2_value = ADC12MEM7;
		process_ECG( ADC_cha2_value );
		break;        // Vector 26:  ADC12MEM7
	case ADC12IV_ADC12IFG8:
		ADC_cha1_value = ADC12MEM8;
		process_phono( ADC_cha1_value );
		break;        // Vector 28:  ADC12MEM8
	case ADC12IV_ADC12IFG9:
		ADC_cha1_value = ADC12MEM9;
		process_phono( ADC_cha1_value );
		break;        // Vector 30:  ADC12MEM9
	case ADC12IV_ADC12IFG10:
		ADC_cha1_value = ADC12MEM10;
		process_phono( ADC_cha1_value );
		break;        // Vector 32:  ADC12MEM10
	case ADC12IV_ADC12IFG11:
		ADC_cha1_value = ADC12MEM11;
		process_phono( ADC_cha1_value );
		break;        // Vector 34:  ADC12MEM11
	case ADC12IV_ADC12IFG12:
		ADC_cha1_value = ADC12MEM12;
		process_phono( ADC_cha1_value );
		break;        // Vector 36:  ADC12MEM12
	case ADC12IV_ADC12IFG13:
		ADC_cha1_value = ADC12MEM13;
		process_phono( ADC_cha1_value );
		break;        // Vector 38:  ADC12MEM13
	case ADC12IV_ADC12IFG14:
		ADC_cha1_value = ADC12MEM14;
		process_phono( ADC_cha1_value );
		break;        // Vector 40:  ADC12MEM14
	case ADC12IV_ADC12IFG15:
		ADC_cha3_value = ADC12MEM15;
		process_Pression( ADC_cha3_value );
		__bic_SR_register_on_exit(LPM3_bits); // Exit active CPU and disable interrupts
		break;        // Vector 42:  ADC12MEM15
	case ADC12IV_ADC12IFG16:  break;        // Vector 44:  ADC12MEM16
	case ADC12IV_ADC12IFG17:  break;        // Vector 46:  ADC12MEM17
	case ADC12IV_ADC12IFG18:  break;        // Vector 48:  ADC12MEM18
	case ADC12IV_ADC12IFG19:  break;        // Vector 50:  ADC12MEM19
	case ADC12IV_ADC12IFG20:  break;        // Vector 52:  ADC12MEM20
	case ADC12IV_ADC12IFG21:  break;        // Vector 54:  ADC12MEM21
	case ADC12IV_ADC12IFG22:  break;        // Vector 56:  ADC12MEM22
	case ADC12IV_ADC12IFG23:  break;        // Vector 58:  ADC12MEM23
	case ADC12IV_ADC12IFG24:  break;        // Vector 60:  ADC12MEM24
	case ADC12IV_ADC12IFG25:  break;        // Vector 62:  ADC12MEM25
	case ADC12IV_ADC12IFG26:  break;        // Vector 64:  ADC12MEM26
	case ADC12IV_ADC12IFG27:  break;        // Vector 66:  ADC12MEM27
	case ADC12IV_ADC12IFG28:  break;        // Vector 68:  ADC12MEM28
	case ADC12IV_ADC12IFG29:  break;        // Vector 70:  ADC12MEM29
	case ADC12IV_ADC12IFG30:  break;        // Vector 72:  ADC12MEM30
	case ADC12IV_ADC12IFG31:  break;        // Vector 74:  ADC12MEM31
	case ADC12IV_ADC12RDYIFG: break;        // Vector 76:  ADC12RDY
	default: break;
	}
}
----------------------------------------------------------------------------------------
#include "tt.h"
unsigned int ADC12_VCC;
double Vsupply;
unsigned char yy;
void process_phono(unsigned int data){
	// codage de la donnée
	// 0xMMMMMM et 1xLLLLLL
	// MSB
	unsigned char MSB = (unsigned char) ((data & 0x0FC0)>>6);
	// LSB
	unsigned char LSB = (unsigned char) ((data & 0x003F) | 0x80 );
	serialWrite(MSB, LSB);

}
void process_ECG(unsigned int data){

	// codage de la donnée
	// 0xMMMMMM et 0xLLLLLL
	// MSB
	unsigned char MSB = (unsigned char) ((data & 0x0FC0)>>6);
	// LSB
	unsigned char LSB = (unsigned char) (data & 0x003F);

	serialWrite(MSB, LSB);
}
void process_Pression(unsigned int data){
	unsigned char MSB,LSB;
	// codage de la donnée
	// 1xMMMMMM et 0xLLLLLL
	// MSB
	MSB = (unsigned char) (((data & 0x0FC0)>>6) | 0x80) ;
	// LSB
	LSB = (unsigned char)  (data & 0x003F);
	serialWrite(MSB, LSB);
}
void serialWrite(uint8_t  data1 , uint8_t data2 )
{
	while(!(UCA1IFG & UCTXIFG));
	UCA1TXBUF = data1;
	//__delay_cycles(3500);
	while(!(UCA1IFG & UCTXIFG));
	UCA1TXBUF = data2;
	//__delay_cycles(3500);
}
void serialWrite1(unsigned int data)
{
	while(!(UCA1IFG & UCTXIFG));
	UCA1TXBUF = data;
}
void serialwriteString(const char *str)
{
	while(*str)
		serialWrite1(*str++);
}
void USART0_Init (void) {	// Controller -> PC
	P2SEL1 |= BIT0| BIT1;                    // Configure UART pins
	P2SEL0 &= ~(BIT0| BIT1);

	// Disable the GPIO power-on default high-impedance mode to activate
	// previously configured port settings
	PM5CTL0 &= ~LOCKLPM5;
	// Startup clock system with max DCO setting ~8MHz
	// Configure USCI_A1 for UART mode
	/*
	  // Startup clock system with max DCO setting ~8MHz
	  CSCTL0_H = CSKEY >> 8;                    // Unlock clock registers
	  CSCTL1 = DCOFSEL_3 | DCORSEL;             // Set DCO to 8MHz
	  CSCTL2 = SELA__VLOCLK | SELS__DCOCLK | SELM__DCOCLK;
	  CSCTL3 = DIVA__1 | DIVS__1 | DIVM__1;     // Set all dividers
	  CSCTL0_H = 0  ;                           // Lock CS registers
	 */
	UCA0CTLW0 = UCSWRST;                      // Put eUSCI in reset
	UCA0CTLW0 |= UCSSEL__SMCLK;               // CLK = SMCLK

	UCA0BR0 =4;                             
	UCA0BR1 = 0x00;
	UCA0MCTLW |=0x55;       //0x49;                         //UCOS16 | UCBRF_1;
	UCA0CTLW0 &= ~UCSWRST;                    // Initialize eUSCI
	// UCA0IE |= UCRXIE;                         // Enable USCI_A0 RX interrupt

}
void USART1_Init (void) {	

	P2SEL1 |= BIT5| BIT6;                    // Configure UART pins
	P2SEL0 &= ~(BIT5| BIT6);

	// Configure USCI_A1 for UART mode
	UCA1CTLW0 = UCSWRST;                      // Put eUSCI in reset
	UCA1CTLW0 |= UCSSEL__SMCLK;               // CLK = SMCLK

	UCA1BR0 = 4;                             
	UCA1BR1 = 0x00;
	UCA1MCTLW |=0x55; 
	UCA1CTLW0 &= ~UCSWRST;                    // Initialize eUSCI
	//UCA1IE |= UCRXIE;                         // Enable USCI_A0 RX interrupt
}

void adc12_alimentation_test(void){

	// Configure ADC12
	ADC12CTL0 = ADC12SHT0_2 | ADC12ON | ADC12MSC;
	ADC12CTL1 |= ADC12SHP | ADC12CONSEQ_1;    // ADCCLK = MODOSC; sampling timer
	ADC12CTL2 |= ADC12RES_2;                  // 12-bit conversion results
	ADC12CTL3 |= ADC12BATMAP;                 // route 1/2 AVcc to the ADC
	ADC12IER0 |= ADC12IE1;
	ADC12MCTL0 |= ADC12INCH_31 ;              // A31 ADC input select;

	// Configure internal reference
	while(REFCTL0 & REFGENBUSY);              // If ref generator busy, WAIT
	REFCTL0 |= REFVSEL_2|REFON;               // Select internal ref = 2.5V
	// Internal Reference ON
	while(!(REFCTL0 & REFGENRDY));            // Wait for reference generator
	// to settle
	ADC12CTL0 |= ADC12ENC | ADC12SC;        // Start sampling/conversion
	ADC12_VCC=ADC12MEM0;
	Vsupply = ((2 * 2.5 * ADC12_VCC) / 4095);

	if(Vsupply > 2.3){

		P1OUT |= BIT0;                      // P1.0 = 1
		__delay_cycles(50000);             //Delay
		P1OUT &= ~BIT0;                           // Clear LED to start
		__delay_cycles(50000);             //Delay
	}
	else {
		P4OUT |= BIT6;                     // P4.6 = 1
		while(1);
	}

	ADC12CTL0 &= ~ (ADC12ENC | ADC12SC);
}
void clk_init(void){
	// Clock System Setup
		  CSCTL0_H = CSKEY >> 8;                    // Unlock CS registers
	  CSCTL1 = DCOFSEL_6;                       // Set DCO to 8MHz
	  //CSCTL1 = DCORSEL | DCOFSEL_4;             // Set DCO to 16MHz
	  CSCTL2 = SELA__LFXTCLK | SELS__DCOCLK | SELM__DCOCLK;
	  CSCTL3 = DIVA__1 | DIVS__1 | DIVM__1;     // Set all dividers
	  CSCTL4 &= ~LFXTOFF;
	  do
	  {
	    CSCTL5 &= ~LFXTOFFG;                    // Clear XT1 fault flag
	    SFRIFG1 &= ~OFIFG;
	  }while (SFRIFG1&OFIFG);
}

  • Without pouring through your entire code, one thing that jumps out is that you are doing stuff during your ADC ISR processing that probably takes WAY too long.

    You read the ADC value, then call a process_phono() function that in turn calls a serialWrite() function. In that serial writing function, you have a spin-loop delay on the TXIFG flag.

    Most likely, you are taking way too long trying to write the bytes to the serial port, all while still in the call stack of the ADC ISR, which during this time all interrupts are disabled. But, ADC continues on, and you end up missing ADC interrupts, so samples are missing, thus your recovered waveform is wrong.

    Have you done any analysis to verify that at your ADC sampling rate that there is enough serial port bandwidth to get all the data out in real time?

    If so, then you should be using a transmit buffer to put the serial data in, and feed that to the UART in the UART's ISR. You shouldn't do anything in any ISR that takes a lot of time.

**Attention** This is a public forum