- Main Page
- Related Pages
- Data Structures
- Files

# ADC.c

Go to the documentation of this file.

    00001 /* This file has been prepared for Doxygen automatic documentation generation.*/
    00034 #include <ioavr.h>
    00035 #include <inavr.h>
    00036
    00037 #include "structs.h"
    00038
    00039 #include "main.h"
    00040 #include "ADC.h"
    00041
    00042
    00043 //******************************************************************************
    00044 // Variables
    00045 //******************************************************************************
    00046 // ADC status struct.
    00048 ADC_Status_t ADCS;
    00049
    00050
    00072 // Maximum battery voltage (affects scaling of samples).
    00073 __eeprom unsigned char VBAT_RANGE = 1;
    00074
    00075
    00076 //******************************************************************************
    00077 // Functions
    00078 //******************************************************************************
    00113 #pragma vector=ADC_vect
    00114 __interrupt void ADC_ISR(void)
    00115 {
    00116         static unsigned char avgIndex = 0;
    00117         unsigned char i, Next, Signed;
    00118         signed int  temp = 0;
    00119
    00120         Signed = FALSE;  // Presume next conversion is unipolar.
    00121         ADCSRA &= ~(1<<ADEN);  // Stop conversion before handling. This makes all
    00122           // conversions take at least 25 ADCCLK. (It is restarted later)
    00123
    00124         // Handle the conversion, depending on what channel it is from, then
    00125         // switch to the next channel in the sequence.
    00126         switch (ADCS.MUX){
    00127                 // MUX = 0b000001 => ADC1 (PA1) = NTC
    00128                 case 0x01:
    00129                         ADCS.rawNTC = ADC;
    00130                         Next=0x02;
    00131                 break;
    00132
    00133
    00134                 // MUX = 0b000010 => ADC2 (PA2) = RID
    00135                 case 0x02:
    00136                         ADCS.rawRID = ADC;
    00137                         Next=0x03;
    00138                 break;
    00139
    00140
    00141                 // MUX = 0b000011 => ADC3 (PA4) = VIN-
    00142                 case 0x03:
    00143                         // Supply voltage is always divided by 16.
    00144                         ADCS.VIN = ScaleU(4, (unsigned int)ADC);  // Cast because ADC is short.
    00145
    00146                         // Is mains failing?
    00147                         if (ADCS.VIN < VIN_MIN) {
    00148                                 ADCS.Mains = FALSE;
    00149                         } else {
    00150                                 ADCS.Mains = TRUE;
    00151                         }
    00152
    00153                         Next=0x05;
    00154                 break;
    00155
    00156
    00157                 // MUX = 0b000101 => ADC5 (PA6) = VBAT-
    00158                 case 0x05:
    00159                         ADCS.rawVBAT = ADC;
    00160
    00161                         // Scale voltage according to jumper setting.
    00162                         ADCS.VBAT = ScaleU(VBAT_RANGE, (unsigned int)ADC); // ADC is a short.
    00163                         Next=0x17;
    00164 //                      Signed = TRUE;  // Next conversion is bipolar. Halves sensitivity!
    00165                 break;
    00166
    00167
    00168                 case 0x17:  // MUX = 0b010111 => 20 x [ADC6(PA7) - ADC5(PA6)] = IBAT
    00169                         // If bipolar, from -512 to 0, to 511:
    00170                         // 0x200 ... 0x3ff, 0x000, 0x001 ... 0x1FF
    00171
    00172                         // Scale sample according to jumper setting, handle negative numbers.
    00173                         if (ADC > 511) {
    00174                                 ADCS.IBAT = -(signed int)ScaleI(VBAT_RANGE,
    00175                                              (1024 - (ADC-ADCS.ADC5_G20_OS)));
    00176                         } else if (ADC > 0) {
    00177                                 ADCS.IBAT = ScaleI(VBAT_RANGE, (ADC-ADCS.ADC5_G20_OS));
    00178                         } else {
    00179                                 ADCS.IBAT = 0;
    00180                         }
    00181
    00182                         // Insert sample of battery current into the averaging-array
    00183                         // (overwriting the oldest sample), then recalculate and store the
    00184                         // average. This is the last conversion in the sequence, so
    00185                         // flag a complete ADC-cycle and restart sequence.
    00186                         ADCS.discIBAT[(avgIndex++ & 0x03)] = ADCS.IBAT;
    00187                         for (i = 0; i < 4 ; i++) {
    00188                                 temp += ADCS.discIBAT[i];
    00189                         }
    00190
    00191                         ADCS.avgIBAT = (temp / 4);
    00192
    00193                         ADCS.Flag = TRUE;
    00194                         Next=0x01;
    00195                         Signed = FALSE;  // This is the only bipolar conversion.
    00196                 break;
    00197
    00198
    00199                 default:  // Should not happen. (Invalid MUX-channel)
    00200                         Next=0x01;  // Start at the beginning of sequence.
    00201                 break;
    00202         }
    00203
    00204         // Update MUX to next channel in sequence, set a bipolar conversion if
    00205         // this has been flagged.
    00206         ADCS.MUX = Next;
    00207         ADMUX = (1<<REFS0) + ADCS.MUX;
    00208
    00209         if (Signed)     {
    00210           ADCSRB |= (1<<BIN);
    00211         } else {
    00212           ADCSRB &= ~(1<<BIN);
    00213         }
    00214
    00215         // Re-enable the ADC unless a halt has been flagged and a conversion
    00216         // cycle has completed.
    00217         if (!((ADCS.Halt) && (ADCS.Flag))) {
    00218           ADCSRA |= (1<<ADEN)|(1<<ADSC);
    00219         }
    00220 }
    00221
    00222
    00246 unsigned int ScaleU(unsigned char setting, unsigned int data)
    00247 {
    00248         // Temporary variable needed.
    00249         unsigned int scaled = 0;
    00250
    00251         // Jumper setting 3: mV/LSB = 29.30 ~= 29 + 1/4 + 1/16
    00252         if (setting == 3)       {
    00253                 scaled = 29 * data;
    00254                 scaled += (data >> 2);
    00255                 scaled += (data >> 4);
    00256         } else {
    00257                 // Jumper setting 4: mV/LSB = 39.06 ~= 39 + 1/16
    00258                 scaled = 39 * data;
    00259                 scaled += (data >> 4);
    00260
    00261                 if (setting <3) {
    00262                         // Jumper setting 0: mV/LSB = 4.883 = 39.06 / 8
    00263                         //                1: mV/LSB = 9.766 = 39.06 / 4
    00264                         //                2: mV/LSB = 19.53 = 39.06 / 2
    00265                         scaled = (scaled >> (3-setting));
    00266                 }
    00267         }
    00268
    00269         return(scaled);
    00270 }
    00271
    00272
    00297 unsigned int ScaleI(unsigned char setting, unsigned int data)
    00298 {
    00299         // Temporary variable needed.
    00300         unsigned int  scaled = 0;
    00301
    00302         // Jumper setting 3: mA/LSB = 20.931mA ~= 21 - 1/16 + 1/128
    00303         if (setting == 3) {
    00304                 scaled = 21 * data;
    00305                 scaled -= (data >> 4);
    00306                 scaled += (data >> 7);
    00307         }       else    { // Jumper setting 4: mA/LSB = 27.909mA ~= 28 - 1/8 + 1/32
    00308                 scaled = 28 * data;
    00309                 scaled -= (data >> 3);
    00310                 scaled += (data >> 5);
    00311
    00312                 if (setting <3) {
    00313                         // Jumper setting 0: mA/LSB = 3.489mA = 27.909 / 8
    00314                         //                1: mA/LSB = 6.978mA = 27.909 / 4
    00315                         //                2: mA/LSB = 13.955mA = 27.909 / 2
    00316                         scaled = (scaled >> (3-setting));
    00317                 }
    00318         }
    00319
    00320         return(scaled);
    00321 }
    00322
    00323
    00330 void ADC_Wait(void)
    00331 {
    00332         // Clear ADC flag and wait for cycle to complete.
    00333         ADCS.Flag = FALSE;
    00334         do {
    00335         } while (ADCS.Flag == FALSE);
    00336
    00337         // Repeat, so we are sure the data beong to the same cycle.
    00338         ADCS.Flag = FALSE;
    00339         do {
    00340         } while (ADCS.Flag == FALSE);
    00341 }
    00342
    00343
    00369 void ADC_Init(void)
    00370 {
    00371         unsigned char i;
    00372
    00373         __disable_interrupt();
    00374
    00375         ADCS.Halt = FALSE; // Enable consecutive runs of ADC.
    00376
    00377         // Configure ADC pins (inputs and disabled pull-ups).
    00378         DDRA &= ~((1<<PA1)|(1<<PA2)|(1<<PA4)|(1<<PA5)|(1<<PA6)|(1<<PA7));
    00379         PORTA &= ~((1<<PA1)|(1<<PA2)|(1<<PA4)|(1<<PA5)|(1<<PA6)|(1<<PA7));
    00380
    00381         // Set ADC3 as reference, and MUX to measure the same pin.
    00382         ADMUX = (1<<REFS0) | (1<<MUX0) | (1<<MUX1);
    00383
    00384         ADCSRB = 0;
    00385
    00386         // Start conversion, no interrupt (disable ADC-ISR).
    00387         ADCSRA = (1<<ADEN) | (1<<ADSC) | ADC_PRESCALER;
    00388
    00389         do { // Wait for conversion to finish.
    00390         } while (!(ADCSRA & (1<<ADIF)));
    00391
    00392         ADCSRA |= (1<<ADIF);  // Clear ADC interrupt flag manually.
    00393
    00394         ADCS.ADC3_G20_OS = ADC;  // Save the sampled offset.
    00395
    00396         ADMUX = (1<<REFS0) | 0x16;  // ADC5/ADC5 (external ref.), 20x
    00397
    00398         // Start conversion, no interrupt. ADC_PRESCALER is defined in ADC.h.
    00399         ADCSRA = (1<<ADEN) | (1<<ADSC) | ADC_PRESCALER;
    00400
    00401         do { // Wait for conversion to finish.
    00402         } while (!(ADCSRA & (1<<ADIF)));
    00403
    00404         ADCSRA |= (1<<ADIF);  // Clear ADC interrupt flag.
    00405
    00406         ADCS.ADC5_G20_OS = ADC;  // Save the sampled offset.
    00407
    00408         // Reset the ADC-cycle.
    00409         ADCS.Flag = FALSE;
    00410         ADCS.MUX = 0x01;
    00411         ADMUX = (1<<REFS0) | ADCS.MUX;
    00412
    00413         // Clear averaged battery current and the discrete readings.
    00414         ADCS.avgIBAT = 0;
    00415
    00416         for (i = 0; i < 4; i++) {
    00417                 ADCS.discIBAT[i] = 0;
    00418         }
    00419
    00420         // Re-enable the ADC and ISR.
    00421         ADCSRA=(1<<ADEN)|(1<<ADSC)|(1<<ADIE)|ADC_PRESCALER;
    00422
    00423         __enable_interrupt();
    00424
    00425         // Get a complete cycle of data before returning.
    00426         ADC_Wait();
    00427 }