ADC Spike2

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers adc.cpp Source File

adc.cpp

00001 /* mbed Library - ADC
00002  * Copyright (c) 2010, sblandford
00003  * released under MIT license http://mbed.org/licence/mit
00004  */
00005 #include "mbed.h"
00006 #include "adc.h"
00007 
00008 
00009 ADC *ADC::instance;
00010 
00011 ADC::ADC(int sample_rate, int cclk_div)
00012     {
00013 
00014     int i, adc_clk_freq, pclk, clock_div, max_div=1;
00015 
00016     //Work out CCLK
00017     adc_clk_freq=CLKS_PER_SAMPLE*sample_rate;
00018     int m = (LPC_SC->PLL0CFG & 0xFFFF) + 1;
00019     int n = (LPC_SC->PLL0CFG >> 16) + 1;
00020     int cclkdiv = LPC_SC->CCLKCFG + 1;
00021     int Fcco = (2 * m * XTAL_FREQ) / n;
00022     int cclk = Fcco / cclkdiv;
00023 
00024     //Power up the ADC        
00025     LPC_SC->PCONP |= (1 << 12);
00026     //Set clock at cclk / 1.
00027     LPC_SC->PCLKSEL0 &= ~(0x3 << 24);    
00028     switch (cclk_div) {
00029         case 1:
00030             LPC_SC->PCLKSEL0 |= 0x1 << 24;
00031             break;
00032         case 2:
00033             LPC_SC->PCLKSEL0 |= 0x2 << 24;
00034             break;
00035         case 4:
00036             LPC_SC->PCLKSEL0 |= 0x0 << 24;
00037             break;
00038         case 8:
00039             LPC_SC->PCLKSEL0 |= 0x3 << 24;
00040             break;
00041         default:
00042             fprintf(stderr, "Warning: ADC CCLK clock divider must be 1, 2, 4 or 8. %u supplied.\n",
00043                 cclk_div);
00044             fprintf(stderr, "Defaulting to 1.\n");
00045             LPC_SC->PCLKSEL0 |= 0x1 << 24;
00046             break;
00047     }
00048     pclk = cclk / cclk_div;
00049     clock_div=pclk / adc_clk_freq;
00050 
00051     if (clock_div > 0xFF) {
00052         fprintf(stderr, "Warning: Clock division is %u which is above 255 limit. Re-Setting at limit.\n",
00053             clock_div);
00054         clock_div=0xFF;
00055     }
00056     if (clock_div == 0) {
00057         fprintf(stderr, "Warning: Clock division is 0. Re-Setting to 1.\n");
00058         clock_div=1;
00059     }
00060 
00061     _adc_clk_freq=pclk / clock_div;
00062     if (_adc_clk_freq > MAX_ADC_CLOCK) {
00063         fprintf(stderr, "Warning: Actual ADC sample rate of %u which is above %u limit\n",
00064             _adc_clk_freq / CLKS_PER_SAMPLE, MAX_ADC_CLOCK / CLKS_PER_SAMPLE);
00065         while ((pclk / max_div) > MAX_ADC_CLOCK) max_div++;
00066         fprintf(stderr, "Maximum recommended sample rate is %u\n", (pclk / max_div) / CLKS_PER_SAMPLE);
00067     }
00068 
00069     LPC_ADC->ADCR =
00070         ((clock_div - 1 ) << 8 ) |    //Clkdiv
00071         ( 1 << 21 );                  //A/D operational
00072 
00073     //Default no channels enabled
00074     LPC_ADC->ADCR &= ~0xFF;
00075     //Default NULL global custom isr
00076     _adc_g_isr = NULL;
00077     //Initialize arrays
00078     for (i=7; i>=0; i--) {
00079         _adc_data[i] = 0;
00080         _adc_isr[i] = NULL;
00081     }
00082 
00083 
00084     //* Attach IRQ
00085     instance = this;
00086     NVIC_SetVector(ADC_IRQn, (uint32_t)&_adcisr);
00087 
00088     //Disable global interrupt
00089     LPC_ADC->ADINTEN &= ~0x100;
00090 
00091 };
00092 
00093 void ADC::_adcisr(void)
00094 {
00095     instance->adcisr();
00096 }
00097 
00098 
00099 void ADC::adcisr(void)  
00100 {
00101     uint32_t stat;
00102     int chan;
00103 
00104     // Read status
00105     stat = LPC_ADC->ADSTAT;
00106     //Scan channels for over-run or done and update array
00107     if (stat & 0x0101) _adc_data[0] = LPC_ADC->ADDR0;
00108     if (stat & 0x0202) _adc_data[1] = LPC_ADC->ADDR1;
00109     if (stat & 0x0404) _adc_data[2] = LPC_ADC->ADDR2;
00110     if (stat & 0x0808) _adc_data[3] = LPC_ADC->ADDR3;
00111     if (stat & 0x1010) _adc_data[4] = LPC_ADC->ADDR4;
00112     if (stat & 0x2020) _adc_data[5] = LPC_ADC->ADDR5;
00113     if (stat & 0x4040) _adc_data[6] = LPC_ADC->ADDR6;
00114     if (stat & 0x8080) _adc_data[7] = LPC_ADC->ADDR7;
00115 
00116     // Channel that triggered interrupt
00117     chan = (LPC_ADC->ADGDR >> 24) & 0x07;
00118     //User defined interrupt handlers
00119     if (_adc_isr[chan] != NULL)
00120         _adc_isr[chan](_adc_data[chan]);
00121     if (_adc_g_isr != NULL)
00122         _adc_g_isr(chan, _adc_data[chan]); 
00123     return;
00124 }
00125 
00126 int ADC::_pin_to_channel(PinName pin) {
00127     int chan;
00128     switch (pin) {
00129         case p15://=p0.23 of LPC1768
00130         default:
00131             chan=0;
00132             break;
00133         case p16://=p0.24 of LPC1768
00134             chan=1;
00135             break;
00136         case p17://=p0.25 of LPC1768
00137             chan=2;
00138             break;
00139         case p18://=p0.26 of LPC1768
00140             chan=3;
00141             break;
00142         case p19://=p1.30 of LPC1768
00143             chan=4;
00144             break;
00145         case p20://=p1.31 of LPC1768
00146             chan=5;
00147             break;
00148     }
00149     return(chan);
00150 }
00151 
00152 PinName ADC::channel_to_pin(int chan) {
00153     const PinName pin[8]={p15, p16, p17, p18, p19, p20, p15, p15};
00154     
00155     if ((chan < 0) || (chan > 5))
00156         fprintf(stderr, "ADC channel %u is outside range available to MBED pins.\n", chan);
00157     return(pin[chan & 0x07]);
00158 } 
00159 
00160 
00161 int ADC::channel_to_pin_number(int chan) {
00162     const int pin[8]={15, 16, 17, 18, 19, 20, 0, 0};
00163     
00164     if ((chan < 0) || (chan > 5))
00165         fprintf(stderr, "ADC channel %u is outside range available to MBED pins.\n", chan);
00166     return(pin[chan & 0x07]);
00167 } 
00168 
00169 
00170 uint32_t ADC::_data_of_pin(PinName pin) {
00171     //If in burst mode and at least one interrupt enabled then
00172     //take all values from _adc_data
00173     if (burst() && (LPC_ADC->ADINTEN & 0x3F)) {
00174         return(_adc_data[_pin_to_channel(pin)]);
00175     } else {
00176         //Return current register value or last value from interrupt
00177         switch (pin) {
00178             case p15://=p0.23 of LPC1768
00179             default:
00180                 return(LPC_ADC->ADINTEN & 0x01?_adc_data[0]:LPC_ADC->ADDR0);
00181             case p16://=p0.24 of LPC1768
00182                 return(LPC_ADC->ADINTEN & 0x02?_adc_data[1]:LPC_ADC->ADDR1);
00183             case p17://=p0.25 of LPC1768
00184                 return(LPC_ADC->ADINTEN & 0x04?_adc_data[2]:LPC_ADC->ADDR2);
00185             case p18://=p0.26 of LPC1768:
00186                 return(LPC_ADC->ADINTEN & 0x08?_adc_data[3]:LPC_ADC->ADDR3);
00187             case p19://=p1.30 of LPC1768
00188                 return(LPC_ADC->ADINTEN & 0x10?_adc_data[4]:LPC_ADC->ADDR4);
00189             case p20://=p1.31 of LPC1768
00190                 return(LPC_ADC->ADINTEN & 0x20?_adc_data[5]:LPC_ADC->ADDR5);
00191         }
00192     }
00193 }
00194 
00195 //Enable or disable an ADC pin
00196 void ADC::setup(PinName pin, int state) {
00197     int chan;    
00198     chan=_pin_to_channel(pin);
00199     if ((state & 1) == 1) {
00200         switch(pin) {
00201             case p15://=p0.23 of LPC1768
00202             default:
00203                 LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 14);
00204                 LPC_PINCON->PINSEL1 |= (unsigned int)0x1 << 14;
00205                 LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 14);
00206                 LPC_PINCON->PINMODE1 |= (unsigned int)0x2 << 14;
00207                 break;
00208             case p16://=p0.24 of LPC1768
00209                 LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 16);
00210                 LPC_PINCON->PINSEL1 |= (unsigned int)0x1 << 16;
00211                 LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 16);
00212                 LPC_PINCON->PINMODE1 |= (unsigned int)0x2 << 16;
00213                 break;
00214             case p17://=p0.25 of LPC1768
00215                 LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 18);
00216                 LPC_PINCON->PINSEL1 |= (unsigned int)0x1 << 18;
00217                 LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 18);
00218                 LPC_PINCON->PINMODE1 |= (unsigned int)0x2 << 18;
00219                 break;
00220             case p18://=p0.26 of LPC1768:
00221                 LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 20);
00222                 LPC_PINCON->PINSEL1 |= (unsigned int)0x1 << 20;
00223                 LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 20);
00224                 LPC_PINCON->PINMODE1 |= (unsigned int)0x2 << 20;
00225                 break;
00226             case p19://=p1.30 of LPC1768
00227                 LPC_PINCON->PINSEL3 &= ~((unsigned int)0x3 << 28);
00228                 LPC_PINCON->PINSEL3 |= (unsigned int)0x3 << 28;
00229                 LPC_PINCON->PINMODE3 &= ~((unsigned int)0x3 << 28);
00230                 LPC_PINCON->PINMODE3 |= (unsigned int)0x2 << 28;
00231                 break;
00232             case p20://=p1.31 of LPC1768
00233                 LPC_PINCON->PINSEL3 &= ~((unsigned int)0x3 << 30);
00234                 LPC_PINCON->PINSEL3 |= (unsigned int)0x3 << 30;
00235                 LPC_PINCON->PINMODE3 &= ~((unsigned int)0x3 << 30);
00236                 LPC_PINCON->PINMODE3 |= (unsigned int)0x2 << 30;
00237                break;
00238         }
00239         //Only one channel can be selected at a time if not in burst mode
00240         if (!burst()) LPC_ADC->ADCR &= ~0xFF;
00241         //Select channel
00242         LPC_ADC->ADCR |= (1 << chan);
00243     }
00244     else {
00245         switch(pin) {
00246             case p15://=p0.23 of LPC1768
00247             default:
00248                 LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 14);
00249                 LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 14);
00250                 break;
00251             case p16://=p0.24 of LPC1768
00252                 LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 16);
00253                 LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 16);
00254                 break;
00255             case p17://=p0.25 of LPC1768
00256                 LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 18);
00257                 LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 18);
00258                 break;
00259             case p18://=p0.26 of LPC1768:
00260                 LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 20);
00261                 LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 20);
00262                 break;
00263             case p19://=p1.30 of LPC1768
00264                 LPC_PINCON->PINSEL3 &= ~((unsigned int)0x3 << 28);
00265                 LPC_PINCON->PINMODE3 &= ~((unsigned int)0x3 << 28);
00266                 break;
00267             case p20://=p1.31 of LPC1768
00268                 LPC_PINCON->PINSEL3 &= ~((unsigned int)0x3 << 30);
00269                 LPC_PINCON->PINMODE3 &= ~((unsigned int)0x3 << 30);
00270                 break;
00271         }
00272         LPC_ADC->ADCR &= ~(1 << chan);
00273     }
00274 }
00275 //Return channel enabled/disabled state
00276 int ADC::setup(PinName pin) {
00277     int chan;
00278     
00279     chan = _pin_to_channel(pin);
00280     return((LPC_ADC->ADCR & (1 << chan)) >> chan);
00281 }
00282 
00283 //Select channel already setup
00284 void ADC::select(PinName pin) {
00285     int chan;
00286     
00287     //Only one channel can be selected at a time if not in burst mode
00288     if (!burst()) LPC_ADC->ADCR &= ~0xFF;
00289     //Select channel
00290     chan = _pin_to_channel(pin);
00291     LPC_ADC->ADCR |= (1 << chan);
00292 }
00293 
00294 //Enable or disable burst mode
00295 void ADC::burst(int state) {
00296     if ((state & 1) == 1) {
00297         if (startmode(0) != 0)
00298             fprintf(stderr, "Warning. startmode is %u. Must be 0 for burst mode.\n", startmode(0));
00299         LPC_ADC->ADCR |= (1 << 16);
00300     }
00301     else 
00302         LPC_ADC->ADCR &= ~(1 << 16);
00303 }
00304 //Return burst mode state
00305 int  ADC::burst(void) {
00306     return((LPC_ADC->ADCR & (1 << 16)) >> 16);
00307 }
00308 
00309 //Set startmode and edge
00310 void ADC::startmode(int mode, int edge) {
00311     int lpc_adc_temp;
00312     
00313     //Reset start mode and edge bit, 
00314     lpc_adc_temp = LPC_ADC->ADCR & ~(0x0F << 24);
00315     //Write with new values
00316     lpc_adc_temp |= ((mode & 7) << 24) | ((edge & 1) << 27);
00317     LPC_ADC->ADCR = lpc_adc_temp;
00318 }
00319 
00320 //Return startmode state according to mode_edge=0: mode and mode_edge=1: edge
00321 int ADC::startmode(int mode_edge){
00322     switch (mode_edge) {
00323         case 0:
00324         default:
00325             return((LPC_ADC->ADCR >> 24) & 0x07);
00326         case 1:
00327             return((LPC_ADC->ADCR >> 27) & 0x01);
00328     }
00329 }
00330 
00331 //Start ADC conversion
00332 void ADC::start(void) {
00333     startmode(1,0);
00334 }
00335 
00336 
00337 //Set interrupt enable/disable for pin to state
00338 void ADC::interrupt_state(PinName pin, int state) {
00339     int chan;
00340     
00341     chan = _pin_to_channel(pin);
00342     if (state == 1) {
00343         LPC_ADC->ADINTEN &= ~0x100;
00344         LPC_ADC->ADINTEN |= 1 << chan;
00345         /* Enable the ADC Interrupt */
00346         NVIC_EnableIRQ(ADC_IRQn);
00347     } else {
00348         LPC_ADC->ADINTEN &= ~( 1 << chan );
00349         //Disable interrrupt if no active pins left
00350         if ((LPC_ADC->ADINTEN & 0xFF) == 0)
00351             NVIC_DisableIRQ(ADC_IRQn);
00352     }
00353 }
00354 
00355 //Return enable/disable state of interrupt for pin
00356 int ADC::interrupt_state(PinName pin) {
00357     int chan;
00358         
00359     chan = _pin_to_channel(pin);
00360     return((LPC_ADC->ADINTEN >> chan) & 0x01);
00361 }
00362 
00363 
00364 //Attach custom interrupt handler replacing default
00365 void ADC::attach(void(*fptr)(void)) {
00366     //* Attach IRQ
00367     NVIC_SetVector(ADC_IRQn, (uint32_t)fptr);
00368 }
00369 
00370 //Restore default interrupt handler
00371 void ADC::detach(void) {
00372     //* Attach IRQ
00373     instance = this;
00374     NVIC_SetVector(ADC_IRQn, (uint32_t)&_adcisr);
00375 }
00376 
00377 
00378 //Append interrupt handler for pin to function isr
00379 void ADC::append(PinName pin, void(*fptr)(uint32_t value)) {
00380     int chan;
00381         
00382     chan = _pin_to_channel(pin);
00383     _adc_isr[chan] = fptr;
00384 }
00385 
00386 //Append interrupt handler for pin to function isr
00387 void ADC::unappend(PinName pin) {
00388     int chan;
00389         
00390     chan = _pin_to_channel(pin);
00391     _adc_isr[chan] = NULL;
00392 }
00393 
00394 //Unappend global interrupt handler to function isr
00395 void ADC::append(void(*fptr)(int chan, uint32_t value)) {
00396     _adc_g_isr = fptr;
00397 }
00398 
00399 //Detach global interrupt handler to function isr
00400 void ADC::unappend() {
00401     _adc_g_isr = NULL;
00402 }
00403 
00404 //Set ADC offset
00405 void offset(int offset) {
00406     LPC_ADC->ADTRM &= ~(0x07 << 4);
00407     LPC_ADC->ADTRM |= (offset & 0x07) << 4;
00408 }
00409 
00410 //Return current ADC offset
00411 int offset(void) {
00412     return((LPC_ADC->ADTRM >> 4) & 0x07);
00413 }
00414 
00415 //Return value of ADC on pin
00416 int ADC::read(PinName pin) {
00417     //Reset DONE and OVERRUN flags of interrupt handled ADC data
00418     _adc_data[_pin_to_channel(pin)] &= ~(((uint32_t)0x01 << 31) | ((uint32_t)0x01 << 30));
00419     //Return value
00420     return((_data_of_pin(pin) >> 4) & 0xFFF);
00421 }
00422 
00423 //Return DONE flag of ADC on pin
00424 int ADC::done(PinName pin) {
00425     return((_data_of_pin(pin) >> 31) & 0x01);
00426 }
00427 
00428 //Return OVERRUN flag of ADC on pin
00429 int ADC::overrun(PinName pin) {
00430     return((_data_of_pin(pin) >> 30) & 0x01);
00431 }
00432 
00433 int ADC::actual_adc_clock(void) {
00434     return(_adc_clk_freq);
00435 }
00436 
00437 int ADC::actual_sample_rate(void) {
00438     return(_adc_clk_freq / CLKS_PER_SAMPLE);
00439 }