Stéphane Cachat
/
Smoothie
smoothie port to mbed online compiler (smoothieware.org)
Embed:
(wiki syntax)
Show/hide line numbers
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 printf("Warning: ADC CCLK clock divider must be 1, 2, 4 or 8. %u supplied.\n", 00043 cclk_div); 00044 printf("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 //printf("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 printf("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 printf("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 printf("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 Tue Jul 12 2022 14:14:39 by 1.7.2