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.
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!
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