/////////////////////////////////////////////////////////////////////////////// // / // IAR Atmel AVR C/C++ Compiler V4.30F/W32 13/Mar/2008 04:49:35 / // Copyright 1996-2007 IAR Systems. All rights reserved. / // / // Source file = C:\home\kevin\pub\src\bc100\IAR\ADC.c / // Command line = C:\home\kevin\pub\src\bc100\IAR\ADC.c / // --cpu=tiny861 -ms -o C:\home\kevin\pub\src\bc1 / // 00\IAR\Release\Obj\ -D NDEBUG -lCN / // C:\home\kevin\pub\src\bc100\IAR\Release\List\ / // -lB C:\home\kevin\pub\src\bc100\IAR\Release\Li / // st\ --initializers_in_flash -s9 / // --no_cross_call --no_tbaa / // -DENABLE_BIT_DEFINITIONS -e -I "C:\Program / // Files\IAR Systems\Embedded Workbench / // 4.0\avr\INC\" -I "C:\Program Files\IAR / // Systems\Embedded Workbench 4.0\avr\INC\CLIB\" / // --eeprom_size 512 --misrac=5-9,11-12,14,16-17, / // 19-21,24-26,29-32,34-35,38-39,42-43,46,50, / // 52-54,56-59,61-62,64-65,68-80,83-84,87-91, / // 94-95,98-100,103-110,112-126 / // Enabled MISRA C rules = 5-9,11-12,14,16-17,19-21,24-26,29-32,34-35, / // 38-39,42-43,46,50,52-54,56-59,61-62,64-65, / // 68-80,83-84,87-91,94-95,98-100,103-110,112-126 / // Checked = 5,7-9,11-12,14,17,19-21,24,29-32,34-35,38-39, / // 42,46,50,52-54,56-59,61-62,64,68-69,71-80, / // 83-84,87-89,91,94-95,98,100,104-105,108-109, / // 112-115,118-126 / // Not checked = 6,16,25-26,43,65,70,90,99,103,106-107,110, / // 116-117 / // List file = C:\home\kevin\pub\src\bc100\IAR\Release\List\A / // DC.s90 / // / // / /////////////////////////////////////////////////////////////////////////////// NAME `ADC` RSEG CSTACK:DATA:NOROOT(0) RSEG RSTACK:DATA:NOROOT(0) EXTERN ?Register_R4_is_cg_reg EXTERN ?SS_DIVMOD_L02 EXTERN ?S_MUL_L02 EXTERN ?US_SHR_L02 EXTERN ?need_segment_init EXTERN __eeget8_16 PUBWEAK `?` PUBWEAK `??ADC_ISR??INTVEC 22` PUBLIC ADCS PUBLIC ADC_ISR PUBLIC ADC_Init PUBLIC ADC_Wait PUBLIC ScaleI PUBLIC ScaleU PUBLIC VBAT_RANGE PUBWEAK _A_ADC PUBWEAK _A_ADCSRA PUBWEAK _A_ADCSRB PUBWEAK _A_ADMUX PUBWEAK _A_DDRA PUBWEAK _A_PORTA PUBWEAK __?EEARH PUBWEAK __?EEARL PUBWEAK __?EECR PUBWEAK __?EEDR ADC_ISR SYMBOL "ADC_ISR" `??ADC_ISR??INTVEC 22` SYMBOL "??INTVEC 22", ADC_ISR // C:\home\kevin\pub\src\bc100\IAR\ADC.c // 1 /* This file has been prepared for Doxygen automatic documentation generation.*/ // 2 /*! \file ********************************************************************* // 3 * // 4 * \brief // 5 * Functions for use of ADC // 6 * // 7 * Contains high level functions for initializing the ADC, interrupt // 8 * handling, and treatment of samples.\n // 9 * The ADC is set to free running mode and uses an external reference // 10 * voltage.\n // 11 * To make all sampling take at least 25 clock cycles the ADC is stopped // 12 * and restarted by the ISR. // 13 * // 14 * \par Application note: // 15 * AVR458: Charging Li-Ion Batteries with BC100 \n // 16 * AVR463: Charging NiMH Batteries with BC100 // 17 * // 18 * \par Documentation: // 19 * For comprehensive code documentation, supported compilers, compiler // 20 * settings and supported devices see readme.html // 21 * // 22 * \author // 23 * Atmel Corporation: http://www.atmel.com \n // 24 * Support email: avr@atmel.com \n // 25 * Original author: \n // 26 * // 27 * $Name$ // 28 * $Revision: 2299 $ // 29 * $RCSfile$ // 30 * $URL: http://svn.norway.atmel.com/AppsAVR8/avr458_Charging_Li-Ion_Batteries_with_BC100/tag/20070904_release_1.0/code/IAR/ADC.c $ // 31 * $Date: 2007-08-23 12:55:51 +0200 (to, 23 aug 2007) $\n // 32 ******************************************************************************/ // 33 // 34 #include ASEGN ABSOLUTE:DATA:NOROOT,03bH // volatile __io _A_PORTA _A_PORTA: DS 1 ASEGN ABSOLUTE:DATA:NOROOT,03aH // volatile __io _A_DDRA _A_DDRA: DS 1 ASEGN ABSOLUTE:DATA:NOROOT,027H // volatile __io _A_ADMUX _A_ADMUX: DS 1 ASEGN ABSOLUTE:DATA:NOROOT,026H // volatile __io _A_ADCSRA _A_ADCSRA: DS 1 ASEGN ABSOLUTE:DATA:NOROOT,024H // volatile __io _A_ADC _A_ADC: DS 2 ASEGN ABSOLUTE:DATA:NOROOT,023H // volatile __io _A_ADCSRB _A_ADCSRB: DS 1 // 35 #include // 36 // 37 #include "structs.h" // 38 // 39 #include "main.h" // 40 #include "ADC.h" // 41 // 42 // 43 //****************************************************************************** // 44 // Variables // 45 //****************************************************************************** // 46 // ADC status struct. // 47 //! \brief Holds sampled data and ADC-status // 48 ADC_Status_t ADCS; // 49 // 50 // 51 /*! \brief Indicates maximum battery voltage. // 52 * // 53 * This variable is stored in EEPROM and indicates how much the battery voltage // 54 * is downscaled by HW before it is sampled. The amount of downscaling depends // 55 * on the maximum battery voltage, and is necessary to avoid saturation of the // 56 * ADC (reference voltage is 2.5 V). // 57 * // 58 * \note Used by the ADC ISR when calling ScaleU() and ScaleI(). // 59 * // 60 * \note Defaults to 1, which means 10 V max battery voltage. // 61 * // 62 * \note Table of settings: // 63 *
//   64  * VBAT_RANGE | Max battery voltage | Jumper setting
//   65  *         0  |             5V      |        1/2
//   66  *         1  |            10V      |        1/4
//   67  *         2  |            20V      |        1/8
//   68  *         3  |            30V      |       1/12
//   69  *         4  |            40V      |       1/16
//   70  * 
// 71 */ // 72 // Maximum battery voltage (affects scaling of samples). RSEG EEPROM_I:XDATA:NOROOT(0) // 73 __eeprom unsigned char VBAT_RANGE = 1; VBAT_RANGE: DB 1 // 74 // 75 // 76 //****************************************************************************** // 77 // Functions // 78 //****************************************************************************** // 79 /*! \brief Interrupt Service routine for ADC. // 80 * // 81 * This ISR stores the sampled values in the ADC status-struct, then // 82 * updates the ADC MUX to the next channel in the scanning-sequence.\n // 83 * Once the sequence is completed, ADCS.Flag is set and unless // 84 * ADCS.Halt has been set, the sequence starts over. Otherwise, the ADC // 85 * is disabled.\n // 86 * If the mains voltage is below minimum, ADCS.Mains gets set to FALSE. // 87 * // 88 * \note Table of scanning sequence: // 89 *
//   90  * Seq |    MUX |  pos I/P |  neg I/P | gain | measure | signed
//   91  * ----+--------+----------+----------+------+---------+-------
//   92  *  01 | 000001 | ADC1/PA1 |      n/a |   1x |     NTC |     no
//   93  *  02 | 000010 | ADC2/PA2 |      n/a |   1x |     RID |     no
//   94  *  03 | 000011 | ADC3/PA4 |      n/a |   1x |    VIN- |     no
//   95  *  04 | 000100 | ADC4/PA5 |      n/a |   1x |    VIN+ |     no
//   96  *  05 | 000101 | ADC5/PA6 |      n/a |   1x |   VBAT- |     no
//   97  *  06 | 000110 | ADC6/PA7 |      n/a |   1x |   VBAT+ |     no
//   98  *  07 | 010010 | ADC4/PA5 | ADC3/PA4 |  20x |     IIN |     no
//   99  *  08 | 010111 | ADC6/PA7 | ADC5/PA6 |  20x |    IBAT |    yes
//  100  * 
// 101 * // 102 * \todo IIN (#7 in sequence) is never used. // 103 * // 104 * \todo Signed is never set. Signed measurements of IBAT will halve the // 105 * measuring sensitivity, and is therefore not favourable. At the moment, // 106 * great currents (f.ex. if something happens with the battery) will be // 107 * interpreted as negative, which might cause unfavourable behaviour during // 108 * charging (depending on what PWM behaviour is defined), f.ex. // 109 * ConstantCurrent() will keep increasing the PWM output. This results in an // 110 * PWM controller error being flagged and the program going into // 111 * error-state and eventually reinitializing. // 112 */ // 113 #pragma vector=ADC_vect RSEG CODE:CODE:NOROOT(1) // 114 __interrupt void ADC_ISR(void) ADC_ISR: // 115 { ST -Y, R4 ST -Y, R27 ST -Y, R26 ST -Y, R25 ST -Y, R24 ST -Y, R31 ST -Y, R30 ST -Y, R3 ST -Y, R2 ST -Y, R1 ST -Y, R0 ST -Y, R23 ST -Y, R22 ST -Y, R21 ST -Y, R20 ST -Y, R19 ST -Y, R18 ST -Y, R17 ST -Y, R16 IN R4, 0x3F REQUIRE ?Register_R4_is_cg_reg // 116 static unsigned char avgIndex = 0; // 117 unsigned char i, Next, Signed; // 118 signed int temp = 0; LDI R24, 0 LDI R25, 0 // 119 // 120 Signed = FALSE; // Presume next conversion is unipolar. // 121 ADCSRA &= ~(1<> 8 LD R16, X ANDI R16, 0x1F DEC R16 BREQ ??ADC_ISR_0 DEC R16 BREQ ??ADC_ISR_1 DEC R16 BREQ ??ADC_ISR_2 SUBI R16, 2 BREQ ??ADC_ISR_3 SUBI R16, 18 BREQ ??ADC_ISR_4 RJMP ??ADC_ISR_5 // 127 // MUX = 0b000001 => ADC1 (PA1) = NTC // 128 case 0x01: // 129 ADCS.rawNTC = ADC; ??ADC_ISR_0: IN R16, 0x04 IN R17, 0x05 MOVW R31:R30, R27:R26 STD Z+4, R16 STD Z+5, R17 // 130 Next=0x02; LDI R16, 2 RJMP ??ADC_ISR_6 // 131 break; // 132 // 133 // 134 // MUX = 0b000010 => ADC2 (PA2) = RID // 135 case 0x02: // 136 ADCS.rawRID = ADC; ??ADC_ISR_1: IN R16, 0x04 IN R17, 0x05 MOVW R31:R30, R27:R26 STD Z+2, R16 STD Z+3, R17 // 137 Next=0x03; LDI R16, 3 RJMP ??ADC_ISR_6 // 138 break; // 139 // 140 // 141 // MUX = 0b000011 => ADC3 (PA4) = VIN- // 142 case 0x03: // 143 // Supply voltage is always divided by 16. // 144 ADCS.VIN = ScaleU(4, (unsigned int)ADC); // Cast because ADC is short. ??ADC_ISR_2: IN R18, 0x04 IN R19, 0x05 LDI R16, 4 RCALL ScaleU MOVW R31:R30, R27:R26 STD Z+8, R16 STD Z+9, R17 // 145 // 146 // Is mains failing? // 147 if (ADCS.VIN < VIN_MIN) { CPI R16, 48 SBCI R17, 17 LD R16, X BRCC ??ADC_ISR_7 // 148 ADCS.Mains = FALSE; ANDI R16, 0xBF RJMP ??ADC_ISR_8 // 149 } else { // 150 ADCS.Mains = TRUE; ??ADC_ISR_7: ORI R16, 0x40 ??ADC_ISR_8: ST X, R16 // 151 } // 152 // 153 Next=0x05; LDI R16, 5 RJMP ??ADC_ISR_6 // 154 break; // 155 // 156 // 157 // MUX = 0b000101 => ADC5 (PA6) = VBAT- // 158 case 0x05: // 159 ADCS.rawVBAT = ADC; ??ADC_ISR_3: IN R16, 0x04 IN R17, 0x05 MOVW R31:R30, R27:R26 STD Z+6, R16 STD Z+7, R17 // 160 // 161 // Scale voltage according to jumper setting. // 162 ADCS.VBAT = ScaleU(VBAT_RANGE, (unsigned int)ADC); // ADC is a short. IN R18, 0x04 IN R19, 0x05 LDI R20, LOW(VBAT_RANGE) LDI R21, (VBAT_RANGE) >> 8 RCALL __eeget8_16 RCALL ScaleU MOVW R31:R30, R27:R26 STD Z+10, R16 STD Z+11, R17 // 163 Next=0x17; LDI R16, 23 RJMP ??ADC_ISR_6 // 164 // Signed = TRUE; // Next conversion is bipolar. Halves sensitivity! // 165 break; // 166 // 167 // 168 case 0x17: // MUX = 0b010111 => 20 x [ADC6(PA7) - ADC5(PA6)] = IBAT // 169 // If bipolar, from -512 to 0, to 511: // 170 // 0x200 ... 0x3ff, 0x000, 0x001 ... 0x1FF // 171 // 172 // Scale sample according to jumper setting, handle negative numbers. // 173 if (ADC > 511) { ??ADC_ISR_4: IN R16, 0x04 IN R17, 0x05 CPI R17, 2 BRCS ??ADC_ISR_9 // 174 ADCS.IBAT = -(signed int)ScaleI(VBAT_RANGE, // 175 (1024 - (ADC-ADCS.ADC5_G20_OS))); LDI R16, 0 LDI R17, 4 IN R18, 0x04 IN R19, 0x05 SUB R16, R18 SBC R17, R19 MOVW R31:R30, R27:R26 LDD R18, Z+1 SWAP R18 ANDI R18, 0x0F LDI R19, 0 ADD R18, R16 ADC R19, R17 LDI R20, LOW(VBAT_RANGE) LDI R21, (VBAT_RANGE) >> 8 RCALL __eeget8_16 RCALL ScaleI NEG R17 NEG R16 SBCI R17, 0 ??ADC_ISR_10: MOVW R31:R30, R27:R26 STD Z+12, R16 STD Z+13, R17 RJMP ??ADC_ISR_11 // 176 } else if (ADC > 0) { ??ADC_ISR_9: IN R16, 0x04 IN R17, 0x05 OR R16, R17 BREQ ??ADC_ISR_12 // 177 ADCS.IBAT = ScaleI(VBAT_RANGE, (ADC-ADCS.ADC5_G20_OS)); IN R18, 0x04 IN R19, 0x05 MOVW R31:R30, R27:R26 LDD R16, Z+1 SWAP R16 ANDI R16, 0x0F SUB R18, R16 SBCI R19, 0 LDI R20, LOW(VBAT_RANGE) LDI R21, (VBAT_RANGE) >> 8 RCALL __eeget8_16 RCALL ScaleI RJMP ??ADC_ISR_10 // 178 } else { // 179 ADCS.IBAT = 0; ??ADC_ISR_12: MOVW R31:R30, R27:R26 STD Z+12, R24 STD Z+13, R24 // 180 } // 181 // 182 // Insert sample of battery current into the averaging-array // 183 // (overwriting the oldest sample), then recalculate and store the // 184 // average. This is the last conversion in the sequence, so // 185 // flag a complete ADC-cycle and restart sequence. // 186 ADCS.discIBAT[(avgIndex++ & 0x03)] = ADCS.IBAT; ??ADC_ISR_11: LDD R18, Z+12 LDD R19, Z+13 LDD R16, Z+24 ANDI R16, 0x03 LSL R16 ADD R30, R16 ADC R31, R24 STD Z+14, R18 STD Z+15, R19 MOVW R31:R30, R27:R26 LDD R16, Z+24 INC R16 STD Z+24, R16 // 187 for (i = 0; i < 4 ; i++) { ADIW R31:R30, 14 LDI R16, 4 // 188 temp += ADCS.discIBAT[i]; ??ADC_ISR_13: LD R18, Z+ LD R19, Z+ ADD R24, R18 ADC R25, R19 // 189 } DEC R16 BRNE ??ADC_ISR_13 // 190 // 191 ADCS.avgIBAT = (temp / 4); MOVW R17:R16, R25:R24 LDI R20, 4 LDI R21, 0 RCALL ?SS_DIVMOD_L02 MOVW R31:R30, R27:R26 STD Z+22, R16 STD Z+23, R17 // 192 // 193 ADCS.Flag = TRUE; LD R16, X ORI R16, 0x20 ST X, R16 // 194 Next=0x01; // 195 Signed = FALSE; // This is the only bipolar conversion. // 196 break; // 197 // 198 // 199 default: // Should not happen. (Invalid MUX-channel) // 200 Next=0x01; // Start at the beginning of sequence. ??ADC_ISR_5: LDI R16, 1 // 201 break; // 202 } // 203 // 204 // Update MUX to next channel in sequence, set a bipolar conversion if // 205 // this has been flagged. // 206 ADCS.MUX = Next; ??ADC_ISR_6: LD R17, X ANDI R17, 0xE0 ANDI R16, 0x1F OR R16, R17 ST X, R16 // 207 ADMUX = (1<` ADCS: DS 24 DS 1 // 221 // 222 // 223 /*! \brief Scales sample to represent "actual voltage" in mV. // 224 * // 225 * This function returns the actual sampled voltage, scaled according // 226 * to the jumper settings. // 227 * // 228 * \param setting Indicates what downscaling was used. // 229 * \param data The sampled value. // 230 * // 231 * \note Table for setting-parameter:\n // 232 *
//  233  * Presume VREF = 2.5V and Gain = 1x.
//  234  * => Resolution @ 1/1 = 2.5V / 1024 = 2.4414 mV/LSB
//  235  * setting | source |   R1 | R2/(R1+R2) | UADC(LSB) | U(MAX)
//  236  * --------+--------+------+------------+-----------+-------
//  237  *     N/A |        |    - |       -    |   2.441mV |  2.50V
//  238  *       0 |   VBAT |  10k |     1/2    |   4.883mV |  5.00V
//  239  *       1 |   VBAT |  30k |     1/4    |   9.766mV |  9.99V
//  240  *       2 |   VBAT |  70k |     1/8    |   19.53mV | 19.98V
//  241  *       3 |   VBAT | 110k |    1/12    |   29.30mV | 29.97V
//  242  *       4 |   VBAT | 150k |    1/16    |   39.06mV | 39.96V
//  243  *       4 |    VIN | 150k |    1/16    |   39.06mV | 39.96V
//  244  * 
// 245 */ RSEG CODE:CODE:NOROOT(1) // 246 unsigned int ScaleU(unsigned char setting, unsigned int data) ScaleU: // 247 { MOV R2, R26 MOVW R23:R22, R25:R24 MOV R26, R16 MOVW R25:R24, R19:R18 // 248 // Temporary variable needed. // 249 unsigned int scaled = 0; // 250 // 251 // Jumper setting 3: mV/LSB = 29.30 ~= 29 + 1/4 + 1/16 // 252 if (setting == 3) { CPI R16, 3 MOVW R21:R20, R19:R18 BRNE ??ScaleU_0 // 253 scaled = 29 * data; // 254 scaled += (data >> 2); // 255 scaled += (data >> 4); LDI R16, 29 LDI R17, 0 RCALL ?S_MUL_L02 LSR R19 ROR R18 LSR R19 ROR R18 ADD R18, R0 ADC R19, R1 LSR R25 ROR R24 LSR R25 ROR R24 LSR R25 ROR R24 LSR R25 ROR R24 ADD R24, R18 ADC R25, R19 RJMP ??ScaleU_1 // 256 } else { // 257 // Jumper setting 4: mV/LSB = 39.06 ~= 39 + 1/16 // 258 scaled = 39 * data; // 259 scaled += (data >> 4); ??ScaleU_0: LDI R16, 39 LDI R17, 0 RCALL ?S_MUL_L02 LSR R25 ROR R24 LSR R25 ROR R24 LSR R25 ROR R24 LSR R25 ROR R24 ADD R24, R0 ADC R25, R1 // 260 // 261 if (setting <3) { CPI R26, 3 BRCC ??ScaleU_1 // 262 // Jumper setting 0: mV/LSB = 4.883 = 39.06 / 8 // 263 // 1: mV/LSB = 9.766 = 39.06 / 4 // 264 // 2: mV/LSB = 19.53 = 39.06 / 2 // 265 scaled = (scaled >> (3-setting)); MOVW R17:R16, R25:R24 LDI R20, 3 SUB R20, R26 RCALL ?US_SHR_L02 MOVW R25:R24, R17:R16 // 266 } // 267 } // 268 // 269 return(scaled); ??ScaleU_1: MOVW R17:R16, R25:R24 MOVW R25:R24, R23:R22 MOV R26, R2 RET // 270 } // 271 // 272 // 273 /*! \brief Scales sample to represent "actual current" in mA. // 274 * // 275 * This function returns the actual sampled current, scaled according // 276 * to the jumper settings. // 277 * // 278 * \param setting Indicates what downscaling was used. // 279 * \param data The sampled value. // 280 * // 281 * \note Table for setting-parameter:\n // 282 *
//  283  * Presume VREF = 2.5V and Gain = 1x or 20x.
//  284  * => Resolution(U) @ (1/1 and 20x) = 2.5V / (GAIN x 1024) = 0.1221 mV/LSB
//  285  * => Resolution(I) = Resolution(U) / Rshunt = Resolution(U) / 0.07
//  286  * Setting |   R1 | R2/(R1+R2) |   U(LSB) |   I(LSB) | I(MAX) | Gain
//  287  * --------+------+------------+----------+----------+--------+-----
//  288  *     N/A |    - |       -    | 0.1221mV |  1.744mA |  1.78A |  20x
//  289  *       0 |  10k |     1/2    | 0.2442mV |  3.489mA |  3.57A |  20x
//  290  *       1 |  30k |     1/4    | 0.4884mV |  6.978mA |  7.14A |  20x
//  291  *       2 |  70k |     1/8    | 0.9768mV | 13.955mA |  14.3A |  20x
//  292  *       3 | 110k |    1/12    | 1.4652mV | 20.931mA |  21.4A |  20x
//  293  *       4 | 150k |    1/16    | 1.9536mV | 27.909mA |  28.5A |  20x
//  294  *       5 |  10k |     1/2    | 2.4414mV | 34.877mA |  35.7A |   1x
//  295  * 
// 296 */ RSEG CODE:CODE:NOROOT(1) // 297 unsigned int ScaleI(unsigned char setting, unsigned int data) ScaleI: // 298 { MOV R2, R26 MOVW R23:R22, R25:R24 MOV R26, R16 MOVW R25:R24, R19:R18 // 299 // Temporary variable needed. // 300 unsigned int scaled = 0; // 301 // 302 // Jumper setting 3: mA/LSB = 20.931mA ~= 21 - 1/16 + 1/128 // 303 if (setting == 3) { CPI R16, 3 MOVW R21:R20, R19:R18 BRNE ??ScaleI_0 // 304 scaled = 21 * data; // 305 scaled -= (data >> 4); // 306 scaled += (data >> 7); LDI R16, 21 LDI R17, 0 RCALL ?S_MUL_L02 LSR R19 ROR R18 LSR R19 ROR R18 LSR R19 ROR R18 LSR R19 ROR R18 SUB R16, R18 SBC R17, R19 LSL R24 MOV R24, R25 ROL R24 LDI R25, 0 ROL R25 ADD R24, R16 ADC R25, R17 RJMP ??ScaleI_1 // 307 } else { // Jumper setting 4: mA/LSB = 27.909mA ~= 28 - 1/8 + 1/32 // 308 scaled = 28 * data; // 309 scaled -= (data >> 3); // 310 scaled += (data >> 5); ??ScaleI_0: LDI R16, 28 LDI R17, 0 RCALL ?S_MUL_L02 MOVW R19:R18, R17:R16 MOVW R17:R16, R25:R24 LSR R17 ROR R16 LSR R17 ROR R16 LSR R17 ROR R16 SUB R18, R16 SBC R19, R17 MOVW R17:R16, R25:R24 LDI R20, 5 RCALL ?US_SHR_L02 MOVW R25:R24, R17:R16 ADD R24, R18 ADC R25, R19 // 311 // 312 if (setting <3) { CPI R26, 3 BRCC ??ScaleI_1 // 313 // Jumper setting 0: mA/LSB = 3.489mA = 27.909 / 8 // 314 // 1: mA/LSB = 6.978mA = 27.909 / 4 // 315 // 2: mA/LSB = 13.955mA = 27.909 / 2 // 316 scaled = (scaled >> (3-setting)); MOVW R17:R16, R25:R24 LDI R20, 3 SUB R20, R26 RCALL ?US_SHR_L02 MOVW R25:R24, R17:R16 // 317 } // 318 } // 319 // 320 return(scaled); ??ScaleI_1: MOVW R17:R16, R25:R24 MOVW R25:R24, R23:R22 MOV R26, R2 RET // 321 } // 322 // 323 // 324 /*! \brief Waits for two full cycles of ADC-conversions to occur. // 325 * // 326 * This function clears the cycle complete-flag, then waits for it to be set // 327 * again. This is then repeated once before the function exits. // 328 * // 329 */ RSEG CODE:CODE:NOROOT(1) // 330 void ADC_Wait(void) ADC_Wait: ??ADC_Wait_0: // 331 { // 332 // Clear ADC flag and wait for cycle to complete. // 333 ADCS.Flag = FALSE; // 334 do { // 335 } while (ADCS.Flag == FALSE); RJMP ??ADC_Wait_0 // 336 // 337 // Repeat, so we are sure the data beong to the same cycle. // 338 ADCS.Flag = FALSE; // 339 do { // 340 } while (ADCS.Flag == FALSE); // 341 } // 342 // 343 // 344 /*! \brief Initializes ADC and input pins. // 345 * // 346 * This function initializes the ADC to free running mode, sampling from // 347 * PA1/2/4/5/6/7, and using an external reference voltage (PA3).\n // 348 * It also measures and stores calibration data for offset. // 349 * // 350 * \todo Odd offset measurement for ADC3_G20_OS? It is never used anyway. // 351 * // 352 * \note Table of MUX settings for offset measurement: // 353 *
//  354  *    Ch | Pin |    Gain |    MUX
//  355  * ------+-----+---------+-------
//  356  *  ADC1 | PA1 |     20x | 001101
//  357  *  ADC3 | PA4 |     20x | 010001
//  358  *  ADC5 | PA6 |     20x | 010110
//  359  *  ADC9 | PB6 |     20x | 011011
//  360  *  ADC0 | PA0 | 20x/32x | 111000
//  361  *  ADC0 | PA0 |   1x/8x | 111001
//  362  *  ADC1 | PA1 | 20x/32x | 111010
//  363  *  ADC2 | PA2 | 20x/32x | 111011
//  364  *  ADC4 | PA5 | 20x/32x | 111100
//  365  *  ADC5 | PA6 | 20x/32x | 111101
//  366  *  ADC6 | PA7 | 20x/32x | 111110
//  367  * 
// 368 */ RSEG CODE:CODE:NOROOT(1) // 369 void ADC_Init(void) ADC_Init: // 370 { // 371 unsigned char i; // 372 // 373 __disable_interrupt(); CLI // 374 // 375 ADCS.Halt = FALSE; // Enable consecutive runs of ADC. LDI R30, LOW(ADCS) LDI R31, (ADCS) >> 8 LD R16, Z ANDI R16, 0x7F ST Z, R16 // 376 // 377 // Configure ADC pins (inputs and disabled pull-ups). // 378 DDRA &= ~((1<`: DW SFE(NEAR_Z) - SFB(NEAR_Z) DW SFB(NEAR_Z) DW 0 REQUIRE ?need_segment_init END // // 7 bytes in segment ABSOLUTE // 746 bytes in segment CODE // 1 byte in segment EEPROM_I // 6 bytes in segment INITTAB // 2 bytes in segment INTVEC // 25 bytes in segment NEAR_Z // // 746 bytes of CODE memory (+ 8 bytes shared) // 25 bytes of DATA memory (+ 7 bytes shared) // 1 byte of XDATA memory // //Errors: none //Warnings: none