It is a library for controlling Wallbot

Dependents:   wallbot_test

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers HighSpeedAnalogIn.cpp Source File

HighSpeedAnalogIn.cpp

00001 
00002 #include "HighSpeedAnalogIn.h"
00003 
00004 HighSpeedAnalogIn *HighSpeedAnalogIn::instance;
00005 int HighSpeedAnalogIn::refcnt = 0;
00006 
00007 HighSpeedAnalogIn::HighSpeedAnalogIn(PinName pin0, PinName pin1, PinName pin2, PinName pin3, PinName pin4, PinName pin5) {
00008 
00009     refcnt++;
00010     if (refcnt > 1) {
00011         error("Please do not use over an object.");
00012     }
00013 
00014     static const int sample_rate = 200000;
00015     static const int cclk_div = 1;
00016 
00017     int 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     LPC_SC->PCONP |= (1 << 12);
00025     LPC_SC->PCLKSEL0 &= ~(0x3 << 24);
00026     switch (cclk_div) {
00027         case 1:
00028             LPC_SC->PCLKSEL0 |= 0x1 << 24;
00029             break;
00030         case 2:
00031             LPC_SC->PCLKSEL0 |= 0x2 << 24;
00032             break;
00033         case 4:
00034             LPC_SC->PCLKSEL0 |= 0x0 << 24;
00035             break;
00036         case 8:
00037             LPC_SC->PCLKSEL0 |= 0x3 << 24;
00038             break;
00039         default:
00040             fprintf(stderr, "Warning: ADC CCLK clock divider must be 1, 2, 4 or 8. %u supplied.\n", cclk_div);
00041             fprintf(stderr, "Defaulting to 1.\n");
00042             LPC_SC->PCLKSEL0 |= 0x1 << 24;
00043             break;
00044     }
00045     int pclk = cclk / cclk_div;
00046     int clock_div = pclk / adc_clk_freq;
00047 
00048     if (clock_div > 0xFF) {
00049         fprintf(stderr, "Warning: Clock division is %u which is above 255 limit. Re-Setting at limit.\n", clock_div);
00050         clock_div = 0xFF;
00051     }
00052     if (clock_div == 0) {
00053         fprintf(stderr, "Warning: Clock division is 0. Re-Setting to 1.\n");
00054         clock_div = 1;
00055     }
00056 
00057     int _adc_clk_freq = pclk / clock_div;
00058     if (_adc_clk_freq > MAX_ADC_CLOCK) {
00059         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);
00060         int max_div = 1;
00061         while ((pclk / max_div) > MAX_ADC_CLOCK) {
00062             max_div++;
00063         }
00064         fprintf(stderr, "Maximum recommended sample rate is %u\n", (pclk / max_div) / CLKS_PER_SAMPLE);
00065     }
00066 
00067     LPC_ADC->ADCR = ((clock_div - 1) << 8) | (1 << 21);
00068     LPC_ADC->ADCR &= ~0xFF;
00069 
00070     for (int i = 0; i < 8; i++) {
00071         _adc_data[i] = 0;
00072     }
00073 
00074     // Attach IRQ
00075     instance = this;
00076     NVIC_SetVector(ADC_IRQn, (uint32_t)&static_adcisr);
00077 
00078     // Disable global interrupt
00079     LPC_ADC->ADINTEN &= ~0x100;
00080 
00081     // Clock frequency.
00082     printf("Clock frequency:%d\n", _adc_clk_freq);
00083 
00084     // Actual sampling rate.
00085     printf("Actual sampling rate:%d\n", _adc_clk_freq / CLKS_PER_SAMPLE);
00086     
00087     int tmp = LPC_ADC->ADCR & ~(0x0F << 24);
00088     tmp |= ((0x0 & 7) << 24) | ((0x0 & 1) << 27);
00089     LPC_ADC->ADCR = tmp;
00090     LPC_ADC->ADCR |= (1 << 16);
00091 
00092     if (pin0 != NC) setup(pin0, 1);
00093     if (pin1 != NC) setup(pin1, 1);
00094     if (pin2 != NC) setup(pin2, 1);
00095     if (pin3 != NC) setup(pin3, 1);
00096     if (pin4 != NC) setup(pin4, 1);
00097     if (pin5 != NC) setup(pin5, 1);
00098 
00099     interrupt_state(pin0, 1);
00100 }
00101 
00102 HighSpeedAnalogIn::~HighSpeedAnalogIn() {
00103 }
00104 
00105 void HighSpeedAnalogIn::static_adcisr(void) {
00106     instance->adcisr();
00107 }
00108 
00109 void HighSpeedAnalogIn::adcisr(void) {
00110     uint32_t stat = LPC_ADC->ADSTAT;
00111     // Scan channels for over-run or done and update array
00112     if (stat & 0x0101) _adc_data[0] = LPC_ADC->ADDR0;
00113     if (stat & 0x0202) _adc_data[1] = LPC_ADC->ADDR1;
00114     if (stat & 0x0404) _adc_data[2] = LPC_ADC->ADDR2;
00115     if (stat & 0x0808) _adc_data[3] = LPC_ADC->ADDR3;
00116     if (stat & 0x1010) _adc_data[4] = LPC_ADC->ADDR4;
00117     if (stat & 0x2020) _adc_data[5] = LPC_ADC->ADDR5;
00118     if (stat & 0x4040) _adc_data[6] = LPC_ADC->ADDR6;
00119     if (stat & 0x8080) _adc_data[7] = LPC_ADC->ADDR7;
00120 }
00121 
00122 int HighSpeedAnalogIn::get_channel(PinName pin) {
00123     int ch;
00124     switch (pin) {
00125         case p15:// =p0.23 of LPC1768
00126             ch = 0;
00127             break;
00128         case p16:// =p0.24 of LPC1768
00129             ch = 1;
00130             break;
00131         case p17:// =p0.25 of LPC1768
00132             ch = 2;
00133             break;
00134         case p18:// =p0.26 of LPC1768
00135             ch = 3;
00136             break;
00137         case p19:// =p1.30 of LPC1768
00138             ch = 4;
00139             break;
00140         case p20:// =p1.31 of LPC1768
00141             ch = 5;
00142             break;
00143         default:
00144             ch = 0;
00145             break;
00146     }
00147     return ch;
00148 }
00149 
00150 uint32_t HighSpeedAnalogIn::get_data(PinName pin) {
00151     // If in burst mode and at least one interrupt enabled then
00152     // take all values from _adc_data
00153     if (LPC_ADC->ADINTEN & 0x3F) {
00154         return (_adc_data[get_channel(pin)]);
00155     } else {
00156         // Return current register value or last value from interrupt
00157         switch (pin) {
00158             case p15:// =p0.23 of LPC1768
00159                 return ((LPC_ADC->ADINTEN & 0x01) ? _adc_data[0] : LPC_ADC->ADDR0);
00160             case p16:// =p0.24 of LPC1768
00161                 return ((LPC_ADC->ADINTEN & 0x02) ? _adc_data[1] : LPC_ADC->ADDR1);
00162             case p17:// =p0.25 of LPC1768
00163                 return ((LPC_ADC->ADINTEN & 0x04) ? _adc_data[2] : LPC_ADC->ADDR2);
00164             case p18:// =p0.26 of LPC1768:
00165                 return ((LPC_ADC->ADINTEN & 0x08) ? _adc_data[3] : LPC_ADC->ADDR3);
00166             case p19:// =p1.30 of LPC1768
00167                 return ((LPC_ADC->ADINTEN & 0x10) ? _adc_data[4] : LPC_ADC->ADDR4);
00168             case p20:// =p1.31 of LPC1768
00169                 return ((LPC_ADC->ADINTEN & 0x20) ? _adc_data[5] : LPC_ADC->ADDR5);
00170             default:
00171                 return 0;
00172         }
00173     }
00174 }
00175 
00176 // Enable or disable an HighSpeedAnalogIn pin
00177 void HighSpeedAnalogIn::setup(PinName pin, int state) {
00178     int ch = get_channel(pin);
00179     if ((state & 1) == 1) {
00180         switch (pin) {
00181             case p15:// =p0.23 of LPC1768
00182                 LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 14);
00183                 LPC_PINCON->PINSEL1 |= (unsigned int)0x1 << 14;
00184                 LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 14);
00185                 LPC_PINCON->PINMODE1 |= (unsigned int)0x2 << 14;
00186                 break;
00187             case p16:// =p0.24 of LPC1768
00188                 LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 16);
00189                 LPC_PINCON->PINSEL1 |= (unsigned int)0x1 << 16;
00190                 LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 16);
00191                 LPC_PINCON->PINMODE1 |= (unsigned int)0x2 << 16;
00192                 break;
00193             case p17:// =p0.25 of LPC1768
00194                 LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 18);
00195                 LPC_PINCON->PINSEL1 |= (unsigned int)0x1 << 18;
00196                 LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 18);
00197                 LPC_PINCON->PINMODE1 |= (unsigned int)0x2 << 18;
00198                 break;
00199             case p18:// =p0.26 of LPC1768:
00200                 LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 20);
00201                 LPC_PINCON->PINSEL1 |= (unsigned int)0x1 << 20;
00202                 LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 20);
00203                 LPC_PINCON->PINMODE1 |= (unsigned int)0x2 << 20;
00204                 break;
00205             case p19:// =p1.30 of LPC1768
00206                 LPC_PINCON->PINSEL3 &= ~((unsigned int)0x3 << 28);
00207                 LPC_PINCON->PINSEL3 |= (unsigned int)0x3 << 28;
00208                 LPC_PINCON->PINMODE3 &= ~((unsigned int)0x3 << 28);
00209                 LPC_PINCON->PINMODE3 |= (unsigned int)0x2 << 28;
00210                 break;
00211             case p20:// =p1.31 of LPC1768
00212                 LPC_PINCON->PINSEL3 &= ~((unsigned int)0x3 << 30);
00213                 LPC_PINCON->PINSEL3 |= (unsigned int)0x3 << 30;
00214                 LPC_PINCON->PINMODE3 &= ~((unsigned int)0x3 << 30);
00215                 LPC_PINCON->PINMODE3 |= (unsigned int)0x2 << 30;
00216                 break;
00217             default:
00218                 error("Invalid pin.");
00219                 break;
00220         }
00221         // Select channel
00222         LPC_ADC->ADCR |= (1 << ch);
00223     } else {
00224         switch (pin) {
00225             case p15://=p0.23 of LPC1768
00226                 LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 14);
00227                 LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 14);
00228                 break;
00229             case p16://=p0.24 of LPC1768
00230                 LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 16);
00231                 LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 16);
00232                 break;
00233             case p17://=p0.25 of LPC1768
00234                 LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 18);
00235                 LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 18);
00236                 break;
00237             case p18://=p0.26 of LPC1768:
00238                 LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 20);
00239                 LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 20);
00240                 break;
00241             case p19://=p1.30 of LPC1768
00242                 LPC_PINCON->PINSEL3 &= ~((unsigned int)0x3 << 28);
00243                 LPC_PINCON->PINMODE3 &= ~((unsigned int)0x3 << 28);
00244                 break;
00245             case p20://=p1.31 of LPC1768
00246                 LPC_PINCON->PINSEL3 &= ~((unsigned int)0x3 << 30);
00247                 LPC_PINCON->PINMODE3 &= ~((unsigned int)0x3 << 30);
00248                 break;
00249             default:
00250                 error("Invalid pin.");
00251                 break;
00252         }
00253         LPC_ADC->ADCR &= ~(1 << ch);
00254     }
00255 }
00256 
00257 void HighSpeedAnalogIn::interrupt_state(PinName pin, int state) {
00258     int ch = get_channel(pin);
00259     if (state == 1) {
00260         LPC_ADC->ADINTEN &= ~0x100;
00261         LPC_ADC->ADINTEN |= 1 << ch;
00262         /* Enable the HighSpeedAnalogIn Interrupt */
00263         NVIC_EnableIRQ(ADC_IRQn);
00264     } else {
00265         LPC_ADC->ADINTEN &= ~(1 << ch);
00266         //Disable interrrupt if no active pins left
00267         if ((LPC_ADC->ADINTEN & 0xFF) == 0)
00268             NVIC_DisableIRQ(ADC_IRQn);
00269     }
00270 }
00271 
00272 float HighSpeedAnalogIn::read(PinName pin) {
00273     /*
00274      * Reset DONE and OVERRUN.
00275      *
00276      * bit 31 : DONE
00277      * bit 30 : OVERRUN
00278      */
00279     _adc_data[get_channel(pin)] &= ~(((uint32_t)0x01 << 31) | ((uint32_t)0x01 << 30));
00280     return (float)((get_data(pin) >> 4) & 0xFFF) / (float)0xFFF;
00281 }
00282 
00283 unsigned short HighSpeedAnalogIn::read_u16(PinName pin) {
00284     /*
00285      * Reset DONE and OVERRUN.
00286      *
00287      * bit 31 : DONE
00288      * bit 30 : OVERRUN
00289      */
00290     _adc_data[get_channel(pin)] &= ~(((uint32_t)0x01 << 31) | ((uint32_t)0x01 << 30));
00291     return ((get_data(pin) >> 4) & 0xFFF);
00292 }