# ADC.h File Reference

## Detailed Description

Headerfile for ADC.c.

Contains definitions for ADC setup, and minimum supply voltage.

Application note:
  AVR458: Charging Li-Ion Batteries with BC100
  AVR463: Charging NiMH Batteries with BC100

Documentation:
  For comprehensive code documentation, supported compilers, compiler settings and supported devices see readme.html

Author:
  Atmel Corporation: http://www.atmel.com
  Support email: avr@atmel.com
  Original author:

$Name$

Revision
  2335

$RCSfile$

URL
  http://revisor.norway.atmel.com/AppsAVR8/avr458_Charging_Li-Ion_Batteries_with_BC100/trunk/code/IAR/ADC.h

Date
  2007-09-07 10:11:19 +0200 (fr, 07 sep 2007)

Definition in file ADC.h.

This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

## Defines
#define | ADC_PRESCALER 0x07
| Prescaling of ADC clock.
#define | VIN_MIN 4400
| Minimum supply voltage (at TP101 = VIN+), in mV.
## Functions
void | ADC_Init (void)
| Initializes ADC and input pins.
__interrupt void | ADC_ISR (void)
| Interrupt Service routine for ADC.
void | ADC_Wait (void)
| Waits for two full cycles of ADC-conversions to occur.
unsigned int | ScaleI (unsigned char setting, unsigned int data)
| Scales sample to represent "actual current" in mA.
unsigned int | ScaleU (unsigned char setting, unsigned int data)
| Scales sample to represent "actual voltage" in mV.
## Variables
ADC_Status_t | ADCS
| Holds sampled data and ADC-status.
__eeprom unsigned char | VBAT_RANGE
| Indicates maximum battery voltage.

## Define Documentation

#define ADC_PRESCALER 0x07

Prescaling of ADC clock.

The ADC will run at 8 MHz (system clock) divided by 128 (prescaler), and every sample will takes approximately 25 ticks: Sample rate = 8 MHz / (128 * 25 cycles/sample) = 2.5 k samples/sec

Definition at line 36 of file ADC.h.

Referenced by ADC_Init().

#define VIN_MIN 4400

Minimum supply voltage (at TP101 = VIN+), in mV.

Definition at line 49 of file ADC.h.

Referenced by ADC_ISR().

## Function Documentation

void ADC_Init | ( | void |  | ) |

Initializes ADC and input pins.

This function initializes the ADC to free running mode, sampling from PA1/2/4/5/6/7, and using an external reference voltage (PA3).
It also measures and stores calibration data for offset.

Todo:
  Odd offset measurement for ADC3_G20_OS? It is never used anyway.

Note:
  Table of MUX settings for offset measurement:

          Ch | Pin |    Gain |    MUX
       ------+-----+---------+-------
        ADC1 | PA1 |     20x | 001101
        ADC3 | PA4 |     20x | 010001
        ADC5 | PA6 |     20x | 010110
        ADC9 | PB6 |     20x | 011011
        ADC0 | PA0 | 20x/32x | 111000
        ADC0 | PA0 |   1x/8x | 111001
        ADC1 | PA1 | 20x/32x | 111010
        ADC2 | PA2 | 20x/32x | 111011
        ADC4 | PA5 | 20x/32x | 111100
        ADC5 | PA6 | 20x/32x | 111101
        ADC6 | PA7 | 20x/32x | 111110

Definition at line 369 of file ADC.c.

References ADC_Status_struct::ADC3_G20_OS, ADC_Status_struct::ADC5_G20_OS, ADC_PRESCALER, ADC_Wait(), ADC_Status_struct::avgIBAT, ADC_Status_struct::discIBAT, FALSE, ADC_Status_struct::Flag, ADC_Status_struct::Halt, and ADC_Status_struct::MUX.

Referenced by Initialize().

    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 }

Here is the call graph for this function:

__interrupt void ADC_ISR | ( | void |  | ) |

Interrupt Service routine for ADC.

This ISR stores the sampled values in the ADC status-struct, then updates the ADC MUX to the next channel in the scanning-sequence.
Once the sequence is completed, ADCS.Flag is set and unless ADCS.Halt has been set, the sequence starts over. Otherwise, the ADC is disabled.
If the mains voltage is below minimum, ADCS.Mains gets set to FALSE.

Note:
  Table of scanning sequence:

       Seq |    MUX |  pos I/P |  neg I/P | gain | measure | signed
       ----+--------+----------+----------+------+---------+-------
        01 | 000001 | ADC1/PA1 |      n/a |   1x |     NTC |     no
        02 | 000010 | ADC2/PA2 |      n/a |   1x |     RID |     no
        03 | 000011 | ADC3/PA4 |      n/a |   1x |    VIN- |     no
        04 | 000100 | ADC4/PA5 |      n/a |   1x |    VIN+ |     no
        05 | 000101 | ADC5/PA6 |      n/a |   1x |   VBAT- |     no
        06 | 000110 | ADC6/PA7 |      n/a |   1x |   VBAT+ |     no
        07 | 010010 | ADC4/PA5 | ADC3/PA4 |  20x |     IIN |     no
        08 | 010111 | ADC6/PA7 | ADC5/PA6 |  20x |    IBAT |    yes

Todo:
  IIN (#7 in sequence) is never used.

Todo:
  Signed is never set. Signed measurements of IBAT will halve the measuring sensitivity, and is therefore not favourable. At the moment, great currents (f.ex. if something happens with the battery) will be interpreted as negative, which might cause unfavourable behaviour during charging (depending on what PWM behaviour is defined), f.ex. ConstantCurrent() will keep increasing the PWM output. This results in an PWM controller error being flagged and the program going into error-state and eventually reinitializing.

Definition at line 114 of file ADC.c.

References ADC_Status_struct::ADC5_G20_OS, ADC_Status_struct::avgIBAT, ADC_Status_struct::discIBAT, FALSE, ADC_Status_struct::Flag, ADC_Status_struct::Halt, ADC_Status_struct::IBAT, ADC_Status_struct::Mains, ADC_Status_struct::MUX, ADC_Status_struct::rawNTC, ADC_Status_struct::rawRID, ADC_Status_struct::rawVBAT, ScaleI(), ScaleU(), TRUE, ADC_Status_struct::VBAT, VBAT_RANGE, ADC_Status_struct::VIN, and VIN_MIN.

    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 }

Here is the call graph for this function:

void ADC_Wait | ( | void |  | ) |

Waits for two full cycles of ADC-conversions to occur.

This function clears the cycle complete-flag, then waits for it to be set again. This is then repeated once before the function exits.

Definition at line 330 of file ADC.c.

References FALSE, and ADC_Status_struct::Flag.

Referenced by ADC_Init(), BatteryControl(), ConstantCurrent(), ConstantVoltage(), Doze(), HaltNow(), Initialize(), JumperCheck(), MaxVoltageAndCurrent(), and Sleep().

    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 }

unsigned int ScaleI | ( | unsigned char | setting,
|  | unsigned int | data |
| ) |  |  |

Scales sample to represent "actual current" in mA.

This function returns the actual sampled current, scaled according to the jumper settings.

Parameters:

  | setting | Indicates what downscaling was used.
  | data | The sampled value.

Note:
  Table for setting-parameter:

       Presume VREF = 2.5V and Gain = 1x or 20x.
       => Resolution(U) @ (1/1 and 20x) = 2.5V / (GAIN x 1024) = 0.1221 mV/LSB
       => Resolution(I) = Resolution(U) / Rshunt = Resolution(U) / 0.07
       Setting |   R1 | R2/(R1+R2) |   U(LSB) |   I(LSB) | I(MAX) | Gain
       --------+------+------------+----------+----------+--------+-----
           N/A |    - |       -    | 0.1221mV |  1.744mA |  1.78A |  20x
             0 |  10k |     1/2    | 0.2442mV |  3.489mA |  3.57A |  20x
             1 |  30k |     1/4    | 0.4884mV |  6.978mA |  7.14A |  20x
             2 |  70k |     1/8    | 0.9768mV | 13.955mA |  14.3A |  20x
             3 | 110k |    1/12    | 1.4652mV | 20.931mA |  21.4A |  20x
             4 | 150k |    1/16    | 1.9536mV | 27.909mA |  28.5A |  20x
             5 |  10k |     1/2    | 2.4414mV | 34.877mA |  35.7A |   1x

Definition at line 297 of file ADC.c.

Referenced by ADC_ISR().

    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 }

unsigned int ScaleU | ( | unsigned char | setting,
|  | unsigned int | data |
| ) |  |  |

Scales sample to represent "actual voltage" in mV.

This function returns the actual sampled voltage, scaled according to the jumper settings.

Parameters:

  | setting | Indicates what downscaling was used.
  | data | The sampled value.

Note:
  Table for setting-parameter:

       Presume VREF = 2.5V and Gain = 1x.
       => Resolution @ 1/1 = 2.5V / 1024 = 2.4414 mV/LSB
       setting | source |   R1 | R2/(R1+R2) | UADC(LSB) | U(MAX)
       --------+--------+------+------------+-----------+-------
           N/A |        |    - |       -    |   2.441mV |  2.50V
             0 |   VBAT |  10k |     1/2    |   4.883mV |  5.00V
             1 |   VBAT |  30k |     1/4    |   9.766mV |  9.99V
             2 |   VBAT |  70k |     1/8    |   19.53mV | 19.98V
             3 |   VBAT | 110k |    1/12    |   29.30mV | 29.97V
             4 |   VBAT | 150k |    1/16    |   39.06mV | 39.96V
             4 |    VIN | 150k |    1/16    |   39.06mV | 39.96V

Definition at line 246 of file ADC.c.

Referenced by ADC_ISR().

    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 }

## Variable Documentation

ADC_Status_t ADCS

Holds sampled data and ADC-status.

Definition at line 48 of file ADC.c.

Referenced by BatteryStatusRefresh(), ConstantCurrent(), ConstantVoltage(), Doze(), HaltNow(), JumperCheck(), MaxVoltageAndCurrent(), NTCLookUp(), RIDLookUp(), and USI_OVF_ISR().

__eeprom unsigned char VBAT_RANGE

Indicates maximum battery voltage.

This variable is stored in EEPROM and indicates how much the battery voltage is downscaled by HW before it is sampled. The amount of downscaling depends on the maximum battery voltage, and is necessary to avoid saturation of the ADC (reference voltage is 2.5 V).

Note:
  Used by the ADC ISR when calling ScaleU() and ScaleI().

  Defaults to 1, which means 10 V max battery voltage.

  Table of settings:

       VBAT_RANGE | Max battery voltage | Jumper setting
               0  |             5V      |        1/2
               1  |            10V      |        1/4
               2  |            20V      |        1/8
               3  |            30V      |       1/12
               4  |            40V      |       1/16

Definition at line 73 of file ADC.c.

Referenced by ADC_ISR().