/////////////////////////////////////////////////////////////////////////////// // / // 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\bc1 / // 00\IAR\Release\Obj\ -D NDEBUG -lCN / // C:\home\kevin\pub\src\bc100\IAR\Release\List\ / // -lB C:\home\kevin\pub\src\bc100\IAR\Release\Li / // st\ --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\b / // attery.s90 / // / // / /////////////////////////////////////////////////////////////////////////////// NAME battery RSEG CSTACK:DATA:NOROOT(0) RSEG RSTACK:DATA:NOROOT(0) 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 ?Register_R8_is_cg_reg 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\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 { ST -Y, R27 ST -Y, R26 ST -Y, R24 // 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 R26, Z+4 LDD R27, Z+5 // 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 LD R24, Y+ LD R26, Y+ LD R27, Y+ 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 */ RSEG CODE:CODE:NOROOT(1) // 169 unsigned char BatteryStatusRefresh(void) BatteryStatusRefresh: // 170 { ST -Y, R27 ST -Y, R26 ST -Y, R25 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; LDI R26, LOW(BattData) LDI R27, (BattData) >> 8 LD R16, X ANDI R16, 0xFC ORI R16, 0x04 ST X, R16 // 177 BattData.Circuit = OW_NONE; LDI R16, 0 MOVW R31:R30, R27:R26 STD Z+1, R16 // 178 BattData.Temperature = 0; STD Z+2, R16 // 179 BattData.Capacity = 0; STD Z+4, R16 STD Z+5, R16 // 180 BattData.MaxCurrent = 0; STD Z+6, R16 STD Z+7, R16 // 181 BattData.MaxTime = 0; STD Z+8, R16 STD Z+9, R16 // 182 BattData.MinCurrent = 0; STD Z+10, R16 STD Z+11, R16 // 183 // 184 NTCLookUp(); RCALL NTCLookUp // 185 BattData.HasRID = RIDLookUp(); RCALL RIDLookUp MOV R17, R16 ANDI R17, 0x01 BST R17, 0 LD R16, X BLD R16, 4 ST X, R16 // 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; LD R16, X ANDI R16, 0xFB ST X, R16 // 190 } // 191 // 192 // Is the battery charged? // 193 if (ADCS.VBAT >= BAT_VOLTAGE_LOW) { ??BatteryStatusRefresh_0: LDD R16, Z+10 CPI R16, 210 SBCI R17, 15 BRCS ??BatteryStatusRefresh_1 // 194 BattData.Charged = TRUE; LD R16, X ORI R16, 0x02 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: IN R16, 0x2C TST R16 BRNE ??BatteryStatusRefresh_2 LD R16, X SBRS R16, 2 RJMP ??BatteryStatusRefresh_3 ??BatteryStatusRefresh_2: IN R16, 0x2C TST R16 BREQ ??BatteryStatusRefresh_4 LDD R24, Z+22 LDD R25, Z+23 CPI R24, 1 SBCI R25, 0 BRLT ??BatteryStatusRefresh_4 // 207 BattData.Present = TRUE; ??BatteryStatusRefresh_3: LD R16, X ORI R16, 0x01 ST X, R16 // 208 success = TRUE; LDI R16, 1 RJMP ??BatteryStatusRefresh_5 // 209 } else { // 210 BattData.Low = FALSE; // (This is just a technicality..) ??BatteryStatusRefresh_4: LD R16, X ANDI R16, 0xFB ST X, R16 // 211 success = FALSE; 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: LD R17, X SBRS R17, 4 // 217 success = FALSE; LDI R16, 0 // 218 } // 219 #endif // 220 // 221 return(success); ??BatteryStatusRefresh_6: LD R24, Y+ LD R25, Y+ LD R26, Y+ LD R27, Y+ RET 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 { ST -Y, R8 ST -Y, R7 ST -Y, R6 ST -Y, R5 ST -Y, R4 ST -Y, R27 ST -Y, R26 ST -Y, R25 ST -Y, R24 REQUIRE ?Register_R4_is_cg_reg REQUIRE ?Register_R5_is_cg_reg REQUIRE ?Register_R6_is_cg_reg REQUIRE ?Register_R7_is_cg_reg 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++) { LDI R25, 0 LDI R26, LOW(BattEEPROM) LDI R27, (BattEEPROM) >> 8 // 244 success = FALSE; ??BatteryDataRefresh_0: CLR R7 // 245 // 246 if (OWI_DetectPresence(OWIBUS) == OWIBUS) { LDI R16, 1 RCALL OWI_DetectPresence CPI R16, 1 BREQ $+2+2 RJMP ??BatteryDataRefresh_1 // 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 R5, R16 // 251 crc = OWI_ComputeCRC8(family,0); LDI R17, 0 RCALL OWI_ComputeCRC8 MOV R24, R16 // 252 // 253 for (i = 0; i < 6; i++) { LDI R16, 6 MOV R4, R16 // 254 crc = OWI_ComputeCRC8(OWI_ReceiveByte(OWIBUS),crc); ??BatteryDataRefresh_2: LDI R16, 1 RCALL OWI_ReceiveByte MOV R17, R24 RCALL OWI_ComputeCRC8 MOV R24, R16 // 255 } DEC R4 BRNE ??BatteryDataRefresh_2 // 256 // 257 // CRC ok, device found. // 258 if (OWI_ComputeCRC8(OWI_ReceiveByte(OWIBUS),crc) == 0) { LDI R16, 1 RCALL OWI_ReceiveByte MOV R17, R24 RCALL OWI_ComputeCRC8 TST R16 BRNE ??BatteryDataRefresh_1 // 259 BattData.Circuit = family; STS (BattData + 1), R5 // 260 // 261 // For now, we only read data from DS2505 EPROMs. // 262 if (BattData.Circuit == OW_DS2505) { LDS R16, (BattData + 1) CPI R16, 9 BRNE ??BatteryDataRefresh_1 // 263 offset = page*32; MOV R4, R25 SWAP R4 LDI R16, 240 AND R4, R16 LSL R4 // 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 // 270 crc = OWI_ComputeCRC8(offset,crc); MOV R17, R16 MOV R16, R4 RCALL OWI_ComputeCRC8 // 271 crc = OWI_ComputeCRC8(0,crc); MOV R17, R16 LDI R16, 0 RCALL OWI_ComputeCRC8 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) { LDI R16, 1 RCALL OWI_ReceiveByte MOV R17, R24 RCALL OWI_ComputeCRC8 TST R16 BRNE ??BatteryDataRefresh_1 // 276 crc = 0; LDI R24, 0 // 277 // 278 // Fill page with data. // 279 for (i=0; i<32; i++) { MOVW R5:R4, R27:R26 LDI R16, 32 MOV R6, R16 // 280 temp = OWI_ReceiveByte(OWIBUS); ??BatteryDataRefresh_3: LDI R16, 1 RCALL OWI_ReceiveByte MOV R8, R16 // 281 crc = OWI_ComputeCRC8(temp, crc); MOV R17, R24 RCALL OWI_ComputeCRC8 MOV R24, R16 // 282 BattEEPROM[page][i] = temp; MOV R16, R8 MOVW R21:R20, R5:R4 RCALL __eeput8_16 // 283 } LDI R16, 1 ADD R4, R16 ADC R5, R7 DEC R6 BRNE ??BatteryDataRefresh_3 // 284 // 285 if (OWI_ComputeCRC8(OWI_ReceiveByte(OWIBUS),crc) == 0) { RCALL OWI_ReceiveByte MOV R17, R24 RCALL OWI_ComputeCRC8 TST R16 BRNE ??BatteryDataRefresh_1 // 286 success = TRUE; // Data read OK INC R7 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: MOVW R21:R20, R27:R26 LDI R17, 32 // 300 BattEEPROM[page][i] = 0; ??BatteryDataRefresh_5: LDI R16, 0 RCALL __eeput8_16 // 301 } SUBI R20, 255 SBCI R21, 255 DEC R17 BRNE ??BatteryDataRefresh_5 // 302 } // 303 } ??BatteryDataRefresh_4: INC R25 ADIW R27:R26, 32 CPI R25, 4 BRCC $+2+2 RJMP ??BatteryDataRefresh_0 // 304 // 305 return(success); MOV R16, R7 LD R24, Y+ LD R25, Y+ LD R26, Y+ LD R27, Y+ LD R4, Y+ LD R5, Y+ LD R6, Y+ LD R7, Y+ LD R8, Y+ 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 */ 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<> 8 LDI R18, 4 LDI R16, LOW(BattData) LDI R17, (BattData) >> 8 // 363 if (ADCS.rawRID >= RID[i].Low) { ??RIDLookUp_0: LDI R26, LOW((ADCS + 2)) LDI R27, HIGH((ADCS + 2)) LD R22, X+ LD R23, X LD R0, Z LDD R1, Z+1 CP R22, R0 CPC R23, R1 BRCS ??RIDLookUp_1 // 364 if (ADCS.rawRID <= RID[i].High) { LDD R0, Z+2 LDD R1, Z+3 CP R0, R22 CPC R1, R23 BRCS ??RIDLookUp_1 // 365 BattData.Capacity = RID[i].Capacity; LDD R20, Z+6 LDD R21, Z+7 MOVW R27:R26, R17:R16 ADIW R27:R26, 4 ST X+, R20 ST X, R21 // 366 BattData.MaxCurrent = RID[i].Icharge; LDD R20, Z+8 LDD R21, Z+9 MOVW R27:R26, R17:R16 ADIW R27:R26, 6 ST X+, R20 ST X, R21 // 367 BattData.MaxTime = RID[i].tCutOff; LDD R20, Z+10 LDD R21, Z+11 MOVW R27:R26, R17:R16 ADIW R27:R26, 8 ST X+, R20 ST X, R21 // 368 BattData.MinCurrent = RID[i].ICutOff; LDD R20, Z+12 LDD R21, Z+13 MOVW R27:R26, R17:R16 ADIW R27:R26, 10 ST X+, R20 ST X, R21 // 369 // 370 found = TRUE; LDI R20, 1 // 371 } // 372 } // 373 } ??RIDLookUp_1: ADIW R31:R30, 14 DEC R18 BRNE ??RIDLookUp_0 // 374 // 375 // If no valid entry is found, use defaults and return FALSE. // 376 if (!found) { TST R20 BRNE ??RIDLookUp_2 // 377 BattData.Capacity = DEF_BAT_CAPACITY; LDI R18, 0 MOVW R31:R30, R17:R16 STD Z+4, R18 STD Z+5, R18 // 378 BattData.MaxCurrent = DEF_BAT_CURRENT_MAX; STD Z+6, R18 STD Z+7, R18 // 379 BattData.MaxTime = DEF_BAT_TIME_MAX; STD Z+8, R18 STD Z+9, R18 // 380 BattData.MinCurrent = DEF_BAT_CURRENT_MIN; STD Z+10, R18 STD Z+11, R18 // 381 } // 382 // 383 return(found); ??RIDLookUp_2: MOV R16, R20 MOV R26, R2 MOV R27, R19 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 */ RSEG CODE:CODE:NOROOT(1) // 398 void NTCLookUp (void) NTCLookUp: // 399 { ST -Y, R27 MOV R3, R26 MOV R2, R24 // 400 unsigned char i; // 401 unsigned char found = FALSE; 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++) { LDI R24, 0 LDI R26, LOW(BattData) LDI R27, (BattData) >> 8 // 407 if (ADCS.rawNTC >= NTC[i].ADC) { ??NTCLookUp_0: MOV R20, R24 LDI R21, 0 MOVW R19:R18, R21:R20 LSL R20 ROL R21 ADD R20, R18 ADC R21, R19 LDI R18, LOW(NTC) LDI R19, (NTC) >> 8 ADD R18, R20 ADC R19, R21 LDI R30, LOW(ADCS) LDI R31, (ADCS) >> 8 LDD R20, Z+4 LDD R21, Z+5 MOVW R31:R30, R19:R18 LD R22, Z LDD R23, Z+1 CP R20, R22 CPC R21, R23 BRCS ??NTCLookUp_1 // 408 BattData.Temperature = (i<<2) ; MOV R16, R24 LSL R16 LSL R16 MOVW R31:R30, R27:R26 STD Z+2, R16 // 409 BattData.ADCSteps = NTC[i].ADCsteps; MOVW R31:R30, R19:R18 LDD R20, Z+2 MOVW R31:R30, R27:R26 STD Z+3, R20 // 410 BattData.Temperature -= ((ADCS.rawNTC - NTC[i].ADC)<<1) / BattData.ADCSteps; LDS R16, (ADCS + 4) MOV R17, R21 MOVW R31:R30, R19:R18 LD R18, Z LDD R19, Z+1 SUB R16, R18 SBC R17, R19 LSL R16 ROL R17 LDI R21, 0 RCALL ?US_DIVMOD_L02 MOVW R31:R30, R27:R26 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 R16, 1 // 413 } // 414 } ??NTCLookUp_1: INC R24 CPI R24, 20 BRCC ??NTCLookUp_2 TST R16 BREQ ??NTCLookUp_0 // 415 // 416 // For safety, is temperature is greater than the NTC // 417 if (!found) { ??NTCLookUp_2: TST R16 BRNE ??NTCLookUp_3 // 418 BattData.Temperature = 80; LDI R16, 80 STS (BattData + 2), R16 // 419 } // 420 } ??NTCLookUp_3: MOV R24, R2 MOV R26, R3 LD R27, Y+ RET 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 // 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