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.

Achieve ADC 1MSPS

Hello every one!!!

I would like to know how to achieve the 1MSPS adc coversion with my MSP432, The first thing that I do is save all the ADC data in a vector(ADC_14_BUF), after that, I transfer the data from the MSP to my computer with UART to see the resolution of the ADC.

The signal is a sinewave with 4000 Hz(in the first photo 1000Hz but in the graphics 4000 Hz), as you can se it does not look like a signal that is sampled with a speed of 1MSPS :'v, Searching some information, I found that the only way to achieve the 1MSPS ADC is using DMA, but I only found DMA examples of the MSP using the DriverLib library. DMA would be another way instead of saving the information in my ADC_14_BUF vector. 

-Is DMA the only way to achieve 1MSPs, if it is, Why???

-There are DMA examples for MSP432 that dont use the DriverLib librarie???

Code:

#include "msp.h"
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#define length(x) (sizeof(x)/sizeof(x[0]))

volatile short ADC_14_BUF[32488];

//volatile short BUF_8[15000];
volatile long BUF_32;
volatile short i=0,j=1;
volatile long x=0,b=0,v=0;
static short s=length(ADC_14_BUF);

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

/*---------------------------------------------------------------------------------------------------------*/
    //Configuracion de la señal de CLK
  CS->KEY = 0x695A;                        // Unlock CS module for register access
  CS->CTL0 = 0;                            // Reset tuning parameters
  CS->CTL0 = CS_CTL0_DCORSEL_5;                   // Set DCO to 48MHz (nominal, center of 8-16MHz range)
                                           // Select ACLK = REFO, SMCLK = MCLK = DCO
  CS->CTL1 = CS_CTL1_SELA_2 | CS_CTL1_SELS_3 | CS_CTL1_SELM_3;
  CS->KEY = 0;                             // Lock CS module from unintended accesses
/*---------------------------------------------------------------------------------------------------------*/

  // Configure GPIO
  P5SEL1 |= BIT5;       // Enable A/D channel A0-A3
  P5SEL0 |= BIT5;

  __enable_interrupt();
  NVIC->ISER[0] = 1 << ((ADC14_IRQn) & 31);// Enable ADC interrupt in NVIC module

  ADC14->CTL0 = ADC14_CTL0_ON | ADC14_CTL0_MSC | ADC14_CTL0_SHT0__4 | ADC14_CTL0_SHP | ADC14_CTL0_CONSEQ_3; // Turn on ADC14, extend sampling time
  ADC14->CTL1 = ADC14_CTL1_RES_2;         // Use sampling timer, 12-bit conversion results

                                                                              // to avoid overflow of results

  ADC14->MCTL[0] = ADC14_MCTLN_INCH_0;                 // ref+=AVcc, channel = A0
  ADC14->IER0 = ADC14_IER0_IE0;                     // Enable ADC14IFG.3

  SCB->SCR &= ~SCB_SCR_SLEEPONEXIT_Msk;             // Wake up on exit from ISR

/*---------------------------------------------------------------------------------------------------------*/
    // Configuracion de los puertos UART
    P1SEL0 |= BIT2 | BIT3;                  // set 2-UART pin as second function

    __enable_interrupt();
    NVIC->ISER[0] = 1 << ((EUSCIA0_IRQn) & 31); // Enable eUSCIA0 interrupt in NVIC module

    // Configuracion de UART
    UCA0CTLW0 |= UCSWRST;
    UCA0CTLW0 |= UCSSEL__SMCLK;             // Pone eUSCI en reseteo
    UCA0BR0 = 26;                           // 48000000/16/9600
    UCA0MCTLW = 0x1000 | 0x0020 | UCOS16;

    UCA0BR1 = 0;
    UCA0CTLW0 &= ~UCSWRST;                  // Inicializa eUSCI
    UCA0IE |= UCRXIE;                       // habilita la interrupcion USCI_A0 RX
/*---------------------------------------------------------------------------------------------------------*/

    while(1)
    {
    ADC14->CTL0 |= ADC14_CTL0_ENC | ADC14_CTL0_SC;        // Start conversion-software trigger

    }

}


// ADC14 interrupt service routine
void ADC14_IRQHandler(void)
{
    if (ADC14->IFGR0 & ADC14_IFGR0_IFG3)

    	{
			ADC_14_BUF[i++] = ADC14->MEM[0];
    	}
//			for(i=0;i<= s+1;i++){ADC_14_BUF[i] = ADC14->MEM[0];}

		    if(i >= s)
		    {
		      if(j <= s)
		      {

		    	for(v=0;v<=4799;v++)								//ESPERA
		    	  {while(!(UCA0IFG&UCTXIFG));UCA0TXBUF = 'i';}

		    	for(j=0;j <= s-2;j=j+2)   //s+1
		    	{
					BUF_32= ADC_14_BUF[j+1];
					BUF_32= (BUF_32<<12)|ADC_14_BUF[j];
					//ADC_14_BUF[j+1]<<12;
					while(!(UCA0IFG&UCTXIFG));
//					BUF_8[x]=(BUF_32 & 0x000000FF);x=x+1;
					UCA0TXBUF = (BUF_32 & 0x000000FF);
					while(!(UCA0IFG&UCTXIFG));
//					BUF_8[x]=(BUF_32 & 0x0000FF00)>>8;x=x+1;
					UCA0TXBUF = (BUF_32 & 0x0000FF00)>>8;
					while(!(UCA0IFG&UCTXIFG));
//					BUF_8[x]=(BUF_32 & 0x00FF0000)>>16;x=x+1;
					UCA0TXBUF = (BUF_32 & 0x00FF0000)>>16;

		    	}

		    	j=s+10;
		      }
		      BUF_32=0x00000000;
		      i=s+10;
		    }// acanga abajo va el codigo de desplazamiento
}

/*---------------------------------------------------------------------------------------------------------*/
// Rutina de interrupcion de UART
void EUSCIA0_IRQHandler(void)
{
   if (UCA0IFG & UCRXIFG)
    {
//      while(!(UCA0IFG&UCTXIFG));
    }
}
/*---------------------------------------------------------------------------------------------------------*/

  • Are you seriously trying to send characters over UART in a busy-loop, within the ADC interrupt ? That's not gonna work.

    First, sending a char takes much longer than the ADC interrupt frequency (1us). Thus your ADC results overflow, resulting in a much lower effective sampling rate.

    Second, the required (UART) baudrate to transfer more than 16 MBit/s is a bit out of range, both on sender and on receiver side.

  • Hi Josue!

    The MSP432P401R is capable of transmitting UART messages at a maximum of 3 MBaud. Keep in mind that a UART byte normally consists of 10 bits: 1 start bit, 8 data bits and 1 stop bit. This means that if you wanted to send data of an ADC with 14 bits at 1 MSPS, you would have to send 2 bytes for each conversion. This means 1.000.000 samples x 2 bytes x 10 bits = 20 MBaud (hopefully I'm not wrong with that now...I'm on holiday in Italy and had a few glasses of wine already). So although the MSP432's UART is quite fast, it is not fast enough to transmit this amount of data. And f.m. is right - never wait for something in an interrupt service routine. You can try to work with the DMA to achieve at least better results.

    Dennis

  • How about this, first save the ADC data and then send them trougth UART:

    #include "msp.h"
    #include <stdint.h>
    #include <stdio.h>
    #include <string.h>
    #define length(x) (sizeof(x)/sizeof(x[0]))
    
    volatile short ADC_14_BUF[32488];
    
    //volatile short BUF_8[15000];
    volatile long BUF_32;
    volatile short i=0,j=1;
    volatile long x=0,b=0,v=0;
    static short s=length(ADC_14_BUF);
    
    int main(void)
    {  WDTCTL = WDTPW+WDTHOLD;                   // Stop watchdog timer
    
    /*---------------------------------------------------------------------------------------------------------*/
        //Configuracion de la señal de CLK
      CS->KEY = 0x695A;                        // Unlock CS module for register access
      CS->CTL0 = 0;                            // Reset tuning parameters
      CS->CTL0 = CS_CTL0_DCORSEL_5;                   // Set DCO to 48MHz (nominal, center of 8-16MHz range)
                                               // Select ACLK = REFO, SMCLK = MCLK = DCO
      CS->CTL1 = CS_CTL1_SELA_2 | CS_CTL1_SELS_3 | CS_CTL1_SELM_3;
      CS->KEY = 0;                             // Lock CS module from unintended accesses
    /*---------------------------------------------------------------------------------------------------------*/
    
      // Configure GPIO
      P5SEL1 |= BIT5;       // Enable A/D channel A0-A3
      P5SEL0 |= BIT5;
    
      __enable_interrupt();
      NVIC->ISER[0] = 1 << ((ADC14_IRQn) & 31);// Enable ADC interrupt in NVIC module
    
      ADC14->CTL0 = ADC14_CTL0_ON | ADC14_CTL0_MSC | ADC14_CTL0_SHT0__4 | ADC14_CTL0_SHP | ADC14_CTL0_CONSEQ_3; // Turn on ADC14, extend sampling time
      ADC14->CTL1 = ADC14_CTL1_RES_2;         // Use sampling timer, 12-bit conversion results
    
                                                                                  // to avoid overflow of results
    
      ADC14->MCTL[0] = ADC14_MCTLN_INCH_0;                 // ref+=AVcc, channel = A0
      ADC14->IER0 = ADC14_IER0_IE0;                     // Enable ADC14IFG.3
    
      SCB->SCR &= ~SCB_SCR_SLEEPONEXIT_Msk;             // Wake up on exit from ISR
    
    /*---------------------------------------------------------------------------------------------------------*/
        // Configuracion de los puertos UART
        P1SEL0 |= BIT2 | BIT3;                  // set 2-UART pin as second function
    
        __enable_interrupt();
        NVIC->ISER[0] = 1 << ((EUSCIA0_IRQn) & 31); // Enable eUSCIA0 interrupt in NVIC module
    
        // Configuracion de UART
        UCA0CTLW0 |= UCSWRST;
        UCA0CTLW0 |= UCSSEL__SMCLK;             // Pone eUSCI en reseteo
        UCA0BR0 = 26;                           // 48000000/16/9600
        UCA0MCTLW = 0x1000 | 0x0020 | UCOS16;
    
        UCA0BR1 = 0;
        UCA0CTLW0 &= ~UCSWRST;                  // Inicializa eUSCI
        UCA0IE |= UCRXIE;                       // habilita la interrupcion USCI_A0 RX
    /*---------------------------------------------------------------------------------------------------------*/
    
        while(i <= s)
        {
        ADC14->CTL0 |= ADC14_CTL0_ENC | ADC14_CTL0_SC;        // Start conversion-software trigger
        }
    /*------------			---------------------------			---------------------		------------------*/
    
        for(v=0;v<=4799;v++)                                //ESPERA
        {while(!(UCA0IFG&UCTXIFG));UCA0TXBUF = 'i';}
    
        for(j=0;j <= s-2;j=j+2)   //s+1
        {
        BUF_32= ADC_14_BUF[j+1];
        BUF_32= (BUF_32<<12)|ADC_14_BUF[j];
        while(!(UCA0IFG&UCTXIFG)); UCA0TXBUF = (BUF_32 & 0x000000FF);
        while(!(UCA0IFG&UCTXIFG)); UCA0TXBUF = (BUF_32 & 0x0000FF00)>>8;
        while(!(UCA0IFG&UCTXIFG)); UCA0TXBUF = (BUF_32 & 0x00FF0000)>>16;
        }
        j=s+10;
    }
    /*------------			---------------------------			---------------------		------------------*/
    /*---------------------------------------------------------------------------------------------------------*/
    // ADC14 interrupt service routine
    void ADC14_IRQHandler(void)
    {
    //    if (ADC14->IFGR0 & ADC14_IFGR0_IFG3)
    //    	{
    			ADC_14_BUF[i++] = ADC14->MEM[0];
    //    	}
    }
    
    /*---------------------------------------------------------------------------------------------------------*/
    // Rutina de interrupcion de UART
    void EUSCIA0_IRQHandler(void)
    {
       if (UCA0IFG & UCRXIFG)
        {
        }
    }
    /*---------------------------------------------------------------------------------------------------------*/

  • I don't know the MSP432 UART specific in detail, but sending sequentially (after sampling, without real-time requirements) should work.
    When thinking about UART communication to PC, don't forget to take the other side into account. Baudrates of 115200 and 230400 often work fine, but above that, the trouble starts. Cheap unmatched/unshielded cables distort the signal, and the OS of desktop PC doesn't treat the "legacy" RS232 as real-time communication. If you need continuous data (streaming), consider USB or I2S.

**Attention** This is a public forum