ADC.c File Reference


Detailed Description

Functions for use of ADC.

Contains high level functions for initializing the ADC, interrupt handling, and treatment of samples.
The ADC is set to free running mode and uses an external reference voltage.
To make all sampling take at least 25 clock cycles the ADC is stopped and restarted by the ISR.

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
2299
$RCSfile$
URL
http://revisor.norway.atmel.com/AppsAVR8/avr458_Charging_Li-Ion_Batteries_with_BC100/trunk/code/IAR/ADC.c
Date
2007-08-23 12:55:51 +0200 (to, 23 aug 2007)

Definition in file ADC.c.

#include <ioavr.h>
#include <inavr.h>
#include "structs.h"
#include "main.h"
#include "ADC.h"

Include dependency graph for ADC.c:

Go to the source code of this file.

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 = 1
 Indicates maximum battery voltage.


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

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 = 1

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().


Generated on Fri Jul 25 12:42:07 2008 for AVR458 Charging Li-Ion Batteries with ATAVRBC100 by  doxygen 1.5.6