1 ///////////////////////////////////////////////////////////////////////////////
\r
3 // IAR Atmel AVR C/C++ Compiler V4.30F/W32 12/Mar/2008 23:01:38 /
\r
4 // Copyright 1996-2007 IAR Systems. All rights reserved. /
\r
6 // Source file = C:\home\kevin\pub\src\bc100_cal\IAR\ADC.c /
\r
7 // Command line = C:\home\kevin\pub\src\bc100_cal\IAR\ADC.c /
\r
8 // --cpu=tiny861 -ms -o C:\home\kevin\pub\src\bc100_cal\IA /
\r
9 // R\Debug\Obj\ -lC C:\home\kevin\pub\src\bc100_cal\IAR\De /
\r
10 // bug\List\ -lB C:\home\kevin\pub\src\bc100_cal\IAR\Debug /
\r
11 // \List\ --initializers_in_flash -z2 --no_cse /
\r
12 // --no_inline --no_code_motion --no_cross_call /
\r
13 // --no_clustering --no_tbaa --debug /
\r
14 // -DENABLE_BIT_DEFINITIONS -e --require_prototypes -I /
\r
15 // "C:\Program Files\IAR Systems\Embedded Workbench /
\r
16 // 4.0\avr\INC\" -I "C:\Program Files\IAR /
\r
17 // Systems\Embedded Workbench 4.0\avr\INC\CLIB\" /
\r
18 // --eeprom_size 512 /
\r
19 // List file = C:\home\kevin\pub\src\bc100_cal\IAR\Debug\List\ADC.s90 /
\r
22 ///////////////////////////////////////////////////////////////////////////////
\r
26 RSEG CSTACK:DATA:NOROOT(0)
\r
27 RSEG RSTACK:DATA:NOROOT(0)
\r
29 EXTERN ?EPILOGUE_B6_L09
\r
30 EXTERN ?PROLOGUE6_L09
\r
31 EXTERN ?Register_R4_is_cg_reg
\r
32 EXTERN ?Register_R5_is_cg_reg
\r
33 EXTERN ?SS_DIVMOD_L02
\r
36 EXTERN ?need_segment_init
\r
39 PUBWEAK `?<Segment init: NEAR_Z>`
\r
40 PUBWEAK `??ADC_ISR??INTVEC 22`
\r
59 ADC_ISR SYMBOL "ADC_ISR"
\r
60 `??ADC_ISR??INTVEC 22` SYMBOL "??INTVEC 22", ADC_ISR
\r
62 // C:\home\kevin\pub\src\bc100_cal\IAR\ADC.c
\r
63 // 1 /* This file has been prepared for Doxygen automatic documentation generation.*/
\r
64 // 2 /*! \file *********************************************************************
\r
67 // 5 * Functions for use of ADC
\r
69 // 7 * Contains high level functions for initializing the ADC, interrupt
\r
70 // 8 * handling, and treatment of samples.\n
\r
71 // 9 * The ADC is set to free running mode and uses an external reference
\r
73 // 11 * To make all sampling take at least 25 clock cycles the ADC is stopped
\r
74 // 12 * and restarted by the ISR.
\r
76 // 14 * \par Application note:
\r
77 // 15 * AVR458: Charging Li-Ion Batteries with BC100 \n
\r
78 // 16 * AVR463: Charging NiMH Batteries with BC100
\r
80 // 18 * \par Documentation:
\r
81 // 19 * For comprehensive code documentation, supported compilers, compiler
\r
82 // 20 * settings and supported devices see readme.html
\r
85 // 23 * Atmel Corporation: http://www.atmel.com \n
\r
86 // 24 * Support email: avr@atmel.com \n
\r
87 // 25 * Original author: \n
\r
90 // 28 * $Revision: 2299 $
\r
92 // 30 * $URL: http://svn.norway.atmel.com/AppsAVR8/avr458_Charging_Li-Ion_Batteries_with_BC100/tag/20070904_release_1.0/code/IAR/ADC.c $
\r
93 // 31 * $Date: 2007-08-23 12:55:51 +0200 (to, 23 aug 2007) $\n
\r
94 // 32 ******************************************************************************/
\r
96 // 34 #include <ioavr.h>
\r
98 ASEGN ABSOLUTE:DATA:NOROOT,03bH
\r
99 // <unnamed> volatile __io _A_PORTA
\r
103 ASEGN ABSOLUTE:DATA:NOROOT,03aH
\r
104 // <unnamed> volatile __io _A_DDRA
\r
108 ASEGN ABSOLUTE:DATA:NOROOT,027H
\r
109 // <unnamed> volatile __io _A_ADMUX
\r
113 ASEGN ABSOLUTE:DATA:NOROOT,026H
\r
114 // <unnamed> volatile __io _A_ADCSRA
\r
118 ASEGN ABSOLUTE:DATA:NOROOT,024H
\r
119 // <unnamed> volatile __io _A_ADC
\r
123 ASEGN ABSOLUTE:DATA:NOROOT,023H
\r
124 // <unnamed> volatile __io _A_ADCSRB
\r
127 // 35 #include <inavr.h>
\r
129 // 37 #include "structs.h"
\r
131 // 39 #include "main.h"
\r
132 // 40 #include "ADC.h"
\r
135 // 43 //******************************************************************************
\r
137 // 45 //******************************************************************************
\r
138 // 46 // ADC status struct.
\r
139 // 47 //! \brief Holds sampled data and ADC-status
\r
141 RSEG NEAR_Z:DATA:NOROOT(0)
\r
142 REQUIRE `?<Segment init: NEAR_Z>`
\r
143 // 48 ADC_Status_t ADCS;
\r
148 // 51 /*! \brief Indicates maximum battery voltage.
\r
150 // 53 * This variable is stored in EEPROM and indicates how much the battery voltage
\r
151 // 54 * is downscaled by HW before it is sampled. The amount of downscaling depends
\r
152 // 55 * on the maximum battery voltage, and is necessary to avoid saturation of the
\r
153 // 56 * ADC (reference voltage is 2.5 V).
\r
155 // 58 * \note Used by the ADC ISR when calling ScaleU() and ScaleI().
\r
157 // 60 * \note Defaults to 1, which means 10 V max battery voltage.
\r
159 // 62 * \note Table of settings:
\r
161 // 64 * VBAT_RANGE | Max battery voltage | Jumper setting
\r
162 // 65 * 0 | 5V | 1/2
\r
163 // 66 * 1 | 10V | 1/4
\r
164 // 67 * 2 | 20V | 1/8
\r
165 // 68 * 3 | 30V | 1/12
\r
166 // 69 * 4 | 40V | 1/16
\r
169 // 72 // Maximum battery voltage (affects scaling of samples).
\r
171 RSEG EEPROM_I:XDATA:NOROOT(0)
\r
172 // 73 __eeprom unsigned char VBAT_RANGE = 1;
\r
177 // 76 //******************************************************************************
\r
179 // 78 //******************************************************************************
\r
180 // 79 /*! \brief Interrupt Service routine for ADC.
\r
182 // 81 * This ISR stores the sampled values in the ADC status-struct, then
\r
183 // 82 * updates the ADC MUX to the next channel in the scanning-sequence.\n
\r
184 // 83 * Once the sequence is completed, ADCS.Flag is set and unless
\r
185 // 84 * ADCS.Halt has been set, the sequence starts over. Otherwise, the ADC
\r
186 // 85 * is disabled.\n
\r
187 // 86 * If the mains voltage is below minimum, ADCS.Mains gets set to FALSE.
\r
189 // 88 * \note Table of scanning sequence:
\r
191 // 90 * Seq | MUX | pos I/P | neg I/P | gain | measure | signed
\r
192 // 91 * ----+--------+----------+----------+------+---------+-------
\r
193 // 92 * 01 | 000001 | ADC1/PA1 | n/a | 1x | NTC | no
\r
194 // 93 * 02 | 000010 | ADC2/PA2 | n/a | 1x | RID | no
\r
195 // 94 * 03 | 000011 | ADC3/PA4 | n/a | 1x | VIN- | no
\r
196 // 95 * 04 | 000100 | ADC4/PA5 | n/a | 1x | VIN+ | no
\r
197 // 96 * 05 | 000101 | ADC5/PA6 | n/a | 1x | VBAT- | no
\r
198 // 97 * 06 | 000110 | ADC6/PA7 | n/a | 1x | VBAT+ | no
\r
199 // 98 * 07 | 010010 | ADC4/PA5 | ADC3/PA4 | 20x | IIN | no
\r
200 // 99 * 08 | 010111 | ADC6/PA7 | ADC5/PA6 | 20x | IBAT | yes
\r
203 // 102 * \todo IIN (#7 in sequence) is never used.
\r
205 // 104 * \todo Signed is never set. Signed measurements of IBAT will halve the
\r
206 // 105 * measuring sensitivity, and is therefore not favourable. At the moment,
\r
207 // 106 * great currents (f.ex. if something happens with the battery) will be
\r
208 // 107 * interpreted as negative, which might cause unfavourable behaviour during
\r
209 // 108 * charging (depending on what PWM behaviour is defined), f.ex.
\r
210 // 109 * ConstantCurrent() will keep increasing the PWM output. This results in an
\r
211 // 110 * PWM controller error being flagged and the program going into
\r
212 // 111 * error-state and eventually reinitializing.
\r
214 // 113 #pragma vector=ADC_vect
\r
216 RSEG CODE:CODE:NOROOT(1)
\r
217 // 114 __interrupt void ADC_ISR(void)
\r
241 REQUIRE ?Register_R4_is_cg_reg
\r
242 REQUIRE ?Register_R5_is_cg_reg
\r
243 // 116 static unsigned char avgIndex = 0;
\r
244 // 117 unsigned char i, Next, Signed;
\r
245 // 118 signed int temp = 0;
\r
249 // 120 Signed = FALSE; // Presume next conversion is unipolar.
\r
251 // 121 ADCSRA &= ~(1<<ADEN); // Stop conversion before handling. This makes all
\r
253 // 122 // conversions take at least 25 ADCCLK. (It is restarted later)
\r
255 // 124 // Handle the conversion, depending on what channel it is from, then
\r
256 // 125 // switch to the next channel in the sequence.
\r
257 // 126 switch (ADCS.MUX){
\r
272 // 127 // MUX = 0b000001 => ADC1 (PA1) = NTC
\r
274 // 129 ADCS.rawNTC = ADC;
\r
279 LDI R31, (ADCS) >> 8
\r
288 // 134 // MUX = 0b000010 => ADC2 (PA2) = RID
\r
290 // 136 ADCS.rawRID = ADC;
\r
295 LDI R31, (ADCS) >> 8
\r
304 // 141 // MUX = 0b000011 => ADC3 (PA4) = VIN-
\r
306 // 143 // Supply voltage is always divided by 16.
\r
307 // 144 ADCS.VIN = ScaleU(4, (unsigned int)ADC); // Cast because ADC is short.
\r
314 LDI R31, (ADCS) >> 8
\r
318 // 146 // Is mains failing?
\r
319 // 147 if (ADCS.VIN < VIN_MIN) {
\r
321 LDI R31, (ADCS) >> 8
\r
328 // 148 ADCS.Mains = FALSE;
\r
330 LDI R31, (ADCS) >> 8
\r
336 // 150 ADCS.Mains = TRUE;
\r
339 LDI R31, (ADCS) >> 8
\r
352 // 157 // MUX = 0b000101 => ADC5 (PA6) = VBAT-
\r
354 // 159 ADCS.rawVBAT = ADC;
\r
359 LDI R31, (ADCS) >> 8
\r
363 // 161 // Scale voltage according to jumper setting.
\r
364 // 162 ADCS.VBAT = ScaleU(VBAT_RANGE, (unsigned int)ADC); // ADC is a short.
\r
367 LDI R20, LOW(VBAT_RANGE)
\r
368 LDI R21, (VBAT_RANGE) >> 8
\r
372 LDI R31, (ADCS) >> 8
\r
378 // 164 // Signed = TRUE; // Next conversion is bipolar. Halves sensitivity!
\r
382 // 168 case 0x17: // MUX = 0b010111 => 20 x [ADC6(PA7) - ADC5(PA6)] = IBAT
\r
383 // 169 // If bipolar, from -512 to 0, to 511:
\r
384 // 170 // 0x200 ... 0x3ff, 0x000, 0x001 ... 0x1FF
\r
386 // 172 // Scale sample according to jumper setting, handle negative numbers.
\r
387 // 173 if (ADC > 511) {
\r
395 // 174 ADCS.IBAT = -(signed int)ScaleI(VBAT_RANGE,
\r
396 // 175 (1024 - (ADC-ADCS.ADC5_G20_OS)));
\r
403 LDS R18, (ADCS + 1)
\r
409 LDI R20, LOW(VBAT_RANGE)
\r
410 LDI R21, (VBAT_RANGE) >> 8
\r
417 LDI R31, (ADCS) >> 8
\r
421 // 176 } else if (ADC > 0) {
\r
427 // 177 ADCS.IBAT = ScaleI(VBAT_RANGE, (ADC-ADCS.ADC5_G20_OS));
\r
430 LDS R16, (ADCS + 1)
\r
436 LDI R20, LOW(VBAT_RANGE)
\r
437 LDI R21, (VBAT_RANGE) >> 8
\r
441 LDI R31, (ADCS) >> 8
\r
446 // 179 ADCS.IBAT = 0;
\r
451 LDI R31, (ADCS) >> 8
\r
456 // 182 // Insert sample of battery current into the averaging-array
\r
457 // 183 // (overwriting the oldest sample), then recalculate and store the
\r
458 // 184 // average. This is the last conversion in the sequence, so
\r
459 // 185 // flag a complete ADC-cycle and restart sequence.
\r
460 // 186 ADCS.discIBAT[(avgIndex++ & 0x03)] = ADCS.IBAT;
\r
463 LDI R31, (ADCS) >> 8
\r
466 LDS R16, ??avgIndex
\r
472 MOVW R31:R30, R17:R16
\r
473 SUBI R30, LOW((-(ADCS) & 0xFFFF))
\r
474 SBCI R31, (-(ADCS) & 0xFFFF) >> 8
\r
477 LDI R30, LOW(??avgIndex)
\r
478 LDI R31, (??avgIndex) >> 8
\r
482 // 187 for (i = 0; i < 4 ; i++) {
\r
487 // 188 temp += ADCS.discIBAT[i];
\r
492 MOVW R31:R30, R17:R16
\r
493 SUBI R30, LOW((-(ADCS) & 0xFFFF))
\r
494 SBCI R31, (-(ADCS) & 0xFFFF) >> 8
\r
503 // 191 ADCS.avgIBAT = (temp / 4);
\r
505 MOVW R17:R16, R27:R26
\r
508 RCALL ?SS_DIVMOD_L02
\r
510 LDI R31, (ADCS) >> 8
\r
514 // 193 ADCS.Flag = TRUE;
\r
516 LDI R31, (ADCS) >> 8
\r
522 // 195 Signed = FALSE; // This is the only bipolar conversion.
\r
528 // 199 default: // Should not happen. (Invalid MUX-channel)
\r
529 // 200 Next=0x01; // Start at the beginning of sequence.
\r
535 // 204 // Update MUX to next channel in sequence, set a bipolar conversion if
\r
536 // 205 // this has been flagged.
\r
537 // 206 ADCS.MUX = Next;
\r
545 // 207 ADMUX = (1<<REFS0) + ADCS.MUX;
\r
551 // 209 if (Signed) {
\r
554 // 210 ADCSRB |= (1<<BIN);
\r
558 // 212 ADCSRB &= ~(1<<BIN);
\r
563 // 215 // Re-enable the ADC unless a halt has been flagged and a conversion
\r
564 // 216 // cycle has completed.
\r
565 // 217 if (!((ADCS.Halt) && (ADCS.Flag))) {
\r
571 // 218 ADCSRA |= (1<<ADEN)|(1<<ADSC);
\r
605 RSEG NEAR_Z:DATA:NOROOT(0)
\r
606 REQUIRE `?<Segment init: NEAR_Z>`
\r
611 // 223 /*! \brief Scales sample to represent "actual voltage" in mV.
\r
613 // 225 * This function returns the actual sampled voltage, scaled according
\r
614 // 226 * to the jumper settings.
\r
616 // 228 * \param setting Indicates what downscaling was used.
\r
617 // 229 * \param data The sampled value.
\r
619 // 231 * \note Table for setting-parameter:\n
\r
621 // 233 * Presume VREF = 2.5V and Gain = 1x.
\r
622 // 234 * => Resolution @ 1/1 = 2.5V / 1024 = 2.4414 mV/LSB
\r
623 // 235 * setting | source | R1 | R2/(R1+R2) | UADC(LSB) | U(MAX)
\r
624 // 236 * --------+--------+------+------------+-----------+-------
\r
625 // 237 * N/A | | - | - | 2.441mV | 2.50V
\r
626 // 238 * 0 | VBAT | 10k | 1/2 | 4.883mV | 5.00V
\r
627 // 239 * 1 | VBAT | 30k | 1/4 | 9.766mV | 9.99V
\r
628 // 240 * 2 | VBAT | 70k | 1/8 | 19.53mV | 19.98V
\r
629 // 241 * 3 | VBAT | 110k | 1/12 | 29.30mV | 29.97V
\r
630 // 242 * 4 | VBAT | 150k | 1/16 | 39.06mV | 39.96V
\r
631 // 243 * 4 | VIN | 150k | 1/16 | 39.06mV | 39.96V
\r
635 RSEG CODE:CODE:NOROOT(1)
\r
636 // 246 unsigned int ScaleU(unsigned char setting, unsigned int data)
\r
639 RCALL ?PROLOGUE6_L09
\r
640 REQUIRE ?Register_R4_is_cg_reg
\r
641 REQUIRE ?Register_R5_is_cg_reg
\r
643 MOVW R25:R24, R19:R18
\r
644 // 248 // Temporary variable needed.
\r
645 // 249 unsigned int scaled = 0;
\r
649 // 251 // Jumper setting 3: mV/LSB = 29.30 ~= 29 + 1/4 + 1/16
\r
650 // 252 if (setting == 3) {
\r
653 // 253 scaled = 29 * data;
\r
654 MOVW R21:R20, R25:R24
\r
658 MOVW R5:R4, R17:R16
\r
659 // 254 scaled += (data >> 2);
\r
660 MOVW R17:R16, R25:R24
\r
667 // 255 scaled += (data >> 4);
\r
668 MOVW R17:R16, R25:R24
\r
675 // 257 // Jumper setting 4: mV/LSB = 39.06 ~= 39 + 1/16
\r
676 // 258 scaled = 39 * data;
\r
678 MOVW R21:R20, R25:R24
\r
682 MOVW R5:R4, R17:R16
\r
683 // 259 scaled += (data >> 4);
\r
684 MOVW R17:R16, R25:R24
\r
690 // 261 if (setting <3) {
\r
693 // 262 // Jumper setting 0: mV/LSB = 4.883 = 39.06 / 8
\r
694 // 263 // 1: mV/LSB = 9.766 = 39.06 / 4
\r
695 // 264 // 2: mV/LSB = 19.53 = 39.06 / 2
\r
696 // 265 scaled = (scaled >> (3-setting));
\r
697 MOVW R17:R16, R5:R4
\r
701 MOVW R5:R4, R17:R16
\r
705 // 269 return(scaled);
\r
707 MOVW R17:R16, R5:R4
\r
709 RJMP ?EPILOGUE_B6_L09
\r
713 // 273 /*! \brief Scales sample to represent "actual current" in mA.
\r
715 // 275 * This function returns the actual sampled current, scaled according
\r
716 // 276 * to the jumper settings.
\r
718 // 278 * \param setting Indicates what downscaling was used.
\r
719 // 279 * \param data The sampled value.
\r
721 // 281 * \note Table for setting-parameter:\n
\r
723 // 283 * Presume VREF = 2.5V and Gain = 1x or 20x.
\r
724 // 284 * => Resolution(U) @ (1/1 and 20x) = 2.5V / (GAIN x 1024) = 0.1221 mV/LSB
\r
725 // 285 * => Resolution(I) = Resolution(U) / Rshunt = Resolution(U) / 0.07
\r
726 // 286 * Setting | R1 | R2/(R1+R2) | U(LSB) | I(LSB) | I(MAX) | Gain
\r
727 // 287 * --------+------+------------+----------+----------+--------+-----
\r
728 // 288 * N/A | - | - | 0.1221mV | 1.744mA | 1.78A | 20x
\r
729 // 289 * 0 | 10k | 1/2 | 0.2442mV | 3.489mA | 3.57A | 20x
\r
730 // 290 * 1 | 30k | 1/4 | 0.4884mV | 6.978mA | 7.14A | 20x
\r
731 // 291 * 2 | 70k | 1/8 | 0.9768mV | 13.955mA | 14.3A | 20x
\r
732 // 292 * 3 | 110k | 1/12 | 1.4652mV | 20.931mA | 21.4A | 20x
\r
733 // 293 * 4 | 150k | 1/16 | 1.9536mV | 27.909mA | 28.5A | 20x
\r
734 // 294 * 5 | 10k | 1/2 | 2.4414mV | 34.877mA | 35.7A | 1x
\r
738 RSEG CODE:CODE:NOROOT(1)
\r
739 // 297 unsigned int ScaleI(unsigned char setting, unsigned int data)
\r
742 RCALL ?PROLOGUE6_L09
\r
743 REQUIRE ?Register_R4_is_cg_reg
\r
744 REQUIRE ?Register_R5_is_cg_reg
\r
746 MOVW R25:R24, R19:R18
\r
747 // 299 // Temporary variable needed.
\r
748 // 300 unsigned int scaled = 0;
\r
752 // 302 // Jumper setting 3: mA/LSB = 20.931mA ~= 21 - 1/16 + 1/128
\r
753 // 303 if (setting == 3) {
\r
756 // 304 scaled = 21 * data;
\r
757 MOVW R21:R20, R25:R24
\r
761 MOVW R5:R4, R17:R16
\r
762 // 305 scaled -= (data >> 4);
\r
763 MOVW R17:R16, R25:R24
\r
768 // 306 scaled += (data >> 7);
\r
769 MOVW R17:R16, R25:R24
\r
778 // 307 } else { // Jumper setting 4: mA/LSB = 27.909mA ~= 28 - 1/8 + 1/32
\r
779 // 308 scaled = 28 * data;
\r
781 MOVW R21:R20, R25:R24
\r
785 MOVW R5:R4, R17:R16
\r
786 // 309 scaled -= (data >> 3);
\r
787 MOVW R17:R16, R25:R24
\r
792 // 310 scaled += (data >> 5);
\r
793 MOVW R17:R16, R25:R24
\r
799 // 312 if (setting <3) {
\r
802 // 313 // Jumper setting 0: mA/LSB = 3.489mA = 27.909 / 8
\r
803 // 314 // 1: mA/LSB = 6.978mA = 27.909 / 4
\r
804 // 315 // 2: mA/LSB = 13.955mA = 27.909 / 2
\r
805 // 316 scaled = (scaled >> (3-setting));
\r
806 MOVW R17:R16, R5:R4
\r
810 MOVW R5:R4, R17:R16
\r
814 // 320 return(scaled);
\r
816 MOVW R17:R16, R5:R4
\r
818 RJMP ?EPILOGUE_B6_L09
\r
822 // 324 /*! \brief Waits for two full cycles of ADC-conversions to occur.
\r
824 // 326 * This function clears the cycle complete-flag, then waits for it to be set
\r
825 // 327 * again. This is then repeated once before the function exits.
\r
829 RSEG CODE:CODE:NOROOT(1)
\r
830 // 330 void ADC_Wait(void)
\r
833 // 332 // Clear ADC flag and wait for cycle to complete.
\r
834 // 333 ADCS.Flag = FALSE;
\r
836 LDI R31, (ADCS) >> 8
\r
841 // 335 } while (ADCS.Flag == FALSE);
\r
844 LDI R31, (ADCS) >> 8
\r
849 // 337 // Repeat, so we are sure the data beong to the same cycle.
\r
850 // 338 ADCS.Flag = FALSE;
\r
852 LDI R31, (ADCS) >> 8
\r
857 // 340 } while (ADCS.Flag == FALSE);
\r
860 LDI R31, (ADCS) >> 8
\r
868 // 344 /*! \brief Initializes ADC and input pins.
\r
870 // 346 * This function initializes the ADC to free running mode, sampling from
\r
871 // 347 * PA1/2/4/5/6/7, and using an external reference voltage (PA3).\n
\r
872 // 348 * It also measures and stores calibration data for offset.
\r
874 // 350 * \todo Odd offset measurement for ADC3_G20_OS? It is never used anyway.
\r
876 // 352 * \note Table of MUX settings for offset measurement:
\r
878 // 354 * Ch | Pin | Gain | MUX
\r
879 // 355 * ------+-----+---------+-------
\r
880 // 356 * ADC1 | PA1 | 20x | 001101
\r
881 // 357 * ADC3 | PA4 | 20x | 010001
\r
882 // 358 * ADC5 | PA6 | 20x | 010110
\r
883 // 359 * ADC9 | PB6 | 20x | 011011
\r
884 // 360 * ADC0 | PA0 | 20x/32x | 111000
\r
885 // 361 * ADC0 | PA0 | 1x/8x | 111001
\r
886 // 362 * ADC1 | PA1 | 20x/32x | 111010
\r
887 // 363 * ADC2 | PA2 | 20x/32x | 111011
\r
888 // 364 * ADC4 | PA5 | 20x/32x | 111100
\r
889 // 365 * ADC5 | PA6 | 20x/32x | 111101
\r
890 // 366 * ADC6 | PA7 | 20x/32x | 111110
\r
894 RSEG CODE:CODE:NOROOT(1)
\r
895 // 369 void ADC_Init(void)
\r
899 // 371 unsigned char i;
\r
901 // 373 __disable_interrupt();
\r
904 // 375 ADCS.Halt = FALSE; // Enable consecutive runs of ADC.
\r
906 LDI R31, (ADCS) >> 8
\r
911 // 377 // Configure ADC pins (inputs and disabled pull-ups).
\r
912 // 378 DDRA &= ~((1<<PA1)|(1<<PA2)|(1<<PA4)|(1<<PA5)|(1<<PA6)|(1<<PA7));
\r
916 // 379 PORTA &= ~((1<<PA1)|(1<<PA2)|(1<<PA4)|(1<<PA5)|(1<<PA6)|(1<<PA7));
\r
921 // 381 // Set ADC3 as reference, and MUX to measure the same pin.
\r
922 // 382 ADMUX = (1<<REFS0) | (1<<MUX0) | (1<<MUX1);
\r
930 // 386 // Start conversion, no interrupt (disable ADC-ISR).
\r
931 // 387 ADCSRA = (1<<ADEN) | (1<<ADSC) | ADC_PRESCALER;
\r
935 // 389 do { // Wait for conversion to finish.
\r
936 // 390 } while (!(ADCSRA & (1<<ADIF)));
\r
941 // 392 ADCSRA |= (1<<ADIF); // Clear ADC interrupt flag manually.
\r
944 // 394 ADCS.ADC3_G20_OS = ADC; // Save the sampled offset.
\r
945 LDS R18, (ADCS + 1)
\r
951 STS (ADCS + 1), R16
\r
953 // 396 ADMUX = (1<<REFS0) | 0x16; // ADC5/ADC5 (external ref.), 20x
\r
957 // 398 // Start conversion, no interrupt. ADC_PRESCALER is defined in ADC.h.
\r
958 // 399 ADCSRA = (1<<ADEN) | (1<<ADSC) | ADC_PRESCALER;
\r
962 // 401 do { // Wait for conversion to finish.
\r
963 // 402 } while (!(ADCSRA & (1<<ADIF)));
\r
968 // 404 ADCSRA |= (1<<ADIF); // Clear ADC interrupt flag.
\r
971 // 406 ADCS.ADC5_G20_OS = ADC; // Save the sampled offset.
\r
972 LDS R18, (ADCS + 1)
\r
979 STS (ADCS + 1), R16
\r
981 // 408 // Reset the ADC-cycle.
\r
982 // 409 ADCS.Flag = FALSE;
\r
984 LDI R31, (ADCS) >> 8
\r
988 // 410 ADCS.MUX = 0x01;
\r
993 // 411 ADMUX = (1<<REFS0) | ADCS.MUX;
\r
999 // 413 // Clear averaged battery current and the discrete readings.
\r
1000 // 414 ADCS.avgIBAT = 0;
\r
1003 LDI R30, LOW(ADCS)
\r
1004 LDI R31, (ADCS) >> 8
\r
1008 // 416 for (i = 0; i < 4; i++) {
\r
1013 // 417 ADCS.discIBAT[i] = 0;
\r
1020 MOVW R31:R30, R19:R18
\r
1021 SUBI R30, LOW((-(ADCS) & 0xFFFF))
\r
1022 SBCI R31, (-(ADCS) & 0xFFFF) >> 8
\r
1029 // 420 // Re-enable the ADC and ISR.
\r
1030 // 421 ADCSRA=(1<<ADEN)|(1<<ADSC)|(1<<ADIE)|ADC_PRESCALER;
\r
1035 // 423 __enable_interrupt();
\r
1038 // 425 // Get a complete cycle of data before returning.
\r
1039 // 426 ADC_Wait();
\r
1051 ASEGN ABSOLUTE:DATA:NOROOT,01cH
\r
1054 ASEGN ABSOLUTE:DATA:NOROOT,01dH
\r
1057 ASEGN ABSOLUTE:DATA:NOROOT,01eH
\r
1060 ASEGN ABSOLUTE:DATA:NOROOT,01fH
\r
1063 COMMON INTVEC:CODE:ROOT(1)
\r
1065 `??ADC_ISR??INTVEC 22`:
\r
1068 RSEG INITTAB:CODE:NOROOT(0)
\r
1069 `?<Segment init: NEAR_Z>`:
\r
1070 DW SFE(NEAR_Z) - SFB(NEAR_Z)
\r
1073 REQUIRE ?need_segment_init
\r
1077 // 7 bytes in segment ABSOLUTE
\r
1078 // 946 bytes in segment CODE
\r
1079 // 1 byte in segment EEPROM_I
\r
1080 // 6 bytes in segment INITTAB
\r
1081 // 2 bytes in segment INTVEC
\r
1082 // 25 bytes in segment NEAR_Z
\r
1084 // 946 bytes of CODE memory (+ 8 bytes shared)
\r
1085 // 25 bytes of DATA memory (+ 7 bytes shared)
\r
1086 // 1 byte of XDATA memory
\r