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.

msp430f1611 adc12 sampling

Other Parts Discussed in Thread: MSP430F1611, MSP430F149

hi,

for MSP430F1611,  I collect samples at 19047 Hz using Timer A

i have a code that collects n number of samples and stores in a ADC12MEM0

All i need to do is to collect the samples in such a way that the 33rd sample is added to the 1st sample 34th  to 2nd sample and so on.. and finally an array of 32 samples

how do i read from the memory buffer?you in nadvance

how do i do this calculation..

i have attatched the code that collects all samples to ADC12MEM0

please help me with the code,

 

//ICC-MSP application builder [F149] : 11/24/2010 3:45:20 PM
//Target 14x device
#include <msp430x16x.h>
#include <msp430def.h>
#include <stdio.h>
#include <math.h> 

volatile  unsigned int sample[32];
void clock(void)
{
 WDTCTL = WDTPW +WDTHOLD;                  // Stop Watchdog Timer
  DCOCTL = DCO0 + DCO1 + DCO2;             // Max DCO
  BCSCTL1 = RSEL0 + RSEL1 + RSEL2;         // XT2on, max RSEL
  BCSCTL2 |= SELS;                         // SMCLK = XT2
    while(1)
  {
  }
} 
void port_init()
{
 P1OUT=0x00;
 P1DIR=0x00;
 P1IES=0x00;
 P1IE=0x00;
 P1SEL=0x00;
 P2OUT=0x00;
 P2DIR=0x00;
 P2IES=0x00;
 P2IE=0x00;
 P2SEL=0x00;
 P3OUT=0x00;
 P3DIR=0x00;
 P3SEL=0x00;
 P4OUT=0x00;
 P4DIR=0x00;
 P4SEL=0x00;
 P5OUT=0x00;
 P5DIR=0x00;
 P5SEL=0x00;
 P6OUT=0x00+BIT2;
 P6DIR=0x04;
 P6SEL=0x00;
}
void timera_init()
//Clock source=SMCLK
//Divider=1
//TIMACLK=4.0000MHz
//Frequency=19.048KHz ( 52.50uS)
{
 TACTL=0x00; //stop timer
 //channel0
 TACCTL0=0x14;//TAOM0.1,TAOM0.0,TACCIE0,TAOUT0
  TACCR0=0xD2;
 //channel1
 TACCTL1=0x00;
 TACCR1=0x00;
 //channel2
 TACCTL2=0x00;
 TACCR2=0x00;
 TAR=0x0000;//clear timer counter
 TACTL=0x216;//TASSEL.1,TAMC.0,1,TAIE
}

void adc12_init()
{
 ADC12CTL0=0x00;
 ADC12CTL1=0x616;//SHS.0,SHP,ADC12SSEL.1,CONSEQ.1,CONSEQ.0
 ADC12IE=0x8000;
 ADC12CTL0=0xFFF2;//SHT1.3,SHT1.2,SHT1.1,SHT1.0,SHT0.3,SHT0.2,SHT0.1,SHT0.0,ADC12MSC,ADC122_5V,ADC12REFON,ADC12ON,ADC12ENC
}

void usart0_init()
//Clock source=SMCLK
//Desired baud=19200
//Actual  baud=19196
{
 UCTL0=0x10;//CHAR0
 UTCTL0=0x20;//SSEL0.1
 URCTL0=0x08;//URXEIE0
 U0BR1=0x00;
 U0BR0=0xD0;
 UMCTL0=0xA2;
}

//call this routine to initialise all peripherals
void init_devices(void)
{
 //stop errant interrupts until set up
 DINT(); //disable all interrupts
 ME1=0X00; //disable sfr peripherals
 ME2=0X00; 
 IE1=0x00; //disable sfr interrupts
 IE2=0x00; 
 //watchdog initialisation including nmi function
 //WDTCTL=0x5A00 | 0x00;
 WDTCTL=0x5A00 | 0x10;//TMSEL
 //initialise other peripherals

 port_init();
 
 timera_init();
 adc12_init();
 usart0_init();
 clock();

 ME1=0xC0;
 ME2=0x00;
 IE1=0x00;
 IE2=0x00;
 EINT(); //re-enable interrupts
}

//interrupt handlers 

void init_adc12(void)
{
 ADC12CTL0=SHT0_15+SHT1_15+ADC12ON+REFON+MSC; 
 ADC12CTL1=CONSEQ_2+ADC12SSEL_2+ADC12DIV_0+SHP+SHS_1+CSTARTADD_0;
 ADC12MCTL0=ADC12MCTL1=ADC12MCTL2=ADC12MCTL3=SREF_1+INCH_9;
 ADC12MCTL4=ADC12MCTL5=ADC12MCTL6=ADC12MCTL7=SREF_1+INCH_9;
 ADC12MCTL8=ADC12MCTL9=ADC12MCTL10=ADC12MCTL11=SREF_1+INCH_9;
 ADC12MCTL12=ADC12MCTL13=ADC12MCTL14=SREF_1+INCH_9;	
 ADC12MCTL15=SREF_1+INCH_9+EOS;	//Vr+=Vref+;//ADC12MEM15 is End Of Sequence
 ADC12IE = 0x8000;     // Enable ADC12IFG0=>ADC12MEM0 //after 16 sequence conversions ADC12MEM15 sets
 ADC12CTL0|=ENC;     //Enable conversions
}//end adc12

void init_timera(void)
 { 
   	TACCTL0 = OUTMOD_1;
	TACCTL0 = CCIE;
	TACCR0=0xD2;
  	TACTL = TASSEL_2 + MC_1; 
}
	
//interrupt handlers 

void main(void)
{
 
 init_devices();
 init_adc12();
 init_timera();
}// end for main


#pragma interrupt_handler timera_0_isr:TIMERA0_VECTOR
void timera_0_isr(void)
{
volatile  unsigned int a;

while(1)
	{
	   ADC12CTL0|=ADC12SC;
	   while ((ADC12IFG & 0x8000)==0); // CHECK FOR CONVERSIONS
	   sample[a]=ADC12MEM0;//Access results
	} 
  	 
}

 

thanking you in advance 

  • Hi shruthi,

    the code below is taken from the MSP430F1611 code examples (http://www.ti.com/litv/zip/slac015n). Should be no problem to convert it to your needs.

    Rgds
    aBUGSworstnightmare

    //******************************************************************************
    //  MSP-FET430P140 Demo - ADC12, Repeated Sequence of Conversions
    //
    //  Description: This example shows how to perform a repeated sequence of
    //  conversions using "repeat sequence-of-channels" mode.  AVcc is used for the
    //  reference and repeated sequence of conversions is performed on Channels A0,
    //  A1, A2, and A3. Each conversion result is stored in ADC12MEM0, ADC12MEM1,
    //  ADC12MEM2, and ADC12MEM3 respectively. After each sequence, the 4 conversion
    //  results are moved to A0results[], A1results[], A2results[], and A3results[].
    //  Test by applying voltages to channels A0 - A3. Open a watch window in
    //  debugger and view the results. Set a breakpoint in the last line to see the
    //  array values change sequentially.
    //
    //  Note that a sequence has no restrictions on which channels are converted.
    //  For example, a valid sequence could be A0, A3, A2, A4, A2, A1, A0, and A7.
    //  See the MSP430x1xx User's Guide for instructions on using the ADC12.
    //
    //
    //                 MSP430F149
    //            -----------------
    //           |                 |
    //   Vin0 -->|P6.0/A0          |
    //   Vin1 -->|P6.1/A1          |
    //   Vin2 -->|P6.2/A2          |
    //   Vin3 -->|P6.3/A3          |
    //           |                 |
    //
    //
    //  M. Mitchell
    //  Texas Instruments Inc.
    //  Feb 2005
    //  Built with CCE Version: 3.2.0 and IAR Embedded Workbench Version: 3.21A
    //******************************************************************************

    #include  <msp430x14x.h>

    #define   Num_of_Results   8

    static unsigned int A0results[Num_of_Results];  // These need to be global in
    static unsigned int A1results[Num_of_Results];  // this example. Otherwise, the
    static unsigned int A2results[Num_of_Results];  // compiler removes them because
    static unsigned int A3results[Num_of_Results];  // they are not used

    void main(void)
    {
      WDTCTL = WDTPW+WDTHOLD;                   // Stop watchdog timer
      P6SEL = 0x0F;                             // Enable A/D channel inputs
      ADC12CTL0 = ADC12ON+MSC+SHT0_8;           // Turn on ADC12, extend sampling time
                                                // to avoid overflow of results
      ADC12CTL1 = SHP+CONSEQ_3;                 // Use sampling timer, repeated sequence
      ADC12MCTL0 = INCH_0;                      // ref+=AVcc, channel = A0
      ADC12MCTL1 = INCH_1;                      // ref+=AVcc, channel = A1
      ADC12MCTL2 = INCH_2;                      // ref+=AVcc, channel = A2
      ADC12MCTL3 = INCH_3+EOS;                  // ref+=AVcc, channel = A3, end seq.
      ADC12IE = 0x08;                           // Enable ADC12IFG.3
      ADC12CTL0 |= ENC;                         // Enable conversions
      ADC12CTL0 |= ADC12SC;                     // Start conversion
      _BIS_SR(LPM0_bits + GIE);                 // Enter LPM0, Enable interrupts
    }

    #pragma vector=ADC12_VECTOR
    __interrupt void ADC12ISR (void)
    {
      static unsigned int index = 0;

      A0results[index] = ADC12MEM0;             // Move A0 results, IFG is cleared
      A1results[index] = ADC12MEM1;             // Move A1 results, IFG is cleared
      A2results[index] = ADC12MEM2;             // Move A2 results, IFG is cleared
      A3results[index] = ADC12MEM3;             // Move A3 results, IFG is cleared
      index = (index+1)%Num_of_Results;         // Increment results index, modulo; Set Breakpoint here
    }

  • Thank you for your immediate reply,

     

     I had written  th code based on this demo, The problem is that I use only one input channel and internal reference voltage for input.

    I need to collect the set of 32 array as output.

    Query is that

    1) if my initialisation of ADC and Interrupt Service Routine correct?

    2) can the memory buffer store the array of 32 values?

    3) if the calculation excecutable?

     

    //ICC-MSP application builder [F149] : 11/9/2010 1:11:08 PM
    //Target 14x device
    
    #include <msp430x16x.h>
    #include <msp430def.h>
    #include <stdio.h>
    #include <math.h> 
    
    #define CR 0x0a
    #define LF 0x0d 
    
    char lcd_display1[16]; //Display-Speicher Zeile 1
    char lcd_display2[16]; //Display-Speicher Zeile 2
    
    volatile int a,b,i,j,k;
    volatile unsigned int adcvalue[32],data[1024];
    
    void clock_init()
    {
      //DCO=0x00
     DCOCTL=0x00;
     BCSCTL2=0x88;//SELM.1,SELS
     BCSCTL1=0x00;
    }
    
    void port_init()
    {
     P1OUT=0x00;
     P1DIR=0x00;
     P1IES=0x00;
     P1IE=0x00;
     P1SEL=0x00;
     P2OUT=0x00;
     P2DIR=0x00;
     P2IES=0x00;
     P2IE=0x00;
     P2SEL=0x00;
     P3OUT=0x00;
     P3DIR=0x00+BIT4;
     P3SEL=0x00+BIT4;
     P4OUT=0x00;
     P4DIR=0x00;
     P4SEL=0x00;
     P5OUT=0x00;
     P5DIR=0x00;
     P5SEL=0x00;
     P6OUT=0x03;
     P6DIR=0x00;
     P6SEL=0x00;
    }
    
    void timera_init()
    //Clock source=SMCLK
    //Divider=1
    //TIMACLK=4.0000MHz
    //Frequency=19.048KHz ( 52.50uS)
    {
     TACTL=0x00; //stop timer
     //channel0
     TACCTL0=0x34;//TAOM0.1,TAOM0.0,TACCIE0,TAOUT0
     TACCR0=0xD2;
     //channel1
     TACCTL1=0x00;
     TACCR1=0x00;
     //channel2
     TACCTL2=0x00;
     TACCR2=0x00;
     TAR=0x0000;//clear timer counter
     TACTL=0x216;//TASSEL.1,TAMC.0,1,TAIE
    }
    
    void adc12_init()
    {
     ADC12CTL0=0x00;
     ADC12CTL1=0x610;//SHS.0,SHP,ADC12SSEL.1
     ADC12IE=0x00;
     ADC12CTL0=0x7F2;//ADC12MSC,ADC122_5V,ADC12REFON,ADC12ON,ADC12ENC
    }
    void usart0_init()
    //Clock source=SMCLK
    //Desired baud=19200
    //Actual  baud=19196
    {
     UCTL0=0x10;//CHAR0
     UTCTL0=0x20;//SSEL0.1
     URCTL0=0x08;//URXEIE0
     U0BR1=0x00;
     U0BR0=0xD0;
     UMCTL0=0xA2;
    }
    
    //call this routine to initialise all peripherals
    void init_devices(void)
    {
     //stop errant interrupts until set up
     DINT(); //disable all interrupts
     ME1=0X00; //disable sfr peripherals
     ME2=0X00; 
     IE1=0x00; //disable sfr interrupts
     IE2=0x00; 
     //watchdog initialisation including nmi function
     //WDTCTL=0x5A00 | 0x00;
     WDTCTL=0x5A00 | 0x10;//TMSEL
     //initialise other peripherals
     clock_init();
     port_init();
     timera_init();
     adc12_init();
     usart0_init();
    
     ME1=0xC0;
     ME2=0x00;
     IE1=0x00;
     IE2=0x00;
     EINT(); //re-enable interrupts
    }
    
    //interrupt handlers 
    
    void init_adc12(void)
    {
    ADC12CTL0=SHT0_15+SHT1_15+ADC12ON+REFON+MSC;
     //ADC12CTL0=SHT0_8+ADC12ON+REFON; 
     ADC12CTL1=CONSEQ_0+ADC12SSEL_2+ADC12DIV_0+SHP+SHS_0+CSTARTADD_0;
    // ADC12CTL1=CONSEQ_0+SHP;
     ADC12MCTL15=SREF_1+INCH_1+EOS;	//Vr+=Vref+
     ADC12IE = 0x8000;
     ADC12CTL0|=ENC;     //Enable conversions
    }//end adc12
    
    void init_timera(void)
     { 
       	TACCTL0 = OUTMOD_1;
    	P6DIR = P6DIR | BIT2;
        TACCTL0 = CCIE;
    	TACCR0=0xD2;
      	TACTL = TASSEL_2 + MC_1; 
    }
    
    
     void wait(unsigned int xxx,unsigned int yyy)
    {
    unsigned int iii,jjj;
     	for (jjj=0;jjj<yyy;jjj++)
    	 {
    	 for (iii=0;iii<xxx;iii++) 
    	    {
         	}
          }
    } //End Wait
    
    
    void ausgabee(unsigned char text[]) //Textoutput with Enter
    {
    int i=0;
    while (text[i] != 0)
    {
     TXBUF0 = text[i];
     wait(3,5);
     i++;
    }
    //print
     TXBUF0 = CR; //return
     wait(5,5);
     TXBUF0 = LF; //Line feed
     wait(5,5);
    }//end output
    
    //main code entry point
    
    //SAMPLE FOR 210 MASTER CLK CYCLES
    void main(void)
    {
     init_devices();
     init_adc12();
     init_timera();
     clock_init();	 
    
     }// end for main
    
    #pragma interrupt_handler timera_0_isr:TIMERA0_VECTOR
    void timera_0_isr(void)
    {
    for(k=0;k<1024;k++)
    	{
    		 ADC12CTL0|=ADC12SC;
    		 while(!(ADC12IFG&0x8000)); // CHECK FOR CONVERSIONS
    		 data[k]=ADC12MEM0;//Access results
    	}
    }	
    #pragma interrupt_handler adc12_isr:ADC_VECTOR
    void adc12_isr(void)
    {
    volatile  unsigned int count=0;
    for(i=0;i<32;i++)
    	{
    	 for(j=0;j<data[k];j+=32)
    		{
    	   	  adcvalue[j]=adcvalue[j]+adcvalue[32*i+j];
    	    }
    	 count++;
    	}
     	//adcvalue[j]=ADC12MEM1;//Access results
    		 P6OUT = P6OUT ^ BIT2;	
    		 sprintf(lcd_display1,"AdcValue=%d ",adcvalue[j]);
    		 ausgabee(lcd_display1);		
    	}
    

     

    thanking you in advance !!!!

     

  • Sorry for not answering you in the other thread - I was a bit busy in the last days and still didn't catch up with the forum. And I didn't have the time to look into your code.
    I'm currently busy writing code for drawing a Sankey diagram in Flex. Which isn't trivial and consumes much time if you want it done right.

    I haven't forgotten you, but looking into source code just consumes too much time at the moment. Sorry.

    shruthi akash said:
    The problem is that I use only one input channel

    ADC12MEMx and input channels form a cross matrix. There is no fixed relation of memory and channel. You can use all 16 ADC12MEMx to sample the same input channel one after another. Or to sample any two channels in alternating order or to sample all 16 in any order you like. It just depends on the configuration of the ADC12MCTLx registers.

    You cannot, however, set up the ADC12 to automatically sample more than 16 values in a row without additional software interception.

  • Hi Michael,

     

    your help has been a valuable thing for me. Hope your work is going good.

     

    Jens-Michael Gross said:

    You cannot, however, set up the ADC12 to automatically sample more than 16 values in a row without additional software interception.

    yeah today while i was going through the samples, i found i was able to collect only 16 samples.

    What exactly do you mean by 'software interception'?

    how do i do that?

    code:

    volatile unsigned long int adcvalue[32],count=0;//global variable

    volatile unsigned int data[1024],i,j,k;

    void main(void)

    {

      init_devices();

     init_adc12();

      init_timera();

     clock();

     for(i=0;i<32;i++)

    {

    for(j=0;j<data[k];j+=32)

    {

       adcvalue[j]=adcvalue[j]+adcvalue[32*i+j];

       }

    count++;

    }

    }

    #pragma interrupt_handler timera_0_isr:TIMERA0_VECTOR

    void timera_0_isr(void)

    {

      ADC12CTL0|=ADC12SC;

      while(!(ADC12IFG&0X0001)); // CHECK FOR CONVERSIONS

     data[k]= ADC12MEM0;//Access results   

    }

    What should i do to make this code excecute?

     

    Thanking you !!!!

  • shruthi akash said:
    your help has been a valuable thing for me.

    And your problem has raised some questions which caused me to check some things, so I had some benefits too :)

    shruthi akash said:
    Hope your work is going good.

    Currently stalled. Writing algorithms under ActionScript is not a problem, btu now I'm batteling with the Flex framework, and this is not easy. The onlien documentation seems to be offline most of the time (extreme loading times up to connection timeouts) and the typical search terms are so generic that google will list almost half of the pages in their database, whether related or not.

    shruthi akash said:
    What exactly do you mean by 'software interception'?

    The ADC an only hold 16 results. Even if you set it up properly, it will either stop after at most 16 samples or start overwriting the first. So at latest after the 16th sdample has been taken, you'll need to copy them.
    It's better to set an IE flag for the 7th and 15th, so you have 8 sample time to copy the first or second half of the 16 instead of having to handle all 16 before the first is overwritten (fouble buffering).

    The ADC10 did not have individual memory registers, but was able to copy the result of n samples into memory.

    There is, however, a way to simulate this. This can be done with using DMA. The ADC is running in repeated single conversion mode, and every ADC interupt will trigger a DMA transfer. so you can set the DMA up to copy 32 samples in a row, get a DMA interrupt, reconfigure the DMA for copying the next block to a different buffer and operate the first row of samples. It will, however, tighten the maximum latency, so the DMA is reconfigured before the next sample is ready.

    Using a timer for triggering the samples and using DMA for copying the results is rather advanced stuff.

  • shruthi akash said:
    void timera_0_isr(void)
    {
      ADC12CTL0|=ADC12SC;
      while(!(ADC12IFG&0X0001)); // CHECK FOR CONVERSIONS
    data[k]= ADC12MEM0;//Access results  
    }

    Hmmm, where does 'k' come from?
    You write a conversion result to data[k], yet in main you _loop_ from 0 to data[k]

    Rather go for the following:

    global:
    unsigned int ready = 0;

    init_adc12():
    ADC12IE |= ADC12IE0;

    void timera_0_isr(void)
    {
      ADC12CTL0|=ADC12SC;
    }

    #pragma interrupt_handler adc12_isr:ADC12_VECTOR
    void adc12_isr(void)
    {
     static unsigned int x = 0;
    data[x++]=ADC12MEM0;
      if (x==32) {
        x= 0;
        ready = 1;

      }
    }

    main:
    while(1)
    {
      while(!ready);
      for(j=0;j<32;;j+=32)
      adcvalue[j]+=data[j];
      ready=0;
    }

     

    this code will wait for 32 values arrived at data[0..31], then add them to adcvalue[0..31]. Each sample is triggered by the timer (this can be automated later using the SHS bit)
    It shouldn't be a problem to change it so it will write to a continuous or moving buffer (data[0..1023], add the values up as required, and then copy the buffer down by 32 (for continued sampling). There ar emany different solutions possible.
    It is, however, better to let the ADC sample two times 8 conversions (setting ADC12IE7 and ADC12IE15), then copy eight at a time in the ADC ISR (it requires detecting which half of the 16  values has beenjsut sampled, but that's easy - you can use (&ADC12MEM0)[x] to access the memory registers as an array of unsigned ints.
    This requires, however, a proper setting of the ADC12 clock and the S&H times or using the automatic timer triggering, or you'd get  bursts of samples rather than equidistant ones.

     

  • Hi Michael,

    Yeah your approach to the progran is good,

    there is a different problem

    Jens-Michael Gross said:

    init_adc12():

    ADC12IE |= ADC12IE0;

    error :undeclared identifier `ADC12IE0'

    why does this error occur?

    Jens-Michael Gross said:

    data[x++]=ADC12MEM0;

     adcvalue[j]+=data[j];

    Error: type error: pointer expected

    I compile in ICC 430 .What is the correction required?

    Thank you.

    (Do you work in Germany?)

     

  • shruthi akash said:
    error :undeclared identifier `ADC12IE0'

    Strange. It should be there as it is an alias used in the datasheet. Maybe it was not defined in your header files by accident. BIT0 does the same (or 0x0001), but ADC12IE0 is more descriptive.

    shruthi akash said:
    Error: type error: pointer expected

    That's strange. Both, data and adcvalue, should be arrays of int. So these assignments should properly compile. Maybe I misinterpreted their definition in your code. But then, you used them similarly:

    shruthi akash said:
    data[k]= ADC12MEM0;//Access results

    So there shouldn't be a problem.

    shruthi akash said:
    (Do you work in Germany?)

    Not only work :)

  • Hi Michael;

    I am sorry for the late reply, had my exams :-) and still 2 more to go ;-)

    admist this the project deadline also holds me tight :-(

    Anyway

    Jens-Michael Gross said:

    It is, however, better to let the ADC sample two times 8 conversions (setting ADC12IE7 and ADC12IE15), then copy eight at a time in the ADC ISR (it requires detecting which half of the 16  values has been just sampled, but that's easy - you can use (&ADC12MEM0)[x] to access the memory registers as an array of unsigned ints.

    I don understand this logic, sorry.

     I had to collect 32 samples in a variable and pass it on to the FFT process wherein my input is sensor signal that is 0-2.5v

    and I am not going to restrict my samples to 1024 instead to n*32 where "n"  depends on the fft process (this is for digital compass)

    When ADC12MEM0 cannot hold all the 32 values (for adding sample values ) how do i do it in two sets?

     

    Thanking you

    Shruthi 

     

     

     

  • hi,

    #pragma interrupt_handler adc12_isr:ADC12_VECTOR

    void adc12_isr(void)

    {

     static unsigned int x = 0,y=16,k;

    data[x++]=ADC12MEM0;

    data[y++]=ADC12MEM1;

      x=(32*n);

      y=(48*n); 

       for(j=0;j<16;j+=16)

       {

      adcvalue_x[j]+=data[j]; 

      }

       for(k=0;k<32;k+=32)

       {

       adcvalue_y[k]+=data[k]; 

       }

        n++;

      {

        x= 0;

        ready = 1;

    }

    }

    Does this store 32 values?

    First 16 samples in ADC12MEM0 ,and second 16 in ADC12MEM1 ?

    Could you help me in the above?

    Thanking you!!!

     

     

     

  • shruthi akash said:
    (&ADC12MEM0)[x]

    is a plain standard C construct. It takes the memory address of ADC12MEM0 as base address pointer to an array of int values. So (&ADC12MEM0)[0] returns the value of ADC12MEM0, (&ADC12MEM0)[1] is the value stored in ADC12MEM1 etc. It's just a different way to look at teh memory registers -not as 16 individual and independent registers but as an array of results.

    Since there are nly 16 ADC12MEM registers, and ny one of them will only hold one result of the last conversion done on the associated logical channel, you cannot colect 32 values at a time. You have to collect them in at least 2 chunks of 16 values, or (better, as it relaxes the timing constraints) in 4 chunks of 8 results.

    Let me lay it out as an event chain:

    AD is programmed for all of its 16 logical channels (ADC12CTL0..15) to sample the same physical channel, ove rand over again.
    ADC samples 8 values into ADC12MEM0..ADC12MEM7
    as soon as teh result has arrived in ADC12MEM7, an interrupt is generated (by having the ADC12IE7 bit set)
    The ISR will check for the ADC12IFG7 bit, to determine whcih half of the 16 registers to process, then it will copy these 8 results to the memory where all the results are stored.
    In the meantime, the ADC will continue sampling to ADC12MEM8..15.
    Once there, another itnerrupt is generated (by having the ADC12IE15 bit set too)
    The ISR will be called once mor, detects that this time the ADC12IFG15 bit is set and therefore the second 8 bytes have to be copied. A static variable will hold a flag which is now set to show that half of the 32 values have been read.
    In the meantime the ADC is sampling new values to ADC12MEM0..7
    Another call to the ISR. Again it is ADC12IFG7 that is set and ADC12MEM0..7 have to be copied. But since therewas the global flag set, this time they go to byte 17..24 of the result memory.
    One the ADC has finished samping the next 8 reults, the ISr is called once more and will see that thsi time byte 25..32 need to be copied form ADC12MEM8..15.
    Once done, 32 bytes have been received, teh ISR will advance the buffer it writes to and signal the main that all data for the next run have arrived.

     

    The advantage of this double-buffering approach is that you have 8 conversion times for storing 8 bytes of data before the ADC will overwrite the first result. If you jsut read it by one channel, you only have one conversion time to handle one data byte.On the average this makes no difference (except that you save 7 ISR entry/exit sequences), but that's unimportant. If you cannot handle the job per result in the average sampling time, then you're hosed anyway as your data would quickly build up unprocessed. The main advantag eis that you have a longer timeframe to react at all.

    It's like with a diver: If  adiver doesn't come back to surface for breathing every, say, 2 minutes, he'll die. If he has an air tank, hel'll not consume less oxygen, but he don't have to come back to the surface that often without dying. Then refilling the flash will take longer than just breathing, so the average downtime is the same, but the timing is way more relaxed.

  • Hello Michael,

     

    I need to sample a continuous sine wave using ADC12 in MSP430F1611.

    what are the register settings of ADC12 that are required?

    the input to adc (sine wave) is at port P6.0.

    reference voltage is 2.5v, sampling rate is 19.047 Khz

    I collect it as an array of 32 samples (adcvalue[32]).

     

    this is my register setting

     

    unsigned int M;

    volatile unsigned long int adcvalue[32] = {0};

    volatile unsigned long int data[32];

    int i,j;

    unsigned int ready = 0;

     

    void init_adc12(void)

    {

     ADC12CTL0=SHT0_1+ADC12ON+REFON; // switch on reference voltage , ref=2.5

     ADC12CTL1=CONSEQ_3+SHP; //repeated sequence of channels

     ADC12MCTL0=SREF_1+INCH_1+EOS; //Vr+=Vref+

     ADC12IE =0x01;

     ADC12CTL0|=ENC;     //Enable conversions

    }

    void init_timera(void)

       TACCTL0 = OUTMOD_1; // timer mode is Output

    TACCTL0 = CCIE; // route to interrupt service routine

    TACCR0=0xD2; // timer ticks at 210

       TACTL = TASSEL_2 + MC_1;     // SMCLK

    }

     

     

    #pragma interrupt_handler adc12_isr:ADC_VECTOR

    void adc12_isr(void)

    {

     static unsigned int x = 0;

     data[x++]=ADC12MEM0; 

        if (x==32) 

      {

        x= 0;

        ready = 1;

      }

     

    }

    #pragma interrupt_handler timera_0_isr:TIMERA0_VECTOR

    void timera_0_isr(void)

    {

      ADC12CTL0|=ADC12SC;  

    }

     

    void main(void)

    {

     init_timera();

    init_adc12();

     

    for(i=0;i<M;i++)

     {

      while(!ready);

      for(j=0;j<32;j++)

      adcvalue[j]+=data[j];// samples in M*32

      ready=0;

     } 

    }

     

    what shout be the port initialisation?

    I get samples only at first array value.. other values are zero.

    What would be the problem?

    do I have to change the ADC settings?

    if so please help me...

     

    its urgent

    Thanking you

     

  • Jens-Michael Gross said:

    this code will wait for 32 values arrived at data[0..31], then add them to adcvalue[0..31]. Each sample is triggered by the timer (this can be automated later using the SHS bit)

    It shouldn't be a problem to change it so it will write to a continuous or moving buffer (data[0..1023], add the values up as required, and then copy the buffer down by 32 (for continued sampling). There are many different solutions possible.
    It is, however, better to let the ADC sample two times 8 conversions (setting ADC12IE7 and ADC12IE15), then copy eight at a time in the ADC ISR (it requires detecting which half of the 16  values has beenjsut sampled, but that's easy - you can use (&ADC12MEM0)[x] to access the memory registers as an array of unsigned ints.
    This requires, however, a proper setting of the ADC12 clock and the S&H times or using the automatic timer triggering, or you'd get  bursts of samples rather than equidistant ones.

     

    Hi

    I am getting the data values as required while sampling the sine wave, the problem is that when I have to add the data[j] to adcvalue[j] 32 times i get the value as zero...

    I dont understand why doesnt it give the added array value..

     

     help me on this case...

     

    Thank you,

     

     

     

     

  • shruthi akash said:
    I dont understand why doesnt it give the added array value..

    Maybe I'm blind, but I don't see why this could fail...

    If adcvalue[] is still unsigned long, there is no overflow.

    How do you know that it fails? Do you look at the results in the debugger? Maybe it's a debugger problem? I remember a different thread about the debugger not properly showing unsigned long variables or arrays.

  • Ya I look the output on NoIce Debugger with Watch

    but the sampling doesnt occur at the required sampling rate..

    there is a problem with the sampling timer. Timer A output is perfect but the samples  are not at the required interval

    Could you please have a look on the code and tell me the corrections

     

    //ICC-MSP application builder [F149] : 11/24/2010 3:45:20 PM
    //Target 16x device
    #include <msp430x16x.h>
    #include <msp430def.h>
    #include <stdio.h>
    #include <math.h> 
    
    unsigned int M=32;
    volatile unsigned long int adcvalue[32] = {0};
    volatile unsigned long int data[32];
    int i,j;
    volatile unsigned int ready = 0;
    
    void clock(void)
    {
     
     volatile unsigned int ic;
     WDTCTL = WDTPW +WDTHOLD;                 	// Stop Watchdog Timer
      BCSCTL1 &= ~XT2OFF;
      do
      {
       IFG1 &= ~OFIFG;
       for(ic=0xFF;ic>0;ic--);
      } 
      while((IFG1 & OFIFG));         		   
      BCSCTL2 |=  SELM_2+SELS;  
    } 
    
    void port_init(void)
    {
     P1OUT=0x00;
     P1DIR=0x00;
     P1IES=0x00;
     P1IE=0x00;
     P1SEL=0x00;
     P2OUT=0x00;
     P2DIR=0x00;
     P2IES=0x00;
     P2IE=0x00;
     P2SEL=0x00;
     P3OUT=0x00;
     P3DIR=0x00;
     P3SEL=0x00;
     P4OUT=0x00;
     P4DIR=0x00;
     P4SEL=0x00;
     P5OUT=0x10;
     P5DIR=0x10;
     P5SEL=0x10;
     P6OUT=0x00;
     P6DIR=0x00;
     P6SEL=0x00+BIT0;
    }
    
    void init_adc12 (void)
    {
     ADC12CTL0=SHT0_7+ADC12ON+REFON+REF2_5V+MSC; // switch on reference voltage , ref=2.5
     ADC12CTL1=CONSEQ_3+SHS_0+ADC12SSEL_2+SHP; //repeated sequence of channels
     ADC12MCTL0=SREF_1+INCH_0+EOS;	 //Vr+=Vref+
     ADC12IE=0x01;
    ADC12CTL0|=ENC
    }
    void init_timera(void)
    { 
      	
      	TACCTL0 = OUTMOD_3;			 // timer mode is  set/reset
        	TACCR0=0xD2;				 // timer ticks at 210
      	TACTL = TASSEL_2 + MC_1; 		 // SMCLK and Up mode
    		
    }
    void usart0_init(void)
    //Clock source=SMCLK
    //Desired baud=19200
    //Actual  baud=19196
    {
     UCTL0=0x10;//CHAR0
     UTCTL0=0x20;//SSEL0.1
     URCTL0=0x08;//URXEIE0
     U0BR1=0x00;
     U0BR0=0xD0;
     UMCTL0=0xA2;
    }
    //interrupt handlers
    
    //call this routine to initialise all peripherals
    void init_devices(void)
    {
     //stop errant interrupts until set up
     DINT(); //disable all interrupts
     ME1=0X00; //disable sfr peripherals
     ME2=0X00; 
     IE1=0x00; //disable sfr interrupts
     IE2=0x00; 
     //watchdog initialisation including nmi function
     //WDTCTL=0x5A00 | 0x00;
     WDTCTL=0x5A00 | 0x10;//TMSEL
     //initialise other peripherals
    
     port_init();
     usart0_init();
     init_adc12();
     init_timera();
     clock();
    
     ME1=0x00;
     ME2=0x00;
     IE1=0x00;
     IE2=0x00;
     EINT(); //re-enable interrupts
    }
    
    //interrupt handlers 
    
    
    #pragma interrupt_handler adc12_isr:ADC_VECTOR
    void adc12_isr(void)
    {
    
     static unsigned int x = 0;
    ADC12CTL0|=ADC12SC+ENC;
     data[x++]=ADC12MEM0; 
    
      if (x==32) 
      {
        x= 0;
        ready = 1;
    	
      }
    }
    
    void main(void)
    
    {
     init_devices();
     sinewave();
     
     while(1)
    
    {
    	 while(!ready);
    	 for(j=0;j<32;j++)
      	 adcvalue[j]+=data[j];// samples in M*32
    	 ready=0;  
    }
    
    /*============================================================================*/
    /*                                                                            */
    /* ----------------------------- Signal generation   ------------------------ */
    /*                                                                            */
    /*============================================================================*/
    static int Sin_tab[32] =
    {
    1843,
    2202,
    2548,
    2867,
    3145,
    3375,
    3545,
    3650,
    3686,
    3650,
    3545,
    3375,
    3146,
    2867,
    2548,
    2202,
    1843,
    1483,
    1138,
    819,
    540,
    311,
    140,
    35,
    0,
    35,
    140,
    311,
    540,
    819,
    1138,
    1483
    };
    
    void sinewave(void)
    {
      WDTCTL = WDTPW + WDTHOLD;                 
      ADC12CTL0 = REFON+REF2_5V;					  		  				//Use 2.5V ADC reference                      
     
      DMA2SA = (int) Sin_tab;                   											//Initialize the DMA source address with the sine lookup table
      DMA2DA = (unsigned int)&DAC12_1DAT;        										//Initialize the DMA destination address with the DAC1 data register
      DMA2SZ = 0x20;                            											//Specify the DMA trasfer size (32)
      DMACTL0 = DMA2TSEL_2;												//Trigger for the DMA transfers (TimerB CCIFG flag)
      DMA2CTL = DMADT_4 + DMASRCINCR_3 + DMAEN; 								//Repeated single transfer,increment the source address & enable DMA
     
      DAC12_1CTL = DAC12LSEL_3 + DAC12IR + DAC12AMP_5 + DAC12IFG + DAC12ENC;		                      //DAC trigger with timerB rising edge & enable DAC
      
      TBCCTL2 = OUTMOD_3;							  			   			 //TimerB output-mode (set/reset)
      TBCCR2 =1;																			                                                      	
      TBCCR0 =0x1D;                           
      TBCTL = TBSSEL_2 + MC_1;   			  									  //Source SMCLK ,UP mode
    } 
      
    
    

  • Some general things:

    ou don't initialize TBCCTL0. Maybe the default is okay, maybe not. For better understanding you should configure it even with the default, to demonstrate that this is intentional and not just forgotten.

    You should configure TBCCR2 as DMA trigger source before you enable the DMA.

    There is no need to snychronize both, DMA and loading of DAC, with the timer. Just use DAC12LSEL_0 to update the DAC the very moment it is written to by the DMA. It's enough to synchronize the DMA with the timer. Even worse, the DMA transfer takes some cycles and the loading is executed imemdiately, so the timer trigger would load the last latched DAC value to the output and THEN the DMA transfer moves the next value, delaying the output by one timer cycle.

    Why do you set DAC12IFG? It is set automatically when a latched value is moved to the output (DAC12LSEL>0) or not at all (DAC12LSEL=0). It is of no use if you don't have an ISR for stuffing the DAC or want to use teh DMA to put a new value in once the old one has been output by a timer trigger. (using DMAxTSEL_5)

    However, none of the above should be a showstopper. As long as you don't enable TBCCR2 interrupts (which would deactivate this interrupt as trigger for the DMA).

    shruthi akash said:
    Timer A output is perfect

    How do you know?Your code doesn't output it to a pin.

    shruthi akash said:
    but the samples  are not at the required interval

    What interval are they? Bursts? twice as fast? Half as fast as expected? What do you expect?

**Attention** This is a public forum