############################################################################### # # # 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\IAR\Debug\Obj\ # # -lC C:\home\kevin\pub\src\bc100_cal\IAR\Debug\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.lst # # Object file = C:\home\kevin\pub\src\bc100_cal\IAR\Debug\Obj\ADC.r90 # # # # # ############################################################################### 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 \ In segment ABSOLUTE, at 0x3b \ volatile __io _A_PORTA \ _A_PORTA: \ 00000000 DS 1 \ In segment ABSOLUTE, at 0x3a \ volatile __io _A_DDRA \ _A_DDRA: \ 00000000 DS 1 \ In segment ABSOLUTE, at 0x27 \ volatile __io _A_ADMUX \ _A_ADMUX: \ 00000000 DS 1 \ In segment ABSOLUTE, at 0x26 \ volatile __io _A_ADCSRA \ _A_ADCSRA: \ 00000000 DS 1 \ In segment ABSOLUTE, at 0x24 \ volatile __io _A_ADC \ _A_ADC: \ 00000000 DS 2 \ In segment ABSOLUTE, at 0x23 \ volatile __io _A_ADCSRB \ _A_ADCSRB: \ 00000000 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 \ In segment NEAR_Z, align 1, keep-with-next \ 00000000 REQUIRE `?` 48 ADC_Status_t ADCS; \ ADCS: \ 00000000 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). \ In segment EEPROM_I, align 1, keep-with-next 73 __eeprom unsigned char VBAT_RANGE = 1; \ VBAT_RANGE: \ 00000000 01 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 \ In segment CODE, align 2, keep-with-next 114 __interrupt void ADC_ISR(void) \ ADC_ISR: 115 { \ 00000000 925A ST -Y, R5 \ 00000002 924A ST -Y, R4 \ 00000004 93BA ST -Y, R27 \ 00000006 93AA ST -Y, R26 \ 00000008 939A ST -Y, R25 \ 0000000A 938A ST -Y, R24 \ 0000000C 93FA ST -Y, R31 \ 0000000E 93EA ST -Y, R30 \ 00000010 923A ST -Y, R3 \ 00000012 922A ST -Y, R2 \ 00000014 921A ST -Y, R1 \ 00000016 920A ST -Y, R0 \ 00000018 937A ST -Y, R23 \ 0000001A 936A ST -Y, R22 \ 0000001C 935A ST -Y, R21 \ 0000001E 934A ST -Y, R20 \ 00000020 933A ST -Y, R19 \ 00000022 932A ST -Y, R18 \ 00000024 931A ST -Y, R17 \ 00000026 930A ST -Y, R16 \ 00000028 B65F IN R5, 0x3F \ 0000002A REQUIRE ?Register_R4_is_cg_reg \ 0000002A REQUIRE ?Register_R5_is_cg_reg 116 static unsigned char avgIndex = 0; 117 unsigned char i, Next, Signed; 118 signed int temp = 0; \ 0000002A E0A0 LDI R26, 0 \ 0000002C E0B0 LDI R27, 0 119 120 Signed = FALSE; // Presume next conversion is unipolar. \ 0000002E 2444 CLR R4 121 ADCSRA &= ~(1< ADC1 (PA1) = NTC 128 case 0x01: 129 ADCS.rawNTC = ADC; \ ??ADC_ISR_0: \ 00000050 B104 IN R16, 0x04 \ 00000052 B115 IN R17, 0x05 \ 00000054 .... LDI R30, LOW(ADCS) \ 00000056 .... LDI R31, (ADCS) >> 8 \ 00000058 8304 STD Z+4, R16 \ 0000005A 8315 STD Z+5, R17 130 Next=0x02; \ 0000005C E092 LDI R25, 2 \ 0000005E C0A8 RJMP ??ADC_ISR_6 131 break; 132 133 134 // MUX = 0b000010 => ADC2 (PA2) = RID 135 case 0x02: 136 ADCS.rawRID = ADC; \ ??ADC_ISR_1: \ 00000060 B104 IN R16, 0x04 \ 00000062 B115 IN R17, 0x05 \ 00000064 .... LDI R30, LOW(ADCS) \ 00000066 .... LDI R31, (ADCS) >> 8 \ 00000068 8302 STD Z+2, R16 \ 0000006A 8313 STD Z+3, R17 137 Next=0x03; \ 0000006C E093 LDI R25, 3 \ 0000006E C0A0 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: \ 00000070 B124 IN R18, 0x04 \ 00000072 B135 IN R19, 0x05 \ 00000074 E004 LDI R16, 4 \ 00000076 .... RCALL ScaleU \ 00000078 .... LDI R30, LOW(ADCS) \ 0000007A .... LDI R31, (ADCS) >> 8 \ 0000007C 8700 STD Z+8, R16 \ 0000007E 8711 STD Z+9, R17 145 146 // Is mains failing? 147 if (ADCS.VIN < VIN_MIN) { \ 00000080 .... LDI R30, LOW(ADCS) \ 00000082 .... LDI R31, (ADCS) >> 8 \ 00000084 8500 LDD R16, Z+8 \ 00000086 8511 LDD R17, Z+9 \ 00000088 3300 CPI R16, 48 \ 0000008A E121 LDI R18, 17 \ 0000008C 0712 CPC R17, R18 \ 0000008E F430 BRCC ??ADC_ISR_7 148 ADCS.Mains = FALSE; \ 00000090 .... LDI R30, LOW(ADCS) \ 00000092 .... LDI R31, (ADCS) >> 8 \ 00000094 8100 LD R16, Z \ 00000096 7B0F ANDI R16, 0xBF \ 00000098 8300 ST Z, R16 \ 0000009A C005 RJMP ??ADC_ISR_8 149 } else { 150 ADCS.Mains = TRUE; \ ??ADC_ISR_7: \ 0000009C .... LDI R30, LOW(ADCS) \ 0000009E .... LDI R31, (ADCS) >> 8 \ 000000A0 8100 LD R16, Z \ 000000A2 6400 ORI R16, 0x40 \ 000000A4 8300 ST Z, R16 151 } 152 153 Next=0x05; \ ??ADC_ISR_8: \ 000000A6 E095 LDI R25, 5 \ 000000A8 C083 RJMP ??ADC_ISR_6 154 break; 155 156 157 // MUX = 0b000101 => ADC5 (PA6) = VBAT- 158 case 0x05: 159 ADCS.rawVBAT = ADC; \ ??ADC_ISR_3: \ 000000AA B104 IN R16, 0x04 \ 000000AC B115 IN R17, 0x05 \ 000000AE .... LDI R30, LOW(ADCS) \ 000000B0 .... LDI R31, (ADCS) >> 8 \ 000000B2 8306 STD Z+6, R16 \ 000000B4 8317 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. \ 000000B6 B124 IN R18, 0x04 \ 000000B8 B135 IN R19, 0x05 \ 000000BA .... LDI R20, LOW(VBAT_RANGE) \ 000000BC .... LDI R21, (VBAT_RANGE) >> 8 \ 000000BE .... RCALL __eeget8_16 \ 000000C0 .... RCALL ScaleU \ 000000C2 .... LDI R30, LOW(ADCS) \ 000000C4 .... LDI R31, (ADCS) >> 8 \ 000000C6 8702 STD Z+10, R16 \ 000000C8 8713 STD Z+11, R17 163 Next=0x17; \ 000000CA E197 LDI R25, 23 \ 000000CC C071 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: \ 000000CE B104 IN R16, 0x04 \ 000000D0 B115 IN R17, 0x05 \ 000000D2 3000 CPI R16, 0 \ 000000D4 E022 LDI R18, 2 \ 000000D6 0712 CPC R17, R18 \ 000000D8 F0C8 BRCS ??ADC_ISR_9 174 ADCS.IBAT = -(signed int)ScaleI(VBAT_RANGE, 175 (1024 - (ADC-ADCS.ADC5_G20_OS))); \ 000000DA E000 LDI R16, 0 \ 000000DC E014 LDI R17, 4 \ 000000DE B124 IN R18, 0x04 \ 000000E0 B135 IN R19, 0x05 \ 000000E2 1B02 SUB R16, R18 \ 000000E4 0B13 SBC R17, R19 \ 000000E6 9120.... LDS R18, (ADCS + 1) \ 000000EA 9522 SWAP R18 \ 000000EC 702F ANDI R18, 0x0F \ 000000EE E030 LDI R19, 0 \ 000000F0 0F20 ADD R18, R16 \ 000000F2 1F31 ADC R19, R17 \ 000000F4 .... LDI R20, LOW(VBAT_RANGE) \ 000000F6 .... LDI R21, (VBAT_RANGE) >> 8 \ 000000F8 .... RCALL __eeget8_16 \ 000000FA .... RCALL ScaleI \ 000000FC 9511 NEG R17 \ 000000FE 9501 NEG R16 \ 00000100 4010 SBCI R17, 0 \ 00000102 .... LDI R30, LOW(ADCS) \ 00000104 .... LDI R31, (ADCS) >> 8 \ 00000106 8704 STD Z+12, R16 \ 00000108 8715 STD Z+13, R17 \ 0000010A C01C RJMP ??ADC_ISR_10 176 } else if (ADC > 0) { \ ??ADC_ISR_9: \ 0000010C B104 IN R16, 0x04 \ 0000010E B115 IN R17, 0x05 \ 00000110 2B01 OR R16, R17 \ 00000112 F091 BREQ ??ADC_ISR_11 177 ADCS.IBAT = ScaleI(VBAT_RANGE, (ADC-ADCS.ADC5_G20_OS)); \ 00000114 B124 IN R18, 0x04 \ 00000116 B135 IN R19, 0x05 \ 00000118 9100.... LDS R16, (ADCS + 1) \ 0000011C 9502 SWAP R16 \ 0000011E 700F ANDI R16, 0x0F \ 00000120 E010 LDI R17, 0 \ 00000122 1B20 SUB R18, R16 \ 00000124 0B31 SBC R19, R17 \ 00000126 .... LDI R20, LOW(VBAT_RANGE) \ 00000128 .... LDI R21, (VBAT_RANGE) >> 8 \ 0000012A .... RCALL __eeget8_16 \ 0000012C .... RCALL ScaleI \ 0000012E .... LDI R30, LOW(ADCS) \ 00000130 .... LDI R31, (ADCS) >> 8 \ 00000132 8704 STD Z+12, R16 \ 00000134 8715 STD Z+13, R17 \ 00000136 C006 RJMP ??ADC_ISR_10 178 } else { 179 ADCS.IBAT = 0; \ ??ADC_ISR_11: \ 00000138 E000 LDI R16, 0 \ 0000013A E010 LDI R17, 0 \ 0000013C .... LDI R30, LOW(ADCS) \ 0000013E .... LDI R31, (ADCS) >> 8 \ 00000140 8704 STD Z+12, R16 \ 00000142 8715 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: \ 00000144 .... LDI R30, LOW(ADCS) \ 00000146 .... LDI R31, (ADCS) >> 8 \ 00000148 8524 LDD R18, Z+12 \ 0000014A 8535 LDD R19, Z+13 \ 0000014C 9100.... LDS R16, ??avgIndex \ 00000150 E010 LDI R17, 0 \ 00000152 7003 ANDI R16, 0x03 \ 00000154 7010 ANDI R17, 0x00 \ 00000156 0F00 LSL R16 \ 00000158 1F11 ROL R17 \ 0000015A 01F8 MOVW R31:R30, R17:R16 \ 0000015C .... SUBI R30, LOW((-(ADCS) & 0xFFFF)) \ 0000015E .... SBCI R31, (-(ADCS) & 0xFFFF) >> 8 \ 00000160 8726 STD Z+14, R18 \ 00000162 8737 STD Z+15, R19 \ 00000164 .... LDI R30, LOW(??avgIndex) \ 00000166 .... LDI R31, (??avgIndex) >> 8 \ 00000168 8100 LD R16, Z \ 0000016A 9503 INC R16 \ 0000016C 8300 ST Z, R16 187 for (i = 0; i < 4 ; i++) { \ 0000016E E080 LDI R24, 0 \ ??ADC_ISR_12: \ 00000170 3084 CPI R24, 4 \ 00000172 F468 BRCC ??ADC_ISR_13 188 temp += ADCS.discIBAT[i]; \ 00000174 2F08 MOV R16, R24 \ 00000176 E010 LDI R17, 0 \ 00000178 0F00 LSL R16 \ 0000017A 1F11 ROL R17 \ 0000017C 01F8 MOVW R31:R30, R17:R16 \ 0000017E .... SUBI R30, LOW((-(ADCS) & 0xFFFF)) \ 00000180 .... SBCI R31, (-(ADCS) & 0xFFFF) >> 8 \ 00000182 8506 LDD R16, Z+14 \ 00000184 8517 LDD R17, Z+15 \ 00000186 0FA0 ADD R26, R16 \ 00000188 1FB1 ADC R27, R17 189 } \ 0000018A 9583 INC R24 \ 0000018C CFF1 RJMP ??ADC_ISR_12 190 191 ADCS.avgIBAT = (temp / 4); \ ??ADC_ISR_13: \ 0000018E 018D MOVW R17:R16, R27:R26 \ 00000190 E044 LDI R20, 4 \ 00000192 E050 LDI R21, 0 \ 00000194 .... RCALL ?SS_DIVMOD_L02 \ 00000196 .... LDI R30, LOW(ADCS) \ 00000198 .... LDI R31, (ADCS) >> 8 \ 0000019A 8B06 STD Z+22, R16 \ 0000019C 8B17 STD Z+23, R17 192 193 ADCS.Flag = TRUE; \ 0000019E .... LDI R30, LOW(ADCS) \ 000001A0 .... LDI R31, (ADCS) >> 8 \ 000001A2 8100 LD R16, Z \ 000001A4 6200 ORI R16, 0x20 \ 000001A6 8300 ST Z, R16 194 Next=0x01; \ 000001A8 E091 LDI R25, 1 195 Signed = FALSE; // This is the only bipolar conversion. \ 000001AA 2444 CLR R4 \ 000001AC C001 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: \ 000001AE E091 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: \ 000001B0 9110.... LDS R17, ADCS \ 000001B4 7E10 ANDI R17, 0xE0 \ 000001B6 2F09 MOV R16, R25 \ 000001B8 710F ANDI R16, 0x1F \ 000001BA 2B01 OR R16, R17 \ 000001BC 9300.... STS ADCS, R16 207 ADMUX = (1<` \ ??avgIndex: \ 00000000 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 */ \ In segment CODE, align 2, keep-with-next 246 unsigned int ScaleU(unsigned char setting, unsigned int data) \ ScaleU: 247 { \ 00000000 .... RCALL ?PROLOGUE6_L09 \ 00000002 REQUIRE ?Register_R4_is_cg_reg \ 00000002 REQUIRE ?Register_R5_is_cg_reg \ 00000002 2FA0 MOV R26, R16 \ 00000004 01C9 MOVW R25:R24, R19:R18 248 // Temporary variable needed. 249 unsigned int scaled = 0; \ 00000006 2444 CLR R4 \ 00000008 2455 CLR R5 250 251 // Jumper setting 3: mV/LSB = 29.30 ~= 29 + 1/4 + 1/16 252 if (setting == 3) { \ 0000000A 30A3 CPI R26, 3 \ 0000000C F491 BRNE ??ScaleU_0 253 scaled = 29 * data; \ 0000000E 01AC MOVW R21:R20, R25:R24 \ 00000010 E10D LDI R16, 29 \ 00000012 E010 LDI R17, 0 \ 00000014 .... RCALL ?S_MUL_L02 \ 00000016 0128 MOVW R5:R4, R17:R16 254 scaled += (data >> 2); \ 00000018 018C MOVW R17:R16, R25:R24 \ 0000001A 9516 LSR R17 \ 0000001C 9507 ROR R16 \ 0000001E 9516 LSR R17 \ 00000020 9507 ROR R16 \ 00000022 0E40 ADD R4, R16 \ 00000024 1E51 ADC R5, R17 255 scaled += (data >> 4); \ 00000026 018C MOVW R17:R16, R25:R24 \ 00000028 E044 LDI R20, 4 \ 0000002A .... RCALL ?US_SHR_L02 \ 0000002C 0E40 ADD R4, R16 \ 0000002E 1E51 ADC R5, R17 \ 00000030 C011 RJMP ??ScaleU_1 256 } else { 257 // Jumper setting 4: mV/LSB = 39.06 ~= 39 + 1/16 258 scaled = 39 * data; \ ??ScaleU_0: \ 00000032 01AC MOVW R21:R20, R25:R24 \ 00000034 E207 LDI R16, 39 \ 00000036 E010 LDI R17, 0 \ 00000038 .... RCALL ?S_MUL_L02 \ 0000003A 0128 MOVW R5:R4, R17:R16 259 scaled += (data >> 4); \ 0000003C 018C MOVW R17:R16, R25:R24 \ 0000003E E044 LDI R20, 4 \ 00000040 .... RCALL ?US_SHR_L02 \ 00000042 0E40 ADD R4, R16 \ 00000044 1E51 ADC R5, R17 260 261 if (setting <3) { \ 00000046 30A3 CPI R26, 3 \ 00000048 F428 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)); \ 0000004A 0182 MOVW R17:R16, R5:R4 \ 0000004C E043 LDI R20, 3 \ 0000004E 1B4A SUB R20, R26 \ 00000050 .... RCALL ?US_SHR_L02 \ 00000052 0128 MOVW R5:R4, R17:R16 266 } 267 } 268 269 return(scaled); \ ??ScaleU_1: \ 00000054 0182 MOVW R17:R16, R5:R4 \ 00000056 E0E6 LDI R30, 6 \ 00000058 .... 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 */ \ In segment CODE, align 2, keep-with-next 297 unsigned int ScaleI(unsigned char setting, unsigned int data) \ ScaleI: 298 { \ 00000000 .... RCALL ?PROLOGUE6_L09 \ 00000002 REQUIRE ?Register_R4_is_cg_reg \ 00000002 REQUIRE ?Register_R5_is_cg_reg \ 00000002 2FA0 MOV R26, R16 \ 00000004 01C9 MOVW R25:R24, R19:R18 299 // Temporary variable needed. 300 unsigned int scaled = 0; \ 00000006 2444 CLR R4 \ 00000008 2455 CLR R5 301 302 // Jumper setting 3: mA/LSB = 20.931mA ~= 21 - 1/16 + 1/128 303 if (setting == 3) { \ 0000000A 30A3 CPI R26, 3 \ 0000000C F499 BRNE ??ScaleI_0 304 scaled = 21 * data; \ 0000000E 01AC MOVW R21:R20, R25:R24 \ 00000010 E105 LDI R16, 21 \ 00000012 E010 LDI R17, 0 \ 00000014 .... RCALL ?S_MUL_L02 \ 00000016 0128 MOVW R5:R4, R17:R16 305 scaled -= (data >> 4); \ 00000018 018C MOVW R17:R16, R25:R24 \ 0000001A E044 LDI R20, 4 \ 0000001C .... RCALL ?US_SHR_L02 \ 0000001E 1A40 SUB R4, R16 \ 00000020 0A51 SBC R5, R17 306 scaled += (data >> 7); \ 00000022 018C MOVW R17:R16, R25:R24 \ 00000024 0F00 LSL R16 \ 00000026 2F01 MOV R16, R17 \ 00000028 1F00 ROL R16 \ 0000002A E010 LDI R17, 0 \ 0000002C 1F11 ROL R17 \ 0000002E 0E40 ADD R4, R16 \ 00000030 1E51 ADC R5, R17 \ 00000032 C016 RJMP ??ScaleI_1 307 } else { // Jumper setting 4: mA/LSB = 27.909mA ~= 28 - 1/8 + 1/32 308 scaled = 28 * data; \ ??ScaleI_0: \ 00000034 01AC MOVW R21:R20, R25:R24 \ 00000036 E10C LDI R16, 28 \ 00000038 E010 LDI R17, 0 \ 0000003A .... RCALL ?S_MUL_L02 \ 0000003C 0128 MOVW R5:R4, R17:R16 309 scaled -= (data >> 3); \ 0000003E 018C MOVW R17:R16, R25:R24 \ 00000040 E043 LDI R20, 3 \ 00000042 .... RCALL ?US_SHR_L02 \ 00000044 1A40 SUB R4, R16 \ 00000046 0A51 SBC R5, R17 310 scaled += (data >> 5); \ 00000048 018C MOVW R17:R16, R25:R24 \ 0000004A E045 LDI R20, 5 \ 0000004C .... RCALL ?US_SHR_L02 \ 0000004E 0E40 ADD R4, R16 \ 00000050 1E51 ADC R5, R17 311 312 if (setting <3) { \ 00000052 30A3 CPI R26, 3 \ 00000054 F428 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)); \ 00000056 0182 MOVW R17:R16, R5:R4 \ 00000058 E043 LDI R20, 3 \ 0000005A 1B4A SUB R20, R26 \ 0000005C .... RCALL ?US_SHR_L02 \ 0000005E 0128 MOVW R5:R4, R17:R16 317 } 318 } 319 320 return(scaled); \ ??ScaleI_1: \ 00000060 0182 MOVW R17:R16, R5:R4 \ 00000062 E0E6 LDI R30, 6 \ 00000064 .... 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 */ \ In segment CODE, align 2, keep-with-next 330 void ADC_Wait(void) \ ADC_Wait: 331 { 332 // Clear ADC flag and wait for cycle to complete. 333 ADCS.Flag = FALSE; \ 00000000 .... LDI R30, LOW(ADCS) \ 00000002 .... LDI R31, (ADCS) >> 8 \ 00000004 8100 LD R16, Z \ 00000006 7D0F ANDI R16, 0xDF \ 00000008 8300 ST Z, R16 334 do { 335 } while (ADCS.Flag == FALSE); \ ??ADC_Wait_0: \ 0000000A .... LDI R30, LOW(ADCS) \ 0000000C .... LDI R31, (ADCS) >> 8 \ 0000000E 8100 LD R16, Z \ 00000010 FF05 SBRS R16, 5 \ 00000012 CFFB RJMP ??ADC_Wait_0 336 337 // Repeat, so we are sure the data beong to the same cycle. 338 ADCS.Flag = FALSE; \ 00000014 .... LDI R30, LOW(ADCS) \ 00000016 .... LDI R31, (ADCS) >> 8 \ 00000018 8100 LD R16, Z \ 0000001A 7D0F ANDI R16, 0xDF \ 0000001C 8300 ST Z, R16 339 do { 340 } while (ADCS.Flag == FALSE); \ ??ADC_Wait_1: \ 0000001E .... LDI R30, LOW(ADCS) \ 00000020 .... LDI R31, (ADCS) >> 8 \ 00000022 8100 LD R16, Z \ 00000024 FF05 SBRS R16, 5 \ 00000026 CFFB RJMP ??ADC_Wait_1 341 } \ 00000028 9508 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 */ \ In segment CODE, align 2, keep-with-next 369 void ADC_Init(void) \ ADC_Init: 370 { \ 00000000 938A ST -Y, R24 371 unsigned char i; 372 373 __disable_interrupt(); \ 00000002 94F8 CLI 374 375 ADCS.Halt = FALSE; // Enable consecutive runs of ADC. \ 00000004 .... LDI R30, LOW(ADCS) \ 00000006 .... LDI R31, (ADCS) >> 8 \ 00000008 8100 LD R16, Z \ 0000000A 770F ANDI R16, 0x7F \ 0000000C 8300 ST Z, R16 376 377 // Configure ADC pins (inputs and disabled pull-ups). 378 DDRA &= ~((1<> 8 \ 00000064 8100 LD R16, Z \ 00000066 7D0F ANDI R16, 0xDF \ 00000068 8300 ST Z, R16 410 ADCS.MUX = 0x01; \ 0000006A 9100.... LDS R16, ADCS \ 0000006E 7E00 ANDI R16, 0xE0 \ 00000070 6001 ORI R16, 0x01 \ 00000072 9300.... STS ADCS, R16 411 ADMUX = (1<> 8 \ 00000088 8B06 STD Z+22, R16 \ 0000008A 8B17 STD Z+23, R17 415 416 for (i = 0; i < 4; i++) { \ 0000008C E080 LDI R24, 0 \ ??ADC_Init_2: \ 0000008E 3084 CPI R24, 4 \ 00000090 F468 BRCC ??ADC_Init_3 417 ADCS.discIBAT[i] = 0; \ 00000092 E000 LDI R16, 0 \ 00000094 E010 LDI R17, 0 \ 00000096 2F28 MOV R18, R24 \ 00000098 E030 LDI R19, 0 \ 0000009A 0F22 LSL R18 \ 0000009C 1F33 ROL R19 \ 0000009E 01F9 MOVW R31:R30, R19:R18 \ 000000A0 .... SUBI R30, LOW((-(ADCS) & 0xFFFF)) \ 000000A2 .... SBCI R31, (-(ADCS) & 0xFFFF) >> 8 \ 000000A4 8706 STD Z+14, R16 \ 000000A6 8717 STD Z+15, R17 418 } \ 000000A8 9583 INC R24 \ 000000AA CFF1 RJMP ??ADC_Init_2 419 420 // Re-enable the ADC and ISR. 421 ADCSRA=(1< ScaleU 20 2 -> ScaleU 20 2 -> ScaleI 20 2 -> ScaleI 20 2 ADC_Init 1 2 -> ADC_Wait 1 2 ADC_Wait 0 2 ScaleI 6 4 ScaleU 6 4 Segment part sizes: Function/Label Bytes -------------- ----- _A_PORTA 1 _A_DDRA 1 _A_ADMUX 1 _A_ADCSRA 1 _A_ADC 2 _A_ADCSRB 1 ADCS 24 VBAT_RANGE 1 ADC_ISR 528 avgIndex 1 ScaleU 90 ScaleI 102 ADC_Wait 42 ADC_Init 184 ??ADC_ISR??INTVEC 22 2 Others 6 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