save loops

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