############################################################################### # # # 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\bc10 # # 0\IAR\Release\Obj\ -D NDEBUG -lCN # # C:\home\kevin\pub\src\bc100\IAR\Release\List\ # # -lB C:\home\kevin\pub\src\bc100\IAR\Release\Lis # # t\ --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\AD # # C.lst # # Object file = C:\home\kevin\pub\src\bc100\IAR\Release\Obj\ADC # # .r90 # # # # # ############################################################################### 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 \ 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 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). \ 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 924A ST -Y, R4 \ 00000002 93BA ST -Y, R27 \ 00000004 93AA ST -Y, R26 \ 00000006 939A ST -Y, R25 \ 00000008 938A ST -Y, R24 \ 0000000A 93FA ST -Y, R31 \ 0000000C 93EA ST -Y, R30 \ 0000000E 923A ST -Y, R3 \ 00000010 922A ST -Y, R2 \ 00000012 921A ST -Y, R1 \ 00000014 920A ST -Y, R0 \ 00000016 937A ST -Y, R23 \ 00000018 936A ST -Y, R22 \ 0000001A 935A ST -Y, R21 \ 0000001C 934A ST -Y, R20 \ 0000001E 933A ST -Y, R19 \ 00000020 932A ST -Y, R18 \ 00000022 931A ST -Y, R17 \ 00000024 930A ST -Y, R16 \ 00000026 B64F IN R4, 0x3F \ 00000028 REQUIRE ?Register_R4_is_cg_reg 116 static unsigned char avgIndex = 0; 117 unsigned char i, Next, Signed; 118 signed int temp = 0; \ 00000028 E080 LDI R24, 0 \ 0000002A E090 LDI R25, 0 119 120 Signed = FALSE; // Presume next conversion is unipolar. 121 ADCSRA &= ~(1<> 8 \ 00000032 910C LD R16, X \ 00000034 710F ANDI R16, 0x1F \ 00000036 950A DEC R16 \ 00000038 F049 BREQ ??ADC_ISR_0 \ 0000003A 950A DEC R16 \ 0000003C F071 BREQ ??ADC_ISR_1 \ 0000003E 950A DEC R16 \ 00000040 F099 BREQ ??ADC_ISR_2 \ 00000042 5002 SUBI R16, 2 \ 00000044 F111 BREQ ??ADC_ISR_3 \ 00000046 5102 SUBI R16, 18 \ 00000048 F181 BREQ ??ADC_ISR_4 \ 0000004A C07E RJMP ??ADC_ISR_5 127 // MUX = 0b000001 => ADC1 (PA1) = NTC 128 case 0x01: 129 ADCS.rawNTC = ADC; \ ??ADC_ISR_0: \ 0000004C B104 IN R16, 0x04 \ 0000004E B115 IN R17, 0x05 \ 00000050 01FD MOVW R31:R30, R27:R26 \ 00000052 8304 STD Z+4, R16 \ 00000054 8315 STD Z+5, R17 130 Next=0x02; \ 00000056 E002 LDI R16, 2 \ 00000058 C078 RJMP ??ADC_ISR_6 131 break; 132 133 134 // MUX = 0b000010 => ADC2 (PA2) = RID 135 case 0x02: 136 ADCS.rawRID = ADC; \ ??ADC_ISR_1: \ 0000005A B104 IN R16, 0x04 \ 0000005C B115 IN R17, 0x05 \ 0000005E 01FD MOVW R31:R30, R27:R26 \ 00000060 8302 STD Z+2, R16 \ 00000062 8313 STD Z+3, R17 137 Next=0x03; \ 00000064 E003 LDI R16, 3 \ 00000066 C071 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: \ 00000068 B124 IN R18, 0x04 \ 0000006A B135 IN R19, 0x05 \ 0000006C E004 LDI R16, 4 \ 0000006E .... RCALL ScaleU \ 00000070 01FD MOVW R31:R30, R27:R26 \ 00000072 8700 STD Z+8, R16 \ 00000074 8711 STD Z+9, R17 145 146 // Is mains failing? 147 if (ADCS.VIN < VIN_MIN) { \ 00000076 3300 CPI R16, 48 \ 00000078 4111 SBCI R17, 17 \ 0000007A 910C LD R16, X \ 0000007C F410 BRCC ??ADC_ISR_7 148 ADCS.Mains = FALSE; \ 0000007E 7B0F ANDI R16, 0xBF \ 00000080 C001 RJMP ??ADC_ISR_8 149 } else { 150 ADCS.Mains = TRUE; \ ??ADC_ISR_7: \ 00000082 6400 ORI R16, 0x40 \ ??ADC_ISR_8: \ 00000084 930C ST X, R16 151 } 152 153 Next=0x05; \ 00000086 E005 LDI R16, 5 \ 00000088 C060 RJMP ??ADC_ISR_6 154 break; 155 156 157 // MUX = 0b000101 => ADC5 (PA6) = VBAT- 158 case 0x05: 159 ADCS.rawVBAT = ADC; \ ??ADC_ISR_3: \ 0000008A B104 IN R16, 0x04 \ 0000008C B115 IN R17, 0x05 \ 0000008E 01FD MOVW R31:R30, R27:R26 \ 00000090 8306 STD Z+6, R16 \ 00000092 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. \ 00000094 B124 IN R18, 0x04 \ 00000096 B135 IN R19, 0x05 \ 00000098 .... LDI R20, LOW(VBAT_RANGE) \ 0000009A .... LDI R21, (VBAT_RANGE) >> 8 \ 0000009C .... RCALL __eeget8_16 \ 0000009E .... RCALL ScaleU \ 000000A0 01FD MOVW R31:R30, R27:R26 \ 000000A2 8702 STD Z+10, R16 \ 000000A4 8713 STD Z+11, R17 163 Next=0x17; \ 000000A6 E107 LDI R16, 23 \ 000000A8 C050 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: \ 000000AA B104 IN R16, 0x04 \ 000000AC B115 IN R17, 0x05 \ 000000AE 3012 CPI R17, 2 \ 000000B0 F0C0 BRCS ??ADC_ISR_9 174 ADCS.IBAT = -(signed int)ScaleI(VBAT_RANGE, 175 (1024 - (ADC-ADCS.ADC5_G20_OS))); \ 000000B2 E000 LDI R16, 0 \ 000000B4 E014 LDI R17, 4 \ 000000B6 B124 IN R18, 0x04 \ 000000B8 B135 IN R19, 0x05 \ 000000BA 1B02 SUB R16, R18 \ 000000BC 0B13 SBC R17, R19 \ 000000BE 01FD MOVW R31:R30, R27:R26 \ 000000C0 8121 LDD R18, Z+1 \ 000000C2 9522 SWAP R18 \ 000000C4 702F ANDI R18, 0x0F \ 000000C6 E030 LDI R19, 0 \ 000000C8 0F20 ADD R18, R16 \ 000000CA 1F31 ADC R19, R17 \ 000000CC .... LDI R20, LOW(VBAT_RANGE) \ 000000CE .... LDI R21, (VBAT_RANGE) >> 8 \ 000000D0 .... RCALL __eeget8_16 \ 000000D2 .... RCALL ScaleI \ 000000D4 9511 NEG R17 \ 000000D6 9501 NEG R16 \ 000000D8 4010 SBCI R17, 0 \ ??ADC_ISR_10: \ 000000DA 01FD MOVW R31:R30, R27:R26 \ 000000DC 8704 STD Z+12, R16 \ 000000DE 8715 STD Z+13, R17 \ 000000E0 C014 RJMP ??ADC_ISR_11 176 } else if (ADC > 0) { \ ??ADC_ISR_9: \ 000000E2 B104 IN R16, 0x04 \ 000000E4 B115 IN R17, 0x05 \ 000000E6 2B01 OR R16, R17 \ 000000E8 F069 BREQ ??ADC_ISR_12 177 ADCS.IBAT = ScaleI(VBAT_RANGE, (ADC-ADCS.ADC5_G20_OS)); \ 000000EA B124 IN R18, 0x04 \ 000000EC B135 IN R19, 0x05 \ 000000EE 01FD MOVW R31:R30, R27:R26 \ 000000F0 8101 LDD R16, Z+1 \ 000000F2 9502 SWAP R16 \ 000000F4 700F ANDI R16, 0x0F \ 000000F6 1B20 SUB R18, R16 \ 000000F8 4030 SBCI R19, 0 \ 000000FA .... LDI R20, LOW(VBAT_RANGE) \ 000000FC .... LDI R21, (VBAT_RANGE) >> 8 \ 000000FE .... RCALL __eeget8_16 \ 00000100 .... RCALL ScaleI \ 00000102 CFEB RJMP ??ADC_ISR_10 178 } else { 179 ADCS.IBAT = 0; \ ??ADC_ISR_12: \ 00000104 01FD MOVW R31:R30, R27:R26 \ 00000106 8784 STD Z+12, R24 \ 00000108 8785 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: \ 0000010A 8524 LDD R18, Z+12 \ 0000010C 8535 LDD R19, Z+13 \ 0000010E 8D00 LDD R16, Z+24 \ 00000110 7003 ANDI R16, 0x03 \ 00000112 0F00 LSL R16 \ 00000114 0FE0 ADD R30, R16 \ 00000116 1FF8 ADC R31, R24 \ 00000118 8726 STD Z+14, R18 \ 0000011A 8737 STD Z+15, R19 \ 0000011C 01FD MOVW R31:R30, R27:R26 \ 0000011E 8D00 LDD R16, Z+24 \ 00000120 9503 INC R16 \ 00000122 8F00 STD Z+24, R16 187 for (i = 0; i < 4 ; i++) { \ 00000124 963E ADIW R31:R30, 14 \ 00000126 E004 LDI R16, 4 188 temp += ADCS.discIBAT[i]; \ ??ADC_ISR_13: \ 00000128 9121 LD R18, Z+ \ 0000012A 9131 LD R19, Z+ \ 0000012C 0F82 ADD R24, R18 \ 0000012E 1F93 ADC R25, R19 189 } \ 00000130 950A DEC R16 \ 00000132 F7D1 BRNE ??ADC_ISR_13 190 191 ADCS.avgIBAT = (temp / 4); \ 00000134 018C MOVW R17:R16, R25:R24 \ 00000136 E044 LDI R20, 4 \ 00000138 E050 LDI R21, 0 \ 0000013A .... RCALL ?SS_DIVMOD_L02 \ 0000013C 01FD MOVW R31:R30, R27:R26 \ 0000013E 8B06 STD Z+22, R16 \ 00000140 8B17 STD Z+23, R17 192 193 ADCS.Flag = TRUE; \ 00000142 910C LD R16, X \ 00000144 6200 ORI R16, 0x20 \ 00000146 930C 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: \ 00000148 E001 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: \ 0000014A 911C LD R17, X \ 0000014C 7E10 ANDI R17, 0xE0 \ 0000014E 710F ANDI R16, 0x1F \ 00000150 2B01 OR R16, R17 \ 00000152 930C ST X, R16 207 ADMUX = (1<` \ ADCS: \ 00000000 DS 24 \ 00000018 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 2E2A MOV R2, R26 \ 00000002 01BC MOVW R23:R22, R25:R24 \ 00000004 2FA0 MOV R26, R16 \ 00000006 01C9 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) { \ 00000008 3003 CPI R16, 3 \ 0000000A 01A9 MOVW R21:R20, R19:R18 \ 0000000C F4A1 BRNE ??ScaleU_0 253 scaled = 29 * data; 254 scaled += (data >> 2); 255 scaled += (data >> 4); \ 0000000E E10D LDI R16, 29 \ 00000010 E010 LDI R17, 0 \ 00000012 .... RCALL ?S_MUL_L02 \ 00000014 9536 LSR R19 \ 00000016 9527 ROR R18 \ 00000018 9536 LSR R19 \ 0000001A 9527 ROR R18 \ 0000001C 0D20 ADD R18, R0 \ 0000001E 1D31 ADC R19, R1 \ 00000020 9596 LSR R25 \ 00000022 9587 ROR R24 \ 00000024 9596 LSR R25 \ 00000026 9587 ROR R24 \ 00000028 9596 LSR R25 \ 0000002A 9587 ROR R24 \ 0000002C 9596 LSR R25 \ 0000002E 9587 ROR R24 \ 00000030 0F82 ADD R24, R18 \ 00000032 1F93 ADC R25, R19 \ 00000034 C014 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: \ 00000036 E207 LDI R16, 39 \ 00000038 E010 LDI R17, 0 \ 0000003A .... RCALL ?S_MUL_L02 \ 0000003C 9596 LSR R25 \ 0000003E 9587 ROR R24 \ 00000040 9596 LSR R25 \ 00000042 9587 ROR R24 \ 00000044 9596 LSR R25 \ 00000046 9587 ROR R24 \ 00000048 9596 LSR R25 \ 0000004A 9587 ROR R24 \ 0000004C 0D80 ADD R24, R0 \ 0000004E 1D91 ADC R25, R1 260 261 if (setting <3) { \ 00000050 30A3 CPI R26, 3 \ 00000052 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)); \ 00000054 018C MOVW R17:R16, R25:R24 \ 00000056 E043 LDI R20, 3 \ 00000058 1B4A SUB R20, R26 \ 0000005A .... RCALL ?US_SHR_L02 \ 0000005C 01C8 MOVW R25:R24, R17:R16 266 } 267 } 268 269 return(scaled); \ ??ScaleU_1: \ 0000005E 018C MOVW R17:R16, R25:R24 \ 00000060 01CB MOVW R25:R24, R23:R22 \ 00000062 2DA2 MOV R26, R2 \ 00000064 9508 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 */ \ In segment CODE, align 2, keep-with-next 297 unsigned int ScaleI(unsigned char setting, unsigned int data) \ ScaleI: 298 { \ 00000000 2E2A MOV R2, R26 \ 00000002 01BC MOVW R23:R22, R25:R24 \ 00000004 2FA0 MOV R26, R16 \ 00000006 01C9 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) { \ 00000008 3003 CPI R16, 3 \ 0000000A 01A9 MOVW R21:R20, R19:R18 \ 0000000C F4A9 BRNE ??ScaleI_0 304 scaled = 21 * data; 305 scaled -= (data >> 4); 306 scaled += (data >> 7); \ 0000000E E105 LDI R16, 21 \ 00000010 E010 LDI R17, 0 \ 00000012 .... RCALL ?S_MUL_L02 \ 00000014 9536 LSR R19 \ 00000016 9527 ROR R18 \ 00000018 9536 LSR R19 \ 0000001A 9527 ROR R18 \ 0000001C 9536 LSR R19 \ 0000001E 9527 ROR R18 \ 00000020 9536 LSR R19 \ 00000022 9527 ROR R18 \ 00000024 1B02 SUB R16, R18 \ 00000026 0B13 SBC R17, R19 \ 00000028 0F88 LSL R24 \ 0000002A 2F89 MOV R24, R25 \ 0000002C 1F88 ROL R24 \ 0000002E E090 LDI R25, 0 \ 00000030 1F99 ROL R25 \ 00000032 0F80 ADD R24, R16 \ 00000034 1F91 ADC R25, R17 \ 00000036 C01A 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: \ 00000038 E10C LDI R16, 28 \ 0000003A E010 LDI R17, 0 \ 0000003C .... RCALL ?S_MUL_L02 \ 0000003E 0198 MOVW R19:R18, R17:R16 \ 00000040 018C MOVW R17:R16, R25:R24 \ 00000042 9516 LSR R17 \ 00000044 9507 ROR R16 \ 00000046 9516 LSR R17 \ 00000048 9507 ROR R16 \ 0000004A 9516 LSR R17 \ 0000004C 9507 ROR R16 \ 0000004E 1B20 SUB R18, R16 \ 00000050 0B31 SBC R19, R17 \ 00000052 018C MOVW R17:R16, R25:R24 \ 00000054 E045 LDI R20, 5 \ 00000056 .... RCALL ?US_SHR_L02 \ 00000058 01C8 MOVW R25:R24, R17:R16 \ 0000005A 0F82 ADD R24, R18 \ 0000005C 1F93 ADC R25, R19 311 312 if (setting <3) { \ 0000005E 30A3 CPI R26, 3 \ 00000060 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)); \ 00000062 018C MOVW R17:R16, R25:R24 \ 00000064 E043 LDI R20, 3 \ 00000066 1B4A SUB R20, R26 \ 00000068 .... RCALL ?US_SHR_L02 \ 0000006A 01C8 MOVW R25:R24, R17:R16 317 } 318 } 319 320 return(scaled); \ ??ScaleI_1: \ 0000006C 018C MOVW R17:R16, R25:R24 \ 0000006E 01CB MOVW R25:R24, R23:R22 \ 00000070 2DA2 MOV R26, R2 \ 00000072 9508 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 */ \ In segment CODE, align 2, keep-with-next 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); \ 00000000 CFFF 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 */ \ In segment CODE, align 2, keep-with-next 369 void ADC_Init(void) \ ADC_Init: 370 { 371 unsigned char i; 372 373 __disable_interrupt(); \ 00000000 94F8 CLI 374 375 ADCS.Halt = FALSE; // Enable consecutive runs of ADC. \ 00000002 .... LDI R30, LOW(ADCS) \ 00000004 .... LDI R31, (ADCS) >> 8 \ 00000006 8100 LD R16, Z \ 00000008 770F ANDI R16, 0x7F \ 0000000A 8300 ST Z, R16 376 377 // Configure ADC pins (inputs and disabled pull-ups). 378 DDRA &= ~((1< ScaleU 19 2 -> ScaleU 19 2 -> ScaleI 19 2 -> ScaleI 19 2 ADC_Init 0 2 ADC_Wait 0 2 ScaleI 3 4 ScaleU 3 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 VBAT_RANGE 1 ADC_ISR 404 ADCS 25 ScaleU 102 ScaleI 116 ??ADC_Wait_0 2 ADC_Init 122 ??ADC_ISR??INTVEC 22 2 Others 6 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