Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of audio_FFT by
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 }
Generated on Wed Jul 13 2022 01:32:39 by
