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.

msp432 trigger adc14 from timerA0

Hi all,

in the code that i post below i want to start adc conversion at TIME_ADC_START (0 or another time) and finish it in TIME_ADC_END. In the isr timer i generate interrupt that turn on and off pin of a external sensor but this is not the problem because it works. My problem is adc: how write in the code, adc start and finish to sampling when i want but i have the doubt that it is not correct. 

So is there another mode of using adc? i read in different posts that adc can be triggered by timer but i do it, it doesn't work :(

An important thing: i need funcion sendallvalues(), so if you modify my code keep it because this function sends my array to server. Other function (send_char and received serve to "speak" with python software and command the msp. These work so the problem is only for adc and timer. 

#include "msp.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>


// ==========Definizione costanti==========

typedef enum {false=0, true=1} bool;      // definizione tipo bool

// costanti dei tempi di acquisizione
#define STEP			5		//	5 us	 tempo dell'interrupt
#define TIME_ON			50		//	50 us	 led IR on, signal = 0 V
#define TIME_ADC_START	0		//	0 us	 inizio istante di acquisizione
#define TIME_OFF		450		//	450 us	 led IR off, signal = 3,3 V
#define TIME_ADC_END	1000	//	1000 us	 fine istante di acquisizione
#define TIME_SAVE		1200	//	1200 us	 controllo fine ciclo
#define TIME_RESET		10000	//	10.000 us periodo del segnale generato

// costanti comandi protocollo trasmissione seriale
#define com_PING  'P'         // ping
#define com_T     'T'         // parametro T (periodo in minuti)
#define com_N     'N'         // parametro N (numero campioni per periodo)
#define com_UTC   'U'         // sincronizzazione data/ora
#define com_MODE  'A'         // 0 (off) - 1 (auto) - 2 (manual)
#define com_START 'S'         // inizio acquisizione degli N valori
#define com_RESET 'R'         // provoca reset

#define com_VALUE 'D'         // invio di N valori
#define com_END   'E'         // fine invio valori
#define com_LOG   'L'         // stringa di log


// ==========Dichiarazione variabili globali==========

// parametri modificabili via seriale a run-time
int T =   5;  // min      // Periodo globale di acquisizione               [N/100/60  < T  < 32767]
int N = 100;              // Numero di campioni memorizzati per periodo    [    1     < N  < 16384]

// variabili tempi
int microsecondi = 0;      // contatore di microsecondi del timer A0        [0 - 10.000]
int minuti = 0;            // contatore di minuti del Real Time Clock       [0 - T]

// indici contatori array
int index_N = 0;           // contatore campioni                            [0 - N]

// variabili acquisizione
uint16_t values[16384];    // array che contiene tutti gli N valori di un periodo

char micro[8];

// variabili ricezione seriale
char RXData[32];           // buffer che contiene la stringa ricevuta
char RXByte;               // ultimo byte ricevuto
int  index_RX;             // indice del ciclo che riempie il buffer RXData



// ==========Funzioni in/out==========

void IR_off()    {P4OUT    |=  BIT2;}
void IR_on()     {P4OUT    &= ~BIT2;}
void led_on()    {P1OUT    |=  BIT0;}
void led_off()   {P1OUT    &= ~BIT0;}
void TA0_on()    {TA0CCTL0 |=  CCIE;}
void TA0_off()   {TA0CCTL0 &= ~CCIE;}
void auto_on(){
	RTCCTL0_H = RTCKEY_H;
	RTCCTL0_L |= RTCTEVIE;
	RTCCTL0_H = 0;}
void auto_off(){
	RTCCTL0_H = RTCKEY_H;
	RTCCTL0_L &= ~RTCTEVIE;
	RTCCTL0_H = 0;}

// ===========================Funzioni Real Time Clock===========================

void get_now(char *now){
	// legge i registri del 'Real Time Clock' e scrive la data in now
	sprintf(now     , "%04x-",  RTCYEAR);
	sprintf(now +  5, "%02x-",  RTCMON);
	sprintf(now +  8, "%02x ",  RTCDAY);
	sprintf(now + 11, "%02x:",  RTCHOUR);
	sprintf(now + 14, "%02x:",  RTCMIN);
	sprintf(now + 17, "%02x\n", RTCSEC);
}

void set_rtc(char *date){
	// riceve una data in formato stringa 'YYYY-MM-DD hh:mm:ss' e scrive i registri del 'Real Time Clock'
	RTCCTL0_H = RTCKEY_H;                       //   Unlock RTC key protected registers
	RTCYEAR = strtol(&date[ 0], NULL, 16);
	RTCMON  = strtol(&date[ 5], NULL, 16);
	RTCDAY  = strtol(&date[ 8], NULL, 16);
	RTCHOUR = strtol(&date[11], NULL, 16);
	RTCMIN  = strtol(&date[14], NULL, 16);
	RTCSEC  = strtol(&date[17], NULL, 16);
    RTCCTL0_H = 0;                              //   Lock RTC key protected registers
}



// ===========================Funzioni Protocollo Seriale===========================

void send_char(char c){                       // invia un carattere sulla seriale
	while(!(UCA0IFG&UCTXIFG)); //finchè c' da trasmettere
	UCA0TXBUF = c; //riempie il buffer di trasmissione
}

int send(char command, char *text){
	send_char(command);                       // invio comando
	int i=0;
	while (text[i] != 10){				      // finchè è diverso da 'a capo \n'
		send_char(text[i]);
		i++;
	}                                         // invio testo
	send_char(10);                            // invio '\n'
	return i+2;                               // restituisce il numero di caratteri inviati
}

void send_all_values(){
	int i, i_N;
	int n=0;
	int samples_per_row = 20; //sono il numero di campioni su gni riga stampati su monitor (10000/20=500 righe di campioni adc)
	char TXData[32];
	char UTC[32];
	get_now(UTC);
	for (i_N=0; i_N<N; i_N++){
		if (i_N == n){
			n += samples_per_row;
			send_char(com_VALUE);
			for(i = 0; i < 19; i++) //19 lunghezza timestamp
				send_char(UTC[i]);
			send_char(';');
		}
		sprintf(TXData, "%d,", values[i_N]);
		for(i = 0; i < strlen(TXData); i++)
			send_char(TXData[i]);
		if (i_N == n-1 || i_N == N-1){
			send_char(10);
		}
	}
	send(com_END, "E\n");
}


void received(){                              // elabora i dati ricevuti dalla seriale
	char TXData[32];
	int mode;
	switch(RXData[0]){
		case (int)com_PING:
			send(com_PING, "ok\n");
			break;
		case (int)com_T:
			T = atoi(&RXData[1]);
			sprintf(TXData, "%d\n", T);
			send(com_T, TXData);
			break;
		case (int)com_N:
			N = atoi(&RXData[1]);
			sprintf(TXData, "%d\n", N);
			send(com_N, TXData);
			break;
		case (int)com_UTC:
			set_rtc(&RXData[1]);
			get_now(TXData);
			send(com_UTC, TXData);
			break;
		case (int)com_MODE:
			mode = atoi(&RXData[1]);
			sprintf(TXData, "%d\n", mode);
			send(com_MODE, TXData);
			if (mode == 1) {
				auto_on();
			}
			else {
				auto_off();
			}
			break;
		case (int)com_START:
			microsecondi = 0;
			TA0_on();
			led_on();
			send(com_START, "\n");
			break;
		case (int)com_RESET:
			send(com_LOG, "ricevuto comando reset\n");
			RSTCTL_RESET_REQ |= (0x6900 | RSTCTL_RESET_REQ_HARD_REQ);
		default:
			send(com_LOG, "comando sconosciuto\n");
			break;
	}
}

// ===========================Funzioni adc===========================
int main(void)
{
	// ==========Configurazioni di base==========
	WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer

	P1DIR |= BIT0;
	P1OUT |= BIT0;                     // Set 1.0 as digital out (led rosso a bordo)

	P4DIR |= BIT2;
	P4OUT |= BIT2;              // Set 4.2 as digital out (IR)

	SCB_SCR |= SCB_SCR_SLEEPONEXIT;    // Enable sleep on exit from ISR
	__enable_interrupt();


	// ==========Configurazione ADC 14 bit==========
	P6SEL1 |= BIT1;
	P6SEL0 |= BIT1;    // Canale A14 (P6.1) configurato per ADC

	ADC14CTL0 &= ~ADC14ENC;							  //Turn off Enable. With few exceptions, the ADC14 control bits can only be modified when ADC14ENC = 0.
	ADC14CTL0 = ADC14ON | ADC14SHP | ADC14CONSEQ_2 | ADC14SHS_1;   // Turn on ADC14, set sampling time, repeat single channel
	ADC14CTL1 = ADC14RES__14BIT;                      // Use sampling timer, 14-bit conversion results
	ADC14MCTL0 = ADC14VRSEL_0 | ADC14INCH_14;         // A0 ADC input select; Vref=AVCC=3.3V
	ADC14CLRIFGR0 |= ADC14IFG0;
	ADC14IER0 |= ADC14IE0;
	//ADC14CTL0 |= ADC14ENC;                          // ADC enable


	// ==========Configurazione clock a 12 MHz==========
	CSKEY = 0x695A;                    // Unlock CS module for register access
	CSCTL0 = 0;                        // Reset tuning parameters
	CSCTL0 = DCORSEL_3;                // Set DCO to 12MHz (nominal, center of 8-16MHz range)
	CSCTL1 = SELA_2 | SELS_3 | SELM_3; // Select ACLK = REFO, SMCLK = MCLK = DCO
	CSKEY = 0;                         // Lock CS module from unintended accesses


	// ==========Configurazione TimerA0==========
	NVIC_ISER0 = 1 << ((INT_TA0_0 - 16) & 31);  // Enable TA0_0 interrupt in NVIC module
	TA0CCTL0 &= ~CCIFG;                         // Interrupt disable
	TA0CCR0 = STEP-1;                             // Overflow (step dell'interrupt)
	TA0CCR1 = STEP/2;
	TA0CCTL1 |= OUTMOD_3;
	TA0CTL = TASSEL__SMCLK | MC__UP | ID_2;     // SMCLK, UP mode, Divisione per 4 (12 MHz / 4 = 3 MHz)
	TA0EX0 |= TAIDEX_2;                         // Divisione per 3 (3 MHz / 3 = 1 MHz)


	// ==========Configurazione Seriale==========
	P1SEL0 |= BIT2 | BIT3;                       // set 2-UART pin as second function
	NVIC_ISER0 = 1 << ((INT_EUSCIA0 - 16) & 31); // Enable eUSCIA0 interrupt in NVIC module

	// Configure UART
	UCA0CTLW0 |= UCSWRST;
	UCA0CTLW0 |= UCSSEL__SMCLK;                  // Put eUSCI in reset
	    /* Baud Rate calculation
	     * 12.000.000/(16*9.600) = 78.125
	     * Fractional portion = 0.125
	     * User's Guide Table 21-4: UCBRSx = 0x10
	     * UCBRFx = int ( (78.125-78)*16) = 2
	     */
	UCA0BR0 = 78;                                 // 12.000.000 / 16 / 9.600 = 78,125
	UCA0BR1 = 0x00;
	UCA0MCTLW = 0x1000 | UCOS16 | 0x0020;
	UCA0CTLW0 &= ~UCSWRST;                        // Initialize eUSCI
	UCA0IE |= UCRXIE;                             // Enable USCI_A0 RX interrupt


	// ==========Configurazione Real Time Clock==========
    RTCCTL0_H = RTCKEY_H;                    // Unlock RTC key protected registers
    RTCCTL0_L &= ~RTCTEVIE;                  // Interrupt disable
    RTCCTL0_L &= ~(RTCTEVIFG);
    RTCCTL1 = RTCBCD | RTCHOLD;              // RTCTEVx -> 00b = Minute changed event
    // RTC enable, BCD mode, RTC hold
    // enable RTC read ready interrupt
    // enable RTC time event interrupt
    RTCCTL1 &= ~(RTCHOLD);                    // Start RTC calendar mode
    RTCCTL0_H = 0;                            // Lock the RTC registers

    NVIC_ISER0 = 1 << ((INT_RTC_C - 16) & 31);

	// ==========Inizializzazione==========
    //fan_off();
    led_off();							// Led msp spento (si accende solo alle acquisizioni)
    IR_off();							// Led IR spento
    set_rtc("2000-01-01 00:00:00");		// Setto rtc

	__sleep();
	//while(1);
}


// ===========================Interrupt Service Routines===========================
/* it doesn't work!!!!
void ADC14_IRQHandler(void) {
	values[index_N] = ADC14MEM0;
	index_N++;
	if (index_N >= N) {
		TA0CCTL1 &= ~OUTMOD_M;
		ADC14CTL0 &= ~ADC14ENC;
		led_off();
                send_all_values();
	}
}
*/

// Timer A0 interrupt service routine
void TimerA0_0IsrHandler(void) {
    TA0CCTL0 &= ~CCIFG;
    /* STEP = 20; Tempo di campionamento compreso tra adc_start, adc_end; Riempio array e invio su seriale */
	if(microsecondi > TIME_ADC_START && microsecondi <= TIME_ADC_END) {
		ADC14CTL0 |= ADC14ENC | ADC14SC; // Start sampling/conversion; Enable and start conversion.
		//sprintf(micro, "%07d\n", microsecondi);	// Converto da intero a stringa dentro variabile micro
		//send(com_LOG, micro);						// ---------->USED TO CONTROL TIMERA AND FREQUENCY
		values[index_N] = ADC14MEM0;				// Scrive valore buffer nell'array
		index_N++;									// Incrementa indice array
	}
    switch (microsecondi){
		case TIME_ON:	// Accendo IR
			IR_on();
			//send(com_LOG, "IR_ON\n");
			break;
		case TIME_OFF:	// Spengo IR
			IR_off();
			//send(com_LOG, "IR_OFF\n");
			break;
			case TIME_SAVE:	// Invio valori
				if (index_N >= N){
					index_N = 0;
					microsecondi = 0;
					TA0_off();
					led_off();
					send_all_values();
				}
		default:
			break;
		}
    microsecondi += STEP;	// Interrupt ogni STEP
    if (microsecondi >= TIME_RESET){
    	microsecondi = 0;
    }
}


// UART interrupt service routine (Seriale)
void eUSCIA0IsrHandler(void) {
	/* Eseguita quando viene ricevuto un byte sulla seriale.
	 * Se il byte e' 10 (\n) chiama received che elabora il messaggio ricevuto
	 */
    if (UCA0IFG & UCRXIFG) {
		while(!(UCA0IFG & UCTXIFG));
		RXByte = UCA0RXBUF;
		RXData[index_RX++] = RXByte;
		if(RXByte==10) {
		  index_RX=0;
		  received();
		}
    }
}

// RTC interrupt service routine (essendo in real time VA IN MINUTI vedi configurazione SOPRA rtc)
void RtcIsrHandler(void) {
    if (RTCCTL0 & RTCTEVIFG) {
    	// Evento abilitato in modalita' automatica, accade ogni minuto
    	if (minuti == 0){
    		TA0_on();
			led_on();
    	}
		minuti++;
		if (minuti >= T) {
			minuti = 0;
			microsecondi = 0;
		}
	}
    // Chiudo l'interrupt flag
	RTCCTL0_H = RTCKEY_H;
	RTCCTL0_L &= ~RTCTEVIFG;
	RTCCTL0_H = 0;
}

  • Hi Luca,

    So your only issue is using a timer to trigger the ADC conversion? It looks like previously you would use a software trigger inside of the timer ISR. Try using a timer source other than one which uses an ISR to complete tasks. A list of ADC14 trigger signal connections is shown in Table 6-51 of the datasheet. Simplify your code to an ADC trigger-sourced example before posting it to the forum. Here is another E2E post with a link to an example that you could find useful: e2e.ti.com/.../467153

    Regards,
    Ryan

**Attention** This is a public forum