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.

Multiple ADC10 Inputs.

Other Parts Discussed in Thread: MSP430G2452

Hello...

I am using MSP430G2452 with launch kit pad. And I need to use the multiple ADC10 inputs.

I have tried to get it with the sample code attached bellow:

Sample Code:

//******************************************************************************
//  MSP430G2x32/G2x52 Demo - ADC10, DTC Sample A2-0, AVcc, Single Sequence, DCO
//
//  Description: Sample A3/A2/A1 as single sequence with reference to AVcc.
//  Software sets ADC10SC to trigger sample sequence. In Mainloop MSP430 waits
//  in LPM0 to save power until ADC10 conversion complete, ADC10_ISR(DTC) will
//  force exit from any LPMx in Mainloop on reti. ADC10_ISR will force any LPMx
//  exit. ADC10 internal oscillator times sample period (16x) and conversion
//  (13x). DTC transfers conversion code to RAM 200h - 206h. P1.0 set at start
//  of conversion burst, reset on completion.
//
//               MSP430G2x32/G2x52
//            -----------------
//        /|\|              XIN|-
//         | |                 |
//         --|RST          XOUT|-
//           |                 |
//       >---|P1.3/A3      P1.0|-->LED
//       >---|P1.2/A2          |
//       >---|P1.1/A1          |
//
//  D. Dang
//  Texas Instruments Inc.
//  December 2010
//  Built with CCS Version 4.2.0 and IAR Embedded Workbench Version: 5.10
//******************************************************************************
#include  "msp430g2452.h"

void main(void)
{
  WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT
  ADC10CTL1 = INCH_3 + CONSEQ_1;            // A3/A2/A1, single sequence
  ADC10CTL0 = ADC10SHT_2 + MSC + ADC10ON + ADC10IE;
  ADC10DTC1 = 0x03;                         // 3 conversions
  ADC10AE0 |= 0x0E;                         // P1.3,2,1 ADC10 option select
  P1DIR |= 0x01;                            // Set P1.0 output

  for (;;)
  {
    ADC10CTL0 &= ~ENC;
    while (ADC10CTL1 & BUSY);               // Wait if ADC10 core is active
    ADC10SA = 0x200;                        // Data buffer start
    P1OUT |= 0x01;                          // P1.0 = 1
    ADC10CTL0 |= ENC + ADC10SC;             // Sampling and conversion start
    __bis_SR_register(CPUOFF + GIE);        // LPM0, ADC10_ISR will force exit
    P1OUT &= ~0x01;                         // P1.0 = 0
  }
}

// ADC10 interrupt service routine
#pragma vector=ADC10_VECTOR
__interrupt void ADC10_ISR(void)
{
  __bic_SR_register_on_exit(CPUOFF);        // Clear CPUOFF bit from 0(SR)
}

//**************************************************************************************************

I want to know how to get separately the values from the 3 ADC10  inputs.

With a single input ADC10, I have already got with the "ADC10MEM".

If someone could help me, I will appreciate so much.

Furthermore, I have a question, Does the MSP430G2452 have different ADC10 modules  or just one shared ADC10 module?

In Advance, Thanks.

  • Pedro Bacheti said:
    I want to know how to get separately the values from the 3 ADC10  inputs.

    Two ways: Eithe royu reporgram the ADC10 input channel after each conversion, or you use the sequence mdoe, in which the ADC10 will sampel all channels starting from 0 to the maximum channel given by INCH_x. However, after each conversion, ADC10MEM needs to be read, either by an ISR, by busy-waiting or by using the DMA-like transfer controller.

    Pedro Bacheti said:
    Furthermore, I have a question, Does the MSP430G2452 have different ADC10 modules  or just one shared ADC10 module?

    Only one. And an input miltiplexer. Like the ADC12 and most of the SD16/SD24 ADCs. Only the few MSPs specifically designed for power line metering (e.g. the MSP430AFE2x) do have multiple ADCs (up to 7), as there synchronous sampling is required.

  • Thanks for your answer, Michael Gross.

    I know I have to read one adc input after another, but I don't know how to do it.

    Could you send me a example code or tell me what registers I have to change?

    I am using MSP430G2452.

    In advance, Thanks so much.

  • Hello,

    you can select the input channel for conversion manually with

    ADC10MEM0 - ADC10INCHx
    Bits 3-0 Input channel select. Writing these bits select the channel for a single-conversion or the highest channel
    for a sequence of conversions. Reading these bits in ADC10CONSEQ = 01,11 returns the channel
    currently converted. ADC10INCHx is not synchronized, so a read while the state machine is not in "wait
    for enable" or "wait for trigger" could lead to a wrong result.

    If you do not want to do a multiple sample and conversion as offered by ADC10, you can switch the input port manually and start the conversion by hand.


    Kind regards Marco

  • Hello,

    I've tried to do  the conversion manually with the below code, but I didn't get success.

    Could you show me what is wrong in this code, please?

    In this code I've just got to read one input port from ADC10MEM.

    In advance thanks.

    Code:

    ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    #include <msp430g2452.h>

    //  MASCÁRAS DE HARDWARE:
    #define UART_TXD   0x02                     // TXD on P1.1 (Timer0_A.OUT0)
    #define UART_RXD   0x04                     // RXD on P1.2 (Timer0_A.CCI1A)

    #define P_X0       0x01                     // pin1.0 -> ADC (TC)
    #define P_X1       0x02                     // pin1.1 -> TXD
    #define P_X2       0x04                     // pin1.2 -> RXD
    #define P_X3       0x08                     // pin1.3 -> S2
    #define P_X4       0x10                     // pin1.4 -> BJT1
    #define P_X5       0x20                     // pin1.5 -> BJT2
    #define P_X6       0x40                     // pin1.6 -> LED2
    #define P_X7       0x80                     // pin1.7 -> ----

    // (Conditions for 2400 Baud SW UART, SMCLK = 1MHz):
    #define UART_TBIT_DIV_2     (1000000 / (2400 * 2))
    #define UART_TBIT           (1000000 / 2400)

    //  VARIAÁVEIS GLOBAIS:
    int cont=0, quant1=0, quant2=0;
    unsigned int valorad1, valorad2;
    unsigned int op1, op2, aux1=0, aux2, mx1[10], mx2[10];
    double tensao, iprimario, isecundario, potencia, consumo=0;
    //unsigned int16 tensao, iprimario, isecundario, potencia, consumo=0;

    unsigned int txData;                        // UART internal variable for TX
    unsigned char rxBuffer=0, txBuffer;         // Received UART character
    //int txBuffer;

    //  FUNÇÕES:

    void calc(unsigned int AD);
    void abre(void);
    void fecha(void);
    unsigned int max(unsigned int adc);

    void TimerA_UART_init(void);
    void TimerA_UART_tx(unsigned char byte);
    void TimerA_UART_print(char *string);

    void clk_init(void);



    #pragma optimize=none
    void delay_ms (unsigned int msec)
    {
       unsigned int asec;
       while(msec--)
       {
           asec = 500;
           while(asec--)
           {
               asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");
               asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");
               asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");
           }
       }
    }



    /*---------------------------------------------------------------------------------------*/
    //    Rotina Principal:
    /*---------------------------------------------------------------------------------------*/

    void main(void)
    {
      WDTCTL = WDT_MDLY_32;                     // WDT ~45ms interval timer  
      IE1 |= WDTIE;                             // Enable WDT interrupt
     
      clk_init();
    //  ADC10CTL1 = INCH_4 + CONSEQ1;
      ADC10CTL0 = ADC10SHT_0 + REFON + ADC10ON;
      ADC10AE0 |= P_X4 + P_X5;
      ADC10DTC1 = 0x02;                             

      P1OUT = 0x00;
      P1SEL = P_X1 + P_X2;
      P1DIR = P_X1 + P_X4 + P_X5 + P_X6 + P_X7;
     
      P2DIR = P_X0 + P_X1 + P_X2 + P_X3 + P_X4 + P_X5;
     
      P1IE  = P_X3;                             // P1.3 interrupt enabled (button)
      P1IES = P_X3;                            // P1.3 Hi/lo edge
      P1IFG = ~P_X3;                           // P1.3 IFG cleared
     
      __enable_interrupt();
     
       TimerA_UART_init();                     // Start Timer_A UART
    //   TimerA_UART_print("Smart Plug\r\n");
    //   TimerA_UART_print("Ligado.\r\n\n");
    //   TimerA_UART_print("\nCOMANDOS\nD - Desligar\nL - Ligar\nM - Medir\n");
    //   TimerA_UART_print("\nDigite o Comando: \r");
     
      while(1)
      {
        __bis_SR_register(LPM0_bits + GIE);     // LPM0, WDT_ISR will force exit
        
        ADC10CTL1 = INCH_4 + CONSEQ_0;
    //    ADC10CTL0 = ADC10SHT_0 + REFON + ADC10ON;
    //    ADC10AE0 |= P_X4;
    //    ADC10DTC1 = 0x01;      
        
        ADC10CTL0 &= ~ENC;
        ADC10SA = 0x200;        // Data transfer location
        ADC10CTL0 |= ENC + ADC10SC;             // Start sampling
        valorad1 = ADC10MEM;
        ADC10CTL0 &= ~ENC;
        
        ADC10CTL1 = INCH_5 + CONSEQ_0;
    //    ADC10CTL0 = ADC10SHT_0 + REFON + ADC10ON;
    //    ADC10AE0 |= P_X5;
    //    ADC10DTC1 = 0X01;
        
        ADC10CTL0 &= ~ENC;
        ADC10SA = 0x220;        // Data transfer location
        ADC10CTL0 |= ENC + ADC10SC;             // Start sampling
        valorad2 = ADC10MEM;
        ADC10CTL0 &= ~ENC;
        
        
        op1 = max(valorad1);
        
        if(op1 != 0)
        {
          mx1[quant1] = op1;
          quant1++;
          aux1=0;
          if(quant1 >= 10)
          {
           quant1=0;
          }
        }
        
        op2 = max(valorad2);
        
        if(op2 != 0)
        {
          mx2[quant2] = op2;
          quant2++;
          aux1=0;
          if(quant2 >= 10)
          {
           quant2=0;
          }
        }
        
    //    ADC10CTL1 = INCH_5 + CONSEQ_1;
    //    ADC10CTL0 = ADC10SHT_2 + REFON + MSC + ADC10ON;
    //    ADC10AE0 |= P_X5;
    //    ADC10DTC1 = 0x04;
    //    
    //    ADC10CTL0 &= ~ENC;
    ////    ADC10SA = 0x400;        // Data transfer location
    //    ADC10CTL0 |= ENC + ADC10SC;             // Start sampling
    //    valorad2 = ADC10MEM;
        
    //    txBuffer = ADC10MEM;
    //    calc(valorad1);
        if(rxBuffer != 0)
        {
          switch(rxBuffer)
          {
          case 'D':
            abre();
            cont++;        
            rxBuffer=0;
            break;
          case 'L':
            fecha();
            cont=0;
            rxBuffer=0;
            break;
          case 'M':
    //        TimerA_UART_print("\nValor lido AD: \n");
    //        TimerA_UART_print("\nCorrente lida: \n");
    //        TimerA_UART_print("\nPotêcia Instantanea: \n");        
            TimerA_UART_tx(txBuffer);
            rxBuffer=0;
            break;
          }   
        }
      }
    }

    /*---------------------------------------------------------------------------------------*/
    //      Tratamento das Funções e Interrupções:
    /*---------------------------------------------------------------------------------------*/


    //    Interrupções:

    #pragma vector = WDT_VECTOR
    __interrupt void WDT_ISR(void)
    {
      __bic_SR_register_on_exit(LPM0_bits);     // Exit LPM0
    }

    // Port 1 interrupt service routine
    #pragma vector=PORT1_VECTOR
    __interrupt void Port_1(void)
    {
      if(cont == 0)
      {
        abre();
        cont++;
      }
      else
      {
        fecha();
        cont=0;
      }  
      P1IFG &= ~0x08;                           // P1.3 IFG cleared
    }


    //------------------------------------------------------------------------------
    // Timer_A UART - Transmit Interrupt Handler
    //------------------------------------------------------------------------------
    #pragma vector = TIMER0_A0_VECTOR
    __interrupt void Timer_A0_ISR(void)
    {
        static unsigned char txBitCnt = 10;

        TACCR0 += UART_TBIT;                    // Add Offset to CCRx
        if (txBitCnt == 0) {                    // All bits TXed?
            TACCTL0 &= ~CCIE;                   // All bits TXed, disable interrupt
            txBitCnt = 10;                      // Re-load bit counter
        }
        else {
            if (txData & 0x01) {
              TACCTL0 &= ~OUTMOD2;              // TX Mark '1'
            }
            else {
              TACCTL0 |= OUTMOD2;               // TX Space '0'
            }
            txData >>= 1;
            txBitCnt--;
        }
    }      
    //------------------------------------------------------------------------------
    // Timer_A UART - Receive Interrupt Handler
    //------------------------------------------------------------------------------
    #pragma vector = TIMER0_A1_VECTOR
    __interrupt void Timer_A1_ISR(void)
    {
        static unsigned char rxBitCnt = 8;
        static unsigned char rxData = 0;

        switch (__even_in_range(TAIV, TAIFG)) { // Use calculated branching
            case TA0IV_TACCR1:                        // TACCR1 CCIFG - UART RX
                TACCR1 += UART_TBIT;                 // Add Offset to CCRx
                if (TACCTL1 & CAP) {                 // Capture mode = start bit edge
                    TACCTL1 &= ~CAP;                 // Switch capture to compare mode
                    TACCR1 += UART_TBIT_DIV_2;       // Point CCRx to middle of D0
                }
                else {
                    rxData >>= 1;
                    if (TACCTL1 & SCCI) {            // Get bit waiting in receive latch
                        rxData |= 0x80;
                    }
                    rxBitCnt--;
                    if (rxBitCnt == 0) {             // All bits RXed?
                        rxBuffer = rxData;           // Store in global variable
                        rxBitCnt = 8;                // Re-load bit counter
                        TACCTL1 |= CAP;              // Switch compare to capture mode
                        __bic_SR_register_on_exit(LPM0_bits);  // Clear LPM0 bits from 0(SR)
                    }
                }
                break;
        }
    }

    //    Funções:

    void calc(unsigned int AD)
    {
        tensao = AD*1.1116*3.41797E-3;          // Cálculo da tensão no resistor (1K) [Fator de conversão 1.1116 Vmédia e Vrms (0,707 / 0,636 = 1.1116)]
        isecundario = tensao/1E3;               // Corrente que passa no resistor (1K)
        iprimario = isecundario*2500;           // Corrente que na carga real (valor a ser medido)
        potencia = iprimario*127;
        if(potencia == 0)
        {
         txBuffer=50;
        }
        else
        {
    //      txBuffer = potencia;
        }
    }


    void clk_init(void)
    {
    //    DCOCTL = 0x00;                          // Set DCOCLK to 1MHz
    //    BCSCTL1 = CALBC1_1MHZ;
    //    DCOCTL = CALDCO_1MHZ;
        
        DCOCTL = XT2S_2;                          // Set DCOCLK to 16MHz
        BCSCTL1 = CALBC1_16MHZ;
        DCOCTL = CALDCO_16MHZ;
    }
    //------------------------------------------------------------------------------
    // Function configures Timer_A for full-duplex UART operation
    //------------------------------------------------------------------------------
    void TimerA_UART_init(void)
    {
        TACCTL0 = OUT;                          // Set TXD Idle as Mark = '1'
        TACCTL1 = SCS + CM1 + CAP + CCIE;       // Sync, Neg Edge, Capture, Int
        TACTL = TASSEL_2 + MC_2;                // SMCLK, start in continuous mode
    }
    //------------------------------------------------------------------------------
    // Outputs one byte using the Timer_A UART
    //------------------------------------------------------------------------------
    void TimerA_UART_tx(unsigned char byte)
    //void TimerA_UART_tx(int byte)
    {
        while (TACCTL0 & CCIE);                 // Ensure last char got TX'd
        TACCR0 = TAR;                           // Current state of TA counter
        TACCR0 += UART_TBIT;                    // One bit time till first bit
        TACCTL0 = OUTMOD0 + CCIE;               // Set TXD on EQU0, Int
        txData = byte;                          // Load global variable
        txData |= 0x100;                        // Add mark stop bit to TXData
        txData <<= 1;                           // Add space start bit
    }

    //------------------------------------------------------------------------------
    // Prints a string over using the Timer_A UART
    //------------------------------------------------------------------------------
    void TimerA_UART_print(char *string)
    {
        while (*string) {
            TimerA_UART_tx(*string++);
        }
    }

    void abre()
    {
      P1OUT &= ~P_X7;
      delay_ms(50);
      P1OUT |= P_X6;
      delay_ms(50);
      P1OUT &= ~P_X6;    
    }

    void fecha()
    {
      P1OUT &= ~P_X6;
      delay_ms(50);
      P1OUT |= P_X7;
      delay_ms(50);
      P1OUT &= ~P_X7;
    }

    unsigned int max(unsigned int adc)
    {   
      unsigned int m=0;
      int dif;
     
      aux2 = adc;
      dif = aux2 - aux1;
      if(dif<0 & aux2>5)
      {
        m = aux1;
      }
      else
      {
        aux1 = aux2;
      }
     
      return m;    
    }

    ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

  • Pedro Bacheti said:

     I want to know how to get separately the values from the 3 ADC10  inputs.

    The ADC data is automatically placed in ram starting at    " ADC10SA = 0x200;    // Data buffer start"

    Use the debugger to inspect values

  • I already know that, but when I read the ADC10MEM, it is setted the same value to the both input ADC10 ports.

    Even when I change the input port reading.

    Did you see my code?

    Have you ever got the separately value from different ports with MSP430G2452?

    If yes, could you send me your code?

    Thanks.

  • In your code I noticed that you change the channel before clearing ENC. Most bits in ADC10CTL0 and 1 can only be changed when ENC is clear. So likely, your attempts to change the channel are futile because ENC is still set when you try :)

**Attention** This is a public forum