/////////////////////////////////////////////////////////////////////////////// // / // IAR Atmel AVR C/C++ Compiler V4.30F/W32 12/Mar/2008 23:01:38 / // Copyright 1996-2007 IAR Systems. All rights reserved. / // / // Source file = C:\home\kevin\pub\src\bc100_cal\IAR\ADC.c / // Command line = C:\home\kevin\pub\src\bc100_cal\IAR\ADC.c / // --cpu=tiny861 -ms -o C:\home\kevin\pub\src\bc100_cal\IA / // R\Debug\Obj\ -lC C:\home\kevin\pub\src\bc100_cal\IAR\De / // bug\List\ -lB C:\home\kevin\pub\src\bc100_cal\IAR\Debug / // \List\ --initializers_in_flash -z2 --no_cse / // --no_inline --no_code_motion --no_cross_call / // --no_clustering --no_tbaa --debug / // -DENABLE_BIT_DEFINITIONS -e --require_prototypes -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 / // List file = C:\home\kevin\pub\src\bc100_cal\IAR\Debug\List\ADC.s90 / // / // / /////////////////////////////////////////////////////////////////////////////// NAME `ADC` RSEG CSTACK:DATA:NOROOT(0) RSEG RSTACK:DATA:NOROOT(0) EXTERN ?EPILOGUE_B6_L09 EXTERN ?PROLOGUE6_L09 EXTERN ?Register_R4_is_cg_reg EXTERN ?Register_R5_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_cal\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 RSEG NEAR_Z:DATA:NOROOT(0) REQUIRE `?` // 48 ADC_Status_t ADCS; ADCS: DS 24 // 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, R5 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 R5, 0x3F REQUIRE ?Register_R4_is_cg_reg REQUIRE ?Register_R5_is_cg_reg // 116 static unsigned char avgIndex = 0; // 117 unsigned char i, Next, Signed; // 118 signed int temp = 0; LDI R26, 0 LDI R27, 0 // 119 // 120 Signed = FALSE; // Presume next conversion is unipolar. CLR R4 // 121 ADCSRA &= ~(1< ADC1 (PA1) = NTC // 128 case 0x01: // 129 ADCS.rawNTC = ADC; ??ADC_ISR_0: IN R16, 0x04 IN R17, 0x05 LDI R30, LOW(ADCS) LDI R31, (ADCS) >> 8 STD Z+4, R16 STD Z+5, R17 // 130 Next=0x02; LDI R25, 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 LDI R30, LOW(ADCS) LDI R31, (ADCS) >> 8 STD Z+2, R16 STD Z+3, R17 // 137 Next=0x03; LDI R25, 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 LDI R30, LOW(ADCS) LDI R31, (ADCS) >> 8 STD Z+8, R16 STD Z+9, R17 // 145 // 146 // Is mains failing? // 147 if (ADCS.VIN < VIN_MIN) { LDI R30, LOW(ADCS) LDI R31, (ADCS) >> 8 LDD R16, Z+8 LDD R17, Z+9 CPI R16, 48 LDI R18, 17 CPC R17, R18 BRCC ??ADC_ISR_7 // 148 ADCS.Mains = FALSE; LDI R30, LOW(ADCS) LDI R31, (ADCS) >> 8 LD R16, Z ANDI R16, 0xBF ST Z, R16 RJMP ??ADC_ISR_8 // 149 } else { // 150 ADCS.Mains = TRUE; ??ADC_ISR_7: LDI R30, LOW(ADCS) LDI R31, (ADCS) >> 8 LD R16, Z ORI R16, 0x40 ST Z, R16 // 151 } // 152 // 153 Next=0x05; ??ADC_ISR_8: LDI R25, 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 LDI R30, LOW(ADCS) LDI R31, (ADCS) >> 8 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 LDI R30, LOW(ADCS) LDI R31, (ADCS) >> 8 STD Z+10, R16 STD Z+11, R17 // 163 Next=0x17; LDI R25, 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 R16, 0 LDI R18, 2 CPC R17, R18 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 LDS R18, (ADCS + 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 LDI R30, LOW(ADCS) LDI R31, (ADCS) >> 8 STD Z+12, R16 STD Z+13, R17 RJMP ??ADC_ISR_10 // 176 } else if (ADC > 0) { ??ADC_ISR_9: IN R16, 0x04 IN R17, 0x05 OR R16, R17 BREQ ??ADC_ISR_11 // 177 ADCS.IBAT = ScaleI(VBAT_RANGE, (ADC-ADCS.ADC5_G20_OS)); IN R18, 0x04 IN R19, 0x05 LDS R16, (ADCS + 1) SWAP R16 ANDI R16, 0x0F LDI R17, 0 SUB R18, R16 SBC R19, R17 LDI R20, LOW(VBAT_RANGE) LDI R21, (VBAT_RANGE) >> 8 RCALL __eeget8_16 RCALL ScaleI LDI R30, LOW(ADCS) LDI R31, (ADCS) >> 8 STD Z+12, R16 STD Z+13, R17 RJMP ??ADC_ISR_10 // 178 } else { // 179 ADCS.IBAT = 0; ??ADC_ISR_11: LDI R16, 0 LDI R17, 0 LDI R30, LOW(ADCS) LDI R31, (ADCS) >> 8 STD Z+12, R16 STD Z+13, R17 // 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_10: LDI R30, LOW(ADCS) LDI R31, (ADCS) >> 8 LDD R18, Z+12 LDD R19, Z+13 LDS R16, ??avgIndex LDI R17, 0 ANDI R16, 0x03 ANDI R17, 0x00 LSL R16 ROL R17 MOVW R31:R30, R17:R16 SUBI R30, LOW((-(ADCS) & 0xFFFF)) SBCI R31, (-(ADCS) & 0xFFFF) >> 8 STD Z+14, R18 STD Z+15, R19 LDI R30, LOW(??avgIndex) LDI R31, (??avgIndex) >> 8 LD R16, Z INC R16 ST Z, R16 // 187 for (i = 0; i < 4 ; i++) { LDI R24, 0 ??ADC_ISR_12: CPI R24, 4 BRCC ??ADC_ISR_13 // 188 temp += ADCS.discIBAT[i]; MOV R16, R24 LDI R17, 0 LSL R16 ROL R17 MOVW R31:R30, R17:R16 SUBI R30, LOW((-(ADCS) & 0xFFFF)) SBCI R31, (-(ADCS) & 0xFFFF) >> 8 LDD R16, Z+14 LDD R17, Z+15 ADD R26, R16 ADC R27, R17 // 189 } INC R24 RJMP ??ADC_ISR_12 // 190 // 191 ADCS.avgIBAT = (temp / 4); ??ADC_ISR_13: MOVW R17:R16, R27:R26 LDI R20, 4 LDI R21, 0 RCALL ?SS_DIVMOD_L02 LDI R30, LOW(ADCS) LDI R31, (ADCS) >> 8 STD Z+22, R16 STD Z+23, R17 // 192 // 193 ADCS.Flag = TRUE; LDI R30, LOW(ADCS) LDI R31, (ADCS) >> 8 LD R16, Z ORI R16, 0x20 ST Z, R16 // 194 Next=0x01; LDI R25, 1 // 195 Signed = FALSE; // This is the only bipolar conversion. CLR R4 RJMP ??ADC_ISR_6 // 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 R25, 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: LDS R17, ADCS ANDI R17, 0xE0 MOV R16, R25 ANDI R16, 0x1F OR R16, R17 STS ADCS, R16 // 207 ADMUX = (1<` ??avgIndex: 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 { RCALL ?PROLOGUE6_L09 REQUIRE ?Register_R4_is_cg_reg REQUIRE ?Register_R5_is_cg_reg MOV R26, R16 MOVW R25:R24, R19:R18 // 248 // Temporary variable needed. // 249 unsigned int scaled = 0; CLR R4 CLR R5 // 250 // 251 // Jumper setting 3: mV/LSB = 29.30 ~= 29 + 1/4 + 1/16 // 252 if (setting == 3) { CPI R26, 3 BRNE ??ScaleU_0 // 253 scaled = 29 * data; MOVW R21:R20, R25:R24 LDI R16, 29 LDI R17, 0 RCALL ?S_MUL_L02 MOVW R5:R4, R17:R16 // 254 scaled += (data >> 2); MOVW R17:R16, R25:R24 LSR R17 ROR R16 LSR R17 ROR R16 ADD R4, R16 ADC R5, R17 // 255 scaled += (data >> 4); MOVW R17:R16, R25:R24 LDI R20, 4 RCALL ?US_SHR_L02 ADD R4, R16 ADC R5, R17 RJMP ??ScaleU_1 // 256 } else { // 257 // Jumper setting 4: mV/LSB = 39.06 ~= 39 + 1/16 // 258 scaled = 39 * data; ??ScaleU_0: MOVW R21:R20, R25:R24 LDI R16, 39 LDI R17, 0 RCALL ?S_MUL_L02 MOVW R5:R4, R17:R16 // 259 scaled += (data >> 4); MOVW R17:R16, R25:R24 LDI R20, 4 RCALL ?US_SHR_L02 ADD R4, R16 ADC R5, R17 // 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, R5:R4 LDI R20, 3 SUB R20, R26 RCALL ?US_SHR_L02 MOVW R5:R4, R17:R16 // 266 } // 267 } // 268 // 269 return(scaled); ??ScaleU_1: MOVW R17:R16, R5:R4 LDI R30, 6 RJMP ?EPILOGUE_B6_L09 // 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 { RCALL ?PROLOGUE6_L09 REQUIRE ?Register_R4_is_cg_reg REQUIRE ?Register_R5_is_cg_reg MOV R26, R16 MOVW R25:R24, R19:R18 // 299 // Temporary variable needed. // 300 unsigned int scaled = 0; CLR R4 CLR R5 // 301 // 302 // Jumper setting 3: mA/LSB = 20.931mA ~= 21 - 1/16 + 1/128 // 303 if (setting == 3) { CPI R26, 3 BRNE ??ScaleI_0 // 304 scaled = 21 * data; MOVW R21:R20, R25:R24 LDI R16, 21 LDI R17, 0 RCALL ?S_MUL_L02 MOVW R5:R4, R17:R16 // 305 scaled -= (data >> 4); MOVW R17:R16, R25:R24 LDI R20, 4 RCALL ?US_SHR_L02 SUB R4, R16 SBC R5, R17 // 306 scaled += (data >> 7); MOVW R17:R16, R25:R24 LSL R16 MOV R16, R17 ROL R16 LDI R17, 0 ROL R17 ADD R4, R16 ADC R5, R17 RJMP ??ScaleI_1 // 307 } else { // Jumper setting 4: mA/LSB = 27.909mA ~= 28 - 1/8 + 1/32 // 308 scaled = 28 * data; ??ScaleI_0: MOVW R21:R20, R25:R24 LDI R16, 28 LDI R17, 0 RCALL ?S_MUL_L02 MOVW R5:R4, R17:R16 // 309 scaled -= (data >> 3); MOVW R17:R16, R25:R24 LDI R20, 3 RCALL ?US_SHR_L02 SUB R4, R16 SBC R5, R17 // 310 scaled += (data >> 5); MOVW R17:R16, R25:R24 LDI R20, 5 RCALL ?US_SHR_L02 ADD R4, R16 ADC R5, R17 // 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, R5:R4 LDI R20, 3 SUB R20, R26 RCALL ?US_SHR_L02 MOVW R5:R4, R17:R16 // 317 } // 318 } // 319 // 320 return(scaled); ??ScaleI_1: MOVW R17:R16, R5:R4 LDI R30, 6 RJMP ?EPILOGUE_B6_L09 // 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: // 331 { // 332 // Clear ADC flag and wait for cycle to complete. // 333 ADCS.Flag = FALSE; LDI R30, LOW(ADCS) LDI R31, (ADCS) >> 8 LD R16, Z ANDI R16, 0xDF ST Z, R16 // 334 do { // 335 } while (ADCS.Flag == FALSE); ??ADC_Wait_0: LDI R30, LOW(ADCS) LDI R31, (ADCS) >> 8 LD R16, Z SBRS R16, 5 RJMP ??ADC_Wait_0 // 336 // 337 // Repeat, so we are sure the data beong to the same cycle. // 338 ADCS.Flag = FALSE; LDI R30, LOW(ADCS) LDI R31, (ADCS) >> 8 LD R16, Z ANDI R16, 0xDF ST Z, R16 // 339 do { // 340 } while (ADCS.Flag == FALSE); ??ADC_Wait_1: LDI R30, LOW(ADCS) LDI R31, (ADCS) >> 8 LD R16, Z SBRS R16, 5 RJMP ??ADC_Wait_1 // 341 } RET // 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 { ST -Y, R24 // 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<> 8 LD R16, Z ANDI R16, 0xDF ST Z, R16 // 410 ADCS.MUX = 0x01; LDS R16, ADCS ANDI R16, 0xE0 ORI R16, 0x01 STS ADCS, R16 // 411 ADMUX = (1<> 8 STD Z+22, R16 STD Z+23, R17 // 415 // 416 for (i = 0; i < 4; i++) { LDI R24, 0 ??ADC_Init_2: CPI R24, 4 BRCC ??ADC_Init_3 // 417 ADCS.discIBAT[i] = 0; LDI R16, 0 LDI R17, 0 MOV R18, R24 LDI R19, 0 LSL R18 ROL R19 MOVW R31:R30, R19:R18 SUBI R30, LOW((-(ADCS) & 0xFFFF)) SBCI R31, (-(ADCS) & 0xFFFF) >> 8 STD Z+14, R16 STD Z+15, R17 // 418 } INC R24 RJMP ??ADC_Init_2 // 419 // 420 // Re-enable the ADC and ISR. // 421 ADCSRA=(1<`: DW SFE(NEAR_Z) - SFB(NEAR_Z) DW SFB(NEAR_Z) DW 0 REQUIRE ?need_segment_init END // // 7 bytes in segment ABSOLUTE // 946 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 // // 946 bytes of CODE memory (+ 8 bytes shared) // 25 bytes of DATA memory (+ 7 bytes shared) // 1 byte of XDATA memory // //Errors: none //Warnings: none