############################################################################### # # # IAR Atmel AVR C/C++ Compiler V4.30F/W32 13/Mar/2008 04:52:02 # # Copyright 1996-2007 IAR Systems. All rights reserved. # # # # Source file = C:\home\kevin\pub\src\bc100\IAR\battery.c # # Command line = C:\home\kevin\pub\src\bc100\IAR\battery.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\ba # # ttery.lst # # Object file = C:\home\kevin\pub\src\bc100\IAR\Release\Obj\bat # # tery.r90 # # # # # ############################################################################### C:\home\kevin\pub\src\bc100\IAR\battery.c 1 /* This file has been prepared for Doxygen automatic documentation generation.*/ 2 /*! \file ********************************************************************* 3 * 4 * \brief 5 * Functions related to battery control and data acquisition. 6 * 7 * Contains functions for enabling/disabling batteries, and looking up 8 * their status and specifications using the ADC. 9 * 10 * \par Application note: 11 * AVR458: Charging Li-Ion Batteries with BC100 \n 12 * AVR463: Charging NiMH Batteries with BC100 13 14 * 15 * \par Documentation 16 * For comprehensive code documentation, supported compilers, compiler 17 * settings and supported devices see readme.html 18 * 19 * \author 20 * Atmel Corporation: http://www.atmel.com \n 21 * Support email: avr@atmel.com 22 * 23 * 24 * $Name$ 25 * $Revision: 2299 $ 26 * $RCSfile$ 27 * $URL: http://svn.norway.atmel.com/AppsAVR8/avr458_Charging_Li-Ion_Batteries_with_BC100/tag/20070904_release_1.0/code/IAR/battery.c $ 28 * $Date: 2007-08-23 12:55:51 +0200 (to, 23 aug 2007) $\n 29 ******************************************************************************/ 30 31 #include \ In segment ABSOLUTE, at 0x4c \ volatile __io _A_OCR1B \ _A_OCR1B: \ 00000000 DS 1 \ In segment ABSOLUTE, at 0x38 \ volatile __io _A_PORTB \ _A_PORTB: \ 00000000 DS 1 32 #include 33 34 #include "structs.h" 35 #include "enums.h" 36 37 #include "ADC.h" 38 #include "battery.h" 39 #include "main.h" 40 #include "OWI.h" 41 #include "time.h" 42 43 #ifdef NIMH 44 #include "NIMHspecs.h" 45 #endif // NIMH 46 47 #ifdef LIION 48 #include "LIIONspecs.h" 49 #endif // LIION 50 51 52 53 //****************************************************************************** 54 // Variables 55 //****************************************************************************** 56 /* Control-struct for batteries */ 57 /*! \brief Holds control data for both batteries 58 * \note Stored in EEPROM. 59 */ \ In segment EEPROM_I, align 1, keep-with-next 60 __eeprom Battery_t BattControl[2] = {{TRUE, TRUE, FALSE}, \ BattControl: \ 00000000 0303 DB 3, 3 61 {TRUE, TRUE, FALSE}}; 62 63 /* Data-struct for battery */ \ In segment NEAR_Z, align 1, keep-with-next \ 00000000 REQUIRE `?` 64 Batteries_t BattData; //!< Holds data for the current battery \ BattData: \ 00000000 DS 12 65 66 67 /* Storage for battery EPROM */ 68 /*! \brief Storage space for data from the batteries' own EPROMs. 69 * \note Stored in EEPROM. 70 */ \ In segment EEPROM_I, align 1, keep-with-next 71 __eeprom unsigned char BattEEPROM[4][32]; \ BattEEPROM: \ 00000000 000000000000 DB 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 \ 000000000000 \ 00000000 \ 00000010 000000000000 DB 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 \ 000000000000 \ 00000000 \ 00000020 000000000000 DB 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 \ 000000000000 \ 00000000 \ 00000030 000000000000 DB 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 \ 000000000000 \ 00000000 \ 00000040 000000000000 DB 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 \ 000000000000 \ 00000000 \ 00000050 000000000000 DB 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 \ 000000000000 \ 00000000 \ 00000060 000000000000 DB 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 \ 000000000000 \ 00000000 \ 00000070 000000000000 DB 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 \ 000000000000 \ 00000000 72 73 74 //! Global that indicates current battery (0 = battery A, 1 = B) \ In segment NEAR_Z, align 1, keep-with-next \ 00000000 REQUIRE `?` 75 unsigned char BattActive; \ BattActive: \ 00000000 DS 1 76 77 78 /*! \brief RID lookup-table 79 * 80 * Contains Resistor ID data specified by manufacturer. 81 * 82 * \note Values have been calculated assuming a +/- 15% tolerance. 83 */ \ In segment NEAR_I, align 1, keep-with-next \ 00000000 REQUIRE `?` 84 const RID_Lookup_t RID[RID_TABLE_SIZE] = { \ RID: \ 00000000 DS 56 \ 00000038 REQUIRE `?` 85 {558, 659, 3900, 550, 260, 300, 10}, 86 {744, 843, 6800, 750, 360, 300, 14}, 87 {869, 958, 10000, 1000, 475, 300, 19}, 88 {1097, 1153, 24000, 2000, 475, 420, 38} 89 }; 90 91 92 /*! \brief NTC lookup-table 93 * 94 * The first entry is 0 degrees. For every entry after, temperature increases 95 * with 4 degrees. With 20 entries, the last one equals (20-1)*4 = 76 degrees.\n 96 * It must be sorted in descending ADC order. 97 * 98 * \note This was calculated for a Mitsubishi RH16-3H103FB NTC. 99 * 100 * \note NTCLookUp() must be modified if this table is changed so that: 101 * - first entry is no longer 0 degrees. 102 * - temperature difference between entries is no longer 4 degrees. 103 * - ADCsteps no longer specifies ADC steps per half degree. 104 */ 105 // FOR VARTA POLYFLEX NTC \ In segment NEAR_I, align 1, keep-with-next \ 00000000 REQUIRE `?` 106 const NTC_Lookup_t NTC[NTC_TABLE_SIZE] = { \ NTC: \ 00000000 DS 60 \ 0000003C REQUIRE `?` 107 {1002, 23}, {953, 25}, {902, 26}, {849, 27}, {796, 27}, 108 {742, 27}, {689, 26}, {637, 26}, {587, 25}, {539, 24}, 109 {494, 22}, {451, 21}, {412, 19}, {375, 18}, {341, 17}, 110 {310, 15}, {282, 14}, {256, 13}, {233, 11}, {212, 10} 111 }; 112 113 114 // FOR MITSUBISHI NTC 115 /* 116 const NTC_Lookup_t NTC[NTC_TABLE_SIZE] = { 117 {1004, 24}, {954, 25}, {903, 26}, {850, 27}, {796, 27}, 118 {742, 27}, {689, 27}, {637, 26}, {587, 25}, {539, 24}, 119 {493, 22}, {451, 21}, {411, 20}, {374, 18}, {340, 17}, 120 {309, 15}, {281, 14}, {255, 13}, {232, 11}, {211, 10} 121 }; 122 */ 123 124 125 //****************************************************************************** 126 // Functions 127 //****************************************************************************** 128 /*! \brief Checks if battery has changed 129 * 130 * Stores current capacity, then attempts to refresh battery status.\n 131 * If the refresh is successful, old capacity is compared with the new one. 132 * 133 * \retval FALSE Battery is disconnected, or capacity has changed. 134 * \retval TRUE All OK. 135 */ \ In segment CODE, align 2, keep-with-next 136 unsigned char BatteryCheck(void) \ BatteryCheck: 137 { \ 00000000 93BA ST -Y, R27 \ 00000002 93AA ST -Y, R26 \ 00000004 938A ST -Y, R24 138 unsigned char success = TRUE; \ 00000006 E081 LDI R24, 1 139 unsigned int oldCapacity; 140 141 // Save to see if battery data has changed. 142 oldCapacity = BattData.Capacity; \ 00000008 .... LDI R30, LOW(BattData) \ 0000000A .... LDI R31, (BattData) >> 8 \ 0000000C 81A4 LDD R26, Z+4 \ 0000000E 81B5 LDD R27, Z+5 143 144 if (!BatteryStatusRefresh()) { \ 00000010 .... RCALL BatteryStatusRefresh \ 00000012 2300 TST R16 \ 00000014 F409 BRNE ??BatteryCheck_0 145 success = FALSE; // Battery not present or RID was invalid. \ 00000016 E080 LDI R24, 0 146 } 147 148 if (oldCapacity != BattData.Capacity) { \ ??BatteryCheck_0: \ 00000018 .... LDI R30, LOW(BattData) \ 0000001A .... LDI R31, (BattData) >> 8 \ 0000001C 8104 LDD R16, Z+4 \ 0000001E 8115 LDD R17, Z+5 \ 00000020 17A0 CP R26, R16 \ 00000022 07B1 CPC R27, R17 \ 00000024 F009 BREQ ??BatteryCheck_1 149 success = FALSE; // Battery configuration has changed. \ 00000026 E080 LDI R24, 0 150 } 151 152 return(success); \ ??BatteryCheck_1: \ 00000028 2F08 MOV R16, R24 \ 0000002A 9189 LD R24, Y+ \ 0000002C 91A9 LD R26, Y+ \ 0000002E 91B9 LD R27, Y+ \ 00000030 9508 RET 153 } 154 155 156 /*! \brief Refreshes battery status information 157 * 158 * Refreshes battery status information, if it is present, based on 159 * RID and NTC (read by ADC).\n 160 * The battery must have been enabled and a complete set of ADC data must have 161 * been collected before calling.\n 162 * 163 * \retval FALSE No battery present. 164 * \retval TRUE Battery present, status refreshed. 165 * 166 * \note If ALLOW_NO_RID is defined, charging will NOT stop if no fitting entry 167 * is found in the lookup table. Instead, default battery data will be used. 168 */ \ In segment CODE, align 2, keep-with-next 169 unsigned char BatteryStatusRefresh(void) \ BatteryStatusRefresh: 170 { \ 00000000 93BA ST -Y, R27 \ 00000002 93AA ST -Y, R26 \ 00000004 939A ST -Y, R25 \ 00000006 938A ST -Y, R24 171 // Assume the worst.. 172 unsigned char success = FALSE; 173 174 BattData.Present = FALSE; 175 BattData.Charged = FALSE; 176 BattData.Low = TRUE; \ 00000008 .... LDI R26, LOW(BattData) \ 0000000A .... LDI R27, (BattData) >> 8 \ 0000000C 910C LD R16, X \ 0000000E 7F0C ANDI R16, 0xFC \ 00000010 6004 ORI R16, 0x04 \ 00000012 930C ST X, R16 177 BattData.Circuit = OW_NONE; \ 00000014 E000 LDI R16, 0 \ 00000016 01FD MOVW R31:R30, R27:R26 \ 00000018 8301 STD Z+1, R16 178 BattData.Temperature = 0; \ 0000001A 8302 STD Z+2, R16 179 BattData.Capacity = 0; \ 0000001C 8304 STD Z+4, R16 \ 0000001E 8305 STD Z+5, R16 180 BattData.MaxCurrent = 0; \ 00000020 8306 STD Z+6, R16 \ 00000022 8307 STD Z+7, R16 181 BattData.MaxTime = 0; \ 00000024 8700 STD Z+8, R16 \ 00000026 8701 STD Z+9, R16 182 BattData.MinCurrent = 0; \ 00000028 8702 STD Z+10, R16 \ 0000002A 8703 STD Z+11, R16 183 184 NTCLookUp(); \ 0000002C .... RCALL NTCLookUp 185 BattData.HasRID = RIDLookUp(); \ 0000002E .... RCALL RIDLookUp \ 00000030 2F10 MOV R17, R16 \ 00000032 7011 ANDI R17, 0x01 \ 00000034 FB10 BST R17, 0 \ 00000036 910C LD R16, X \ 00000038 F904 BLD R16, 4 \ 0000003A 930C ST X, R16 186 187 // Is the battery voltage above minimum safe cell voltage? 188 if (ADCS.VBAT >= BAT_VOLTAGE_MIN) { \ 0000003C .... LDI R30, LOW(ADCS) \ 0000003E .... LDI R31, (ADCS) >> 8 \ 00000040 8502 LDD R16, Z+10 \ 00000042 8513 LDD R17, Z+11 \ 00000044 3600 CPI R16, 96 \ 00000046 E029 LDI R18, 9 \ 00000048 0712 CPC R17, R18 \ 0000004A F018 BRCS ??BatteryStatusRefresh_0 189 BattData.Low = FALSE; \ 0000004C 910C LD R16, X \ 0000004E 7F0B ANDI R16, 0xFB \ 00000050 930C ST X, R16 190 } 191 192 // Is the battery charged? 193 if (ADCS.VBAT >= BAT_VOLTAGE_LOW) { \ ??BatteryStatusRefresh_0: \ 00000052 8502 LDD R16, Z+10 \ 00000054 3D02 CPI R16, 210 \ 00000056 401F SBCI R17, 15 \ 00000058 F018 BRCS ??BatteryStatusRefresh_1 194 BattData.Charged = TRUE; \ 0000005A 910C LD R16, X \ 0000005C 6002 ORI R16, 0x02 \ 0000005E 930C ST X, R16 195 } 196 197 // If we are not charging, yet VBAT is above safe limit, battery is present. 198 // If we are charging and there's a current flowing, the battery is present. 199 200 /*! \todo If ABORT_IF_PWM_MAX is defined this last check battery presence 201 * check is redundant since charging will be aborted due to low current at 202 * max duty cycle. That is preferrable since the charge current reading is 203 * not 100% proof. 204 */ 205 if (((OCR1B == 0) && (!BattData.Low)) || 206 ((OCR1B != 0) && (ADCS.avgIBAT > 0))) { \ ??BatteryStatusRefresh_1: \ 00000060 B50C IN R16, 0x2C \ 00000062 2300 TST R16 \ 00000064 F419 BRNE ??BatteryStatusRefresh_2 \ 00000066 910C LD R16, X \ 00000068 FF02 SBRS R16, 2 \ 0000006A C008 RJMP ??BatteryStatusRefresh_3 \ ??BatteryStatusRefresh_2: \ 0000006C B50C IN R16, 0x2C \ 0000006E 2300 TST R16 \ 00000070 F051 BREQ ??BatteryStatusRefresh_4 \ 00000072 8986 LDD R24, Z+22 \ 00000074 8997 LDD R25, Z+23 \ 00000076 3081 CPI R24, 1 \ 00000078 4090 SBCI R25, 0 \ 0000007A F02C BRLT ??BatteryStatusRefresh_4 207 BattData.Present = TRUE; \ ??BatteryStatusRefresh_3: \ 0000007C 910C LD R16, X \ 0000007E 6001 ORI R16, 0x01 \ 00000080 930C ST X, R16 208 success = TRUE; \ 00000082 E001 LDI R16, 1 \ 00000084 C004 RJMP ??BatteryStatusRefresh_5 209 } else { 210 BattData.Low = FALSE; // (This is just a technicality..) \ ??BatteryStatusRefresh_4: \ 00000086 910C LD R16, X \ 00000088 7F0B ANDI R16, 0xFB \ 0000008A 930C ST X, R16 211 success = FALSE; \ 0000008C E000 LDI R16, 0 212 } 213 214 #ifndef ALLOW_NO_RID 215 // Return FALSE if no valid RID entry was found, to stop charging. 216 if(!BattData.HasRID) { \ ??BatteryStatusRefresh_5: \ 0000008E 911C LD R17, X \ 00000090 FF14 SBRS R17, 4 217 success = FALSE; \ 00000092 E000 LDI R16, 0 218 } 219 #endif 220 221 return(success); \ ??BatteryStatusRefresh_6: \ 00000094 9189 LD R24, Y+ \ 00000096 9199 LD R25, Y+ \ 00000098 91A9 LD R26, Y+ \ 0000009A 91B9 LD R27, Y+ \ 0000009C 9508 RET \ 0000009E REQUIRE _A_OCR1B 222 } 223 224 225 /*! \brief Refreshes battery data in the EEPROM 226 * 227 * Attempts to read 4 pages of 32 bytes each from the battery's EPROM and store 228 * these data in on-chip EEPROM.\n 229 * If unsuccessful (CRC doesn't check out), the on-chip EEPROM is cleared. 230 * 231 * \todo Updating BattData with these data. Specs needed. 232 * 233 * \retval FALSE Refresh failed. 234 * \retval TRUE Refresh successful. 235 */ \ In segment CODE, align 2, keep-with-next 236 unsigned char BatteryDataRefresh(void) \ BatteryDataRefresh: 237 { \ 00000000 928A ST -Y, R8 \ 00000002 927A ST -Y, R7 \ 00000004 926A ST -Y, R6 \ 00000006 925A ST -Y, R5 \ 00000008 924A ST -Y, R4 \ 0000000A 93BA ST -Y, R27 \ 0000000C 93AA ST -Y, R26 \ 0000000E 939A ST -Y, R25 \ 00000010 938A ST -Y, R24 \ 00000012 REQUIRE ?Register_R4_is_cg_reg \ 00000012 REQUIRE ?Register_R5_is_cg_reg \ 00000012 REQUIRE ?Register_R6_is_cg_reg \ 00000012 REQUIRE ?Register_R7_is_cg_reg \ 00000012 REQUIRE ?Register_R8_is_cg_reg 238 unsigned char offset; 239 unsigned char i, crc, family, temp, page; 240 unsigned char success; 241 242 // Look for EPROM and read 4 pages of 32 bytes each worth of data, if found. 243 for (page = 0; page < 4; page++) { \ 00000012 E090 LDI R25, 0 \ 00000014 .... LDI R26, LOW(BattEEPROM) \ 00000016 .... LDI R27, (BattEEPROM) >> 8 244 success = FALSE; \ ??BatteryDataRefresh_0: \ 00000018 2477 CLR R7 245 246 if (OWI_DetectPresence(OWIBUS) == OWIBUS) { \ 0000001A E001 LDI R16, 1 \ 0000001C .... RCALL OWI_DetectPresence \ 0000001E 3001 CPI R16, 1 \ 00000020 F009 BREQ $+2+2 \ 00000022 C055 RJMP ??BatteryDataRefresh_1 247 248 // Presence detected, check type and CRC. 249 OWI_SendByte(OWI_ROM_READ, OWIBUS); \ 00000024 E011 LDI R17, 1 \ 00000026 E303 LDI R16, 51 \ 00000028 .... RCALL OWI_SendByte 250 family = OWI_ReceiveByte(OWIBUS); \ 0000002A E001 LDI R16, 1 \ 0000002C .... RCALL OWI_ReceiveByte \ 0000002E 2E50 MOV R5, R16 251 crc = OWI_ComputeCRC8(family,0); \ 00000030 E010 LDI R17, 0 \ 00000032 .... RCALL OWI_ComputeCRC8 \ 00000034 2F80 MOV R24, R16 252 253 for (i = 0; i < 6; i++) { \ 00000036 E006 LDI R16, 6 \ 00000038 2E40 MOV R4, R16 254 crc = OWI_ComputeCRC8(OWI_ReceiveByte(OWIBUS),crc); \ ??BatteryDataRefresh_2: \ 0000003A E001 LDI R16, 1 \ 0000003C .... RCALL OWI_ReceiveByte \ 0000003E 2F18 MOV R17, R24 \ 00000040 .... RCALL OWI_ComputeCRC8 \ 00000042 2F80 MOV R24, R16 255 } \ 00000044 944A DEC R4 \ 00000046 F7C9 BRNE ??BatteryDataRefresh_2 256 257 // CRC ok, device found. 258 if (OWI_ComputeCRC8(OWI_ReceiveByte(OWIBUS),crc) == 0) { \ 00000048 E001 LDI R16, 1 \ 0000004A .... RCALL OWI_ReceiveByte \ 0000004C 2F18 MOV R17, R24 \ 0000004E .... RCALL OWI_ComputeCRC8 \ 00000050 2300 TST R16 \ 00000052 F5E9 BRNE ??BatteryDataRefresh_1 259 BattData.Circuit = family; \ 00000054 9250.... STS (BattData + 1), R5 260 261 // For now, we only read data from DS2505 EPROMs. 262 if (BattData.Circuit == OW_DS2505) { \ 00000058 9100.... LDS R16, (BattData + 1) \ 0000005C 3009 CPI R16, 9 \ 0000005E F5B9 BRNE ??BatteryDataRefresh_1 263 offset = page*32; \ 00000060 2E49 MOV R4, R25 \ 00000062 9442 SWAP R4 \ 00000064 EF00 LDI R16, 240 \ 00000066 2240 AND R4, R16 \ 00000068 0C44 LSL R4 264 OWI_SendByte(DS2505_DATA_READ, OWIBUS); // Command: read data. \ 0000006A E011 LDI R17, 1 \ 0000006C EC03 LDI R16, 195 \ 0000006E .... RCALL OWI_SendByte 265 OWI_SendByte(offset, OWIBUS); // Data: low address. \ 00000070 E011 LDI R17, 1 \ 00000072 2D04 MOV R16, R4 \ 00000074 .... RCALL OWI_SendByte 266 OWI_SendByte(0, OWIBUS); // Data: high address. \ 00000076 E011 LDI R17, 1 \ 00000078 E000 LDI R16, 0 \ 0000007A .... RCALL OWI_SendByte 267 268 // Calculate checksums. 269 crc = OWI_ComputeCRC8(DS2505_DATA_READ,0); \ 0000007C E010 LDI R17, 0 \ 0000007E EC03 LDI R16, 195 \ 00000080 .... RCALL OWI_ComputeCRC8 270 crc = OWI_ComputeCRC8(offset,crc); \ 00000082 2F10 MOV R17, R16 \ 00000084 2D04 MOV R16, R4 \ 00000086 .... RCALL OWI_ComputeCRC8 271 crc = OWI_ComputeCRC8(0,crc); \ 00000088 2F10 MOV R17, R16 \ 0000008A E000 LDI R16, 0 \ 0000008C .... RCALL OWI_ComputeCRC8 \ 0000008E 2F80 MOV R24, R16 272 273 // Command received succesfully, now start reading data 274 // and writing it to EEPROM. 275 if (OWI_ComputeCRC8(OWI_ReceiveByte(OWIBUS),crc) == 0) { \ 00000090 E001 LDI R16, 1 \ 00000092 .... RCALL OWI_ReceiveByte \ 00000094 2F18 MOV R17, R24 \ 00000096 .... RCALL OWI_ComputeCRC8 \ 00000098 2300 TST R16 \ 0000009A F4C9 BRNE ??BatteryDataRefresh_1 276 crc = 0; \ 0000009C E080 LDI R24, 0 277 278 // Fill page with data. 279 for (i=0; i<32; i++) { \ 0000009E 012D MOVW R5:R4, R27:R26 \ 000000A0 E200 LDI R16, 32 \ 000000A2 2E60 MOV R6, R16 280 temp = OWI_ReceiveByte(OWIBUS); \ ??BatteryDataRefresh_3: \ 000000A4 E001 LDI R16, 1 \ 000000A6 .... RCALL OWI_ReceiveByte \ 000000A8 2E80 MOV R8, R16 281 crc = OWI_ComputeCRC8(temp, crc); \ 000000AA 2F18 MOV R17, R24 \ 000000AC .... RCALL OWI_ComputeCRC8 \ 000000AE 2F80 MOV R24, R16 282 BattEEPROM[page][i] = temp; \ 000000B0 2D08 MOV R16, R8 \ 000000B2 01A2 MOVW R21:R20, R5:R4 \ 000000B4 .... RCALL __eeput8_16 283 } \ 000000B6 E001 LDI R16, 1 \ 000000B8 0E40 ADD R4, R16 \ 000000BA 1C57 ADC R5, R7 \ 000000BC 946A DEC R6 \ 000000BE F791 BRNE ??BatteryDataRefresh_3 284 285 if (OWI_ComputeCRC8(OWI_ReceiveByte(OWIBUS),crc) == 0) { \ 000000C0 .... RCALL OWI_ReceiveByte \ 000000C2 2F18 MOV R17, R24 \ 000000C4 .... RCALL OWI_ComputeCRC8 \ 000000C6 2300 TST R16 \ 000000C8 F411 BRNE ??BatteryDataRefresh_1 286 success = TRUE; // Data read OK \ 000000CA 9473 INC R7 \ 000000CC C008 RJMP ??BatteryDataRefresh_4 287 } 288 } else { // Not able to start reading data. 289 } 290 } else { // Wrong device type. 291 } 292 } else { // No device found. 293 } 294 } else { // No presence detected on one-wire bus. 295 } 296 297 // Erase local EEPROM page if there were any errors during transfer. 298 if (!success) { 299 for (i=0; i<32; i++) { \ ??BatteryDataRefresh_1: \ 000000CE 01AD MOVW R21:R20, R27:R26 \ 000000D0 E210 LDI R17, 32 300 BattEEPROM[page][i] = 0; \ ??BatteryDataRefresh_5: \ 000000D2 E000 LDI R16, 0 \ 000000D4 .... RCALL __eeput8_16 301 } \ 000000D6 5F4F SUBI R20, 255 \ 000000D8 4F5F SBCI R21, 255 \ 000000DA 951A DEC R17 \ 000000DC F7D1 BRNE ??BatteryDataRefresh_5 302 } 303 } \ ??BatteryDataRefresh_4: \ 000000DE 9593 INC R25 \ 000000E0 9690 ADIW R27:R26, 32 \ 000000E2 3094 CPI R25, 4 \ 000000E4 F408 BRCC $+2+2 \ 000000E6 CF98 RJMP ??BatteryDataRefresh_0 304 305 return(success); \ 000000E8 2D07 MOV R16, R7 \ 000000EA 9189 LD R24, Y+ \ 000000EC 9199 LD R25, Y+ \ 000000EE 91A9 LD R26, Y+ \ 000000F0 91B9 LD R27, Y+ \ 000000F2 9049 LD R4, Y+ \ 000000F4 9059 LD R5, Y+ \ 000000F6 9069 LD R6, Y+ \ 000000F8 9079 LD R7, Y+ \ 000000FA 9089 LD R8, Y+ \ 000000FC 9508 RET 306 } 307 308 309 /*! \brief Enables specified battery 310 * 311 * Updates \ref BattActive to specified battery, then sets PB4/PB5 and clears 312 * PB5/PB4 in PORTB, depending on which battery is specified.\n 313 * The function takes 100 ms to allow the port switch to settle. 314 * 315 * \param bat Specifies which battery to enable (0 = battery A, 1 = B) 316 */ \ In segment CODE, align 2, keep-with-next 317 void EnableBattery(unsigned char bat) \ EnableBattery: 318 { \ 00000000 938A ST -Y, R24 \ 00000002 2F80 MOV R24, R16 319 // Use general timer, set timeout to 100ms. 320 Time_Set(TIMER_GEN,0,0,100); \ 00000004 E644 LDI R20, 100 \ 00000006 E010 LDI R17, 0 \ 00000008 E020 LDI R18, 0 \ 0000000A E030 LDI R19, 0 \ 0000000C E002 LDI R16, 2 \ 0000000E .... RCALL Time_Set 321 322 // Set specified battery as the active one. 323 BattActive = bat; \ 00000010 9380.... STS BattActive, R24 324 325 // Enable current battery in hardware, light LED & connect battery. 326 PORTB |= (1 << (PB4+bat)); \ 00000014 E001 LDI R16, 1 \ 00000016 E010 LDI R17, 0 \ 00000018 2F48 MOV R20, R24 \ 0000001A 5F4C SUBI R20, 252 \ 0000001C .... RCALL ?S_SHL_L02 \ 0000001E B318 IN R17, 0x18 \ 00000020 2B10 OR R17, R16 \ 00000022 BB18 OUT 0x18, R17 327 328 // Disconnect other battery. 329 PORTB &= ~(1<<(PB5-bat)); \ 00000024 E001 LDI R16, 1 \ 00000026 E010 LDI R17, 0 \ 00000028 E045 LDI R20, 5 \ 0000002A 1B48 SUB R20, R24 \ 0000002C .... RCALL ?S_SHL_L02 \ 0000002E 9500 COM R16 \ 00000030 B318 IN R17, 0x18 \ 00000032 2310 AND R17, R16 \ 00000034 BB18 OUT 0x18, R17 330 331 do { // Let port switch settle. 332 } while (Time_Left(TIMER_GEN)); \ ??EnableBattery_0: \ 00000036 E002 LDI R16, 2 \ 00000038 .... RCALL Time_Left \ 0000003A 2300 TST R16 \ 0000003C F7E1 BRNE ??EnableBattery_0 333 } \ 0000003E 9189 LD R24, Y+ \ 00000040 9508 RET \ 00000042 REQUIRE _A_PORTB 334 335 336 /*! \brief Disables both batteries 337 * 338 * Clears PB4 and PB5 in PORTB, disabling both batteries. 339 */ \ In segment CODE, align 2, keep-with-next 340 void DisableBatteries(void) \ DisableBatteries: 341 { 342 // Turn off LEDs and disconnect batteries. 343 PORTB &= ~((1<> 8 \ 0000000A E024 LDI R18, 4 \ 0000000C .... LDI R16, LOW(BattData) \ 0000000E .... LDI R17, (BattData) >> 8 363 if (ADCS.rawRID >= RID[i].Low) { \ ??RIDLookUp_0: \ 00000010 .... LDI R26, LOW((ADCS + 2)) \ 00000012 .... LDI R27, HIGH((ADCS + 2)) \ 00000014 916D LD R22, X+ \ 00000016 917C LD R23, X \ 00000018 8000 LD R0, Z \ 0000001A 8011 LDD R1, Z+1 \ 0000001C 1560 CP R22, R0 \ 0000001E 0571 CPC R23, R1 \ 00000020 F0F0 BRCS ??RIDLookUp_1 364 if (ADCS.rawRID <= RID[i].High) { \ 00000022 8002 LDD R0, Z+2 \ 00000024 8013 LDD R1, Z+3 \ 00000026 1606 CP R0, R22 \ 00000028 0617 CPC R1, R23 \ 0000002A F0C8 BRCS ??RIDLookUp_1 365 BattData.Capacity = RID[i].Capacity; \ 0000002C 8146 LDD R20, Z+6 \ 0000002E 8157 LDD R21, Z+7 \ 00000030 01D8 MOVW R27:R26, R17:R16 \ 00000032 9614 ADIW R27:R26, 4 \ 00000034 934D ST X+, R20 \ 00000036 935C ST X, R21 366 BattData.MaxCurrent = RID[i].Icharge; \ 00000038 8540 LDD R20, Z+8 \ 0000003A 8551 LDD R21, Z+9 \ 0000003C 01D8 MOVW R27:R26, R17:R16 \ 0000003E 9616 ADIW R27:R26, 6 \ 00000040 934D ST X+, R20 \ 00000042 935C ST X, R21 367 BattData.MaxTime = RID[i].tCutOff; \ 00000044 8542 LDD R20, Z+10 \ 00000046 8553 LDD R21, Z+11 \ 00000048 01D8 MOVW R27:R26, R17:R16 \ 0000004A 9618 ADIW R27:R26, 8 \ 0000004C 934D ST X+, R20 \ 0000004E 935C ST X, R21 368 BattData.MinCurrent = RID[i].ICutOff; \ 00000050 8544 LDD R20, Z+12 \ 00000052 8555 LDD R21, Z+13 \ 00000054 01D8 MOVW R27:R26, R17:R16 \ 00000056 961A ADIW R27:R26, 10 \ 00000058 934D ST X+, R20 \ 0000005A 935C ST X, R21 369 370 found = TRUE; \ 0000005C E041 LDI R20, 1 371 } 372 } 373 } \ ??RIDLookUp_1: \ 0000005E 963E ADIW R31:R30, 14 \ 00000060 952A DEC R18 \ 00000062 F6B1 BRNE ??RIDLookUp_0 374 375 // If no valid entry is found, use defaults and return FALSE. 376 if (!found) { \ 00000064 2344 TST R20 \ 00000066 F451 BRNE ??RIDLookUp_2 377 BattData.Capacity = DEF_BAT_CAPACITY; \ 00000068 E020 LDI R18, 0 \ 0000006A 01F8 MOVW R31:R30, R17:R16 \ 0000006C 8324 STD Z+4, R18 \ 0000006E 8325 STD Z+5, R18 378 BattData.MaxCurrent = DEF_BAT_CURRENT_MAX; \ 00000070 8326 STD Z+6, R18 \ 00000072 8327 STD Z+7, R18 379 BattData.MaxTime = DEF_BAT_TIME_MAX; \ 00000074 8720 STD Z+8, R18 \ 00000076 8721 STD Z+9, R18 380 BattData.MinCurrent = DEF_BAT_CURRENT_MIN; \ 00000078 8722 STD Z+10, R18 \ 0000007A 8723 STD Z+11, R18 381 } 382 383 return(found); \ ??RIDLookUp_2: \ 0000007C 2F04 MOV R16, R20 \ 0000007E 2DA2 MOV R26, R2 \ 00000080 2FB3 MOV R27, R19 \ 00000082 9508 RET 384 } 385 386 387 /*! \brief Calculates temperature from a lookup table 388 * 389 * Looks up the highest NTC value below or equal to the measured one.\n 390 * With the current lookup table, temperature is calculated with the formula:\n 391 * 4*(index of entry) - 2*(measured NTC - NTC from entry) / (ADCsteps of entry) 392 * 393 * \note If the NTC-measurement is saturated, with the current lookup table, 394 * the temperature will be reported as -1 C. 395 * 396 * \note If no valid entry is found, battery temperature is set to 80. 397 */ \ In segment CODE, align 2, keep-with-next 398 void NTCLookUp (void) \ NTCLookUp: 399 { \ 00000000 93BA ST -Y, R27 \ 00000002 2E3A MOV R3, R26 \ 00000004 2E28 MOV R2, R24 400 unsigned char i; 401 unsigned char found = FALSE; \ 00000006 E000 LDI R16, 0 402 403 // Lookup in the NTC-table. Use the first entry which is equal or below 404 // sampled NTC. Calculate temperature by using the index number, and the 405 // difference between the measured NTC value and the one in the entry. 406 for (i=0 ; (i < NTC_TABLE_SIZE) && (!found); i++) { \ 00000008 E080 LDI R24, 0 \ 0000000A .... LDI R26, LOW(BattData) \ 0000000C .... LDI R27, (BattData) >> 8 407 if (ADCS.rawNTC >= NTC[i].ADC) { \ ??NTCLookUp_0: \ 0000000E 2F48 MOV R20, R24 \ 00000010 E050 LDI R21, 0 \ 00000012 019A MOVW R19:R18, R21:R20 \ 00000014 0F44 LSL R20 \ 00000016 1F55 ROL R21 \ 00000018 0F42 ADD R20, R18 \ 0000001A 1F53 ADC R21, R19 \ 0000001C .... LDI R18, LOW(NTC) \ 0000001E .... LDI R19, (NTC) >> 8 \ 00000020 0F24 ADD R18, R20 \ 00000022 1F35 ADC R19, R21 \ 00000024 .... LDI R30, LOW(ADCS) \ 00000026 .... LDI R31, (ADCS) >> 8 \ 00000028 8144 LDD R20, Z+4 \ 0000002A 8155 LDD R21, Z+5 \ 0000002C 01F9 MOVW R31:R30, R19:R18 \ 0000002E 8160 LD R22, Z \ 00000030 8171 LDD R23, Z+1 \ 00000032 1746 CP R20, R22 \ 00000034 0757 CPC R21, R23 \ 00000036 F0D0 BRCS ??NTCLookUp_1 408 BattData.Temperature = (i<<2) ; \ 00000038 2F08 MOV R16, R24 \ 0000003A 0F00 LSL R16 \ 0000003C 0F00 LSL R16 \ 0000003E 01FD MOVW R31:R30, R27:R26 \ 00000040 8302 STD Z+2, R16 409 BattData.ADCSteps = NTC[i].ADCsteps; \ 00000042 01F9 MOVW R31:R30, R19:R18 \ 00000044 8142 LDD R20, Z+2 \ 00000046 01FD MOVW R31:R30, R27:R26 \ 00000048 8343 STD Z+3, R20 410 BattData.Temperature -= ((ADCS.rawNTC - NTC[i].ADC)<<1) / BattData.ADCSteps; \ 0000004A 9100.... LDS R16, (ADCS + 4) \ 0000004E 2F15 MOV R17, R21 \ 00000050 01F9 MOVW R31:R30, R19:R18 \ 00000052 8120 LD R18, Z \ 00000054 8131 LDD R19, Z+1 \ 00000056 1B02 SUB R16, R18 \ 00000058 0B13 SBC R17, R19 \ 0000005A 0F00 LSL R16 \ 0000005C 1F11 ROL R17 \ 0000005E E050 LDI R21, 0 \ 00000060 .... RCALL ?US_DIVMOD_L02 \ 00000062 01FD MOVW R31:R30, R27:R26 \ 00000064 8112 LDD R17, Z+2 \ 00000066 1B10 SUB R17, R16 \ 00000068 8312 STD Z+2, R17 411 412 found = TRUE; // Could be done with a break, but that violates MISRA. \ 0000006A E001 LDI R16, 1 413 } 414 } \ ??NTCLookUp_1: \ 0000006C 9583 INC R24 \ 0000006E 3184 CPI R24, 20 \ 00000070 F410 BRCC ??NTCLookUp_2 \ 00000072 2300 TST R16 \ 00000074 F261 BREQ ??NTCLookUp_0 415 416 // For safety, is temperature is greater than the NTC 417 if (!found) { \ ??NTCLookUp_2: \ 00000076 2300 TST R16 \ 00000078 F419 BRNE ??NTCLookUp_3 418 BattData.Temperature = 80; \ 0000007A E500 LDI R16, 80 \ 0000007C 9300.... STS (BattData + 2), R16 419 } 420 } \ ??NTCLookUp_3: \ 00000080 2D82 MOV R24, R2 \ 00000082 2DA3 MOV R26, R3 \ 00000084 91B9 LD R27, Y+ \ 00000086 9508 RET \ In segment NEAR_ID, align 1, keep-with-next \ `?`: \ 00000000 022E02930F3C DW 558, 659, 3900, 550, 260, 300, 10, 744, 843, 6800, 750, 360, 300, 14 \ 02260104012C \ 000A02E8034B \ 1A9002EE0168 \ 012C000E \ 0000001C 036503BE2710 DW 869, 958, 10000, 1000, 475, 300, 19, 1097, 1153, 24000, 2000, 475 \ 03E801DB012C \ 001304490481 \ 5DC007D001DB \ 00000034 01A40026 DW 420, 38 \ In segment NEAR_ID, align 1, keep-with-next \ `?`: \ 00000000 03EA DW 1002 \ 00000002 17 DB 23 \ 00000003 03B9 DW 953 \ 00000005 19 DB 25 \ 00000006 0386 DW 902 \ 00000008 1A DB 26 \ 00000009 0351 DW 849 \ 0000000B 1B DB 27 \ 0000000C 031C DW 796 \ 0000000E 1B DB 27 \ 0000000F 02E6 DW 742 \ 00000011 1B DB 27 \ 00000012 02B1 DW 689 \ 00000014 1A DB 26 \ 00000015 027D DW 637 \ 00000017 1A DB 26 \ 00000018 024B DW 587 \ 0000001A 19 DB 25 \ 0000001B 021B DW 539 \ 0000001D 18 DB 24 \ 0000001E 01EE DW 494 \ 00000020 16 DB 22 \ 00000021 01C3 DW 451 \ 00000023 15 DB 21 \ 00000024 019C DW 412 \ 00000026 13 DB 19 \ 00000027 0177 DW 375 \ 00000029 12 DB 18 \ 0000002A 0155 DW 341 \ 0000002C 11 DB 17 \ 0000002D 0136 DW 310 \ 0000002F 0F DB 15 \ 00000030 011A DW 282 \ 00000032 0E DB 14 \ 00000033 0100 DW 256 \ 00000035 0D DB 13 \ 00000036 00E9 DW 233 \ 00000038 0B DB 11 \ 00000039 00D4 DW 212 \ 0000003B 0A DB 10 Maximum stack usage in bytes: Function CSTACK RSTACK -------- ------ ------ BatteryCheck 3 2 -> BatteryStatusRefresh 3 2 BatteryDataRefresh 9 4 -> OWI_DetectPresence 9 2 -> OWI_SendByte 9 2 -> OWI_ReceiveByte 9 2 -> OWI_ComputeCRC8 9 2 -> OWI_ReceiveByte 9 2 -> OWI_ComputeCRC8 9 2 -> OWI_ReceiveByte 9 2 -> OWI_ComputeCRC8 9 2 -> OWI_SendByte 9 2 -> OWI_SendByte 9 2 -> OWI_SendByte 9 2 -> OWI_ComputeCRC8 9 2 -> OWI_ComputeCRC8 9 2 -> OWI_ComputeCRC8 9 2 -> OWI_ReceiveByte 9 2 -> OWI_ComputeCRC8 9 2 -> OWI_ReceiveByte 9 2 -> OWI_ComputeCRC8 9 2 -> OWI_ReceiveByte 9 2 -> OWI_ComputeCRC8 9 2 BatteryStatusRefresh 4 2 -> NTCLookUp 4 2 -> RIDLookUp 4 2 DisableBatteries 0 2 EnableBattery 1 4 -> Time_Set 1 2 -> Time_Left 1 2 NTCLookUp 3 4 RIDLookUp 0 2 Segment part sizes: Function/Label Bytes -------------- ----- _A_OCR1B 1 _A_PORTB 1 BattControl 2 BattData 12 BattEEPROM 128 BattActive 1 RID 56 NTC 60 BatteryCheck 50 BatteryStatusRefresh 158 BatteryDataRefresh 254 EnableBattery 66 DisableBatteries 8 RIDLookUp 132 NTCLookUp 136 ? 56 ? 60 Others 12 2 bytes in segment ABSOLUTE 804 bytes in segment CODE 130 bytes in segment EEPROM_I 12 bytes in segment INITTAB 116 bytes in segment NEAR_I 116 bytes in segment NEAR_ID 13 bytes in segment NEAR_Z 920 bytes of CODE memory (+ 12 bytes shared) 129 bytes of DATA memory (+ 2 bytes shared) 130 bytes of XDATA memory Errors: none Warnings: none