00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00082
00083
00084 #ifdef __GNUC__
00085
00086 #include <string.h>
00087 #include <avr/sleep.h>
00088 #include <sys/heap.h>
00089 #include <sys/atom.h>
00090 #include <sys/nutconfig.h>
00091
00092 #include <dev/irqreg.h>
00093 #include <dev/adc.h>
00094
00095 #ifndef ADC_INITIAL_CHANNEL
00096 #define ADC_INITIAL_CHANNEL ADC0
00097 #endif
00098
00099 #ifndef ADC_INITIAL_REF
00100 #define ADC_INITIAL_REF AVCC
00101 #endif
00102
00103 #ifndef ADC_INITIAL_MODE
00104 #define ADC_INITIAL_MODE SINGLE_CONVERSION
00105 #endif
00106
00107 #ifndef ADC_INITIAL_PRESCALE
00108 #define ADC_INITIAL_PRESCALE ADC_PRESCALE_DIV64
00109 #endif
00110
00111 #define ADC_BUF_SIZE 16 // this may only be a power of two
00112
00113 #if defined(__GNUC__) && defined(__AVR_ENHANCED__)
00114 u_char adc_sleep_mode = SLEEP_MODE_ADC;
00115
00116
00117 #if defined(SMCR)
00118 #define AVR_SLEEP_CTRL_REG SMCR
00119 #else
00120 #define AVR_SLEEP_CTRL_REG MCUCR
00121 #endif
00122 #endif
00123
00124
00125
00126
00127 adc_mode_t current_mode = ADC_OFF;
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138 #define _adc_buf_head ADC_BUF_SIZE
00139 #define _adc_buf_tail ADC_BUF_SIZE+1
00140
00141 u_short *ADC_buffer = NULL;
00142
00143 inline int ADCBufRead(u_short * buf, u_short * read)
00144 {
00145 u_char tail, head;
00146 tail = buf[_adc_buf_tail];
00147 head = buf[_adc_buf_head];
00148 if (head != tail) {
00149 *read = buf[tail];
00150 buf[_adc_buf_tail] = (tail + 1) & (ADC_BUF_SIZE-1);
00151 return 0;
00152 }
00153 return 1;
00154 }
00155
00156 inline int ADCBufWrite(u_short * buf, u_short * write)
00157 {
00158 u_char tail, head;
00159 tail = buf[_adc_buf_tail];
00160 head = buf[_adc_buf_head];
00161 if ((head + 1) % ADC_BUF_SIZE != tail) {
00162 buf[head] = *write;
00163 buf[_adc_buf_head] = (head + 1) & (ADC_BUF_SIZE-1);
00164 return 0;
00165 }
00166 return 1;
00167 }
00168
00169 void ADCBufInit(u_short * buf)
00170 {
00171 buf[_adc_buf_head] = 0;
00172 buf[_adc_buf_tail] = 0;
00173 }
00174
00175 static void ADCInterrupt(void *arg)
00176 {
00177 u_short ADC_value;
00178
00179 ADC_value = inw(ADCW);
00180
00181 if (ADCBufWrite(ADC_buffer, &ADC_value) != 0) {
00182
00183 }
00184
00185 }
00186
00187 void ADCInit()
00188 {
00189 if (ADC_buffer) return;
00190
00191 ADCSetChannel(ADC_INITIAL_CHANNEL);
00192 ADCSetRef(ADC_INITIAL_REF);
00193 ADCSetMode(ADC_INITIAL_MODE);
00194 ADCSetPrescale(ADC_INITIAL_PRESCALE);
00195
00196 ADC_buffer = NutHeapAlloc(sizeof(u_short) * ADC_BUF_SIZE + 2);
00197 ADCBufInit(ADC_buffer);
00198
00199 if (NutRegisterIrqHandler(&sig_ADC, ADCInterrupt, NULL)) {
00200
00201 return;
00202 }
00203
00204 sbi(ADCSR, ADEN);
00205
00206
00207 sbi(ADCSR, ADIE);
00208 }
00209
00210 void ADCSetRef(adc_ref_t reference)
00211 {
00212 ADCStopConversion();
00213
00214 #ifdef __AVR_ENHANCED__
00215 switch (reference) {
00216 case AVCC:
00217 cbi(ADMUX, REFS1);
00218 sbi(ADMUX, REFS0);
00219 break;
00220 case AREF:
00221 cbi(ADMUX, REFS1);
00222 cbi(ADMUX, REFS0);
00223 break;
00224 case INTERNAL_256:
00225 sbi(ADMUX, REFS1);
00226 sbi(ADMUX, REFS0);
00227 break;
00228 }
00229 #endif
00230
00231 }
00232
00233 void ADCSetMode(adc_mode_t mode)
00234 {
00235 ADCStopConversion();
00236
00237 switch (mode) {
00238 case FREE_RUNNING:
00239 sbi(ADCSR, ADFR);
00240 break;
00241 case SINGLE_CONVERSION:
00242 cbi(ADCSR, ADFR);
00243 break;
00244 case ADC_OFF:
00245 break;
00246 }
00247 current_mode = mode;
00248 }
00249
00250 u_char ADCSetPrescale(u_char prescalar)
00251 {
00252
00253 ADCStopConversion();
00254
00255 if (prescalar > 128) {
00256 prescalar = 128;
00257 }
00258
00259 switch (prescalar) {
00260 case ADC_PRESCALE_DIV2:
00261 cbi(ADCSR, ADPS2);
00262 cbi(ADCSR, ADPS1);
00263 cbi(ADCSR, ADPS0);
00264 break;
00265 case ADC_PRESCALE_DIV4:
00266 cbi(ADCSR, ADPS2);
00267 sbi(ADCSR, ADPS1);
00268 cbi(ADCSR, ADPS0);
00269 break;
00270 case ADC_PRESCALE_DIV8:
00271 cbi(ADCSR, ADPS2);
00272 sbi(ADCSR, ADPS1);
00273 sbi(ADCSR, ADPS0);
00274 break;
00275 case ADC_PRESCALE_DIV16:
00276 sbi(ADCSR, ADPS2);
00277 cbi(ADCSR, ADPS1);
00278 cbi(ADCSR, ADPS0);
00279 break;
00280 case ADC_PRESCALE_DIV32:
00281 sbi(ADCSR, ADPS2);
00282 cbi(ADCSR, ADPS1);
00283 sbi(ADCSR, ADPS0);
00284 break;
00285 case ADC_PRESCALE_DIV64:
00286 sbi(ADCSR, ADPS2);
00287 sbi(ADCSR, ADPS1);
00288 cbi(ADCSR, ADPS0);
00289 break;
00290 case ADC_PRESCALE_DIV128:
00291 sbi(ADCSR, ADPS2);
00292 sbi(ADCSR, ADPS1);
00293 sbi(ADCSR, ADPS0);
00294 break;
00295
00296 default:
00297 return 1;
00298 break;
00299 }
00300
00301 return 0;
00302 }
00303
00304 void ADCSetChannel(adc_channel_t adc_channel)
00305 {
00306 u_char current_admux;
00307
00308 current_admux = inb(ADMUX) & 0xF8;
00309
00310 outb(ADMUX, (current_admux | adc_channel));
00311 }
00312
00313 void ADCBufferFlush(void)
00314 {
00315 ADCBufInit(ADC_buffer);
00316 }
00317
00318 void ADCStartConversion()
00319 {
00320 sbi(ADCSR, ADSC);
00321 }
00322
00323 void ADCStartLowNoiseConversion()
00324 {
00325 ADCSetMode(SINGLE_CONVERSION);
00326
00327 #if defined(__GNUC__) && defined(__AVR_ENHANCED__)
00328 {
00329 u_char sleep_mode = AVR_SLEEP_CTRL_REG & _SLEEP_MODE_MASK;
00330 set_sleep_mode(adc_sleep_mode);
00331
00332
00333 AVR_SLEEP_CTRL_REG |= _BV(SE);
00334 __asm__ __volatile__ ("sleep" "\n\t" :: );
00335 AVR_SLEEP_CTRL_REG &= ~_BV(SE);
00336 set_sleep_mode(sleep_mode);
00337 }
00338 #else
00339 sbi(ADCSR, ADSC);
00340 #endif
00341 }
00342
00343 void ADCStopConversion()
00344 {
00345 if (current_mode != FREE_RUNNING) {
00346
00347 return;
00348 }
00349
00350
00351
00352 cbi(ADCSR, ADEN);
00353 cbi(ADCSR, ADSC);
00354 sbi(ADCSR, ADEN);
00355 }
00356
00357 u_char ADCRead(u_short * value)
00358 {
00359 return ADCBufRead(ADC_buffer, value);
00360 }
00361
00362 inline adc_mode_t ADCGetMode(void)
00363 {
00364 return (current_mode);
00365 }
00366 #endif
00367