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.
Definition in file ADC.c.
#include <ioavr.h>
#include <inavr.h>
#include "structs.h"
#include "main.h"
#include "ADC.h"
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. |
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.
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 }
__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.
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
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 }
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.
setting | Indicates what downscaling was used. | |
data | The sampled value. |
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.
setting | Indicates what downscaling was used. | |
data | The sampled value. |
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 }
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).
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().