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 adc14 clock divider

Hello, i have a question about adc14div_x of msp432. If we set DCO = 24Mhz and SMCLK = 12Mhz and this clock (smclk) is the source clock of adc14, then if i want to sample every 10 microsecond (it means that every 10us i want the value converted and in memory from adc14mem), so have i set the adc14 clock or set adc14div_x to give him the correct frequency??

an example of code could be:

CSKEY = 0x695A;                    // Unlock CS module for register access
CSCTL0 = 0;                        // Reset tuning parameters
CSCTL0 = DCORSEL_4;                // Set DCO to 24MHz
CSCTL1 = CSCTL1 & ~(SELS_M | DIVS_M); // Clear existing registers
CSCTL1 = CSCTL1 | (SELS_3 | DIVS_1); // For SMCLK, select DCO as source then divide by 2
CSKEY = 0;                         // Lock CS module from unintended accesses

P6SEL1 |= BIT1;
P6SEL0 |= BIT1;    // adc pin

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

In this case i have 96S&H cycles + 16Conversion(14 bit) --> 96+16/12Mhz = 9.3 us (<10us). Is it correct this?

I add that the start conversion is in Timer_A of msp432. In particulart the code is set as:

void TimerA0_0IsrHandler(void) {
TA0CCTL0 &= ~CCIFG;
if(microseconds > 0 && microseconds <= 1000) {
	ADC14CTL0 |= ADC14SC; // Start sampling/conversion; Enable and start conversion.
	values[index_N] = ADC14MEM0;	
	index_N++;	
}
[......]

Where microsecond is a variable that increments with timer_A (set to 1Mhz -> 1us)

Thanks

  • Hi Luca!

    Your approach looks more like you want to ensure that the conversion takes about 10µs with the side effect that there is a conversion each 10µs when having repeated sampling.

    A timer could trigger a new conversion every 10µs.

    Dennis
  • Using my example how can i make this? I'm not expert :( In my code I need to start conversion and finish on schedule. And I thought this was the most effective system so that I can be sure that ADC conversion is only between 50 and 1000 (or more times)
  • Hi Luca!

    Maybe you want to explain the desired functionality a little bit more in detail. What exactly shall happen? Do you need the long S&H time or was it just to extend the time to ~10µs?

    Dennis

  • I have a sensor that turn on and off a IR_led. In this period i want sampling with adc. So for example i start sampling from 0 to 1000 (while the led turn on at time 50 and turn off at time 450). All time are expressed in microsecond. My problem is sampling rate: i'm trying to find the right frequency of adc that determines the number of samples. For this i use a timer that counts. Every step (that i decide in variable STEP) i have a sample of adc.

    The comunication from msp and me is with a software written in python that send parameters and other commands.

    i hope this help you. Sorry if my english is not perfect. If you want i post my code here.

    #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			10		//	10 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]
    int secondi = 0;		   // contatore di secondi del Real Time Clock
    
    // indici contatori array
    int index_N = 0;           // contatore campioni                            [0 - N]
    
    // variabili acquisizione
    uint16_t values[200];    // 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(){
    	//fan_on();
    	RTCCTL0_H = RTCKEY_H;
    	RTCPS1CTL |= RT1PSIE;
    	RTCCTL0_H = 0;}
    void auto_off(){
    	//fan_off();
    	RTCCTL0_H = RTCKEY_H;
    	RTCPS1CTL &= ~RT1PSIE;
    	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;
    	}
    }
    
    void error(void)
    {
        volatile uint32_t z;
        P1DIR |= BIT0;
        while (1)
        {
            P1OUT ^= BIT0;
            for(z=0;z<20000;z++);       // Blink LED forever
        }
    }
    
    // ===========================Funzioni adc===========================
    int main(void)
    {
    	// ==========Configurazioni di base==========
    	uint32_t currentPowerState;
    	WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer
    
    	/* Step 1: Transition to VCORE Level 1: AM0_LDO --> AM1_LDO */
    	currentPowerState = PCMCTL0 & CPM_M;
    	if (currentPowerState != CPM_0)
    		error();
    
    	while ((PCMCTL1 & PMR_BUSY));
    	PCMCTL0 = PCM_CTL_KEY_VAL | AMR_1;
    	while ((PCMCTL1 & PMR_BUSY));
    	if (PCMIFG & AM_INVALID_TR_IFG)
    		error();                            // Error if transition was not successful
    	if ((PCMCTL0 & CPM_M) != CPM_1)
    		error();                            // Error if device is not in AM1_LDO mode
    
    	/* Step 2: Configure Flash wait-state to 2 for both banks 0 & 1 */
    	FLCTL_BANK0_RDCTL = FLCTL_BANK0_RDCTL & ~FLCTL_BANK0_RDCTL_WAIT_M | FLCTL_BANK0_RDCTL_WAIT_0;
    	FLCTL_BANK1_RDCTL = FLCTL_BANK0_RDCTL & ~FLCTL_BANK1_RDCTL_WAIT_M | FLCTL_BANK1_RDCTL_WAIT_0;
    
    	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 (24Mhz)==========
    	P6SEL1 |= BIT1;
    	P6SEL0 |= BIT1;    // Canale A14 (P6.1) configurato per ADC
    
    	//NVIC_ISER0 = 1 << ((INT_ADC14 - 16) & 31);
    
    	ADC14CTL0 &= ~ADC14ENC;							  //Turn off Enable. With few exceptions, the ADC14 control bits can only be modified when ADC14ENC = 0.
    	ADC14CTL0 = ADC14ON | ADC14SHT0_5 | ADC14CONSEQ_2 | ADC14SSEL_4 | ADC14SHP | ADC14SHS_0;   // Turn on ADC14, set sampling time, repeat single channel (ssel = mclk)
    	ADC14CTL1 = ADC14RES__14BIT;                      // Use sampling timer, 14-bit conversion results (16 clock cycles)
    	ADC14MCTL0 = ADC14VRSEL_0 | ADC14INCH_14;         // A0 ADC input select; Vref=AVCC=3.3V
    	//ADC14CLRIFGR0 |= ADC14IFG0;
    	ADC14IER0 |= ADC14IE0;
    	ADC14CTL0 |= ADC14ENC;                          // ADC enable
    
    
    	// ==========Configurazione clock a 24 MHz==========
    	CSKEY = 0x695A;                    // Unlock CS module for register access
    	CSCTL0 = 0;                        // Reset tuning parameters
    	CSCTL0 = DCORSEL_4;                // Set DCO to 24MHz
    	CSCTL1 = CSCTL1 & ~(SELS_M | DIVS_M); // Clear existing registers
    	//CSCTL1 = SELM_3; // Se uso mclk come adc = 24Mhz. Se uso smclk tolgo
    	CSCTL1 = CSCTL1 | (SELS_3 | DIVS_1); // For SMCLK, select DCO as source then divide by 2 (SMCLK = 12Mhz for serial it works)
    	//CSCTL1 = SELA_2 | SELS_3 | SELM_3; // Select ACLK = REFO, SMCLK = MCLK = DCO
    	CSKEY = 0;                         // Lock CS module from unintended accesses
    
    	/* Step 4: Output MCLK to port pin to demonstrate 12MHz operation */
    	P4DIR |= BIT3;
    	P4SEL0 |=BIT3;
    	P4SEL1 &= ~(BIT3);
    
    
    	// ==========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)
    	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
        RTCPS1CTL &= ~RT1PSIE;					 // Interrupt disable
        RTCPS1CTL |= RT1IP_6;					 // 128Hz / 128 = 1Hz (contatore 1 secondo)
        RTCPS1CTL &= ~(RT1PSIFG);
        RTCCTL1 = RTCBCD | RTCHOLD;              // BCD select (calendar register), RTCHOLD counters and prescale counters actived
        // 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);
    }
    
    
    // Timer A0 interrupt service routine
    void TimerA0_0IsrHandler(void) {
        TA0CCTL0 &= ~CCIFG;
    	if(microsecondi > TIME_ADC_START && microsecondi <= TIME_ADC_END) {
    		ADC14CTL0 |= 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
    		//while(!(ADC14IFGR0 & BIT0));				// Controlla che non abbia finito
    		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
    void RtcIsrHandler(void) {
        if (RTCPS1CTL & RT1PSIFG) {
        	// Evento abilitato in modalita' automatica, accade ogni minuto
        	if (secondi == 0){
        		TA0_on();
    			led_on();
        	}
    		secondi++;
    		if (secondi >= T) {
    			secondi = 0;
    			microsecondi = 0;
    		}
    	}
        // Chiudo l'interrupt flag
    	RTCCTL0_H = RTCKEY_H;
    	RTCPS1CTL &= ~RT1PSIFG;
    	RTCCTL0_H = 0;
    }
    

    Scheme:

    | 0 adc start -- | 50 turn On led -- | 450 tunr Off led -- | 1000 adc end -- | send values -- | end cycle -- | ......... repeat cycle every 2 seconds (parameter)

**Attention** This is a public forum