Read an audio signal from the ADC, write it out to a file on the filestytem and perform a 1024 point FFT, writing frequency data to a csv file

Dependencies:   mbed

Committer:
jcobb
Date:
Sun Mar 21 18:06:46 2010 +0000
Revision:
0:5b7b619f59cd

        

Who changed what in which revision?

UserRevisionLine numberNew contents of line
jcobb 0:5b7b619f59cd 1 /* mbed Library - ADC
jcobb 0:5b7b619f59cd 2 * Copyright (c) 2010, sblandford
jcobb 0:5b7b619f59cd 3 * released under MIT license http://mbed.org/licence/mit
jcobb 0:5b7b619f59cd 4 */
jcobb 0:5b7b619f59cd 5 #include "mbed.h"
jcobb 0:5b7b619f59cd 6 #include "adc.h"
jcobb 0:5b7b619f59cd 7
jcobb 0:5b7b619f59cd 8
jcobb 0:5b7b619f59cd 9 ADC *ADC::instance;
jcobb 0:5b7b619f59cd 10
jcobb 0:5b7b619f59cd 11 ADC::ADC(int sample_rate, int cclk_div)
jcobb 0:5b7b619f59cd 12 {
jcobb 0:5b7b619f59cd 13
jcobb 0:5b7b619f59cd 14 int i, adc_clk_freq, pclk, clock_div, max_div=1;
jcobb 0:5b7b619f59cd 15
jcobb 0:5b7b619f59cd 16 //Work out CCLK
jcobb 0:5b7b619f59cd 17 adc_clk_freq=CLKS_PER_SAMPLE*sample_rate;
jcobb 0:5b7b619f59cd 18 int m = (LPC_SC->PLL0CFG & 0xFFFF) + 1;
jcobb 0:5b7b619f59cd 19 int n = (LPC_SC->PLL0CFG >> 16) + 1;
jcobb 0:5b7b619f59cd 20 int cclkdiv = LPC_SC->CCLKCFG + 1;
jcobb 0:5b7b619f59cd 21 int Fcco = (2 * m * XTAL_FREQ) / n;
jcobb 0:5b7b619f59cd 22 int cclk = Fcco / cclkdiv;
jcobb 0:5b7b619f59cd 23
jcobb 0:5b7b619f59cd 24 //Power up the ADC
jcobb 0:5b7b619f59cd 25 LPC_SC->PCONP |= (1 << 12);
jcobb 0:5b7b619f59cd 26 //Set clock at cclk / 1.
jcobb 0:5b7b619f59cd 27 LPC_SC->PCLKSEL0 &= ~(0x3 << 24);
jcobb 0:5b7b619f59cd 28 switch (cclk_div) {
jcobb 0:5b7b619f59cd 29 case 1:
jcobb 0:5b7b619f59cd 30 LPC_SC->PCLKSEL0 |= 0x1 << 24;
jcobb 0:5b7b619f59cd 31 break;
jcobb 0:5b7b619f59cd 32 case 2:
jcobb 0:5b7b619f59cd 33 LPC_SC->PCLKSEL0 |= 0x2 << 24;
jcobb 0:5b7b619f59cd 34 break;
jcobb 0:5b7b619f59cd 35 case 4:
jcobb 0:5b7b619f59cd 36 LPC_SC->PCLKSEL0 |= 0x0 << 24;
jcobb 0:5b7b619f59cd 37 break;
jcobb 0:5b7b619f59cd 38 case 8:
jcobb 0:5b7b619f59cd 39 LPC_SC->PCLKSEL0 |= 0x3 << 24;
jcobb 0:5b7b619f59cd 40 break;
jcobb 0:5b7b619f59cd 41 default:
jcobb 0:5b7b619f59cd 42 fprintf(stderr, "Warning: ADC CCLK clock divider must be 1, 2, 4 or 8. %u supplied.\n",
jcobb 0:5b7b619f59cd 43 cclk_div);
jcobb 0:5b7b619f59cd 44 fprintf(stderr, "Defaulting to 1.\n");
jcobb 0:5b7b619f59cd 45 LPC_SC->PCLKSEL0 |= 0x1 << 24;
jcobb 0:5b7b619f59cd 46 break;
jcobb 0:5b7b619f59cd 47 }
jcobb 0:5b7b619f59cd 48 pclk = cclk / cclk_div;
jcobb 0:5b7b619f59cd 49 clock_div=pclk / adc_clk_freq;
jcobb 0:5b7b619f59cd 50
jcobb 0:5b7b619f59cd 51 if (clock_div > 0xFF) {
jcobb 0:5b7b619f59cd 52 fprintf(stderr, "Warning: Clock division is %u which is above 255 limit. Re-Setting at limit.\n",
jcobb 0:5b7b619f59cd 53 clock_div);
jcobb 0:5b7b619f59cd 54 clock_div=0xFF;
jcobb 0:5b7b619f59cd 55 }
jcobb 0:5b7b619f59cd 56 if (clock_div == 0) {
jcobb 0:5b7b619f59cd 57 fprintf(stderr, "Warning: Clock division is 0. Re-Setting to 1.\n");
jcobb 0:5b7b619f59cd 58 clock_div=1;
jcobb 0:5b7b619f59cd 59 }
jcobb 0:5b7b619f59cd 60
jcobb 0:5b7b619f59cd 61 _adc_clk_freq=pclk / clock_div;
jcobb 0:5b7b619f59cd 62 if (_adc_clk_freq > MAX_ADC_CLOCK) {
jcobb 0:5b7b619f59cd 63 fprintf(stderr, "Warning: Actual ADC sample rate of %u which is above %u limit\n",
jcobb 0:5b7b619f59cd 64 _adc_clk_freq / CLKS_PER_SAMPLE, MAX_ADC_CLOCK / CLKS_PER_SAMPLE);
jcobb 0:5b7b619f59cd 65 while ((pclk / max_div) > MAX_ADC_CLOCK) max_div++;
jcobb 0:5b7b619f59cd 66 fprintf(stderr, "Maximum recommended sample rate is %u\n", (pclk / max_div) / CLKS_PER_SAMPLE);
jcobb 0:5b7b619f59cd 67 }
jcobb 0:5b7b619f59cd 68
jcobb 0:5b7b619f59cd 69 LPC_ADC->ADCR =
jcobb 0:5b7b619f59cd 70 ((clock_div - 1 ) << 8 ) | //Clkdiv
jcobb 0:5b7b619f59cd 71 ( 1 << 21 ); //A/D operational
jcobb 0:5b7b619f59cd 72
jcobb 0:5b7b619f59cd 73 //Default no channels enabled
jcobb 0:5b7b619f59cd 74 LPC_ADC->ADCR &= ~0xFF;
jcobb 0:5b7b619f59cd 75 //Default NULL global custom isr
jcobb 0:5b7b619f59cd 76 _adc_g_isr = NULL;
jcobb 0:5b7b619f59cd 77 //Initialize arrays
jcobb 0:5b7b619f59cd 78 for (i=7; i>=0; i--) {
jcobb 0:5b7b619f59cd 79 _adc_data[i] = 0;
jcobb 0:5b7b619f59cd 80 _adc_isr[i] = NULL;
jcobb 0:5b7b619f59cd 81 }
jcobb 0:5b7b619f59cd 82
jcobb 0:5b7b619f59cd 83
jcobb 0:5b7b619f59cd 84 //* Attach IRQ
jcobb 0:5b7b619f59cd 85 instance = this;
jcobb 0:5b7b619f59cd 86 NVIC_SetVector(ADC_IRQn, (uint32_t)&_adcisr);
jcobb 0:5b7b619f59cd 87
jcobb 0:5b7b619f59cd 88 //Disable global interrupt
jcobb 0:5b7b619f59cd 89 LPC_ADC->ADINTEN &= ~0x100;
jcobb 0:5b7b619f59cd 90
jcobb 0:5b7b619f59cd 91 };
jcobb 0:5b7b619f59cd 92
jcobb 0:5b7b619f59cd 93 void ADC::_adcisr(void)
jcobb 0:5b7b619f59cd 94 {
jcobb 0:5b7b619f59cd 95 instance->adcisr();
jcobb 0:5b7b619f59cd 96 }
jcobb 0:5b7b619f59cd 97
jcobb 0:5b7b619f59cd 98
jcobb 0:5b7b619f59cd 99 void ADC::adcisr(void)
jcobb 0:5b7b619f59cd 100 {
jcobb 0:5b7b619f59cd 101 uint32_t stat;
jcobb 0:5b7b619f59cd 102 int chan;
jcobb 0:5b7b619f59cd 103
jcobb 0:5b7b619f59cd 104 // Read status
jcobb 0:5b7b619f59cd 105 stat = LPC_ADC->ADSTAT;
jcobb 0:5b7b619f59cd 106 //Scan channels for over-run or done and update array
jcobb 0:5b7b619f59cd 107 if (stat & 0x0101) _adc_data[0] = LPC_ADC->ADDR0;
jcobb 0:5b7b619f59cd 108 if (stat & 0x0202) _adc_data[1] = LPC_ADC->ADDR1;
jcobb 0:5b7b619f59cd 109 if (stat & 0x0404) _adc_data[2] = LPC_ADC->ADDR2;
jcobb 0:5b7b619f59cd 110 if (stat & 0x0808) _adc_data[3] = LPC_ADC->ADDR3;
jcobb 0:5b7b619f59cd 111 if (stat & 0x1010) _adc_data[4] = LPC_ADC->ADDR4;
jcobb 0:5b7b619f59cd 112 if (stat & 0x2020) _adc_data[5] = LPC_ADC->ADDR5;
jcobb 0:5b7b619f59cd 113 if (stat & 0x4040) _adc_data[6] = LPC_ADC->ADDR6;
jcobb 0:5b7b619f59cd 114 if (stat & 0x8080) _adc_data[7] = LPC_ADC->ADDR7;
jcobb 0:5b7b619f59cd 115
jcobb 0:5b7b619f59cd 116 // Channel that triggered interrupt
jcobb 0:5b7b619f59cd 117 chan = (LPC_ADC->ADGDR >> 24) & 0x07;
jcobb 0:5b7b619f59cd 118 //User defined interrupt handlers
jcobb 0:5b7b619f59cd 119 if (_adc_isr[chan] != NULL)
jcobb 0:5b7b619f59cd 120 _adc_isr[chan](_adc_data[chan]);
jcobb 0:5b7b619f59cd 121 if (_adc_g_isr != NULL)
jcobb 0:5b7b619f59cd 122 _adc_g_isr(chan, _adc_data[chan]);
jcobb 0:5b7b619f59cd 123 return;
jcobb 0:5b7b619f59cd 124 }
jcobb 0:5b7b619f59cd 125
jcobb 0:5b7b619f59cd 126 int ADC::_pin_to_channel(PinName pin) {
jcobb 0:5b7b619f59cd 127 int chan;
jcobb 0:5b7b619f59cd 128 switch (pin) {
jcobb 0:5b7b619f59cd 129 case p15://=p0.23 of LPC1768
jcobb 0:5b7b619f59cd 130 default:
jcobb 0:5b7b619f59cd 131 chan=0;
jcobb 0:5b7b619f59cd 132 break;
jcobb 0:5b7b619f59cd 133 case p16://=p0.24 of LPC1768
jcobb 0:5b7b619f59cd 134 chan=1;
jcobb 0:5b7b619f59cd 135 break;
jcobb 0:5b7b619f59cd 136 case p17://=p0.25 of LPC1768
jcobb 0:5b7b619f59cd 137 chan=2;
jcobb 0:5b7b619f59cd 138 break;
jcobb 0:5b7b619f59cd 139 case p18://=p0.26 of LPC1768
jcobb 0:5b7b619f59cd 140 chan=3;
jcobb 0:5b7b619f59cd 141 break;
jcobb 0:5b7b619f59cd 142 case p19://=p1.30 of LPC1768
jcobb 0:5b7b619f59cd 143 chan=4;
jcobb 0:5b7b619f59cd 144 break;
jcobb 0:5b7b619f59cd 145 case p20://=p1.31 of LPC1768
jcobb 0:5b7b619f59cd 146 chan=5;
jcobb 0:5b7b619f59cd 147 break;
jcobb 0:5b7b619f59cd 148 }
jcobb 0:5b7b619f59cd 149 return(chan);
jcobb 0:5b7b619f59cd 150 }
jcobb 0:5b7b619f59cd 151
jcobb 0:5b7b619f59cd 152 PinName ADC::channel_to_pin(int chan) {
jcobb 0:5b7b619f59cd 153 const PinName pin[8]={p15, p16, p17, p18, p19, p20, p15, p15};
jcobb 0:5b7b619f59cd 154
jcobb 0:5b7b619f59cd 155 if ((chan < 0) || (chan > 5))
jcobb 0:5b7b619f59cd 156 fprintf(stderr, "ADC channel %u is outside range available to MBED pins.\n", chan);
jcobb 0:5b7b619f59cd 157 return(pin[chan & 0x07]);
jcobb 0:5b7b619f59cd 158 }
jcobb 0:5b7b619f59cd 159
jcobb 0:5b7b619f59cd 160
jcobb 0:5b7b619f59cd 161 int ADC::channel_to_pin_number(int chan) {
jcobb 0:5b7b619f59cd 162 const int pin[8]={15, 16, 17, 18, 19, 20, 0, 0};
jcobb 0:5b7b619f59cd 163
jcobb 0:5b7b619f59cd 164 if ((chan < 0) || (chan > 5))
jcobb 0:5b7b619f59cd 165 fprintf(stderr, "ADC channel %u is outside range available to MBED pins.\n", chan);
jcobb 0:5b7b619f59cd 166 return(pin[chan & 0x07]);
jcobb 0:5b7b619f59cd 167 }
jcobb 0:5b7b619f59cd 168
jcobb 0:5b7b619f59cd 169
jcobb 0:5b7b619f59cd 170 uint32_t ADC::_data_of_pin(PinName pin) {
jcobb 0:5b7b619f59cd 171 //If in burst mode and at least one interrupt enabled then
jcobb 0:5b7b619f59cd 172 //take all values from _adc_data
jcobb 0:5b7b619f59cd 173 if (burst() && (LPC_ADC->ADINTEN & 0x3F)) {
jcobb 0:5b7b619f59cd 174 return(_adc_data[_pin_to_channel(pin)]);
jcobb 0:5b7b619f59cd 175 } else {
jcobb 0:5b7b619f59cd 176 //Return current register value or last value from interrupt
jcobb 0:5b7b619f59cd 177 switch (pin) {
jcobb 0:5b7b619f59cd 178 case p15://=p0.23 of LPC1768
jcobb 0:5b7b619f59cd 179 default:
jcobb 0:5b7b619f59cd 180 return(LPC_ADC->ADINTEN & 0x01?_adc_data[0]:LPC_ADC->ADDR0);
jcobb 0:5b7b619f59cd 181 case p16://=p0.24 of LPC1768
jcobb 0:5b7b619f59cd 182 return(LPC_ADC->ADINTEN & 0x02?_adc_data[1]:LPC_ADC->ADDR1);
jcobb 0:5b7b619f59cd 183 case p17://=p0.25 of LPC1768
jcobb 0:5b7b619f59cd 184 return(LPC_ADC->ADINTEN & 0x04?_adc_data[2]:LPC_ADC->ADDR2);
jcobb 0:5b7b619f59cd 185 case p18://=p0.26 of LPC1768:
jcobb 0:5b7b619f59cd 186 return(LPC_ADC->ADINTEN & 0x08?_adc_data[3]:LPC_ADC->ADDR3);
jcobb 0:5b7b619f59cd 187 case p19://=p1.30 of LPC1768
jcobb 0:5b7b619f59cd 188 return(LPC_ADC->ADINTEN & 0x10?_adc_data[4]:LPC_ADC->ADDR4);
jcobb 0:5b7b619f59cd 189 case p20://=p1.31 of LPC1768
jcobb 0:5b7b619f59cd 190 return(LPC_ADC->ADINTEN & 0x20?_adc_data[5]:LPC_ADC->ADDR5);
jcobb 0:5b7b619f59cd 191 }
jcobb 0:5b7b619f59cd 192 }
jcobb 0:5b7b619f59cd 193 }
jcobb 0:5b7b619f59cd 194
jcobb 0:5b7b619f59cd 195 //Enable or disable an ADC pin
jcobb 0:5b7b619f59cd 196 void ADC::setup(PinName pin, int state) {
jcobb 0:5b7b619f59cd 197 int chan;
jcobb 0:5b7b619f59cd 198 chan=_pin_to_channel(pin);
jcobb 0:5b7b619f59cd 199 if ((state & 1) == 1) {
jcobb 0:5b7b619f59cd 200 switch(pin) {
jcobb 0:5b7b619f59cd 201 case p15://=p0.23 of LPC1768
jcobb 0:5b7b619f59cd 202 default:
jcobb 0:5b7b619f59cd 203 LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 14);
jcobb 0:5b7b619f59cd 204 LPC_PINCON->PINSEL1 |= (unsigned int)0x1 << 14;
jcobb 0:5b7b619f59cd 205 LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 14);
jcobb 0:5b7b619f59cd 206 LPC_PINCON->PINMODE1 |= (unsigned int)0x2 << 14;
jcobb 0:5b7b619f59cd 207 break;
jcobb 0:5b7b619f59cd 208 case p16://=p0.24 of LPC1768
jcobb 0:5b7b619f59cd 209 LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 16);
jcobb 0:5b7b619f59cd 210 LPC_PINCON->PINSEL1 |= (unsigned int)0x1 << 16;
jcobb 0:5b7b619f59cd 211 LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 16);
jcobb 0:5b7b619f59cd 212 LPC_PINCON->PINMODE1 |= (unsigned int)0x2 << 16;
jcobb 0:5b7b619f59cd 213 break;
jcobb 0:5b7b619f59cd 214 case p17://=p0.25 of LPC1768
jcobb 0:5b7b619f59cd 215 LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 18);
jcobb 0:5b7b619f59cd 216 LPC_PINCON->PINSEL1 |= (unsigned int)0x1 << 18;
jcobb 0:5b7b619f59cd 217 LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 18);
jcobb 0:5b7b619f59cd 218 LPC_PINCON->PINMODE1 |= (unsigned int)0x2 << 18;
jcobb 0:5b7b619f59cd 219 break;
jcobb 0:5b7b619f59cd 220 case p18://=p0.26 of LPC1768:
jcobb 0:5b7b619f59cd 221 LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 20);
jcobb 0:5b7b619f59cd 222 LPC_PINCON->PINSEL1 |= (unsigned int)0x1 << 20;
jcobb 0:5b7b619f59cd 223 LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 20);
jcobb 0:5b7b619f59cd 224 LPC_PINCON->PINMODE1 |= (unsigned int)0x2 << 20;
jcobb 0:5b7b619f59cd 225 break;
jcobb 0:5b7b619f59cd 226 case p19://=p1.30 of LPC1768
jcobb 0:5b7b619f59cd 227 LPC_PINCON->PINSEL3 &= ~((unsigned int)0x3 << 28);
jcobb 0:5b7b619f59cd 228 LPC_PINCON->PINSEL3 |= (unsigned int)0x3 << 28;
jcobb 0:5b7b619f59cd 229 LPC_PINCON->PINMODE3 &= ~((unsigned int)0x3 << 28);
jcobb 0:5b7b619f59cd 230 LPC_PINCON->PINMODE3 |= (unsigned int)0x2 << 28;
jcobb 0:5b7b619f59cd 231 break;
jcobb 0:5b7b619f59cd 232 case p20://=p1.31 of LPC1768
jcobb 0:5b7b619f59cd 233 LPC_PINCON->PINSEL3 &= ~((unsigned int)0x3 << 30);
jcobb 0:5b7b619f59cd 234 LPC_PINCON->PINSEL3 |= (unsigned int)0x3 << 30;
jcobb 0:5b7b619f59cd 235 LPC_PINCON->PINMODE3 &= ~((unsigned int)0x3 << 30);
jcobb 0:5b7b619f59cd 236 LPC_PINCON->PINMODE3 |= (unsigned int)0x2 << 30;
jcobb 0:5b7b619f59cd 237 break;
jcobb 0:5b7b619f59cd 238 }
jcobb 0:5b7b619f59cd 239 //Only one channel can be selected at a time if not in burst mode
jcobb 0:5b7b619f59cd 240 if (!burst()) LPC_ADC->ADCR &= ~0xFF;
jcobb 0:5b7b619f59cd 241 //Select channel
jcobb 0:5b7b619f59cd 242 LPC_ADC->ADCR |= (1 << chan);
jcobb 0:5b7b619f59cd 243 }
jcobb 0:5b7b619f59cd 244 else {
jcobb 0:5b7b619f59cd 245 switch(pin) {
jcobb 0:5b7b619f59cd 246 case p15://=p0.23 of LPC1768
jcobb 0:5b7b619f59cd 247 default:
jcobb 0:5b7b619f59cd 248 LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 14);
jcobb 0:5b7b619f59cd 249 LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 14);
jcobb 0:5b7b619f59cd 250 break;
jcobb 0:5b7b619f59cd 251 case p16://=p0.24 of LPC1768
jcobb 0:5b7b619f59cd 252 LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 16);
jcobb 0:5b7b619f59cd 253 LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 16);
jcobb 0:5b7b619f59cd 254 break;
jcobb 0:5b7b619f59cd 255 case p17://=p0.25 of LPC1768
jcobb 0:5b7b619f59cd 256 LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 18);
jcobb 0:5b7b619f59cd 257 LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 18);
jcobb 0:5b7b619f59cd 258 break;
jcobb 0:5b7b619f59cd 259 case p18://=p0.26 of LPC1768:
jcobb 0:5b7b619f59cd 260 LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 20);
jcobb 0:5b7b619f59cd 261 LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 20);
jcobb 0:5b7b619f59cd 262 break;
jcobb 0:5b7b619f59cd 263 case p19://=p1.30 of LPC1768
jcobb 0:5b7b619f59cd 264 LPC_PINCON->PINSEL3 &= ~((unsigned int)0x3 << 28);
jcobb 0:5b7b619f59cd 265 LPC_PINCON->PINMODE3 &= ~((unsigned int)0x3 << 28);
jcobb 0:5b7b619f59cd 266 break;
jcobb 0:5b7b619f59cd 267 case p20://=p1.31 of LPC1768
jcobb 0:5b7b619f59cd 268 LPC_PINCON->PINSEL3 &= ~((unsigned int)0x3 << 30);
jcobb 0:5b7b619f59cd 269 LPC_PINCON->PINMODE3 &= ~((unsigned int)0x3 << 30);
jcobb 0:5b7b619f59cd 270 break;
jcobb 0:5b7b619f59cd 271 }
jcobb 0:5b7b619f59cd 272 LPC_ADC->ADCR &= ~(1 << chan);
jcobb 0:5b7b619f59cd 273 }
jcobb 0:5b7b619f59cd 274 }
jcobb 0:5b7b619f59cd 275 //Return channel enabled/disabled state
jcobb 0:5b7b619f59cd 276 int ADC::setup(PinName pin) {
jcobb 0:5b7b619f59cd 277 int chan;
jcobb 0:5b7b619f59cd 278
jcobb 0:5b7b619f59cd 279 chan = _pin_to_channel(pin);
jcobb 0:5b7b619f59cd 280 return((LPC_ADC->ADCR & (1 << chan)) >> chan);
jcobb 0:5b7b619f59cd 281 }
jcobb 0:5b7b619f59cd 282
jcobb 0:5b7b619f59cd 283 //Select channel already setup
jcobb 0:5b7b619f59cd 284 void ADC::select(PinName pin) {
jcobb 0:5b7b619f59cd 285 int chan;
jcobb 0:5b7b619f59cd 286
jcobb 0:5b7b619f59cd 287 //Only one channel can be selected at a time if not in burst mode
jcobb 0:5b7b619f59cd 288 if (!burst()) LPC_ADC->ADCR &= ~0xFF;
jcobb 0:5b7b619f59cd 289 //Select channel
jcobb 0:5b7b619f59cd 290 chan = _pin_to_channel(pin);
jcobb 0:5b7b619f59cd 291 LPC_ADC->ADCR |= (1 << chan);
jcobb 0:5b7b619f59cd 292 }
jcobb 0:5b7b619f59cd 293
jcobb 0:5b7b619f59cd 294 //Enable or disable burst mode
jcobb 0:5b7b619f59cd 295 void ADC::burst(int state) {
jcobb 0:5b7b619f59cd 296 if ((state & 1) == 1) {
jcobb 0:5b7b619f59cd 297 if (startmode(0) != 0)
jcobb 0:5b7b619f59cd 298 fprintf(stderr, "Warning. startmode is %u. Must be 0 for burst mode.\n", startmode(0));
jcobb 0:5b7b619f59cd 299 LPC_ADC->ADCR |= (1 << 16);
jcobb 0:5b7b619f59cd 300 }
jcobb 0:5b7b619f59cd 301 else
jcobb 0:5b7b619f59cd 302 LPC_ADC->ADCR &= ~(1 << 16);
jcobb 0:5b7b619f59cd 303 }
jcobb 0:5b7b619f59cd 304 //Return burst mode state
jcobb 0:5b7b619f59cd 305 int ADC::burst(void) {
jcobb 0:5b7b619f59cd 306 return((LPC_ADC->ADCR & (1 << 16)) >> 16);
jcobb 0:5b7b619f59cd 307 }
jcobb 0:5b7b619f59cd 308
jcobb 0:5b7b619f59cd 309 //Set startmode and edge
jcobb 0:5b7b619f59cd 310 void ADC::startmode(int mode, int edge) {
jcobb 0:5b7b619f59cd 311 int lpc_adc_temp;
jcobb 0:5b7b619f59cd 312
jcobb 0:5b7b619f59cd 313 //Reset start mode and edge bit,
jcobb 0:5b7b619f59cd 314 lpc_adc_temp = LPC_ADC->ADCR & ~(0x0F << 24);
jcobb 0:5b7b619f59cd 315 //Write with new values
jcobb 0:5b7b619f59cd 316 lpc_adc_temp |= ((mode & 7) << 24) | ((edge & 1) << 27);
jcobb 0:5b7b619f59cd 317 LPC_ADC->ADCR = lpc_adc_temp;
jcobb 0:5b7b619f59cd 318 }
jcobb 0:5b7b619f59cd 319
jcobb 0:5b7b619f59cd 320 //Return startmode state according to mode_edge=0: mode and mode_edge=1: edge
jcobb 0:5b7b619f59cd 321 int ADC::startmode(int mode_edge){
jcobb 0:5b7b619f59cd 322 switch (mode_edge) {
jcobb 0:5b7b619f59cd 323 case 0:
jcobb 0:5b7b619f59cd 324 default:
jcobb 0:5b7b619f59cd 325 return((LPC_ADC->ADCR >> 24) & 0x07);
jcobb 0:5b7b619f59cd 326 case 1:
jcobb 0:5b7b619f59cd 327 return((LPC_ADC->ADCR >> 27) & 0x01);
jcobb 0:5b7b619f59cd 328 }
jcobb 0:5b7b619f59cd 329 }
jcobb 0:5b7b619f59cd 330
jcobb 0:5b7b619f59cd 331 //Start ADC conversion
jcobb 0:5b7b619f59cd 332 void ADC::start(void) {
jcobb 0:5b7b619f59cd 333 startmode(1,0);
jcobb 0:5b7b619f59cd 334 }
jcobb 0:5b7b619f59cd 335
jcobb 0:5b7b619f59cd 336
jcobb 0:5b7b619f59cd 337 //Set interrupt enable/disable for pin to state
jcobb 0:5b7b619f59cd 338 void ADC::interrupt_state(PinName pin, int state) {
jcobb 0:5b7b619f59cd 339 int chan;
jcobb 0:5b7b619f59cd 340
jcobb 0:5b7b619f59cd 341 chan = _pin_to_channel(pin);
jcobb 0:5b7b619f59cd 342 if (state == 1) {
jcobb 0:5b7b619f59cd 343 LPC_ADC->ADINTEN &= ~0x100;
jcobb 0:5b7b619f59cd 344 LPC_ADC->ADINTEN |= 1 << chan;
jcobb 0:5b7b619f59cd 345 /* Enable the ADC Interrupt */
jcobb 0:5b7b619f59cd 346 NVIC_EnableIRQ(ADC_IRQn);
jcobb 0:5b7b619f59cd 347 } else {
jcobb 0:5b7b619f59cd 348 LPC_ADC->ADINTEN &= ~( 1 << chan );
jcobb 0:5b7b619f59cd 349 //Disable interrrupt if no active pins left
jcobb 0:5b7b619f59cd 350 if ((LPC_ADC->ADINTEN & 0xFF) == 0)
jcobb 0:5b7b619f59cd 351 NVIC_DisableIRQ(ADC_IRQn);
jcobb 0:5b7b619f59cd 352 }
jcobb 0:5b7b619f59cd 353 }
jcobb 0:5b7b619f59cd 354
jcobb 0:5b7b619f59cd 355 //Return enable/disable state of interrupt for pin
jcobb 0:5b7b619f59cd 356 int ADC::interrupt_state(PinName pin) {
jcobb 0:5b7b619f59cd 357 int chan;
jcobb 0:5b7b619f59cd 358
jcobb 0:5b7b619f59cd 359 chan = _pin_to_channel(pin);
jcobb 0:5b7b619f59cd 360 return((LPC_ADC->ADINTEN >> chan) & 0x01);
jcobb 0:5b7b619f59cd 361 }
jcobb 0:5b7b619f59cd 362
jcobb 0:5b7b619f59cd 363
jcobb 0:5b7b619f59cd 364 //Attach custom interrupt handler replacing default
jcobb 0:5b7b619f59cd 365 void ADC::attach(void(*fptr)(void)) {
jcobb 0:5b7b619f59cd 366 //* Attach IRQ
jcobb 0:5b7b619f59cd 367 NVIC_SetVector(ADC_IRQn, (uint32_t)fptr);
jcobb 0:5b7b619f59cd 368 }
jcobb 0:5b7b619f59cd 369
jcobb 0:5b7b619f59cd 370 //Restore default interrupt handler
jcobb 0:5b7b619f59cd 371 void ADC::detach(void) {
jcobb 0:5b7b619f59cd 372 //* Attach IRQ
jcobb 0:5b7b619f59cd 373 instance = this;
jcobb 0:5b7b619f59cd 374 NVIC_SetVector(ADC_IRQn, (uint32_t)&_adcisr);
jcobb 0:5b7b619f59cd 375 }
jcobb 0:5b7b619f59cd 376
jcobb 0:5b7b619f59cd 377
jcobb 0:5b7b619f59cd 378 //Append interrupt handler for pin to function isr
jcobb 0:5b7b619f59cd 379 void ADC::append(PinName pin, void(*fptr)(uint32_t value)) {
jcobb 0:5b7b619f59cd 380 int chan;
jcobb 0:5b7b619f59cd 381
jcobb 0:5b7b619f59cd 382 chan = _pin_to_channel(pin);
jcobb 0:5b7b619f59cd 383 _adc_isr[chan] = fptr;
jcobb 0:5b7b619f59cd 384 }
jcobb 0:5b7b619f59cd 385
jcobb 0:5b7b619f59cd 386 //Append interrupt handler for pin to function isr
jcobb 0:5b7b619f59cd 387 void ADC::unappend(PinName pin) {
jcobb 0:5b7b619f59cd 388 int chan;
jcobb 0:5b7b619f59cd 389
jcobb 0:5b7b619f59cd 390 chan = _pin_to_channel(pin);
jcobb 0:5b7b619f59cd 391 _adc_isr[chan] = NULL;
jcobb 0:5b7b619f59cd 392 }
jcobb 0:5b7b619f59cd 393
jcobb 0:5b7b619f59cd 394 //Unappend global interrupt handler to function isr
jcobb 0:5b7b619f59cd 395 void ADC::append(void(*fptr)(int chan, uint32_t value)) {
jcobb 0:5b7b619f59cd 396 _adc_g_isr = fptr;
jcobb 0:5b7b619f59cd 397 }
jcobb 0:5b7b619f59cd 398
jcobb 0:5b7b619f59cd 399 //Detach global interrupt handler to function isr
jcobb 0:5b7b619f59cd 400 void ADC::unappend() {
jcobb 0:5b7b619f59cd 401 _adc_g_isr = NULL;
jcobb 0:5b7b619f59cd 402 }
jcobb 0:5b7b619f59cd 403
jcobb 0:5b7b619f59cd 404 //Set ADC offset
jcobb 0:5b7b619f59cd 405 void offset(int offset) {
jcobb 0:5b7b619f59cd 406 LPC_ADC->ADTRM &= ~(0x07 << 4);
jcobb 0:5b7b619f59cd 407 LPC_ADC->ADTRM |= (offset & 0x07) << 4;
jcobb 0:5b7b619f59cd 408 }
jcobb 0:5b7b619f59cd 409
jcobb 0:5b7b619f59cd 410 //Return current ADC offset
jcobb 0:5b7b619f59cd 411 int offset(void) {
jcobb 0:5b7b619f59cd 412 return((LPC_ADC->ADTRM >> 4) & 0x07);
jcobb 0:5b7b619f59cd 413 }
jcobb 0:5b7b619f59cd 414
jcobb 0:5b7b619f59cd 415 //Return value of ADC on pin
jcobb 0:5b7b619f59cd 416 int ADC::read(PinName pin) {
jcobb 0:5b7b619f59cd 417 //Reset DONE and OVERRUN flags of interrupt handled ADC data
jcobb 0:5b7b619f59cd 418 _adc_data[_pin_to_channel(pin)] &= ~(((uint32_t)0x01 << 31) | ((uint32_t)0x01 << 30));
jcobb 0:5b7b619f59cd 419 //Return value
jcobb 0:5b7b619f59cd 420 return((_data_of_pin(pin) >> 4) & 0xFFF);
jcobb 0:5b7b619f59cd 421 }
jcobb 0:5b7b619f59cd 422
jcobb 0:5b7b619f59cd 423 //Return DONE flag of ADC on pin
jcobb 0:5b7b619f59cd 424 int ADC::done(PinName pin) {
jcobb 0:5b7b619f59cd 425 return((_data_of_pin(pin) >> 31) & 0x01);
jcobb 0:5b7b619f59cd 426 }
jcobb 0:5b7b619f59cd 427
jcobb 0:5b7b619f59cd 428 //Return OVERRUN flag of ADC on pin
jcobb 0:5b7b619f59cd 429 int ADC::overrun(PinName pin) {
jcobb 0:5b7b619f59cd 430 return((_data_of_pin(pin) >> 30) & 0x01);
jcobb 0:5b7b619f59cd 431 }
jcobb 0:5b7b619f59cd 432
jcobb 0:5b7b619f59cd 433 int ADC::actual_adc_clock(void) {
jcobb 0:5b7b619f59cd 434 return(_adc_clk_freq);
jcobb 0:5b7b619f59cd 435 }
jcobb 0:5b7b619f59cd 436
jcobb 0:5b7b619f59cd 437 int ADC::actual_sample_rate(void) {
jcobb 0:5b7b619f59cd 438 return(_adc_clk_freq / CLKS_PER_SAMPLE);
jcobb 0:5b7b619f59cd 439 }