1 ///////////////////////////////////////////////////////////////////////////////
\r
3 // IAR Atmel AVR C/C++ Compiler V4.30F/W32 12/Mar/2008 23:01:38 /
\r
4 // Copyright 1996-2007 IAR Systems. All rights reserved. /
\r
6 // Source file = C:\home\kevin\pub\src\bc100_cal\IAR\battery.c /
\r
7 // Command line = C:\home\kevin\pub\src\bc100_cal\IAR\battery.c /
\r
8 // --cpu=tiny861 -ms -o C:\home\kevin\pub\src\bc100_cal\IA /
\r
9 // R\Debug\Obj\ -lC C:\home\kevin\pub\src\bc100_cal\IAR\De /
\r
10 // bug\List\ -lB C:\home\kevin\pub\src\bc100_cal\IAR\Debug /
\r
11 // \List\ --initializers_in_flash -z2 --no_cse /
\r
12 // --no_inline --no_code_motion --no_cross_call /
\r
13 // --no_clustering --no_tbaa --debug /
\r
14 // -DENABLE_BIT_DEFINITIONS -e --require_prototypes -I /
\r
15 // "C:\Program Files\IAR Systems\Embedded Workbench /
\r
16 // 4.0\avr\INC\" -I "C:\Program Files\IAR /
\r
17 // Systems\Embedded Workbench 4.0\avr\INC\CLIB\" /
\r
18 // --eeprom_size 512 /
\r
19 // List file = C:\home\kevin\pub\src\bc100_cal\IAR\Debug\List\battery. /
\r
23 ///////////////////////////////////////////////////////////////////////////////
\r
27 RSEG CSTACK:DATA:NOROOT(0)
\r
28 RSEG RSTACK:DATA:NOROOT(0)
\r
30 EXTERN ?EPILOGUE_B4_L09
\r
31 EXTERN ?EPILOGUE_B8_L09
\r
32 EXTERN ?PROLOGUE4_L09
\r
33 EXTERN ?PROLOGUE8_L09
\r
34 EXTERN ?Register_R4_is_cg_reg
\r
35 EXTERN ?Register_R5_is_cg_reg
\r
36 EXTERN ?Register_R6_is_cg_reg
\r
37 EXTERN ?Register_R7_is_cg_reg
\r
40 EXTERN ?US_DIVMOD_L02
\r
41 EXTERN ?need_segment_init
\r
44 PUBWEAK `?<Segment init: NEAR_I>`
\r
45 PUBWEAK `?<Segment init: NEAR_Z>`
\r
51 PUBLIC BatteryDataRefresh
\r
52 PUBLIC BatteryStatusRefresh
\r
53 PUBLIC DisableBatteries
\r
54 PUBLIC EnableBattery
\r
66 EXTERN OWI_DetectPresence
\r
68 EXTERN OWI_ReceiveByte
\r
69 EXTERN OWI_ComputeCRC8
\r
74 // C:\home\kevin\pub\src\bc100_cal\IAR\battery.c
\r
75 // 1 /* This file has been prepared for Doxygen automatic documentation generation.*/
\r
76 // 2 /*! \file *********************************************************************
\r
79 // 5 * Functions related to battery control and data acquisition.
\r
81 // 7 * Contains functions for enabling/disabling batteries, and looking up
\r
82 // 8 * their status and specifications using the ADC.
\r
84 // 10 * \par Application note:
\r
85 // 11 * AVR458: Charging Li-Ion Batteries with BC100 \n
\r
86 // 12 * AVR463: Charging NiMH Batteries with BC100
\r
89 // 15 * \par Documentation
\r
90 // 16 * For comprehensive code documentation, supported compilers, compiler
\r
91 // 17 * settings and supported devices see readme.html
\r
94 // 20 * Atmel Corporation: http://www.atmel.com \n
\r
95 // 21 * Support email: avr@atmel.com
\r
99 // 25 * $Revision: 2299 $
\r
101 // 27 * $URL: http://svn.norway.atmel.com/AppsAVR8/avr458_Charging_Li-Ion_Batteries_with_BC100/tag/20070904_release_1.0/code/IAR/battery.c $
\r
102 // 28 * $Date: 2007-08-23 12:55:51 +0200 (to, 23 aug 2007) $\n
\r
103 // 29 ******************************************************************************/
\r
105 // 31 #include <ioavr.h>
\r
107 ASEGN ABSOLUTE:DATA:NOROOT,04cH
\r
108 // <unnamed> volatile __io _A_OCR1B
\r
112 ASEGN ABSOLUTE:DATA:NOROOT,038H
\r
113 // <unnamed> volatile __io _A_PORTB
\r
116 // 32 #include <inavr.h>
\r
118 // 34 #include "structs.h"
\r
119 // 35 #include "enums.h"
\r
121 // 37 #include "ADC.h"
\r
122 // 38 #include "battery.h"
\r
123 // 39 #include "main.h"
\r
124 // 40 #include "OWI.h"
\r
125 // 41 #include "time.h"
\r
128 // 44 #include "NIMHspecs.h"
\r
129 // 45 #endif // NIMH
\r
132 // 48 #include "LIIONspecs.h"
\r
133 // 49 #endif // LIION
\r
137 // 53 //******************************************************************************
\r
139 // 55 //******************************************************************************
\r
140 // 56 /* Control-struct for batteries */
\r
141 // 57 /*! \brief Holds control data for both batteries
\r
142 // 58 * \note Stored in EEPROM.
\r
145 RSEG EEPROM_I:XDATA:NOROOT(0)
\r
146 // 60 __eeprom Battery_t BattControl[2] = {{TRUE, TRUE, FALSE},
\r
149 // 61 {TRUE, TRUE, FALSE}};
\r
151 // 63 /* Data-struct for battery */
\r
153 RSEG NEAR_Z:DATA:NOROOT(0)
\r
154 REQUIRE `?<Segment init: NEAR_Z>`
\r
155 // 64 Batteries_t BattData; //!< Holds data for the current battery
\r
160 // 67 /* Storage for battery EPROM */
\r
161 // 68 /*! \brief Storage space for data from the batteries' own EPROMs.
\r
162 // 69 * \note Stored in EEPROM.
\r
165 RSEG EEPROM_I:XDATA:NOROOT(0)
\r
166 // 71 __eeprom unsigned char BattEEPROM[4][32];
\r
168 DB 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
\r
169 DB 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
\r
170 DB 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
\r
171 DB 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
\r
172 DB 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
\r
173 DB 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
\r
174 DB 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
\r
175 DB 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
\r
178 // 74 //! Global that indicates current battery (0 = battery A, 1 = B)
\r
180 RSEG NEAR_Z:DATA:NOROOT(0)
\r
181 REQUIRE `?<Segment init: NEAR_Z>`
\r
182 // 75 unsigned char BattActive;
\r
187 // 78 /*! \brief RID lookup-table
\r
189 // 80 * Contains Resistor ID data specified by manufacturer.
\r
191 // 82 * \note Values have been calculated assuming a +/- 15% tolerance.
\r
194 RSEG NEAR_I:DATA:NOROOT(0)
\r
195 REQUIRE `?<Segment init: NEAR_I>`
\r
196 // 84 const RID_Lookup_t RID[RID_TABLE_SIZE] = {
\r
199 REQUIRE `?<Initializer for RID>`
\r
200 // 85 {558, 659, 3900, 550, 260, 300, 10},
\r
201 // 86 {744, 843, 6800, 750, 360, 300, 14},
\r
202 // 87 {869, 958, 10000, 1000, 475, 300, 19},
\r
203 // 88 {1097, 1153, 24000, 2000, 475, 420, 38}
\r
207 // 92 /*! \brief NTC lookup-table
\r
209 // 94 * The first entry is 0 degrees. For every entry after, temperature increases
\r
210 // 95 * with 4 degrees. With 20 entries, the last one equals (20-1)*4 = 76 degrees.\n
\r
211 // 96 * It must be sorted in descending ADC order.
\r
213 // 98 * \note This was calculated for a Mitsubishi RH16-3H103FB NTC.
\r
215 // 100 * \note NTCLookUp() must be modified if this table is changed so that:
\r
216 // 101 * - first entry is no longer 0 degrees.
\r
217 // 102 * - temperature difference between entries is no longer 4 degrees.
\r
218 // 103 * - ADCsteps no longer specifies ADC steps per half degree.
\r
220 // 105 // FOR VARTA POLYFLEX NTC
\r
222 RSEG NEAR_I:DATA:NOROOT(0)
\r
223 REQUIRE `?<Segment init: NEAR_I>`
\r
224 // 106 const NTC_Lookup_t NTC[NTC_TABLE_SIZE] = {
\r
227 REQUIRE `?<Initializer for NTC>`
\r
228 // 107 {1002, 23}, {953, 25}, {902, 26}, {849, 27}, {796, 27},
\r
229 // 108 {742, 27}, {689, 26}, {637, 26}, {587, 25}, {539, 24},
\r
230 // 109 {494, 22}, {451, 21}, {412, 19}, {375, 18}, {341, 17},
\r
231 // 110 {310, 15}, {282, 14}, {256, 13}, {233, 11}, {212, 10}
\r
235 // 114 // FOR MITSUBISHI NTC
\r
237 // 116 const NTC_Lookup_t NTC[NTC_TABLE_SIZE] = {
\r
238 // 117 {1004, 24}, {954, 25}, {903, 26}, {850, 27}, {796, 27},
\r
239 // 118 {742, 27}, {689, 27}, {637, 26}, {587, 25}, {539, 24},
\r
240 // 119 {493, 22}, {451, 21}, {411, 20}, {374, 18}, {340, 17},
\r
241 // 120 {309, 15}, {281, 14}, {255, 13}, {232, 11}, {211, 10}
\r
246 // 125 //******************************************************************************
\r
247 // 126 // Functions
\r
248 // 127 //******************************************************************************
\r
249 // 128 /*! \brief Checks if battery has changed
\r
251 // 130 * Stores current capacity, then attempts to refresh battery status.\n
\r
252 // 131 * If the refresh is successful, old capacity is compared with the new one.
\r
254 // 133 * \retval FALSE Battery is disconnected, or capacity has changed.
\r
255 // 134 * \retval TRUE All OK.
\r
258 RSEG CODE:CODE:NOROOT(1)
\r
259 // 136 unsigned char BatteryCheck(void)
\r
262 RCALL ?PROLOGUE4_L09
\r
263 // 138 unsigned char success = TRUE;
\r
265 // 139 unsigned int oldCapacity;
\r
267 // 141 // Save to see if battery data has changed.
\r
268 // 142 oldCapacity = BattData.Capacity;
\r
269 LDI R30, LOW(BattData)
\r
270 LDI R31, (BattData) >> 8
\r
273 MOVW R27:R26, R17:R16
\r
275 // 144 if (!BatteryStatusRefresh()) {
\r
276 RCALL BatteryStatusRefresh
\r
278 BRNE ??BatteryCheck_0
\r
279 // 145 success = FALSE; // Battery not present or RID was invalid.
\r
283 // 148 if (oldCapacity != BattData.Capacity) {
\r
285 LDI R30, LOW(BattData)
\r
286 LDI R31, (BattData) >> 8
\r
291 BREQ ??BatteryCheck_1
\r
292 // 149 success = FALSE; // Battery configuration has changed.
\r
296 // 152 return(success);
\r
300 RJMP ?EPILOGUE_B4_L09
\r
304 // 156 /*! \brief Refreshes battery status information
\r
306 // 158 * Refreshes battery status information, if it is present, based on
\r
307 // 159 * RID and NTC (read by ADC).\n
\r
308 // 160 * The battery must have been enabled and a complete set of ADC data must have
\r
309 // 161 * been collected before calling.\n
\r
311 // 163 * \retval FALSE No battery present.
\r
312 // 164 * \retval TRUE Battery present, status refreshed.
\r
314 // 166 * \note If ALLOW_NO_RID is defined, charging will NOT stop if no fitting entry
\r
315 // 167 * is found in the lookup table. Instead, default battery data will be used.
\r
318 RSEG CODE:CODE:NOROOT(1)
\r
319 // 169 unsigned char BatteryStatusRefresh(void)
\r
320 BatteryStatusRefresh:
\r
322 RCALL ?PROLOGUE4_L09
\r
323 // 171 // Assume the worst..
\r
324 // 172 unsigned char success = FALSE;
\r
327 // 174 BattData.Present = FALSE;
\r
328 LDI R30, LOW(BattData)
\r
329 LDI R31, (BattData) >> 8
\r
333 // 175 BattData.Charged = FALSE;
\r
334 LDI R30, LOW(BattData)
\r
335 LDI R31, (BattData) >> 8
\r
339 // 176 BattData.Low = TRUE;
\r
340 LDI R30, LOW(BattData)
\r
341 LDI R31, (BattData) >> 8
\r
345 // 177 BattData.Circuit = OW_NONE;
\r
347 STS (BattData + 1), R16
\r
348 // 178 BattData.Temperature = 0;
\r
350 STS (BattData + 2), R16
\r
351 // 179 BattData.Capacity = 0;
\r
354 LDI R30, LOW(BattData)
\r
355 LDI R31, (BattData) >> 8
\r
358 // 180 BattData.MaxCurrent = 0;
\r
361 LDI R30, LOW(BattData)
\r
362 LDI R31, (BattData) >> 8
\r
365 // 181 BattData.MaxTime = 0;
\r
368 LDI R30, LOW(BattData)
\r
369 LDI R31, (BattData) >> 8
\r
372 // 182 BattData.MinCurrent = 0;
\r
375 LDI R30, LOW(BattData)
\r
376 LDI R31, (BattData) >> 8
\r
380 // 184 NTCLookUp();
\r
382 // 185 BattData.HasRID = RIDLookUp();
\r
386 LDI R30, LOW(BattData)
\r
387 LDI R31, (BattData) >> 8
\r
395 // 187 // Is the battery voltage above minimum safe cell voltage?
\r
396 // 188 if (ADCS.VBAT >= BAT_VOLTAGE_MIN) {
\r
398 LDI R31, (ADCS) >> 8
\r
404 BRCS ??BatteryStatusRefresh_0
\r
405 // 189 BattData.Low = FALSE;
\r
406 LDI R30, LOW(BattData)
\r
407 LDI R31, (BattData) >> 8
\r
413 // 192 // Is the battery charged?
\r
414 // 193 if (ADCS.VBAT >= BAT_VOLTAGE_LOW) {
\r
415 ??BatteryStatusRefresh_0:
\r
417 LDI R31, (ADCS) >> 8
\r
423 BRCS ??BatteryStatusRefresh_1
\r
424 // 194 BattData.Charged = TRUE;
\r
425 LDI R30, LOW(BattData)
\r
426 LDI R31, (BattData) >> 8
\r
432 // 197 // If we are not charging, yet VBAT is above safe limit, battery is present.
\r
433 // 198 // If we are charging and there's a current flowing, the battery is present.
\r
435 // 200 /*! \todo If ABORT_IF_PWM_MAX is defined this last check battery presence
\r
436 // 201 * check is redundant since charging will be aborted due to low current at
\r
437 // 202 * max duty cycle. That is preferrable since the charge current reading is
\r
438 // 203 * not 100% proof.
\r
440 // 205 if (((OCR1B == 0) && (!BattData.Low)) ||
\r
441 // 206 ((OCR1B != 0) && (ADCS.avgIBAT > 0))) {
\r
442 ??BatteryStatusRefresh_1:
\r
445 BRNE ??BatteryStatusRefresh_2
\r
446 LDI R30, LOW(BattData)
\r
447 LDI R31, (BattData) >> 8
\r
450 RJMP ??BatteryStatusRefresh_3
\r
451 ??BatteryStatusRefresh_2:
\r
454 BREQ ??BatteryStatusRefresh_4
\r
455 LDI R26, LOW((ADCS + 22))
\r
456 LDI R27, HIGH((ADCS + 22))
\r
461 BRLT ??BatteryStatusRefresh_4
\r
462 // 207 BattData.Present = TRUE;
\r
463 ??BatteryStatusRefresh_3:
\r
464 LDI R30, LOW(BattData)
\r
465 LDI R31, (BattData) >> 8
\r
469 // 208 success = TRUE;
\r
471 RJMP ??BatteryStatusRefresh_5
\r
473 // 210 BattData.Low = FALSE; // (This is just a technicality..)
\r
474 ??BatteryStatusRefresh_4:
\r
475 LDI R30, LOW(BattData)
\r
476 LDI R31, (BattData) >> 8
\r
480 // 211 success = FALSE;
\r
484 // 214 #ifndef ALLOW_NO_RID
\r
485 // 215 // Return FALSE if no valid RID entry was found, to stop charging.
\r
486 // 216 if(!BattData.HasRID) {
\r
487 ??BatteryStatusRefresh_5:
\r
488 LDI R30, LOW(BattData)
\r
489 LDI R31, (BattData) >> 8
\r
492 // 217 success = FALSE;
\r
497 // 221 return(success);
\r
498 ??BatteryStatusRefresh_6:
\r
501 RJMP ?EPILOGUE_B4_L09
\r
506 // 225 /*! \brief Refreshes battery data in the EEPROM
\r
508 // 227 * Attempts to read 4 pages of 32 bytes each from the battery's EPROM and store
\r
509 // 228 * these data in on-chip EEPROM.\n
\r
510 // 229 * If unsuccessful (CRC doesn't check out), the on-chip EEPROM is cleared.
\r
512 // 231 * \todo Updating BattData with these data. Specs needed.
\r
514 // 233 * \retval FALSE Refresh failed.
\r
515 // 234 * \retval TRUE Refresh successful.
\r
518 RSEG CODE:CODE:NOROOT(1)
\r
519 // 236 unsigned char BatteryDataRefresh(void)
\r
520 BatteryDataRefresh:
\r
522 RCALL ?PROLOGUE8_L09
\r
523 REQUIRE ?Register_R4_is_cg_reg
\r
524 REQUIRE ?Register_R5_is_cg_reg
\r
525 REQUIRE ?Register_R6_is_cg_reg
\r
526 REQUIRE ?Register_R7_is_cg_reg
\r
527 // 238 unsigned char offset;
\r
528 // 239 unsigned char i, crc, family, temp, page;
\r
529 // 240 unsigned char success;
\r
531 // 242 // Look for EPROM and read 4 pages of 32 bytes each worth of data, if found.
\r
532 // 243 for (page = 0; page < 4; page++) {
\r
534 ??BatteryDataRefresh_0:
\r
537 RJMP ??BatteryDataRefresh_1
\r
538 // 244 success = FALSE;
\r
541 // 246 if (OWI_DetectPresence(OWIBUS) == OWIBUS) {
\r
543 RCALL OWI_DetectPresence
\r
546 RJMP ??BatteryDataRefresh_2
\r
548 // 248 // Presence detected, check type and CRC.
\r
549 // 249 OWI_SendByte(OWI_ROM_READ, OWIBUS);
\r
553 // 250 family = OWI_ReceiveByte(OWIBUS);
\r
555 RCALL OWI_ReceiveByte
\r
557 // 251 crc = OWI_ComputeCRC8(family,0);
\r
560 RCALL OWI_ComputeCRC8
\r
563 // 253 for (i = 0; i < 6; i++) {
\r
565 ??BatteryDataRefresh_3:
\r
567 BRCC ??BatteryDataRefresh_4
\r
568 // 254 crc = OWI_ComputeCRC8(OWI_ReceiveByte(OWIBUS),crc);
\r
570 RCALL OWI_ReceiveByte
\r
572 RCALL OWI_ComputeCRC8
\r
576 RJMP ??BatteryDataRefresh_3
\r
578 // 257 // CRC ok, device found.
\r
579 // 258 if (OWI_ComputeCRC8(OWI_ReceiveByte(OWIBUS),crc) == 0) {
\r
580 ??BatteryDataRefresh_4:
\r
582 RCALL OWI_ReceiveByte
\r
584 RCALL OWI_ComputeCRC8
\r
587 RJMP ??BatteryDataRefresh_2
\r
588 // 259 BattData.Circuit = family;
\r
589 STS (BattData + 1), R6
\r
591 // 261 // For now, we only read data from DS2505 EPROMs.
\r
592 // 262 if (BattData.Circuit == OW_DS2505) {
\r
593 LDS R16, (BattData + 1)
\r
596 RJMP ??BatteryDataRefresh_2
\r
597 // 263 offset = page*32;
\r
603 // 264 OWI_SendByte(DS2505_DATA_READ, OWIBUS); // Command: read data.
\r
607 // 265 OWI_SendByte(offset, OWIBUS); // Data: low address.
\r
611 // 266 OWI_SendByte(0, OWIBUS); // Data: high address.
\r
616 // 268 // Calculate checksums.
\r
617 // 269 crc = OWI_ComputeCRC8(DS2505_DATA_READ,0);
\r
620 RCALL OWI_ComputeCRC8
\r
622 // 270 crc = OWI_ComputeCRC8(offset,crc);
\r
625 RCALL OWI_ComputeCRC8
\r
627 // 271 crc = OWI_ComputeCRC8(0,crc);
\r
630 RCALL OWI_ComputeCRC8
\r
633 // 273 // Command received succesfully, now start reading data
\r
634 // 274 // and writing it to EEPROM.
\r
635 // 275 if (OWI_ComputeCRC8(OWI_ReceiveByte(OWIBUS),crc) == 0) {
\r
637 RCALL OWI_ReceiveByte
\r
639 RCALL OWI_ComputeCRC8
\r
641 BRNE ??BatteryDataRefresh_2
\r
645 // 278 // Fill page with data.
\r
646 // 279 for (i=0; i<32; i++) {
\r
648 ??BatteryDataRefresh_5:
\r
650 BRCC ??BatteryDataRefresh_6
\r
651 // 280 temp = OWI_ReceiveByte(OWIBUS);
\r
653 RCALL OWI_ReceiveByte
\r
655 // 281 crc = OWI_ComputeCRC8(temp, crc);
\r
658 RCALL OWI_ComputeCRC8
\r
660 // 282 BattEEPROM[page][i] = temp;
\r
666 LDI R20, LOW(BattEEPROM)
\r
667 LDI R21, (BattEEPROM) >> 8
\r
678 RJMP ??BatteryDataRefresh_5
\r
680 // 285 if (OWI_ComputeCRC8(OWI_ReceiveByte(OWIBUS),crc) == 0) {
\r
681 ??BatteryDataRefresh_6:
\r
683 RCALL OWI_ReceiveByte
\r
685 RCALL OWI_ComputeCRC8
\r
687 BRNE ??BatteryDataRefresh_2
\r
688 // 286 success = TRUE; // Data read OK
\r
691 // 288 } else { // Not able to start reading data.
\r
693 // 290 } else { // Wrong device type.
\r
695 // 292 } else { // No device found.
\r
697 // 294 } else { // No presence detected on one-wire bus.
\r
700 // 297 // Erase local EEPROM page if there were any errors during transfer.
\r
701 // 298 if (!success) {
\r
702 ??BatteryDataRefresh_2:
\r
704 BRNE ??BatteryDataRefresh_7
\r
705 // 299 for (i=0; i<32; i++) {
\r
707 ??BatteryDataRefresh_8:
\r
709 BRCC ??BatteryDataRefresh_7
\r
710 // 300 BattEEPROM[page][i] = 0;
\r
717 LDI R20, LOW(BattEEPROM)
\r
718 LDI R21, (BattEEPROM) >> 8
\r
729 RJMP ??BatteryDataRefresh_8
\r
732 ??BatteryDataRefresh_7:
\r
734 RJMP ??BatteryDataRefresh_0
\r
736 // 305 return(success);
\r
737 ??BatteryDataRefresh_1:
\r
740 RJMP ?EPILOGUE_B8_L09
\r
744 // 309 /*! \brief Enables specified battery
\r
746 // 311 * Updates \ref BattActive to specified battery, then sets PB4/PB5 and clears
\r
747 // 312 * PB5/PB4 in PORTB, depending on which battery is specified.\n
\r
748 // 313 * The function takes 100 ms to allow the port switch to settle.
\r
750 // 315 * \param bat Specifies which battery to enable (0 = battery A, 1 = B)
\r
753 RSEG CODE:CODE:NOROOT(1)
\r
754 // 317 void EnableBattery(unsigned char bat)
\r
759 // 319 // Use general timer, set timeout to 100ms.
\r
760 // 320 Time_Set(TIMER_GEN,0,0,100);
\r
768 // 322 // Set specified battery as the active one.
\r
769 // 323 BattActive = bat;
\r
770 STS BattActive, R24
\r
772 // 325 // Enable current battery in hardware, light LED & connect battery.
\r
773 // 326 PORTB |= (1 << (PB4+bat));
\r
783 // 328 // Disconnect other battery.
\r
784 // 329 PORTB &= ~(1<<(PB5-bat));
\r
795 // 331 do { // Let port switch settle.
\r
796 // 332 } while (Time_Left(TIMER_GEN));
\r
801 BRNE ??EnableBattery_0
\r
808 // 336 /*! \brief Disables both batteries
\r
810 // 338 * Clears PB4 and PB5 in PORTB, disabling both batteries.
\r
813 RSEG CODE:CODE:NOROOT(1)
\r
814 // 340 void DisableBatteries(void)
\r
817 // 342 // Turn off LEDs and disconnect batteries.
\r
818 // 343 PORTB &= ~((1<<PB4)|(1<<PB5));
\r
827 // 347 /*! \brief Looks up battery data from RID table
\r
829 // 349 * Attempts to find data for the battery from the RID lookup-table.\n
\r
830 // 350 * If no valid entry is found, default data (defined in battery.h)
\r
833 // 353 * \retval TRUE Entry found, battery data updated.
\r
834 // 354 * \retval FALSE No entry found, using defaults for battery data.
\r
837 RSEG CODE:CODE:NOROOT(1)
\r
838 // 356 unsigned char RIDLookUp (void)
\r
841 RCALL ?PROLOGUE4_L09
\r
842 // 358 unsigned char i, found = FALSE;
\r
845 // 360 // Lookup in the RID-table. If measured RID is within the limits
\r
846 // 361 // of an entry, those data are used, and TRUE is returned.
\r
847 // 362 for (i = 0 ; i < RID_TABLE_SIZE; i++) {
\r
853 // 363 if (ADCS.rawRID >= RID[i].Low) {
\r
855 LDI R31, (ADCS) >> 8
\r
863 MOVW R31:R30, R17:R16
\r
864 SUBI R30, LOW((-(RID) & 0xFFFF))
\r
865 SBCI R31, (-(RID) & 0xFFFF) >> 8
\r
872 // 364 if (ADCS.rawRID <= RID[i].High) {
\r
878 MOVW R31:R30, R17:R16
\r
879 SUBI R30, LOW((-(RID) & 0xFFFF))
\r
880 SBCI R31, (-(RID) & 0xFFFF) >> 8
\r
884 LDI R31, (ADCS) >> 8
\r
890 // 365 BattData.Capacity = RID[i].Capacity;
\r
896 MOVW R31:R30, R17:R16
\r
897 SUBI R30, LOW((-(RID) & 0xFFFF))
\r
898 SBCI R31, (-(RID) & 0xFFFF) >> 8
\r
901 LDI R30, LOW(BattData)
\r
902 LDI R31, (BattData) >> 8
\r
905 // 366 BattData.MaxCurrent = RID[i].Icharge;
\r
911 MOVW R31:R30, R17:R16
\r
912 SUBI R30, LOW((-(RID) & 0xFFFF))
\r
913 SBCI R31, (-(RID) & 0xFFFF) >> 8
\r
916 LDI R30, LOW(BattData)
\r
917 LDI R31, (BattData) >> 8
\r
920 // 367 BattData.MaxTime = RID[i].tCutOff;
\r
926 MOVW R31:R30, R17:R16
\r
927 SUBI R30, LOW((-(RID) & 0xFFFF))
\r
928 SBCI R31, (-(RID) & 0xFFFF) >> 8
\r
931 LDI R30, LOW(BattData)
\r
932 LDI R31, (BattData) >> 8
\r
935 // 368 BattData.MinCurrent = RID[i].ICutOff;
\r
941 MOVW R31:R30, R17:R16
\r
942 SUBI R30, LOW((-(RID) & 0xFFFF))
\r
943 SBCI R31, (-(RID) & 0xFFFF) >> 8
\r
946 LDI R30, LOW(BattData)
\r
947 LDI R31, (BattData) >> 8
\r
951 // 370 found = TRUE;
\r
960 // 375 // If no valid entry is found, use defaults and return FALSE.
\r
961 // 376 if (!found) {
\r
965 // 377 BattData.Capacity = DEF_BAT_CAPACITY;
\r
968 LDI R30, LOW(BattData)
\r
969 LDI R31, (BattData) >> 8
\r
972 // 378 BattData.MaxCurrent = DEF_BAT_CURRENT_MAX;
\r
975 LDI R30, LOW(BattData)
\r
976 LDI R31, (BattData) >> 8
\r
979 // 379 BattData.MaxTime = DEF_BAT_TIME_MAX;
\r
982 LDI R30, LOW(BattData)
\r
983 LDI R31, (BattData) >> 8
\r
986 // 380 BattData.MinCurrent = DEF_BAT_CURRENT_MIN;
\r
989 LDI R30, LOW(BattData)
\r
990 LDI R31, (BattData) >> 8
\r
995 // 383 return(found);
\r
999 RJMP ?EPILOGUE_B4_L09
\r
1003 // 387 /*! \brief Calculates temperature from a lookup table
\r
1005 // 389 * Looks up the highest NTC value below or equal to the measured one.\n
\r
1006 // 390 * With the current lookup table, temperature is calculated with the formula:\n
\r
1007 // 391 * 4*(index of entry) - 2*(measured NTC - NTC from entry) / (ADCsteps of entry)
\r
1009 // 393 * \note If the NTC-measurement is saturated, with the current lookup table,
\r
1010 // 394 * the temperature will be reported as -1 C.
\r
1012 // 396 * \note If no valid entry is found, battery temperature is set to 80.
\r
1015 RSEG CODE:CODE:NOROOT(1)
\r
1016 // 398 void NTCLookUp (void)
\r
1019 RCALL ?PROLOGUE4_L09
\r
1020 // 400 unsigned char i;
\r
1021 // 401 unsigned char found = FALSE;
\r
1024 // 403 // Lookup in the NTC-table. Use the first entry which is equal or below
\r
1025 // 404 // sampled NTC. Calculate temperature by using the index number, and the
\r
1026 // 405 // difference between the measured NTC value and the one in the entry.
\r
1027 // 406 for (i=0 ; (i < NTC_TABLE_SIZE) && (!found); i++) {
\r
1032 RJMP ??NTCLookUp_1
\r
1035 RJMP ??NTCLookUp_1
\r
1036 // 407 if (ADCS.rawNTC >= NTC[i].ADC) {
\r
1037 LDI R30, LOW(ADCS)
\r
1038 LDI R31, (ADCS) >> 8
\r
1046 MOVW R31:R30, R17:R16
\r
1047 SUBI R30, LOW((-(NTC) & 0xFFFF))
\r
1048 SBCI R31, (-(NTC) & 0xFFFF) >> 8
\r
1053 BRCS ??NTCLookUp_2
\r
1054 // 408 BattData.Temperature = (i<<2) ;
\r
1058 STS (BattData + 2), R16
\r
1059 // 409 BattData.ADCSteps = NTC[i].ADCsteps;
\r
1065 MOVW R31:R30, R17:R16
\r
1066 SUBI R30, LOW((-(NTC) & 0xFFFF))
\r
1067 SBCI R31, (-(NTC) & 0xFFFF) >> 8
\r
1069 STS (BattData + 3), R16
\r
1070 // 410 BattData.Temperature -= ((ADCS.rawNTC - NTC[i].ADC)<<1) / BattData.ADCSteps;
\r
1071 LDI R30, LOW(ADCS)
\r
1072 LDI R31, (ADCS) >> 8
\r
1080 MOVW R31:R30, R17:R16
\r
1081 SUBI R30, LOW((-(NTC) & 0xFFFF))
\r
1082 SBCI R31, (-(NTC) & 0xFFFF) >> 8
\r
1089 MOVW R17:R16, R27:R26
\r
1090 LDS R20, (BattData + 3)
\r
1092 RCALL ?US_DIVMOD_L02
\r
1093 LDI R30, LOW(BattData)
\r
1094 LDI R31, (BattData) >> 8
\r
1099 // 412 found = TRUE; // Could be done with a break, but that violates MISRA.
\r
1105 RJMP ??NTCLookUp_0
\r
1107 // 416 // For safety, is temperature is greater than the NTC
\r
1108 // 417 if (!found) {
\r
1111 BRNE ??NTCLookUp_3
\r
1112 // 418 BattData.Temperature = 80;
\r
1114 STS (BattData + 2), R16
\r
1119 RJMP ?EPILOGUE_B4_L09
\r
1121 ASEGN ABSOLUTE:DATA:NOROOT,01cH
\r
1124 ASEGN ABSOLUTE:DATA:NOROOT,01dH
\r
1127 ASEGN ABSOLUTE:DATA:NOROOT,01eH
\r
1130 ASEGN ABSOLUTE:DATA:NOROOT,01fH
\r
1133 RSEG INITTAB:CODE:NOROOT(0)
\r
1134 `?<Segment init: NEAR_Z>`:
\r
1135 DW SFE(NEAR_Z) - SFB(NEAR_Z)
\r
1138 REQUIRE ?need_segment_init
\r
1140 RSEG NEAR_ID:CODE:NOROOT(0)
\r
1141 `?<Initializer for RID>`:
\r
1142 DW 558, 659, 3900, 550, 260, 300, 10, 744, 843, 6800, 750, 360, 300, 14
\r
1143 DW 869, 958, 10000, 1000, 475, 300, 19, 1097, 1153, 24000, 2000, 475
\r
1146 RSEG INITTAB:CODE:NOROOT(0)
\r
1147 `?<Segment init: NEAR_I>`:
\r
1148 DW SFE(NEAR_I) - SFB(NEAR_I)
\r
1151 REQUIRE ?need_segment_init
\r
1153 RSEG NEAR_ID:CODE:NOROOT(0)
\r
1154 `?<Initializer for NTC>`:
\r
1198 // 2 bytes in segment ABSOLUTE
\r
1199 // 1 064 bytes in segment CODE
\r
1200 // 130 bytes in segment EEPROM_I
\r
1201 // 12 bytes in segment INITTAB
\r
1202 // 116 bytes in segment NEAR_I
\r
1203 // 116 bytes in segment NEAR_ID
\r
1204 // 13 bytes in segment NEAR_Z
\r
1206 // 1 180 bytes of CODE memory (+ 12 bytes shared)
\r
1207 // 129 bytes of DATA memory (+ 2 bytes shared)
\r
1208 // 130 bytes of XDATA memory
\r