/////////////////////////////////////////////////////////////////////////////// // / // 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\battery.c / // Command line = C:\home\kevin\pub\src\bc100_cal\IAR\battery.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\battery. / // s90 / // / // / /////////////////////////////////////////////////////////////////////////////// NAME battery RSEG CSTACK:DATA:NOROOT(0) RSEG RSTACK:DATA:NOROOT(0) EXTERN ?EPILOGUE_B4_L09 EXTERN ?EPILOGUE_B8_L09 EXTERN ?PROLOGUE4_L09 EXTERN ?PROLOGUE8_L09 EXTERN ?Register_R4_is_cg_reg EXTERN ?Register_R5_is_cg_reg EXTERN ?Register_R6_is_cg_reg EXTERN ?Register_R7_is_cg_reg EXTERN ?S_MUL_L02 EXTERN ?S_SHL_L02 EXTERN ?US_DIVMOD_L02 EXTERN ?need_segment_init EXTERN __eeput8_16 PUBWEAK `?` PUBWEAK `?` PUBLIC BattActive PUBLIC BattControl PUBLIC BattData PUBLIC BattEEPROM PUBLIC BatteryCheck PUBLIC BatteryDataRefresh PUBLIC BatteryStatusRefresh PUBLIC DisableBatteries PUBLIC EnableBattery PUBLIC NTC PUBLIC NTCLookUp PUBLIC RID PUBLIC RIDLookUp PUBWEAK _A_OCR1B PUBWEAK _A_PORTB PUBWEAK __?EEARH PUBWEAK __?EEARL PUBWEAK __?EECR PUBWEAK __?EEDR EXTERN OWI_DetectPresence EXTERN OWI_SendByte EXTERN OWI_ReceiveByte EXTERN OWI_ComputeCRC8 EXTERN Time_Set EXTERN Time_Left EXTERN ADCS // C:\home\kevin\pub\src\bc100_cal\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 ASEGN ABSOLUTE:DATA:NOROOT,04cH // volatile __io _A_OCR1B _A_OCR1B: DS 1 ASEGN ABSOLUTE:DATA:NOROOT,038H // volatile __io _A_PORTB _A_PORTB: 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 */ RSEG EEPROM_I:XDATA:NOROOT(0) // 60 __eeprom Battery_t BattControl[2] = {{TRUE, TRUE, FALSE}, BattControl: DB 3, 3 // 61 {TRUE, TRUE, FALSE}}; // 62 // 63 /* Data-struct for battery */ RSEG NEAR_Z:DATA:NOROOT(0) REQUIRE `?` // 64 Batteries_t BattData; //!< Holds data for the current battery BattData: 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 */ RSEG EEPROM_I:XDATA:NOROOT(0) // 71 __eeprom unsigned char BattEEPROM[4][32]; BattEEPROM: DB 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 DB 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 DB 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 DB 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 DB 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 DB 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 DB 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 DB 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // 72 // 73 // 74 //! Global that indicates current battery (0 = battery A, 1 = B) RSEG NEAR_Z:DATA:NOROOT(0) REQUIRE `?` // 75 unsigned char BattActive; BattActive: 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 */ RSEG NEAR_I:DATA:NOROOT(0) REQUIRE `?` // 84 const RID_Lookup_t RID[RID_TABLE_SIZE] = { RID: DS 56 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 RSEG NEAR_I:DATA:NOROOT(0) REQUIRE `?` // 106 const NTC_Lookup_t NTC[NTC_TABLE_SIZE] = { NTC: DS 60 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 */ RSEG CODE:CODE:NOROOT(1) // 136 unsigned char BatteryCheck(void) BatteryCheck: // 137 { RCALL ?PROLOGUE4_L09 // 138 unsigned char success = TRUE; LDI R24, 1 // 139 unsigned int oldCapacity; // 140 // 141 // Save to see if battery data has changed. // 142 oldCapacity = BattData.Capacity; LDI R30, LOW(BattData) LDI R31, (BattData) >> 8 LDD R16, Z+4 LDD R17, Z+5 MOVW R27:R26, R17:R16 // 143 // 144 if (!BatteryStatusRefresh()) { RCALL BatteryStatusRefresh TST R16 BRNE ??BatteryCheck_0 // 145 success = FALSE; // Battery not present or RID was invalid. LDI R24, 0 // 146 } // 147 // 148 if (oldCapacity != BattData.Capacity) { ??BatteryCheck_0: LDI R30, LOW(BattData) LDI R31, (BattData) >> 8 LDD R16, Z+4 LDD R17, Z+5 CP R26, R16 CPC R27, R17 BREQ ??BatteryCheck_1 // 149 success = FALSE; // Battery configuration has changed. LDI R24, 0 // 150 } // 151 // 152 return(success); ??BatteryCheck_1: MOV R16, R24 LDI R30, 4 RJMP ?EPILOGUE_B4_L09 // 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 */ RSEG CODE:CODE:NOROOT(1) // 169 unsigned char BatteryStatusRefresh(void) BatteryStatusRefresh: // 170 { RCALL ?PROLOGUE4_L09 // 171 // Assume the worst.. // 172 unsigned char success = FALSE; LDI R24, 0 // 173 // 174 BattData.Present = FALSE; LDI R30, LOW(BattData) LDI R31, (BattData) >> 8 LD R16, Z ANDI R16, 0xFE ST Z, R16 // 175 BattData.Charged = FALSE; LDI R30, LOW(BattData) LDI R31, (BattData) >> 8 LD R16, Z ANDI R16, 0xFD ST Z, R16 // 176 BattData.Low = TRUE; LDI R30, LOW(BattData) LDI R31, (BattData) >> 8 LD R16, Z ORI R16, 0x04 ST Z, R16 // 177 BattData.Circuit = OW_NONE; LDI R16, 0 STS (BattData + 1), R16 // 178 BattData.Temperature = 0; LDI R16, 0 STS (BattData + 2), R16 // 179 BattData.Capacity = 0; LDI R16, 0 LDI R17, 0 LDI R30, LOW(BattData) LDI R31, (BattData) >> 8 STD Z+4, R16 STD Z+5, R17 // 180 BattData.MaxCurrent = 0; LDI R16, 0 LDI R17, 0 LDI R30, LOW(BattData) LDI R31, (BattData) >> 8 STD Z+6, R16 STD Z+7, R17 // 181 BattData.MaxTime = 0; LDI R16, 0 LDI R17, 0 LDI R30, LOW(BattData) LDI R31, (BattData) >> 8 STD Z+8, R16 STD Z+9, R17 // 182 BattData.MinCurrent = 0; LDI R16, 0 LDI R17, 0 LDI R30, LOW(BattData) LDI R31, (BattData) >> 8 STD Z+10, R16 STD Z+11, R17 // 183 // 184 NTCLookUp(); RCALL NTCLookUp // 185 BattData.HasRID = RIDLookUp(); RCALL RIDLookUp MOV R17, R16 ANDI R17, 0x01 LDI R30, LOW(BattData) LDI R31, (BattData) >> 8 BST R17, 0 LD R16, Z BLD R16, 4 ST Z, R16 LDI R16, 0 BLD R16, 0 // 186 // 187 // Is the battery voltage above minimum safe cell voltage? // 188 if (ADCS.VBAT >= BAT_VOLTAGE_MIN) { LDI R30, LOW(ADCS) LDI R31, (ADCS) >> 8 LDD R16, Z+10 LDD R17, Z+11 CPI R16, 96 LDI R18, 9 CPC R17, R18 BRCS ??BatteryStatusRefresh_0 // 189 BattData.Low = FALSE; LDI R30, LOW(BattData) LDI R31, (BattData) >> 8 LD R16, Z ANDI R16, 0xFB ST Z, R16 // 190 } // 191 // 192 // Is the battery charged? // 193 if (ADCS.VBAT >= BAT_VOLTAGE_LOW) { ??BatteryStatusRefresh_0: LDI R30, LOW(ADCS) LDI R31, (ADCS) >> 8 LDD R16, Z+10 LDD R17, Z+11 CPI R16, 210 LDI R18, 15 CPC R17, R18 BRCS ??BatteryStatusRefresh_1 // 194 BattData.Charged = TRUE; LDI R30, LOW(BattData) LDI R31, (BattData) >> 8 LD R16, Z ORI R16, 0x02 ST Z, 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: IN R16, 0x2C TST R16 BRNE ??BatteryStatusRefresh_2 LDI R30, LOW(BattData) LDI R31, (BattData) >> 8 LD R16, Z SBRS R16, 2 RJMP ??BatteryStatusRefresh_3 ??BatteryStatusRefresh_2: IN R16, 0x2C TST R16 BREQ ??BatteryStatusRefresh_4 LDI R26, LOW((ADCS + 22)) LDI R27, HIGH((ADCS + 22)) LD R30, X+ LD R31, X SBIW R27:R26, 1 SBIW R31:R30, 1 BRLT ??BatteryStatusRefresh_4 // 207 BattData.Present = TRUE; ??BatteryStatusRefresh_3: LDI R30, LOW(BattData) LDI R31, (BattData) >> 8 LD R16, Z ORI R16, 0x01 ST Z, R16 // 208 success = TRUE; LDI R24, 1 RJMP ??BatteryStatusRefresh_5 // 209 } else { // 210 BattData.Low = FALSE; // (This is just a technicality..) ??BatteryStatusRefresh_4: LDI R30, LOW(BattData) LDI R31, (BattData) >> 8 LD R16, Z ANDI R16, 0xFB ST Z, R16 // 211 success = FALSE; LDI R24, 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: LDI R30, LOW(BattData) LDI R31, (BattData) >> 8 LD R16, Z SBRS R16, 4 // 217 success = FALSE; LDI R24, 0 // 218 } // 219 #endif // 220 // 221 return(success); ??BatteryStatusRefresh_6: MOV R16, R24 LDI R30, 4 RJMP ?EPILOGUE_B4_L09 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 */ RSEG CODE:CODE:NOROOT(1) // 236 unsigned char BatteryDataRefresh(void) BatteryDataRefresh: // 237 { RCALL ?PROLOGUE8_L09 REQUIRE ?Register_R4_is_cg_reg REQUIRE ?Register_R5_is_cg_reg REQUIRE ?Register_R6_is_cg_reg REQUIRE ?Register_R7_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++) { LDI R25, 0 ??BatteryDataRefresh_0: CPI R25, 4 BRCS $+2+2 RJMP ??BatteryDataRefresh_1 // 244 success = FALSE; LDI R27, 0 // 245 // 246 if (OWI_DetectPresence(OWIBUS) == OWIBUS) { LDI R16, 1 RCALL OWI_DetectPresence CPI R16, 1 BREQ $+2+2 RJMP ??BatteryDataRefresh_2 // 247 // 248 // Presence detected, check type and CRC. // 249 OWI_SendByte(OWI_ROM_READ, OWIBUS); LDI R17, 1 LDI R16, 51 RCALL OWI_SendByte // 250 family = OWI_ReceiveByte(OWIBUS); LDI R16, 1 RCALL OWI_ReceiveByte MOV R6, R16 // 251 crc = OWI_ComputeCRC8(family,0); LDI R17, 0 MOV R16, R6 RCALL OWI_ComputeCRC8 MOV R5, R16 // 252 // 253 for (i = 0; i < 6; i++) { LDI R24, 0 ??BatteryDataRefresh_3: CPI R24, 6 BRCC ??BatteryDataRefresh_4 // 254 crc = OWI_ComputeCRC8(OWI_ReceiveByte(OWIBUS),crc); LDI R16, 1 RCALL OWI_ReceiveByte MOV R17, R5 RCALL OWI_ComputeCRC8 MOV R5, R16 // 255 } INC R24 RJMP ??BatteryDataRefresh_3 // 256 // 257 // CRC ok, device found. // 258 if (OWI_ComputeCRC8(OWI_ReceiveByte(OWIBUS),crc) == 0) { ??BatteryDataRefresh_4: LDI R16, 1 RCALL OWI_ReceiveByte MOV R17, R5 RCALL OWI_ComputeCRC8 TST R16 BREQ $+2+2 RJMP ??BatteryDataRefresh_2 // 259 BattData.Circuit = family; STS (BattData + 1), R6 // 260 // 261 // For now, we only read data from DS2505 EPROMs. // 262 if (BattData.Circuit == OW_DS2505) { LDS R16, (BattData + 1) CPI R16, 9 BREQ $+2+2 RJMP ??BatteryDataRefresh_2 // 263 offset = page*32; MOV R16, R25 SWAP R16 ANDI R16, 0xF0 LSL R16 MOV R4, R16 // 264 OWI_SendByte(DS2505_DATA_READ, OWIBUS); // Command: read data. LDI R17, 1 LDI R16, 195 RCALL OWI_SendByte // 265 OWI_SendByte(offset, OWIBUS); // Data: low address. LDI R17, 1 MOV R16, R4 RCALL OWI_SendByte // 266 OWI_SendByte(0, OWIBUS); // Data: high address. LDI R17, 1 LDI R16, 0 RCALL OWI_SendByte // 267 // 268 // Calculate checksums. // 269 crc = OWI_ComputeCRC8(DS2505_DATA_READ,0); LDI R17, 0 LDI R16, 195 RCALL OWI_ComputeCRC8 MOV R5, R16 // 270 crc = OWI_ComputeCRC8(offset,crc); MOV R17, R5 MOV R16, R4 RCALL OWI_ComputeCRC8 MOV R5, R16 // 271 crc = OWI_ComputeCRC8(0,crc); MOV R17, R5 LDI R16, 0 RCALL OWI_ComputeCRC8 MOV R5, 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) { LDI R16, 1 RCALL OWI_ReceiveByte MOV R17, R5 RCALL OWI_ComputeCRC8 TST R16 BRNE ??BatteryDataRefresh_2 // 276 crc = 0; CLR R5 // 277 // 278 // Fill page with data. // 279 for (i=0; i<32; i++) { LDI R24, 0 ??BatteryDataRefresh_5: CPI R24, 32 BRCC ??BatteryDataRefresh_6 // 280 temp = OWI_ReceiveByte(OWIBUS); LDI R16, 1 RCALL OWI_ReceiveByte MOV R7, R16 // 281 crc = OWI_ComputeCRC8(temp, crc); MOV R17, R5 MOV R16, R7 RCALL OWI_ComputeCRC8 MOV R5, R16 // 282 BattEEPROM[page][i] = temp; MOV R20, R25 LDI R21, 0 LDI R16, 32 LDI R17, 0 RCALL ?S_MUL_L02 LDI R20, LOW(BattEEPROM) LDI R21, (BattEEPROM) >> 8 ADD R20, R16 ADC R21, R17 MOV R16, R24 LDI R17, 0 ADD R20, R16 ADC R21, R17 MOV R16, R7 RCALL __eeput8_16 // 283 } INC R24 RJMP ??BatteryDataRefresh_5 // 284 // 285 if (OWI_ComputeCRC8(OWI_ReceiveByte(OWIBUS),crc) == 0) { ??BatteryDataRefresh_6: LDI R16, 1 RCALL OWI_ReceiveByte MOV R17, R5 RCALL OWI_ComputeCRC8 TST R16 BRNE ??BatteryDataRefresh_2 // 286 success = TRUE; // Data read OK LDI R27, 1 // 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) { ??BatteryDataRefresh_2: TST R27 BRNE ??BatteryDataRefresh_7 // 299 for (i=0; i<32; i++) { LDI R24, 0 ??BatteryDataRefresh_8: CPI R24, 32 BRCC ??BatteryDataRefresh_7 // 300 BattEEPROM[page][i] = 0; LDI R26, 0 MOV R20, R25 LDI R21, 0 LDI R16, 32 LDI R17, 0 RCALL ?S_MUL_L02 LDI R20, LOW(BattEEPROM) LDI R21, (BattEEPROM) >> 8 ADD R20, R16 ADC R21, R17 MOV R16, R24 LDI R17, 0 ADD R20, R16 ADC R21, R17 MOV R16, R26 RCALL __eeput8_16 // 301 } INC R24 RJMP ??BatteryDataRefresh_8 // 302 } // 303 } ??BatteryDataRefresh_7: INC R25 RJMP ??BatteryDataRefresh_0 // 304 // 305 return(success); ??BatteryDataRefresh_1: MOV R16, R27 LDI R30, 8 RJMP ?EPILOGUE_B8_L09 // 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 */ RSEG CODE:CODE:NOROOT(1) // 317 void EnableBattery(unsigned char bat) EnableBattery: // 318 { ST -Y, R24 MOV R24, R16 // 319 // Use general timer, set timeout to 100ms. // 320 Time_Set(TIMER_GEN,0,0,100); LDI R20, 100 LDI R17, 0 LDI R18, 0 LDI R19, 0 LDI R16, 2 RCALL Time_Set // 321 // 322 // Set specified battery as the active one. // 323 BattActive = bat; STS BattActive, R24 // 324 // 325 // Enable current battery in hardware, light LED & connect battery. // 326 PORTB |= (1 << (PB4+bat)); LDI R16, 1 LDI R17, 0 MOV R20, R24 SUBI R20, 252 RCALL ?S_SHL_L02 IN R17, 0x18 OR R17, R16 OUT 0x18, R17 // 327 // 328 // Disconnect other battery. // 329 PORTB &= ~(1<<(PB5-bat)); LDI R16, 1 LDI R17, 0 LDI R20, 5 SUB R20, R24 RCALL ?S_SHL_L02 COM R16 IN R17, 0x18 AND R17, R16 OUT 0x18, R17 // 330 // 331 do { // Let port switch settle. // 332 } while (Time_Left(TIMER_GEN)); ??EnableBattery_0: LDI R16, 2 RCALL Time_Left TST R16 BRNE ??EnableBattery_0 // 333 } LD R24, Y+ RET REQUIRE _A_PORTB // 334 // 335 // 336 /*! \brief Disables both batteries // 337 * // 338 * Clears PB4 and PB5 in PORTB, disabling both batteries. // 339 */ RSEG CODE:CODE:NOROOT(1) // 340 void DisableBatteries(void) DisableBatteries: // 341 { // 342 // Turn off LEDs and disconnect batteries. // 343 PORTB &= ~((1<= RID[i].Low) { LDI R30, LOW(ADCS) LDI R31, (ADCS) >> 8 LDD R26, Z+2 LDD R27, Z+3 MOV R20, R24 LDI R21, 0 LDI R16, 14 LDI R17, 0 RCALL ?S_MUL_L02 MOVW R31:R30, R17:R16 SUBI R30, LOW((-(RID) & 0xFFFF)) SBCI R31, (-(RID) & 0xFFFF) >> 8 LD R16, Z LDD R17, Z+1 CP R26, R16 CPC R27, R17 BRCC $+2+2 RJMP ??RIDLookUp_2 // 364 if (ADCS.rawRID <= RID[i].High) { MOV R20, R24 LDI R21, 0 LDI R16, 14 LDI R17, 0 RCALL ?S_MUL_L02 MOVW R31:R30, R17:R16 SUBI R30, LOW((-(RID) & 0xFFFF)) SBCI R31, (-(RID) & 0xFFFF) >> 8 LDD R16, Z+2 LDD R17, Z+3 LDI R30, LOW(ADCS) LDI R31, (ADCS) >> 8 LDD R18, Z+2 LDD R19, Z+3 CP R16, R18 CPC R17, R19 BRCS ??RIDLookUp_2 // 365 BattData.Capacity = RID[i].Capacity; MOV R20, R24 LDI R21, 0 LDI R16, 14 LDI R17, 0 RCALL ?S_MUL_L02 MOVW R31:R30, R17:R16 SUBI R30, LOW((-(RID) & 0xFFFF)) SBCI R31, (-(RID) & 0xFFFF) >> 8 LDD R16, Z+6 LDD R17, Z+7 LDI R30, LOW(BattData) LDI R31, (BattData) >> 8 STD Z+4, R16 STD Z+5, R17 // 366 BattData.MaxCurrent = RID[i].Icharge; MOV R20, R24 LDI R21, 0 LDI R16, 14 LDI R17, 0 RCALL ?S_MUL_L02 MOVW R31:R30, R17:R16 SUBI R30, LOW((-(RID) & 0xFFFF)) SBCI R31, (-(RID) & 0xFFFF) >> 8 LDD R16, Z+8 LDD R17, Z+9 LDI R30, LOW(BattData) LDI R31, (BattData) >> 8 STD Z+6, R16 STD Z+7, R17 // 367 BattData.MaxTime = RID[i].tCutOff; MOV R20, R24 LDI R21, 0 LDI R16, 14 LDI R17, 0 RCALL ?S_MUL_L02 MOVW R31:R30, R17:R16 SUBI R30, LOW((-(RID) & 0xFFFF)) SBCI R31, (-(RID) & 0xFFFF) >> 8 LDD R16, Z+10 LDD R17, Z+11 LDI R30, LOW(BattData) LDI R31, (BattData) >> 8 STD Z+8, R16 STD Z+9, R17 // 368 BattData.MinCurrent = RID[i].ICutOff; MOV R20, R24 LDI R21, 0 LDI R16, 14 LDI R17, 0 RCALL ?S_MUL_L02 MOVW R31:R30, R17:R16 SUBI R30, LOW((-(RID) & 0xFFFF)) SBCI R31, (-(RID) & 0xFFFF) >> 8 LDD R16, Z+12 LDD R17, Z+13 LDI R30, LOW(BattData) LDI R31, (BattData) >> 8 STD Z+10, R16 STD Z+11, R17 // 369 // 370 found = TRUE; LDI R25, 1 // 371 } // 372 } // 373 } ??RIDLookUp_2: INC R24 RJMP ??RIDLookUp_0 // 374 // 375 // If no valid entry is found, use defaults and return FALSE. // 376 if (!found) { ??RIDLookUp_1: TST R25 BRNE ??RIDLookUp_3 // 377 BattData.Capacity = DEF_BAT_CAPACITY; LDI R16, 0 LDI R17, 0 LDI R30, LOW(BattData) LDI R31, (BattData) >> 8 STD Z+4, R16 STD Z+5, R17 // 378 BattData.MaxCurrent = DEF_BAT_CURRENT_MAX; LDI R16, 0 LDI R17, 0 LDI R30, LOW(BattData) LDI R31, (BattData) >> 8 STD Z+6, R16 STD Z+7, R17 // 379 BattData.MaxTime = DEF_BAT_TIME_MAX; LDI R16, 0 LDI R17, 0 LDI R30, LOW(BattData) LDI R31, (BattData) >> 8 STD Z+8, R16 STD Z+9, R17 // 380 BattData.MinCurrent = DEF_BAT_CURRENT_MIN; LDI R16, 0 LDI R17, 0 LDI R30, LOW(BattData) LDI R31, (BattData) >> 8 STD Z+10, R16 STD Z+11, R17 // 381 } // 382 // 383 return(found); ??RIDLookUp_3: MOV R16, R25 LDI R30, 4 RJMP ?EPILOGUE_B4_L09 // 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 */ RSEG CODE:CODE:NOROOT(1) // 398 void NTCLookUp (void) NTCLookUp: // 399 { RCALL ?PROLOGUE4_L09 // 400 unsigned char i; // 401 unsigned char found = FALSE; LDI R25, 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++) { LDI R24, 0 ??NTCLookUp_0: CPI R24, 20 BRCS $+2+2 RJMP ??NTCLookUp_1 TST R25 BREQ $+2+2 RJMP ??NTCLookUp_1 // 407 if (ADCS.rawNTC >= NTC[i].ADC) { LDI R30, LOW(ADCS) LDI R31, (ADCS) >> 8 LDD R26, Z+4 LDD R27, Z+5 MOV R20, R24 LDI R21, 0 LDI R16, 3 LDI R17, 0 RCALL ?S_MUL_L02 MOVW R31:R30, R17:R16 SUBI R30, LOW((-(NTC) & 0xFFFF)) SBCI R31, (-(NTC) & 0xFFFF) >> 8 LD R16, Z LDD R17, Z+1 CP R26, R16 CPC R27, R17 BRCS ??NTCLookUp_2 // 408 BattData.Temperature = (i<<2) ; MOV R16, R24 LSL R16 LSL R16 STS (BattData + 2), R16 // 409 BattData.ADCSteps = NTC[i].ADCsteps; MOV R20, R24 LDI R21, 0 LDI R16, 3 LDI R17, 0 RCALL ?S_MUL_L02 MOVW R31:R30, R17:R16 SUBI R30, LOW((-(NTC) & 0xFFFF)) SBCI R31, (-(NTC) & 0xFFFF) >> 8 LDD R16, Z+2 STS (BattData + 3), R16 // 410 BattData.Temperature -= ((ADCS.rawNTC - NTC[i].ADC)<<1) / BattData.ADCSteps; LDI R30, LOW(ADCS) LDI R31, (ADCS) >> 8 LDD R26, Z+4 LDD R27, Z+5 MOV R20, R24 LDI R21, 0 LDI R16, 3 LDI R17, 0 RCALL ?S_MUL_L02 MOVW R31:R30, R17:R16 SUBI R30, LOW((-(NTC) & 0xFFFF)) SBCI R31, (-(NTC) & 0xFFFF) >> 8 LD R16, Z LDD R17, Z+1 SUB R26, R16 SBC R27, R17 LSL R26 ROL R27 MOVW R17:R16, R27:R26 LDS R20, (BattData + 3) LDI R21, 0 RCALL ?US_DIVMOD_L02 LDI R30, LOW(BattData) LDI R31, (BattData) >> 8 LDD R17, Z+2 SUB R17, R16 STD Z+2, R17 // 411 // 412 found = TRUE; // Could be done with a break, but that violates MISRA. LDI R25, 1 // 413 } // 414 } ??NTCLookUp_2: INC R24 RJMP ??NTCLookUp_0 // 415 // 416 // For safety, is temperature is greater than the NTC // 417 if (!found) { ??NTCLookUp_1: TST R25 BRNE ??NTCLookUp_3 // 418 BattData.Temperature = 80; LDI R16, 80 STS (BattData + 2), R16 // 419 } // 420 } ??NTCLookUp_3: LDI R30, 4 RJMP ?EPILOGUE_B4_L09 ASEGN ABSOLUTE:DATA:NOROOT,01cH __?EECR: ASEGN ABSOLUTE:DATA:NOROOT,01dH __?EEDR: ASEGN ABSOLUTE:DATA:NOROOT,01eH __?EEARL: ASEGN ABSOLUTE:DATA:NOROOT,01fH __?EEARH: RSEG INITTAB:CODE:NOROOT(0) `?`: DW SFE(NEAR_Z) - SFB(NEAR_Z) DW SFB(NEAR_Z) DW 0 REQUIRE ?need_segment_init RSEG NEAR_ID:CODE:NOROOT(0) `?`: DW 558, 659, 3900, 550, 260, 300, 10, 744, 843, 6800, 750, 360, 300, 14 DW 869, 958, 10000, 1000, 475, 300, 19, 1097, 1153, 24000, 2000, 475 DW 420, 38 RSEG INITTAB:CODE:NOROOT(0) `?`: DW SFE(NEAR_I) - SFB(NEAR_I) DW SFB(NEAR_I) DW SFB(NEAR_ID) REQUIRE ?need_segment_init RSEG NEAR_ID:CODE:NOROOT(0) `?`: DW 1002 DB 23 DW 953 DB 25 DW 902 DB 26 DW 849 DB 27 DW 796 DB 27 DW 742 DB 27 DW 689 DB 26 DW 637 DB 26 DW 587 DB 25 DW 539 DB 24 DW 494 DB 22 DW 451 DB 21 DW 412 DB 19 DW 375 DB 18 DW 341 DB 17 DW 310 DB 15 DW 282 DB 14 DW 256 DB 13 DW 233 DB 11 DW 212 DB 10 END // // 2 bytes in segment ABSOLUTE // 1 064 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 // // 1 180 bytes of CODE memory (+ 12 bytes shared) // 129 bytes of DATA memory (+ 2 bytes shared) // 130 bytes of XDATA memory // //Errors: none //Warnings: none