Mbed ADC

From emboxit
Revision as of 16:51, 11 September 2015 by Admin (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Getting the best ADC performance from mbed


topic 1514 Mbed design of analog part

File:Bead-1.jpg

topic 1866 AnalogIn 'glitches' --- a 'cure' and a tool


  • user Armin Strobel 09 Aug 2011:
I read 3 times directly and chose than the averages of the two values with the least difference. Its a dirty hack but it works very well.

<cpp> raw[0] = ax.read_u16(); raw[1] = ax.read_u16(); raw[2] = ax.read_u16(); raw01 = abs(raw[0]-raw[1]); raw12 = abs(raw[1]-raw[2]); raw20 = abs(raw[2]-raw[0]); if((raw01<=raw12)&&(raw01<=raw20))

   rawM = (raw[0]+raw[1])/2;

if((raw12<=raw01)&&(raw12<=raw20))

   rawM = (raw[1]+raw[2])/2;

if((raw20<=raw12)&&(raw20<=raw01))

   rawM = (raw[2]+raw[0])/2;

</cpp>


  • user David Peters # 08 Aug 2011:
Its a very simple way to filter, but it works good for me, see the result here:

<cpp> for(int i=0; i<1024; i++) {

       if (abs((samples[i]-samples[i-1]))>3500 && i!=0){samples[i]=((samples[i-1]+samples[i+1])/2);}
       sampleresult= (float(samples[i])*3.3)/(65536);
       printf("%.2f,\r", sampleresult);
       }

</cpp>

topic 131 AnalogIn problem

Hi Rob,

I too would like to get to the bottom of this; sorry to disappoint you about the time it has taken for us to officially address it.

I'd definitely encourage people to have a play directly with the analog hardware (or any functions of the chip for that matter). The high-level libraries are certainly meant to help get going, but are not meant to stand in the way of you writing directly to the hardware as you would normally.

Here is some basic code I just put together for you to control the ADC directly - please feel free to have a play around:


<cpp> // analog input p20 (ADC0[5], pin 3) test

  1. include "mbed.h"

int main() {

   // power on, clk divider /4
   LPC_SC->PCONP |= (1 << 12);          
   LPC_SC->PCLKSEL0 &= ~(0x3 << 24);    
       
   // software-controlled ADC settings
   LPC_ADC->ADCR = (0 << 0) // SEL: 0 = no channels selected
             | (25 << 8)    // CLKDIV: PCLK max ~= 25MHz, /25 to give safe 1MHz
             | (0 << 16)    // BURST: 0 = software control 
             | (0 << 17)    // CLKS: not applicable 
             | (1 << 21)    // PDN: 1 = operational
             | (0 << 24)    // START: 0 = no start
             | (0 << 27);   // EDGE: not applicable
   // setup P1_31 as sel 3 (ADC), mode 2 (no pull)    
   LPC_PINCON->PINSEL3 &= ~((unsigned int)0x3 << 30);
   LPC_PINCON->PINSEL3 |= (unsigned int)0x3 << 30;
   
   LPC_PINCON->PINMODE3 &= ~((unsigned int)0x3 << 30);
   LPC_PINCON->PINMODE3 |= (unsigned int)0x2 << 30;
   while(1) {
       // Select channel and start conversion
       LPC_ADC->ADCR &= ~0xFF;
       LPC_ADC->ADCR |= 1 << 5; // ADC0[5]
       LPC_ADC->ADCR |= 1 << 24;
   
       // Repeatedly get the sample data until DONE bit
       unsigned int data;
       do {
          data = LPC_ADC->ADGDR;
       } while ((data & ((unsigned int)1 << 31)) == 0);
       // Stop conversion    
       LPC_ADC->ADCR &= ~(1 << 24);
   
       printf("0x%3X\n", data);   
   }

} </cpp>

topic 131 page2



topic 2849 Analog In

The beta has done two things for AnalogIn:
1) Sampling rate has been increased (i.e. reads are up to 3 times faster now)
2) Each read() takes 3 consecutive samples and outputs the middle one. It does all this in a signle read read().
I don't know if this will be 'fast' enough for you. It depends on the project requirements. But you should see a big improvement on both fronts.
Let us know how it goes :)

topic 2919 spikes again

...ends with...I see a significant improvement in reading stability with the V29 Library. Thanks to everyone who worked on this...

topic 2871 Increasing Sampling Frequency

...V29 AnalogIn...the final sampling rate is 49.8khz without any changes! :)


Hiroshi Yamaguchi, AnalogIn2 Library and Program

  • AnalogIn2 library
  • HIGHLIGHTS:
    • Uses Median Filter
      • AnalogIn2(median-window-size)
    • Based on Simon Ford code from topic 131
    • Sort algorithmn from "Numerical recipes in C"
      • Page 455 of edition III of book "Numerical recipes in C", section 8.5 Selecting the Mth Largest, note by NX
      • Page 365 of edition 2 of book "Numerical recipes in C", section 8.5 Selecting the Mth Largest, note by NX
    • Good implementation
    • Easy to understand code
    • Control with START and DONE bits, no Burst mode
  • program Imported to compiler

<cpp> /* AnalogIn2.cpp */

  1. include "AnalogIn2.h"

short int quickSelect(unsigned short arr[], int n);

AnalogIn2::AnalogIn2(PinName pinName) : pinName(pinName) {

   switch (pinName) {
       case p15:
           channel = 0;
           break;
       case p16:
           channel = 1;
           break;
       case p17:
           channel = 2;
           break;
       case p18:
           channel = 3;
           break;
       case p19:
           channel = 4;
           break;
       case p20:
           channel = 5;
           break;
   }
   read_u16(1);

}

unsigned short AnalogIn2::read_u16(int nSamples) {

   // power on, clk divider /4
   LPC_SC->PCONP |= (1 << 12);
   LPC_SC->PCLKSEL0 &= ~(0x3 << 24);
   // software-controlled ADC settings
   LPC_ADC->ADCR = (0 << 0) // SEL: 0 = no channels selected
(25 << 8) // CLKDIV: PCLK max ~= 25MHz, /25 to give safe 1MHz (0 << 16) // BURST: 0 = software control (0 << 17) // CLKS: not applicable (1 << 21) // PDN: 1 = operational (0 << 24) // START: 0 = no start (0 << 27); // EDGE: not applicable
   switch (pinName) {
       case p15:// =p0.23 of LPC1768
           LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 14);
           LPC_PINCON->PINSEL1 |= (unsigned int)0x1 << 14;
           LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 14);
           LPC_PINCON->PINMODE1 |= (unsigned int)0x2 << 14;
           break;
       case p16:// =p0.24 of LPC1768
           LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 16);
           LPC_PINCON->PINSEL1 |= (unsigned int)0x1 << 16;
           LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 16);
           LPC_PINCON->PINMODE1 |= (unsigned int)0x2 << 16;
           break;
       case p17:// =p0.25 of LPC1768
           LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 18);
           LPC_PINCON->PINSEL1 |= (unsigned int)0x1 << 18;
           LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 18);
           LPC_PINCON->PINMODE1 |= (unsigned int)0x2 << 18;
           break;
       case p18:// =p0.26 of LPC1768:
           LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 20);
           LPC_PINCON->PINSEL1 |= (unsigned int)0x1 << 20;
           LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 20);
           LPC_PINCON->PINMODE1 |= (unsigned int)0x2 << 20;
           break;
       case p19:// =p1.30 of LPC1768
           LPC_PINCON->PINSEL3 &= ~((unsigned int)0x3 << 28);
           LPC_PINCON->PINSEL3 |= (unsigned int)0x3 << 28;
           LPC_PINCON->PINMODE3 &= ~((unsigned int)0x3 << 28);
           LPC_PINCON->PINMODE3 |= (unsigned int)0x2 << 28;
           break;
       case p20:// =p1.31 of LPC1768
           LPC_PINCON->PINSEL3 &= ~((unsigned int)0x3 << 30);
           LPC_PINCON->PINSEL3 |= (unsigned int)0x3 << 30;
           LPC_PINCON->PINMODE3 &= ~((unsigned int)0x3 << 30);
           LPC_PINCON->PINMODE3 |= (unsigned int)0x2 << 30;
           break;
   }
   // Repeatedly get the sample data until DONE bit
   unsigned short a[nSamples];
   for (int i = 0; i < nSamples; i++) {
       unsigned int data;
       // Select channel and start conversion
       LPC_ADC->ADCR &= ~0xFF;
       LPC_ADC->ADCR |= 1 << channel;
       LPC_ADC->ADCR |= 1 << 24;
       do {
           data = LPC_ADC->ADGDR;
       } while ((data & ((unsigned int)1 << 31)) == 0);
       // Stop conversion
       LPC_ADC->ADCR &= ~(1 << 24);
       a[i] = data & 65535;
   }
   return quickSelect(a, nSamples);

}

float AnalogIn2::read(int nSamples) {

   return (read_u16(nSamples) >> 4) / 4096.0;

}

AnalogIn2::operator float() {

   return read();

}

/*

* This Quickselect routine is based on the algorithm described in
* "Numerical recipes in C", Second Edition,
* Cambridge University Press, 1992, Section 8.5, ISBN 0-521-43108-5
* This code by Nicolas Devillard - 1998. Public domain. */

/* Page 455 of edition III of the above book, section 8.5 Selecting the Mth Largest, note by NX

  Page 365 of edition 2 of the  book, section 8.5 Selecting the Mth Largest, note by NX   */
  1. define SWAP(a,b) {unsigned int t = (a); (a) = (b); (b) = t;}

short int quickSelect(unsigned short arr[], int n) {

   int low = 0, high = n - 1;
   unsigned int median = (low + high) / 2;
   for (;;) {
       if (high <= low) /* One element only */
           return arr[median];
       if (high == low + 1) { /* Two elements only */
           if (arr[low] > arr[high])
               SWAP(arr[low], arr[high]);
           return arr[median];
       }
       /* Find median of low, middle and high items; swap into position low */
       int middle = (low + high) / 2;
       if (arr[middle] > arr[high])
           SWAP(arr[middle], arr[high]);
       if (arr[low] > arr[high])
           SWAP(arr[low], arr[high]);
       if (arr[middle] > arr[low])
           SWAP(arr[middle], arr[low]);
       /* Swap low item (now in position middle) into position (low + 1) */
       SWAP(arr[middle], arr[low + 1]);
       /* Nibble from each end towards middle, swapping items when stuck */
       int ll = low + 1;
       int hh = high;
       for (;;) {
           do {
               ll++;
           } while (arr[low] > arr[ll]);
           do {
               hh--;
           } while (arr[hh] > arr[low]);
           if (hh < ll)
               break;
           SWAP(arr[ll], arr[hh]);
       }
       /* Swap middle item (in position low) back into correct position */
       SWAP(arr[low], arr[hh]);
       /* Re-set active partition */
       if (hh <= median)
           low = ll;
       if (hh >= median)
           high = hh - 1;
   }

} </cpp>

<cpp> /* AnalogIn2.h */

  1. ifndef MBED_ANALOG_IN2
  2. define MBED_ANALOG_IN2
  1. include "mbed.h"

class AnalogIn2 { public:

   AnalogIn2(PinName pinName);
   float read(int nSamples = 10);
   unsigned short read_u16(int nSamples = 10);
   operator float();
   

private:

   PinName pinName;
   int channel;

};

  1. endif

</cpp>

<cpp> /* main.cpp */

  1. include "mbed.h"
  2. include "AnalogIn2.h"

AnalogIn2 a20(p20); AnalogIn2 a15(p15);

int main() {

   printf("Temperature AnalogIn2 test\n");
   printf("a15 %d, %f\n", a15.read_u16(), (3.3 * a15.read() - 0.424) / 0.00625);
   printf("a20 %d, %f\n", a20.read_u16(100), (3.3 * a20.read(100) - 0.424) / 0.00625);
   wait(1);

} </cpp>



Simon Blandford ADC Library

<cpp>

  1. define SAMPLE_RATE 187500

ADC adc(SAMPLE_RATE, 1); //Initialise ADC to maximum SAMPLE_RATE and cclk divide set to 1 </cpp>


ADC_test program, tested in Compiler

<cpp> /*adc.cpp*/

/* mbed Library - ADC

* Copyright (c) 2010, sblandford
* released under MIT license http://mbed.org/licence/mit
*/
  1. include "mbed.h"
  2. include "adc.h"


ADC *ADC::instance;

ADC::ADC(int sample_rate, int cclk_div)

   {
   int i, adc_clk_freq, pclk, clock_div, max_div=1;
   //Work out CCLK
   adc_clk_freq=CLKS_PER_SAMPLE*sample_rate;
   int m = (LPC_SC->PLL0CFG & 0xFFFF) + 1;
   int n = (LPC_SC->PLL0CFG >> 16) + 1;
   int cclkdiv = LPC_SC->CCLKCFG + 1;
   int Fcco = (2 * m * XTAL_FREQ) / n;
   int cclk = Fcco / cclkdiv;
   //Power up the ADC        
   LPC_SC->PCONP |= (1 << 12);
   //Set clock at cclk / 1.
   LPC_SC->PCLKSEL0 &= ~(0x3 << 24);    
   switch (cclk_div) {
       case 1:
           LPC_SC->PCLKSEL0 |= 0x1 << 24;
           break;
       case 2:
           LPC_SC->PCLKSEL0 |= 0x2 << 24;
           break;
       case 4:
           LPC_SC->PCLKSEL0 |= 0x0 << 24;
           break;
       case 8:
           LPC_SC->PCLKSEL0 |= 0x3 << 24;
           break;
       default:
           fprintf(stderr, "Warning: ADC CCLK clock divider must be 1, 2, 4 or 8. %u supplied.\n",
               cclk_div);
           fprintf(stderr, "Defaulting to 1.\n");
           LPC_SC->PCLKSEL0 |= 0x1 << 24;
           break;
   }
   pclk = cclk / cclk_div;
   clock_div=pclk / adc_clk_freq;
   if (clock_div > 0xFF) {
       fprintf(stderr, "Warning: Clock division is %u which is above 255 limit. Re-Setting at limit.\n",
           clock_div);
       clock_div=0xFF;
   }
   if (clock_div == 0) {
       fprintf(stderr, "Warning: Clock division is 0. Re-Setting to 1.\n");
       clock_div=1;
   }
   _adc_clk_freq=pclk / clock_div;
   if (_adc_clk_freq > MAX_ADC_CLOCK) {
       fprintf(stderr, "Warning: Actual ADC sample rate of %u which is above %u limit\n",
           _adc_clk_freq / CLKS_PER_SAMPLE, MAX_ADC_CLOCK / CLKS_PER_SAMPLE);
       while ((pclk / max_div) > MAX_ADC_CLOCK) max_div++;
       fprintf(stderr, "Maximum recommended sample rate is %u\n", (pclk / max_div) / CLKS_PER_SAMPLE);
   }
   LPC_ADC->ADCR =
       ((clock_div - 1 ) << 8 ) |    //Clkdiv
       ( 1 << 21 );                  //A/D operational
   //Default no channels enabled
   LPC_ADC->ADCR &= ~0xFF;
   //Default NULL global custom isr
   _adc_g_isr = NULL;
   //Initialize arrays
   for (i=7; i>=0; i--) {
       _adc_data[i] = 0;
       _adc_isr[i] = NULL;
   }


   //* Attach IRQ
   instance = this;
   NVIC_SetVector(ADC_IRQn, (uint32_t)&_adcisr);
   //Disable global interrupt
   LPC_ADC->ADINTEN &= ~0x100;

};

void ADC::_adcisr(void) {

   instance->adcisr();

}


void ADC::adcisr(void) {

   uint32_t stat;
   int chan;
   // Read status
   stat = LPC_ADC->ADSTAT;
   //Scan channels for over-run or done and update array
   if (stat & 0x0101) _adc_data[0] = LPC_ADC->ADDR0;
   if (stat & 0x0202) _adc_data[1] = LPC_ADC->ADDR1;
   if (stat & 0x0404) _adc_data[2] = LPC_ADC->ADDR2;
   if (stat & 0x0808) _adc_data[3] = LPC_ADC->ADDR3;
   if (stat & 0x1010) _adc_data[4] = LPC_ADC->ADDR4;
   if (stat & 0x2020) _adc_data[5] = LPC_ADC->ADDR5;
   if (stat & 0x4040) _adc_data[6] = LPC_ADC->ADDR6;
   if (stat & 0x8080) _adc_data[7] = LPC_ADC->ADDR7;
   // Channel that triggered interrupt
   chan = (LPC_ADC->ADGDR >> 24) & 0x07;
   //User defined interrupt handlers
   if (_adc_isr[chan] != NULL)
       _adc_isr[chan](_adc_data[chan]);
   if (_adc_g_isr != NULL)
       _adc_g_isr(chan, _adc_data[chan]); 
   return;

}

int ADC::_pin_to_channel(PinName pin) {

   int chan;
   switch (pin) {
       case p15://=p0.23 of LPC1768
       default:
           chan=0;
           break;
       case p16://=p0.24 of LPC1768
           chan=1;
           break;
       case p17://=p0.25 of LPC1768
           chan=2;
           break;
       case p18://=p0.26 of LPC1768
           chan=3;
           break;
       case p19://=p1.30 of LPC1768
           chan=4;
           break;
       case p20://=p1.31 of LPC1768
           chan=5;
           break;
   }
   return(chan);

}

PinName ADC::channel_to_pin(int chan) {

   const PinName pin[8]={p15, p16, p17, p18, p19, p20, p15, p15};
   
   if ((chan < 0) || (chan > 5))
       fprintf(stderr, "ADC channel %u is outside range available to MBED pins.\n", chan);
   return(pin[chan & 0x07]);

}


int ADC::channel_to_pin_number(int chan) {

   const int pin[8]={15, 16, 17, 18, 19, 20, 0, 0};
   
   if ((chan < 0) || (chan > 5))
       fprintf(stderr, "ADC channel %u is outside range available to MBED pins.\n", chan);
   return(pin[chan & 0x07]);

}


uint32_t ADC::_data_of_pin(PinName pin) {

   //If in burst mode and at least one interrupt enabled then
   //take all values from _adc_data
   if (burst() && (LPC_ADC->ADINTEN & 0x3F)) {
       return(_adc_data[_pin_to_channel(pin)]);
   } else {
       //Return current register value or last value from interrupt
       switch (pin) {
           case p15://=p0.23 of LPC1768
           default:
               return(LPC_ADC->ADINTEN & 0x01?_adc_data[0]:LPC_ADC->ADDR0);
           case p16://=p0.24 of LPC1768
               return(LPC_ADC->ADINTEN & 0x02?_adc_data[1]:LPC_ADC->ADDR1);
           case p17://=p0.25 of LPC1768
               return(LPC_ADC->ADINTEN & 0x04?_adc_data[2]:LPC_ADC->ADDR2);
           case p18://=p0.26 of LPC1768:
               return(LPC_ADC->ADINTEN & 0x08?_adc_data[3]:LPC_ADC->ADDR3);
           case p19://=p1.30 of LPC1768
               return(LPC_ADC->ADINTEN & 0x10?_adc_data[4]:LPC_ADC->ADDR4);
           case p20://=p1.31 of LPC1768
               return(LPC_ADC->ADINTEN & 0x20?_adc_data[5]:LPC_ADC->ADDR5);
       }
   }

}

//Enable or disable an ADC pin void ADC::setup(PinName pin, int state) {

   int chan;    
   chan=_pin_to_channel(pin);
   if ((state & 1) == 1) {
       switch(pin) {
           case p15://=p0.23 of LPC1768
           default:
               LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 14);
               LPC_PINCON->PINSEL1 |= (unsigned int)0x1 << 14;
               LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 14);
               LPC_PINCON->PINMODE1 |= (unsigned int)0x2 << 14;
               break;
           case p16://=p0.24 of LPC1768
               LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 16);
               LPC_PINCON->PINSEL1 |= (unsigned int)0x1 << 16;
               LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 16);
               LPC_PINCON->PINMODE1 |= (unsigned int)0x2 << 16;
               break;
           case p17://=p0.25 of LPC1768
               LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 18);
               LPC_PINCON->PINSEL1 |= (unsigned int)0x1 << 18;
               LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 18);
               LPC_PINCON->PINMODE1 |= (unsigned int)0x2 << 18;
               break;
           case p18://=p0.26 of LPC1768:
               LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 20);
               LPC_PINCON->PINSEL1 |= (unsigned int)0x1 << 20;
               LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 20);
               LPC_PINCON->PINMODE1 |= (unsigned int)0x2 << 20;
               break;
           case p19://=p1.30 of LPC1768
               LPC_PINCON->PINSEL3 &= ~((unsigned int)0x3 << 28);
               LPC_PINCON->PINSEL3 |= (unsigned int)0x3 << 28;
               LPC_PINCON->PINMODE3 &= ~((unsigned int)0x3 << 28);
               LPC_PINCON->PINMODE3 |= (unsigned int)0x2 << 28;
               break;
           case p20://=p1.31 of LPC1768
               LPC_PINCON->PINSEL3 &= ~((unsigned int)0x3 << 30);
               LPC_PINCON->PINSEL3 |= (unsigned int)0x3 << 30;
               LPC_PINCON->PINMODE3 &= ~((unsigned int)0x3 << 30);
               LPC_PINCON->PINMODE3 |= (unsigned int)0x2 << 30;
              break;
       }
       //Only one channel can be selected at a time if not in burst mode
       if (!burst()) LPC_ADC->ADCR &= ~0xFF;
       //Select channel
       LPC_ADC->ADCR |= (1 << chan);
   }
   else {
       switch(pin) {
           case p15://=p0.23 of LPC1768
           default:
               LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 14);
               LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 14);
               break;
           case p16://=p0.24 of LPC1768
               LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 16);
               LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 16);
               break;
           case p17://=p0.25 of LPC1768
               LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 18);
               LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 18);
               break;
           case p18://=p0.26 of LPC1768:
               LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 20);
               LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 20);
               break;
           case p19://=p1.30 of LPC1768
               LPC_PINCON->PINSEL3 &= ~((unsigned int)0x3 << 28);
               LPC_PINCON->PINMODE3 &= ~((unsigned int)0x3 << 28);
               break;
           case p20://=p1.31 of LPC1768
               LPC_PINCON->PINSEL3 &= ~((unsigned int)0x3 << 30);
               LPC_PINCON->PINMODE3 &= ~((unsigned int)0x3 << 30);
               break;
       }
       LPC_ADC->ADCR &= ~(1 << chan);
   }

} //Return channel enabled/disabled state int ADC::setup(PinName pin) {

   int chan;
   
   chan = _pin_to_channel(pin);
   return((LPC_ADC->ADCR & (1 << chan)) >> chan);

}

//Select channel already setup void ADC::select(PinName pin) {

   int chan;
   
   //Only one channel can be selected at a time if not in burst mode
   if (!burst()) LPC_ADC->ADCR &= ~0xFF;
   //Select channel
   chan = _pin_to_channel(pin);
   LPC_ADC->ADCR |= (1 << chan);

}

//Enable or disable burst mode void ADC::burst(int state) {

   if ((state & 1) == 1) {
       if (startmode(0) != 0)
           fprintf(stderr, "Warning. startmode is %u. Must be 0 for burst mode.\n", startmode(0));
       LPC_ADC->ADCR |= (1 << 16);
   }
   else 
       LPC_ADC->ADCR &= ~(1 << 16);

} //Return burst mode state int ADC::burst(void) {

   return((LPC_ADC->ADCR & (1 << 16)) >> 16);

}

//Set startmode and edge void ADC::startmode(int mode, int edge) {

   int lpc_adc_temp;
   
   //Reset start mode and edge bit, 
   lpc_adc_temp = LPC_ADC->ADCR & ~(0x0F << 24);
   //Write with new values
   lpc_adc_temp |= ((mode & 7) << 24) | ((edge & 1) << 27);
   LPC_ADC->ADCR = lpc_adc_temp;

}

//Return startmode state according to mode_edge=0: mode and mode_edge=1: edge int ADC::startmode(int mode_edge){

   switch (mode_edge) {
       case 0:
       default:
           return((LPC_ADC->ADCR >> 24) & 0x07);
       case 1:
           return((LPC_ADC->ADCR >> 27) & 0x01);
   }

}

//Start ADC conversion void ADC::start(void) {

   startmode(1,0);

}


//Set interrupt enable/disable for pin to state void ADC::interrupt_state(PinName pin, int state) {

   int chan;
   
   chan = _pin_to_channel(pin);
   if (state == 1) {
       LPC_ADC->ADINTEN &= ~0x100;
       LPC_ADC->ADINTEN |= 1 << chan;
       /* Enable the ADC Interrupt */
       NVIC_EnableIRQ(ADC_IRQn);
   } else {
       LPC_ADC->ADINTEN &= ~( 1 << chan );
       //Disable interrrupt if no active pins left
       if ((LPC_ADC->ADINTEN & 0xFF) == 0)
           NVIC_DisableIRQ(ADC_IRQn);
   }

}

//Return enable/disable state of interrupt for pin int ADC::interrupt_state(PinName pin) {

   int chan;
       
   chan = _pin_to_channel(pin);
   return((LPC_ADC->ADINTEN >> chan) & 0x01);

}


//Attach custom interrupt handler replacing default void ADC::attach(void(*fptr)(void)) {

   //* Attach IRQ
   NVIC_SetVector(ADC_IRQn, (uint32_t)fptr);

}

//Restore default interrupt handler void ADC::detach(void) {

   //* Attach IRQ
   instance = this;
   NVIC_SetVector(ADC_IRQn, (uint32_t)&_adcisr);

}


//Append interrupt handler for pin to function isr void ADC::append(PinName pin, void(*fptr)(uint32_t value)) {

   int chan;
       
   chan = _pin_to_channel(pin);
   _adc_isr[chan] = fptr;

}

//Append interrupt handler for pin to function isr void ADC::unappend(PinName pin) {

   int chan;
       
   chan = _pin_to_channel(pin);
   _adc_isr[chan] = NULL;

}

//Unappend global interrupt handler to function isr void ADC::append(void(*fptr)(int chan, uint32_t value)) {

   _adc_g_isr = fptr;

}

//Detach global interrupt handler to function isr void ADC::unappend() {

   _adc_g_isr = NULL;

}

//Set ADC offset void offset(int offset) {

   LPC_ADC->ADTRM &= ~(0x07 << 4);
   LPC_ADC->ADTRM |= (offset & 0x07) << 4;

}

//Return current ADC offset int offset(void) {

   return((LPC_ADC->ADTRM >> 4) & 0x07);

}

//Return value of ADC on pin int ADC::read(PinName pin) {

   //Reset DONE and OVERRUN flags of interrupt handled ADC data
   _adc_data[_pin_to_channel(pin)] &= ~(((uint32_t)0x01 << 31) | ((uint32_t)0x01 << 30));
   //Return value
   return((_data_of_pin(pin) >> 4) & 0xFFF);

}

//Return DONE flag of ADC on pin int ADC::done(PinName pin) {

   return((_data_of_pin(pin) >> 31) & 0x01);

}

//Return OVERRUN flag of ADC on pin int ADC::overrun(PinName pin) {

   return((_data_of_pin(pin) >> 30) & 0x01);

}

int ADC::actual_adc_clock(void) {

   return(_adc_clk_freq);

}

int ADC::actual_sample_rate(void) {

   return(_adc_clk_freq / CLKS_PER_SAMPLE);

} </cpp>


<cpp> /*adc.h*/

/* mbed Library - ADC

* Copyright (c) 2010, sblandford
* released under MIT license http://mbed.org/licence/mit
*/
  1. ifndef MBED_ADC_H
  2. define MBED_ADC_H
  1. include "mbed.h"
  2. define XTAL_FREQ 12000000
  3. define MAX_ADC_CLOCK 13000000
  4. define CLKS_PER_SAMPLE 64

class ADC { public:

   //Initialize ADC with ADC maximum sample rate of
   //sample_rate and system clock divider of cclk_div
   //Maximum recommened sample rate is 184000
   ADC(int sample_rate, int cclk_div);
   //Enable/disable ADC on pin according to state
   //and also select/de-select for next conversion
   void setup(PinName pin, int state);
   //Return enabled/disabled state of ADC on pin
   int setup(PinName pin);
   //Enable/disable burst mode according to state
   void burst(int state);
   //Select channel already setup
   void select(PinName pin);
   //Return burst mode enabled/disabled
   int burst(void);
   /*Set start condition and edge according to mode:
   0 - No start (this value should be used when clearing PDN to 0).
   1 - Start conversion now.
   2 - Start conversion when the edge selected by bit 27 occurs on the P2.10 / EINT0 / NMI pin.
   3 - Start conversion when the edge selected by bit 27 occurs on the P1.27 / CLKOUT /
       USB_OVRCRn / CAP0.1 pin.
   4 - Start conversion when the edge selected by bit 27 occurs on MAT0.1. Note that this does
       not require that the MAT0.1 function appear on a device pin.
   5 - Start conversion when the edge selected by bit 27 occurs on MAT0.3. Note that it is not
       possible to cause the MAT0.3 function to appear on a device pin.
   6 - Start conversion when the edge selected by bit 27 occurs on MAT1.0. Note that this does
       not require that the MAT1.0 function appear on a device pin.
   7 - Start conversion when the edge selected by bit 27 occurs on MAT1.1. Note that this does
       not require that the MAT1.1 function appear on a device pin.
   When mode >= 2, conversion is triggered by edge:
   0 - Rising edge
   1 - Falling edge
   */
   void startmode(int mode, int edge);
   
   //Return startmode state according to mode_edge=0: mode and mode_edge=1: edge
   int startmode(int mode_edge);
   
   //Start ADC conversion
   void start(void);
   //Set interrupt enable/disable for pin to state
   void interrupt_state(PinName pin, int state);
   
   //Return enable/disable state of interrupt for pin
   int interrupt_state(PinName pin);
   //Attach custom interrupt handler replacing default
   void attach(void(*fptr)(void));
   //Restore default interrupt handler
   void detach(void);
   //Append custom interrupt handler for pin
   void append(PinName pin, void(*fptr)(uint32_t value));
   //Unappend custom interrupt handler for pin
   void unappend(PinName pin);
   //Append custom global interrupt handler
   void append(void(*fptr)(int chan, uint32_t value));
   //Unappend custom global interrupt handler
   void unappend(void);
   //Set ADC offset to a value 0-7
   void offset(int offset);
   
   //Return current ADC offset
   int offset(void);
   //Return value of ADC on pin
   int read(PinName pin);
   //Return DONE flag of ADC on pin
   int done(PinName pin);
   
   //Return OVERRUN flag of ADC on pin
   int overrun(PinName pin);
   //Return actual ADC clock
   int actual_adc_clock(void);
   
   //Return actual maximum sample rate
   int actual_sample_rate(void);
   //Return pin ID of ADC channel
   PinName channel_to_pin(int chan);
   //Return pin number of ADC channel
   int channel_to_pin_number(int chan);


private:

   int _pin_to_channel(PinName pin);
   uint32_t _data_of_pin(PinName pin);
   int _adc_clk_freq;
   void adcisr(void);
   static void _adcisr(void);
   static ADC *instance;
   
   uint32_t _adc_data[8];
   void(*_adc_isr[8])(uint32_t value);
   void(*_adc_g_isr)(int chan, uint32_t value);
   void(*_adc_m_isr)(void);

};

  1. endif

</cpp>


<cpp> /*main.cpp*/

  1. define SAMPLE_RATE 150000
  1. include "mbed.h"
  2. include "adc.h"

DigitalOut int_led(p19);

//Initialise ADC to maximum SAMPLE_RATE and cclk divide set to 1 ADC adc(SAMPLE_RATE, 1);

//Toggle LED on interrupt void led_toggle(int chan, uint32_t value) {

   int_led = !int_led;

}

//Report ADC value on interrupt void print_value(int chan, uint32_t value) {

   printf("ADC interrupt on pin %u, value=%04u.\n", 
       adc.channel_to_pin_number(chan), (value >> 4) & 0xFFF);

}


int main() {

   int i;
   
   printf("Requested max sample rate is %u, actual max sample rate is %u.\n",
       SAMPLE_RATE, adc.actual_sample_rate());
   while (1) {
           
       adc.setup(p17,1);           //Set up ADC on pin 17        
       adc.setup(p15,1);           //Set up ADC on pin 15
       wait(1);        
       
       adc.select(p17);            //Measure pin 17        
       adc.start();                //Start ADC conversion       
       while(!adc.done(p17));      //Wait for it to complete
       printf("Measured value on pin 17 is %04u.\n", adc.read(p17));
       wait(1);
       
       adc.select(p15);            //Measure pin 15        
       adc.start();                //Start ADC conversion        
       while(!adc.done(p15));      //Wait for it to complete
       printf("Measured value on pin 15 is %04u.\n", adc.read(p15));
       wait(1);   
       
       adc.append(print_value);    //Append an interrupt handler that prints the channel and value        
       adc.select(p17);            //Measure pin 17        
       adc.interrupt_state(p20,1); //Enable the interrupt        
       adc.start();                //Start ADC conversion       
       while(!adc.done(p17));      //Wait for it to complete
       wait(1);
           
       adc.setup(p17,0);           //Unset pin 17
   
       //Togle LED on each converstion.
       //Should be 12.5KHz on LED for all 6 pins.
       //Sample rate=150KHz / 6 channels / 2
       adc.append(led_toggle);
   
       //Prepare for burst mode on all ADC pins
       adc.startmode(0,0);
       adc.burst(1);
       adc.setup(p20,1);
       adc.setup(p19,1);
       adc.setup(p18,1);
       adc.setup(p17,1);
       adc.setup(p16,1);
       adc.setup(p15,1);
       //For burst mode, only one interrupt is required
       //which can be on any enabled pin. We have enabled all
       //of them here.
       adc.interrupt_state(p15,1);
       printf("Burst mode, printing once per second...\n");
       for (i=0; i<5; i++)
       {
           printf("%04u %04u %04u %04u %04u %04u\n", 
               adc.read(p20),
               adc.read(p19),
               adc.read(p18),
               adc.read(p17),
               adc.read(p16),
               adc.read(p15));
           wait(1);
       }
       adc.burst(0);
       adc.setup(p20,0);
       adc.setup(p19,0);
       adc.setup(p18,0);
       adc.setup(p17,0);
       adc.setup(p16,0);
       adc.setup(p15,0);
       adc.interrupt_state(p20,0);
       adc.interrupt_state(p19,0);
       adc.interrupt_state(p18,0);
       adc.interrupt_state(p17,0);
       adc.interrupt_state(p16,0);
       adc.interrupt_state(p15,0);
       
       printf("\n");
   }

} </cpp>



AD7190 with mbed