1 ###############################################################################
\r
3 # IAR Atmel AVR C/C++ Compiler V4.30F/W32 12/Mar/2008 23:01:39 #
\r
4 # Copyright 1996-2007 IAR Systems. All rights reserved. #
\r
6 # Source file = C:\home\kevin\pub\src\bc100_cal\IAR\statefunc.c #
\r
7 # Command line = C:\home\kevin\pub\src\bc100_cal\IAR\statefunc.c #
\r
8 # --cpu=tiny861 -ms -o C:\home\kevin\pub\src\bc100_cal\IAR #
\r
9 # \Debug\Obj\ -lC C:\home\kevin\pub\src\bc100_cal\IAR\Debu #
\r
10 # g\List\ -lB C:\home\kevin\pub\src\bc100_cal\IAR\Debug\Li #
\r
11 # st\ --initializers_in_flash -z2 --no_cse --no_inline #
\r
12 # --no_code_motion --no_cross_call --no_clustering #
\r
13 # --no_tbaa --debug -DENABLE_BIT_DEFINITIONS -e #
\r
14 # --require_prototypes -I "C:\Program Files\IAR #
\r
15 # Systems\Embedded Workbench 4.0\avr\INC\" -I "C:\Program #
\r
16 # Files\IAR Systems\Embedded Workbench 4.0\avr\INC\CLIB\" #
\r
17 # --eeprom_size 512 #
\r
18 # List file = C:\home\kevin\pub\src\bc100_cal\IAR\Debug\List\statefunc #
\r
20 # Object file = C:\home\kevin\pub\src\bc100_cal\IAR\Debug\Obj\statefunc. #
\r
24 ###############################################################################
\r
26 C:\home\kevin\pub\src\bc100_cal\IAR\statefunc.c
\r
27 1 /* This file has been prepared for Doxygen automatic documentation generation.*/
\r
28 2 /*! \file *********************************************************************
\r
33 7 * Contains the functions related to the states defined in menu.h.\n
\r
34 8 * Also contains related functions, i.e. for checking jumpers, setting
\r
35 9 * error flags and "dozing".
\r
37 11 * \note The state function Charge() is in a separate file since it
\r
38 12 * should easily be changed with regard to battery type.
\r
40 14 * \par Application note:
\r
41 15 * AVR458: Charging Li-Ion Batteries with BC100 \n
\r
42 16 * AVR463: Charging NiMH Batteries with BC100
\r
44 18 * \par Documentation
\r
45 19 * For comprehensive code documentation, supported compilers, compiler
\r
46 20 * settings and supported devices see readme.html
\r
49 23 * Atmel Corporation: http://www.atmel.com \n
\r
50 24 * Support email: avr@atmel.com
\r
54 28 * $Revision: 2299 $
\r
56 30 * $URL: http://svn.norway.atmel.com/AppsAVR8/avr458_Charging_Li-Ion_Batteries_with_BC100/tag/20070904_release_1.0/code/IAR/statefunc.c $
\r
57 31 * $Date: 2007-08-23 12:55:51 +0200 (to, 23 aug 2007) $\n
\r
58 32 ******************************************************************************/
\r
60 34 #include <ioavr.h>
\r
62 \ In segment ABSOLUTE, at 0x55
\r
63 \ <unnamed> volatile __io _A_MCUCR
\r
67 \ In segment ABSOLUTE, at 0x54
\r
68 \ <unnamed> volatile __io _A_MCUSR
\r
72 \ In segment ABSOLUTE, at 0x48
\r
73 \ <unnamed> volatile __io _A_CLKPR
\r
77 \ In segment ABSOLUTE, at 0x41
\r
78 \ <unnamed> volatile __io _A_WDTCR
\r
82 \ In segment ABSOLUTE, at 0x37
\r
83 \ <unnamed> volatile __io _A_DDRB
\r
87 \ In segment ABSOLUTE, at 0x26
\r
88 \ <unnamed> volatile __io _A_ADCSRA
\r
91 35 #include <inavr.h>
\r
92 36 #include <stdlib.h>
\r
94 38 #include "structs.h"
\r
95 39 #include "enums.h"
\r
98 42 #include "statefunc.h"
\r
99 43 #include "battery.h"
\r
100 44 #include "charge.h"
\r
101 45 #include "main.h"
\r
102 46 #include "menu.h"
\r
103 47 #include "OWI.h"
\r
104 48 #include "PWM.h"
\r
105 49 #include "time.h"
\r
106 50 #include "USI.h"
\r
109 53 //******************************************************************************
\r
111 55 //******************************************************************************
\r
113 \ In segment NEAR_Z, align 1, keep-with-next
\r
114 \ 00000000 REQUIRE `?<Segment init: NEAR_Z>`
\r
115 56 unsigned char ErrorFlags; //!< \brief Holds error flags.
\r
118 57 //!< \note See statefunc.h for definitions of flags.
\r
120 59 //! \brief Holds the state in which latest error flag was set.
\r
121 60 //! \note See menu.h for definitions of states.
\r
123 \ In segment NEAR_Z, align 1, keep-with-next
\r
124 \ 00000000 REQUIRE `?<Segment init: NEAR_Z>`
\r
125 61 unsigned char ErrorState;
\r
130 64 //******************************************************************************
\r
132 66 //******************************************************************************
\r
133 67 /*! \brief Initialization
\r
135 69 * - Sets the system clock prescaler to 1 (run at 8 MHz)
\r
136 70 * - Initializes the one-wire interface
\r
137 71 * - Clears on-chip EEPROM
\r
138 72 * - Sets battery enable pins as outputs, then disables batteries
\r
139 73 * - Initializes SPI according to \ref SPIMODE
\r
140 74 * - Initializes ADC
\r
141 75 * - Initializes timers
\r
142 76 * - Reads battery data from both battery inputs (via ADC)
\r
143 77 * - Disables batteries again
\r
144 78 * - Sets battery A as the current one (\ref BattActive = 0)
\r
145 79 * - Clears ErrorFlags
\r
147 81 * \param inp Not used.
\r
149 83 * \retval ST_BATCON Next state in the sequence.
\r
152 \ In segment CODE, align 2, keep-with-next
\r
153 85 unsigned char Initialize(unsigned char inp)
\r
156 \ 00000000 .... RCALL ?PROLOGUE4_L09
\r
157 \ 00000002 2FB0 MOV R27, R16
\r
158 87 unsigned char i, page;
\r
160 89 // Disable interrupts while setting prescaler.
\r
161 90 __disable_interrupt();
\r
162 \ 00000004 94F8 CLI
\r
164 92 CLKPR = (1<<CLKPCE); // Enable CLKPS bit modification.
\r
165 \ 00000006 E800 LDI R16, 128
\r
166 \ 00000008 BD08 OUT 0x28, R16
\r
167 93 CLKPR = 0; // Set prescaler 1 => 8 MHz clock frequency.
\r
168 \ 0000000A E000 LDI R16, 0
\r
169 \ 0000000C BD08 OUT 0x28, R16
\r
171 95 // Init 1-Wire(R) interface.
\r
172 96 OWI_Init(OWIBUS);
\r
173 \ 0000000E E001 LDI R16, 1
\r
174 \ 00000010 .... RCALL OWI_Init
\r
176 98 // Clear on-chip EEPROM.
\r
177 99 for (page = 0; page < 4; page++) {
\r
178 \ 00000012 E090 LDI R25, 0
\r
180 \ 00000014 3094 CPI R25, 4
\r
181 \ 00000016 F4B8 BRCC ??Initialize_1
\r
182 100 for (i = 0; i < 32; i++) {
\r
183 \ 00000018 E080 LDI R24, 0
\r
185 \ 0000001A 3280 CPI R24, 32
\r
186 \ 0000001C F490 BRCC ??Initialize_3
\r
187 101 BattEEPROM[page][i] = 0;
\r
188 \ 0000001E E0A0 LDI R26, 0
\r
189 \ 00000020 2F49 MOV R20, R25
\r
190 \ 00000022 E050 LDI R21, 0
\r
191 \ 00000024 E200 LDI R16, 32
\r
192 \ 00000026 E010 LDI R17, 0
\r
193 \ 00000028 .... RCALL ?S_MUL_L02
\r
194 \ 0000002A .... LDI R20, LOW(BattEEPROM)
\r
195 \ 0000002C .... LDI R21, (BattEEPROM) >> 8
\r
196 \ 0000002E 0F40 ADD R20, R16
\r
197 \ 00000030 1F51 ADC R21, R17
\r
198 \ 00000032 2F08 MOV R16, R24
\r
199 \ 00000034 E010 LDI R17, 0
\r
200 \ 00000036 0F40 ADD R20, R16
\r
201 \ 00000038 1F51 ADC R21, R17
\r
202 \ 0000003A 2F0A MOV R16, R26
\r
203 \ 0000003C .... RCALL __eeput8_16
\r
205 \ 0000003E 9583 INC R24
\r
206 \ 00000040 CFEC RJMP ??Initialize_2
\r
209 \ 00000042 9593 INC R25
\r
210 \ 00000044 CFE7 RJMP ??Initialize_0
\r
212 105 DDRB = (1<<PB4) | (1<<PB5); // Set battery enable pins as outputs.
\r
214 \ 00000046 E300 LDI R16, 48
\r
215 \ 00000048 BB07 OUT 0x17, R16
\r
216 106 DisableBatteries();
\r
217 \ 0000004A .... RCALL DisableBatteries
\r
218 107 SPI_Init(SPIMODE);
\r
219 \ 0000004C E000 LDI R16, 0
\r
220 \ 0000004E .... RCALL SPI_Init
\r
222 \ 00000050 .... RCALL ADC_Init
\r
224 \ 00000052 .... RCALL Time_Init
\r
226 111 // Attempt to get ADC-readings (also gets RID-data) from both batteries.
\r
227 112 for (i = 0; i < 2; i++) {
\r
228 \ 00000054 E080 LDI R24, 0
\r
230 \ 00000056 3082 CPI R24, 2
\r
231 \ 00000058 F430 BRCC ??Initialize_5
\r
232 113 EnableBattery(i);
\r
233 \ 0000005A 2F08 MOV R16, R24
\r
234 \ 0000005C .... RCALL EnableBattery
\r
236 \ 0000005E .... RCALL ADC_Wait
\r
237 115 BatteryStatusRefresh();
\r
238 \ 00000060 .... RCALL BatteryStatusRefresh
\r
240 \ 00000062 9583 INC R24
\r
241 \ 00000064 CFF8 RJMP ??Initialize_4
\r
243 118 DisableBatteries();
\r
245 \ 00000066 .... RCALL DisableBatteries
\r
247 120 BattActive = 0; // We have to start somewhere..
\r
248 \ 00000068 E000 LDI R16, 0
\r
249 \ 0000006A 9300.... STS BattActive, R16
\r
250 121 ErrorFlags = 0;
\r
251 \ 0000006E E000 LDI R16, 0
\r
252 \ 00000070 9300.... STS ErrorFlags, R16
\r
254 123 // Init complete! Go to ST_BATCON next.
\r
255 124 return(ST_BATCON);
\r
256 \ 00000074 E104 LDI R16, 20
\r
257 \ 00000076 E0E4 LDI R30, 4
\r
258 \ 00000078 .... RJMP ?EPILOGUE_B4_L09
\r
259 \ 0000007A REQUIRE _A_CLKPR
\r
260 \ 0000007A REQUIRE _A_DDRB
\r
264 128 /*! \brief Tests jumper settings and batteries, starts charging if necessary.
\r
266 130 * First, JumperCheck() is called. If successful, the function checks if any
\r
267 131 * valid batteries are connected and attempts to charge these, if necessary.\n
\r
268 132 * If no charging is necessary, the charger goes to ST_SLEEP next.\n
\r
269 133 * ST_ERROR is next if either JumperCheck() fails or there are no valid
\r
270 134 * batteries. In this last case, the error is also flagged.
\r
272 136 * \param inp Not used.
\r
274 138 * \retval ST_ERROR Next state if either the jumper check failed, or there are
\r
275 139 * no valid batteries.
\r
276 140 * \retval ST_PREQUAL Next state if a battery is found to enabled and not fully
\r
278 142 * \retval ST_SLEEP Next state if battery/batteries are enabled and fully
\r
282 \ In segment CODE, align 2, keep-with-next
\r
283 145 unsigned char BatteryControl(unsigned char inp)
\r
286 \ 00000000 .... RCALL ?PROLOGUE3_L09
\r
287 \ 00000002 2FA0 MOV R26, R16
\r
288 147 unsigned char i;
\r
290 149 // Make sure ADC inputs are configured properly! (Will disables batteries.)
\r
291 150 if (!JumperCheck()) {
\r
292 \ 00000004 .... RCALL JumperCheck
\r
293 \ 00000006 2300 TST R16
\r
294 \ 00000008 F411 BRNE ??BatteryControl_0
\r
295 151 return(ST_ERROR); // Error. Exit before damage is done!
\r
296 \ 0000000A E50A LDI R16, 90
\r
297 \ 0000000C C02E RJMP ??BatteryControl_1
\r
300 154 // If neither battery is valid, flag error and go to error state
\r
301 155 if ((!BattControl[0].Enabled) && (!BattControl[1].Enabled)) {
\r
302 \ ??BatteryControl_0:
\r
303 \ 0000000E .... LDI R20, LOW(BattControl)
\r
304 \ 00000010 .... LDI R21, (BattControl) >> 8
\r
305 \ 00000012 .... RCALL __eeget8_16
\r
306 \ 00000014 7001 ANDI R16, 0x01
\r
307 \ 00000016 2300 TST R16
\r
308 \ 00000018 F451 BRNE ??BatteryControl_2
\r
309 \ 0000001A .... LDI R20, LOW((BattControl + 1))
\r
310 \ 0000001C .... LDI R21, HIGH((BattControl + 1))
\r
311 \ 0000001E .... RCALL __eeget8_16
\r
312 \ 00000020 7001 ANDI R16, 0x01
\r
313 \ 00000022 2300 TST R16
\r
314 \ 00000024 F421 BRNE ??BatteryControl_2
\r
315 156 SetErrorFlag(ERR_NO_BATTERIES_ENABLED);
\r
316 \ 00000026 E002 LDI R16, 2
\r
317 \ 00000028 .... RCALL SetErrorFlag
\r
319 158 return(ST_ERROR);
\r
320 \ 0000002A E50A LDI R16, 90
\r
321 \ 0000002C C01E RJMP ??BatteryControl_1
\r
324 161 // Get ADC-readings, try to read EPROM, and start prequalification
\r
325 162 // of any uncharged battery.
\r
326 163 for (i = 0; i < 2; i++) {
\r
327 \ ??BatteryControl_2:
\r
328 \ 0000002E E080 LDI R24, 0
\r
329 \ ??BatteryControl_3:
\r
330 \ 00000030 3082 CPI R24, 2
\r
331 \ 00000032 F4C8 BRCC ??BatteryControl_4
\r
332 164 if (BattControl[i].Enabled) {
\r
333 \ 00000034 E090 LDI R25, 0
\r
334 \ 00000036 .... LDI R20, LOW(BattControl)
\r
335 \ 00000038 .... LDI R21, (BattControl) >> 8
\r
336 \ 0000003A 0F48 ADD R20, R24
\r
337 \ 0000003C 1F59 ADC R21, R25
\r
338 \ 0000003E .... RCALL __eeget8_16
\r
339 \ 00000040 7001 ANDI R16, 0x01
\r
340 \ 00000042 2300 TST R16
\r
341 \ 00000044 F071 BREQ ??BatteryControl_5
\r
342 165 EnableBattery(i);
\r
343 \ 00000046 2F08 MOV R16, R24
\r
344 \ 00000048 .... RCALL EnableBattery
\r
346 \ 0000004A .... RCALL ADC_Wait
\r
348 168 if (BatteryStatusRefresh()) {
\r
349 \ 0000004C .... RCALL BatteryStatusRefresh
\r
350 \ 0000004E 2300 TST R16
\r
351 \ 00000050 F041 BREQ ??BatteryControl_5
\r
352 169 if (!BattData.Charged) {
\r
353 \ 00000052 .... LDI R30, LOW(BattData)
\r
354 \ 00000054 .... LDI R31, (BattData) >> 8
\r
355 \ 00000056 8100 LD R16, Z
\r
356 \ 00000058 FD01 SBRC R16, 1
\r
357 \ 0000005A C003 RJMP ??BatteryControl_5
\r
358 170 BatteryDataRefresh();
\r
359 \ 0000005C .... RCALL BatteryDataRefresh
\r
361 172 return(ST_PREQUAL);
\r
362 \ 0000005E E10E LDI R16, 30
\r
363 \ 00000060 C004 RJMP ??BatteryControl_1
\r
368 \ ??BatteryControl_5:
\r
369 \ 00000062 9583 INC R24
\r
370 \ 00000064 CFE5 RJMP ??BatteryControl_3
\r
372 178 // If we end up here, one or two batteries are found and fully charged.
\r
373 179 // Disconnect, so we don't drain them, and go to sleep.
\r
374 180 DisableBatteries();
\r
375 \ ??BatteryControl_4:
\r
376 \ 00000066 .... RCALL DisableBatteries
\r
378 182 return(ST_SLEEP);
\r
379 \ 00000068 E208 LDI R16, 40
\r
380 \ ??BatteryControl_1:
\r
381 \ 0000006A E0E3 LDI R30, 3
\r
382 \ 0000006C .... RJMP ?EPILOGUE_B3_L09
\r
386 186 /*! \brief Start running on batteries
\r
388 188 * \todo Run on batteries, if battery voltage high enough.
\r
389 189 * \todo Jump here when mains voltage drops below threshold
\r
393 \ In segment CODE, align 2, keep-with-next
\r
394 192 unsigned char Discharge(unsigned char inp)
\r
397 \ 00000000 2F10 MOV R17, R16
\r
398 194 return(ST_BATCON); // Supply voltage restored, start charging
\r
399 \ 00000002 E104 LDI R16, 20
\r
400 \ 00000004 9508 RET
\r
404 198 /*! \brief Sleeps until either battery needs charging
\r
406 200 * Calls Doze(), then refreshes the status for both batteries on wakeup. If
\r
407 201 * connected batteries are both charged, the function will loop. If not, it's
\r
408 202 * back to ST_BATCON.
\r
410 204 * \param inp Not used.
\r
412 206 * \retval ST_BATCON Next state if a connected battery isn't fully charged.
\r
415 \ In segment CODE, align 2, keep-with-next
\r
416 208 unsigned char Sleep(unsigned char inp)
\r
419 \ 00000000 .... RCALL ?PROLOGUE2_L09
\r
420 \ 00000002 2F90 MOV R25, R16
\r
421 210 unsigned char i;
\r
424 213 Doze(); // Take a nap (~8 seconds).
\r
426 \ 00000004 .... RCALL Doze
\r
428 215 // If any batteries need charging, go to ST_BATCON.
\r
429 216 // Otherwise, keep sleeping.
\r
430 217 for (i = 0; i < 2; i++) {
\r
431 \ 00000006 E080 LDI R24, 0
\r
433 \ 00000008 3082 CPI R24, 2
\r
434 \ 0000000A F478 BRCC ??Sleep_2
\r
435 218 EnableBattery(i);
\r
436 \ 0000000C 2F08 MOV R16, R24
\r
437 \ 0000000E .... RCALL EnableBattery
\r
439 \ 00000010 .... RCALL ADC_Wait
\r
440 220 if ((BatteryStatusRefresh()) && (!BattData.Charged)) {
\r
441 \ 00000012 .... RCALL BatteryStatusRefresh
\r
442 \ 00000014 2300 TST R16
\r
443 \ 00000016 F039 BREQ ??Sleep_3
\r
444 \ 00000018 .... LDI R30, LOW(BattData)
\r
445 \ 0000001A .... LDI R31, (BattData) >> 8
\r
446 \ 0000001C 8100 LD R16, Z
\r
447 \ 0000001E FD01 SBRC R16, 1
\r
448 \ 00000020 C002 RJMP ??Sleep_3
\r
449 221 return(ST_BATCON);
\r
450 \ 00000022 E104 LDI R16, 20
\r
451 \ 00000024 C004 RJMP ??Sleep_4
\r
453 \ 00000026 9583 INC R24
\r
454 \ 00000028 CFEF RJMP ??Sleep_1
\r
458 225 DisableBatteries(); // Disable both batteries before Doze()!
\r
460 \ 0000002A .... RCALL DisableBatteries
\r
461 226 } while (TRUE);
\r
462 \ 0000002C CFEB RJMP ??Sleep_0
\r
464 \ 0000002E E0E2 LDI R30, 2
\r
465 \ 00000030 .... RJMP ?EPILOGUE_B2_L09
\r
469 230 /*! \brief Doze off for approx. 8 seconds (Vcc = 5 V)
\r
471 232 * Waits for ADC-cycles to complete, disables the ADC, then sleeps for
\r
472 233 * approx. 8 seconds (Vcc = 5 V) using the watchdog timer.
\r
473 234 * On wakeup, ADC is re-enabled.
\r
476 \ In segment CODE, align 2, keep-with-next
\r
477 236 void Doze(void)
\r
480 238 // Wait for this ADC cycle to complete, then halt after the next one.
\r
482 \ 00000000 .... RCALL ADC_Wait
\r
483 240 ADCS.Halt = TRUE;
\r
484 \ 00000002 .... LDI R30, LOW(ADCS)
\r
485 \ 00000004 .... LDI R31, (ADCS) >> 8
\r
486 \ 00000006 8100 LD R16, Z
\r
487 \ 00000008 6800 ORI R16, 0x80
\r
488 \ 0000000A 8300 ST Z, R16
\r
489 241 ADCS.Flag = FALSE;
\r
490 \ 0000000C .... LDI R30, LOW(ADCS)
\r
491 \ 0000000E .... LDI R31, (ADCS) >> 8
\r
492 \ 00000010 8100 LD R16, Z
\r
493 \ 00000012 7D0F ANDI R16, 0xDF
\r
494 \ 00000014 8300 ST Z, R16
\r
497 244 } while (ADCS.Flag == FALSE);
\r
499 \ 00000016 .... LDI R30, LOW(ADCS)
\r
500 \ 00000018 .... LDI R31, (ADCS) >> 8
\r
501 \ 0000001A 8100 LD R16, Z
\r
502 \ 0000001C FF05 SBRS R16, 5
\r
503 \ 0000001E CFFB RJMP ??Doze_0
\r
505 246 WDTCR = (1<<WDP3)|(1<<WDP0); // 8.0 seconds at 5 volts VCC.
\r
506 \ 00000020 E201 LDI R16, 33
\r
507 \ 00000022 BD01 OUT 0x21, R16
\r
508 247 WDTCR |= (1<<WDIF)|(1<<WDIE)|(1<<WDE); // Clear flag and enable watchdog.
\r
509 \ 00000024 B501 IN R16, 0x21
\r
510 \ 00000026 6C08 ORI R16, 0xC8
\r
511 \ 00000028 BD01 OUT 0x21, R16
\r
512 248 MCUCR |= (1<<SE) | (1<<SM1)|(1<<SM0); // Sleep enable, mode = standby.
\r
513 \ 0000002A B705 IN R16, 0x35
\r
514 \ 0000002C 6308 ORI R16, 0x38
\r
515 \ 0000002E BF05 OUT 0x35, R16
\r
516 249 __sleep(); // Go to sleep, wake up by WDT.
\r
517 \ 00000030 9588 SLEEP
\r
519 251 __watchdog_reset(); // Clear watchdog reset flag.
\r
520 \ 00000032 95A8 WDR
\r
521 252 MCUSR &= ~(1<<WDRF);
\r
522 \ 00000034 B704 IN R16, 0x34
\r
523 \ 00000036 7F07 ANDI R16, 0xF7
\r
524 \ 00000038 BF04 OUT 0x34, R16
\r
525 253 WDTCR |= (1<<WDCE)|(1<<WDE); // Watchdog change enable.
\r
526 \ 0000003A B501 IN R16, 0x21
\r
527 \ 0000003C 6108 ORI R16, 0x18
\r
528 \ 0000003E BD01 OUT 0x21, R16
\r
529 254 WDTCR = 0; // Turn off watchdog.
\r
530 \ 00000040 E000 LDI R16, 0
\r
531 \ 00000042 BD01 OUT 0x21, R16
\r
533 256 ADCS.Halt = FALSE; // Enable consecutive runs of ADC.
\r
534 \ 00000044 .... LDI R30, LOW(ADCS)
\r
535 \ 00000046 .... LDI R31, (ADCS) >> 8
\r
536 \ 00000048 8100 LD R16, Z
\r
537 \ 0000004A 770F ANDI R16, 0x7F
\r
538 \ 0000004C 8300 ST Z, R16
\r
539 257 ADCSRA |= (1<<ADEN)|(1<<ADSC); // Enable ADC & start conversion.
\r
540 \ 0000004E B106 IN R16, 0x06
\r
541 \ 00000050 6C00 ORI R16, 0xC0
\r
542 \ 00000052 B906 OUT 0x06, R16
\r
544 259 // Wait for this cycle to complete.
\r
546 \ 00000054 .... RCALL ADC_Wait
\r
548 \ 00000056 9508 RET
\r
549 \ 00000058 REQUIRE _A_MCUCR
\r
550 \ 00000058 REQUIRE _A_MCUSR
\r
551 \ 00000058 REQUIRE _A_WDTCR
\r
552 \ 00000058 REQUIRE _A_ADCSRA
\r
555 264 /*! \brief Handles errors
\r
557 266 * Stops PWM output and disables batteries. The function then goes into a loop
\r
558 267 * that starts with a call to Doze(), then attempts to handle each error. The
\r
559 268 * loop will reiterate until all flags are cleared.\n
\r
560 269 * The charger will reinitialize after this.
\r
562 271 * Jumper errors are handled by clearing the flag, then calling JumperCheck().
\r
563 272 * If unsuccessful, the error flag will now have been set again.\n
\r
565 274 * If there are no valid batteries, the loop will simply reiterate until a
\r
566 275 * valid battery is found. The error flag will then be cleared.\n
\r
568 277 * In the case of PWM controller or battery temperature errors, the error
\r
569 278 * flag is simply cleared. This is because the problem may have gone away during
\r
570 279 * Doze(), or after reinitializing.\n
\r
572 281 * If a battery is exhausted, we clear its exhausted-flag in \ref BattData,
\r
573 282 * and change batteries before clearing the error flag.
\r
575 284 * \param inp Not used.
\r
578 \ In segment CODE, align 2, keep-with-next
\r
579 286 unsigned char Error(unsigned char inp)
\r
582 \ 00000000 .... RCALL ?PROLOGUE2_L09
\r
583 \ 00000002 2F90 MOV R25, R16
\r
584 288 unsigned char i;
\r
586 290 PWM_Stop(); // Stop charging.
\r
587 \ 00000004 .... RCALL PWM_Stop
\r
588 291 DisableBatteries(); // Disable all loads.
\r
589 \ 00000006 .... RCALL DisableBatteries
\r
592 294 Doze(); // Take a nap.
\r
594 \ 00000008 .... RCALL Doze
\r
596 296 // For each bit in ErrorFlags, starting with LSB, handle
\r
597 297 // associated error, if the flag is set.
\r
598 298 for (i = 0x01; i!=0; i<<=1) {
\r
599 \ 0000000A E081 LDI R24, 1
\r
601 \ 0000000C 2388 TST R24
\r
602 \ 0000000E F409 BRNE $+2+2
\r
603 \ 00000010 C057 RJMP ??Error_2
\r
604 299 if(i & ErrorFlags) {
\r
605 \ 00000012 9100.... LDS R16, ErrorFlags
\r
606 \ 00000016 2308 AND R16, R24
\r
607 \ 00000018 2300 TST R16
\r
608 \ 0000001A F409 BRNE $+2+2
\r
609 \ 0000001C C04F RJMP ??Error_3
\r
611 \ 0000001E 2F08 MOV R16, R24
\r
612 \ 00000020 5001 SUBI R16, 1
\r
613 \ 00000022 F049 BREQ ??Error_4
\r
614 \ 00000024 950A DEC R16
\r
615 \ 00000026 F081 BREQ ??Error_5
\r
616 \ 00000028 5002 SUBI R16, 2
\r
617 \ 0000002A F111 BREQ ??Error_6
\r
618 \ 0000002C 5004 SUBI R16, 4
\r
619 \ 0000002E F141 BREQ ??Error_7
\r
620 \ 00000030 5008 SUBI R16, 8
\r
621 \ 00000032 F171 BREQ ??Error_8
\r
622 \ 00000034 C043 RJMP ??Error_3
\r
624 302 case ERR_JUMPER_MISMATCH:
\r
625 303 // Clear flag & recheck.
\r
626 304 ErrorFlags &= ~i;
\r
628 \ 00000036 2F08 MOV R16, R24
\r
629 \ 00000038 9500 COM R16
\r
630 \ 0000003A .... LDI R30, LOW(ErrorFlags)
\r
631 \ 0000003C .... LDI R31, (ErrorFlags) >> 8
\r
632 \ 0000003E 8110 LD R17, Z
\r
633 \ 00000040 2310 AND R17, R16
\r
634 \ 00000042 8310 ST Z, R17
\r
636 \ 00000044 .... RCALL JumperCheck
\r
637 \ 00000046 C03A RJMP ??Error_3
\r
641 309 case ERR_NO_BATTERIES_ENABLED:
\r
642 310 // Clear if any battery gets enabled.
\r
643 311 if ((BattControl[0].Enabled) || (BattControl[1].Enabled)) {
\r
645 \ 00000048 .... LDI R20, LOW(BattControl)
\r
646 \ 0000004A .... LDI R21, (BattControl) >> 8
\r
647 \ 0000004C .... RCALL __eeget8_16
\r
648 \ 0000004E 7001 ANDI R16, 0x01
\r
649 \ 00000050 2300 TST R16
\r
650 \ 00000052 F431 BRNE ??Error_9
\r
651 \ 00000054 .... LDI R20, LOW((BattControl + 1))
\r
652 \ 00000056 .... LDI R21, HIGH((BattControl + 1))
\r
653 \ 00000058 .... RCALL __eeget8_16
\r
654 \ 0000005A 7001 ANDI R16, 0x01
\r
655 \ 0000005C 2300 TST R16
\r
656 \ 0000005E F171 BREQ ??Error_3
\r
657 312 ErrorFlags &= ~i;
\r
659 \ 00000060 2F08 MOV R16, R24
\r
660 \ 00000062 9500 COM R16
\r
661 \ 00000064 .... LDI R30, LOW(ErrorFlags)
\r
662 \ 00000066 .... LDI R31, (ErrorFlags) >> 8
\r
663 \ 00000068 8110 LD R17, Z
\r
664 \ 0000006A 2310 AND R17, R16
\r
665 \ 0000006C 8310 ST Z, R17
\r
666 \ 0000006E C026 RJMP ??Error_3
\r
671 317 case ERR_PWM_CONTROL:
\r
673 319 ErrorFlags &= ~i;
\r
675 \ 00000070 2F08 MOV R16, R24
\r
676 \ 00000072 9500 COM R16
\r
677 \ 00000074 .... LDI R30, LOW(ErrorFlags)
\r
678 \ 00000076 .... LDI R31, (ErrorFlags) >> 8
\r
679 \ 00000078 8110 LD R17, Z
\r
680 \ 0000007A 2310 AND R17, R16
\r
681 \ 0000007C 8310 ST Z, R17
\r
682 \ 0000007E C01E RJMP ??Error_3
\r
686 323 case ERR_BATTERY_TEMPERATURE:
\r
688 325 ErrorFlags &= ~i;
\r
690 \ 00000080 2F08 MOV R16, R24
\r
691 \ 00000082 9500 COM R16
\r
692 \ 00000084 .... LDI R30, LOW(ErrorFlags)
\r
693 \ 00000086 .... LDI R31, (ErrorFlags) >> 8
\r
694 \ 00000088 8110 LD R17, Z
\r
695 \ 0000008A 2310 AND R17, R16
\r
696 \ 0000008C 8310 ST Z, R17
\r
697 \ 0000008E C016 RJMP ??Error_3
\r
701 329 case ERR_BATTERY_EXHAUSTED:
\r
702 330 // Try the other battery.
\r
703 331 BattData.Exhausted = FALSE;
\r
705 \ 00000090 .... LDI R30, LOW(BattData)
\r
706 \ 00000092 .... LDI R31, (BattData) >> 8
\r
707 \ 00000094 8100 LD R16, Z
\r
708 \ 00000096 7F07 ANDI R16, 0xF7
\r
709 \ 00000098 8300 ST Z, R16
\r
710 332 BattActive = (BattActive + 1) % 2;
\r
711 \ 0000009A 91E0.... LDS R30, BattActive
\r
712 \ 0000009E E0F0 LDI R31, 0
\r
713 \ 000000A0 9631 ADIW R31:R30, 1
\r
714 \ 000000A2 018F MOVW R17:R16, R31:R30
\r
715 \ 000000A4 E042 LDI R20, 2
\r
716 \ 000000A6 E050 LDI R21, 0
\r
717 \ 000000A8 .... RCALL ?SS_DIVMOD_L02
\r
718 \ 000000AA 9340.... STS BattActive, R20
\r
719 333 ErrorFlags &= ~i;
\r
720 \ 000000AE 2F08 MOV R16, R24
\r
721 \ 000000B0 9500 COM R16
\r
722 \ 000000B2 .... LDI R30, LOW(ErrorFlags)
\r
723 \ 000000B4 .... LDI R31, (ErrorFlags) >> 8
\r
724 \ 000000B6 8110 LD R17, Z
\r
725 \ 000000B8 2310 AND R17, R16
\r
726 \ 000000BA 8310 ST Z, R17
\r
736 \ 000000BC 0F88 LSL R24
\r
737 \ 000000BE CFA6 RJMP ??Error_1
\r
738 342 } while (ErrorFlags);
\r
740 \ 000000C0 9100.... LDS R16, ErrorFlags
\r
741 \ 000000C4 2300 TST R16
\r
742 \ 000000C6 F009 BREQ $+2+2
\r
743 \ 000000C8 CF9F RJMP ??Error_0
\r
745 344 return(ST_INIT);
\r
746 \ 000000CA E00A LDI R16, 10
\r
747 \ 000000CC E0E2 LDI R30, 2
\r
748 \ 000000CE .... RJMP ?EPILOGUE_B2_L09
\r
752 348 /*! \brief Sets the specified error-flag and saves the current state
\r
754 350 * Updates \ref ErrorFlags and \ref ErrorState.
\r
756 352 * \note Error flags are specified in statefunc.h.
\r
758 354 * \param Flag Specifies what error to flag.
\r
761 \ In segment CODE, align 2, keep-with-next
\r
762 356 void SetErrorFlag(unsigned char Flag)
\r
765 358 ErrorFlags |= Flag;
\r
766 \ 00000000 .... LDI R30, LOW(ErrorFlags)
\r
767 \ 00000002 .... LDI R31, (ErrorFlags) >> 8
\r
768 \ 00000004 8110 LD R17, Z
\r
769 \ 00000006 2B10 OR R17, R16
\r
770 \ 00000008 8310 ST Z, R17
\r
771 359 ErrorState = CurrentState;
\r
772 \ 0000000A 9110.... LDS R17, CurrentState
\r
773 \ 0000000E 9310.... STS ErrorState, R17
\r
775 \ 00000012 9508 RET
\r
778 363 /*! \brief Checks on-board jumpers.
\r
780 365 * Checks on-board jumpers by disconnecting all loads, engaging the PWM and
\r
781 366 * increasing the duty cycle until conditioned output voltage equals conditioned
\r
782 367 * input voltage. At low PWM duty and no load buck output should be zero and,
\r
783 368 * when increasing PWM duty, should quickly jump to steady state output roughly
\r
784 369 * equal to input voltage. Will disable and leave disabled all batteries.
\r
786 371 * \retval FALSE If jumper or load mismatch.
\r
787 372 * \retval TRUE If everything OK.
\r
790 \ In segment CODE, align 2, keep-with-next
\r
791 374 unsigned char JumperCheck(void)
\r
794 376 DisableBatteries(); // Disconnect, or loads may be destroyed!
\r
795 \ 00000000 .... RCALL DisableBatteries
\r
797 378 PWM_Start(); // Start PWM (controls the buck charger).
\r
798 \ 00000002 .... RCALL PWM_Start
\r
800 380 // Use general timer: shouldn't take longer than (6 x 255) / 2500 ~= 0.62s.
\r
801 381 Time_Set(TIMER_GEN,0,1,0);
\r
802 \ 00000004 E040 LDI R20, 0
\r
803 \ 00000006 E011 LDI R17, 1
\r
804 \ 00000008 E020 LDI R18, 0
\r
805 \ 0000000A E030 LDI R19, 0
\r
806 \ 0000000C E002 LDI R16, 2
\r
807 \ 0000000E .... RCALL Time_Set
\r
810 384 // If the PWM output voltage saturates the ADC, stop PWM output and
\r
811 385 // report a failure.
\r
812 386 if (ADCS.rawVBAT == 1023) {
\r
814 \ 00000010 .... LDI R30, LOW(ADCS)
\r
815 \ 00000012 .... LDI R31, (ADCS) >> 8
\r
816 \ 00000014 8106 LDD R16, Z+6
\r
817 \ 00000016 8117 LDD R17, Z+7
\r
818 \ 00000018 3F0F CPI R16, 255
\r
819 \ 0000001A E023 LDI R18, 3
\r
820 \ 0000001C 0712 CPC R17, R18
\r
821 \ 0000001E F419 BRNE ??JumperCheck_1
\r
823 \ 00000020 .... RCALL PWM_Stop
\r
825 \ 00000022 E000 LDI R16, 0
\r
826 \ 00000024 9508 RET
\r
829 391 // If the absolute difference between measured (VIN - VBAT) and the
\r
830 392 // typical value are below our set maximum, everything is OK.
\r
831 393 if (abs((signed int)(ADCS.VIN - VIN_VBAT_DIFF_TYP - ADCS.VBAT)) <
\r
832 394 VIN_VBAT_DIFF_MAX ) {
\r
834 \ 00000026 .... LDI R30, LOW(ADCS)
\r
835 \ 00000028 .... LDI R31, (ADCS) >> 8
\r
836 \ 0000002A 8500 LDD R16, Z+8
\r
837 \ 0000002C 8511 LDD R17, Z+9
\r
838 \ 0000002E 5508 SUBI R16, 88
\r
839 \ 00000030 4012 SBCI R17, 2
\r
840 \ 00000032 .... LDI R30, LOW(ADCS)
\r
841 \ 00000034 .... LDI R31, (ADCS) >> 8
\r
842 \ 00000036 8522 LDD R18, Z+10
\r
843 \ 00000038 8533 LDD R19, Z+11
\r
844 \ 0000003A 1B02 SUB R16, R18
\r
845 \ 0000003C 0B13 SBC R17, R19
\r
846 \ 0000003E .... RCALL abs
\r
847 \ 00000040 3F04 CPI R16, 244
\r
848 \ 00000042 E021 LDI R18, 1
\r
849 \ 00000044 0712 CPC R17, R18
\r
850 \ 00000046 F41C BRGE ??JumperCheck_2
\r
853 \ 00000048 .... RCALL PWM_Stop
\r
855 \ 0000004A E001 LDI R16, 1
\r
856 \ 0000004C 9508 RET
\r
859 400 // Charge current is too high -> check load and jumper J405 and J406.
\r
860 401 if (abs(ADCS.IBAT) > 100) {
\r
862 \ 0000004E .... LDI R30, LOW(ADCS)
\r
863 \ 00000050 .... LDI R31, (ADCS) >> 8
\r
864 \ 00000052 8504 LDD R16, Z+12
\r
865 \ 00000054 8515 LDD R17, Z+13
\r
866 \ 00000056 .... RCALL abs
\r
867 \ 00000058 3605 CPI R16, 101
\r
868 \ 0000005A E020 LDI R18, 0
\r
869 \ 0000005C 0712 CPC R17, R18
\r
870 \ 0000005E F01C BRLT ??JumperCheck_3
\r
872 \ 00000060 .... RCALL PWM_Stop
\r
874 \ 00000062 E000 LDI R16, 0
\r
875 \ 00000064 9508 RET
\r
878 406 // If the PWM output can't be increased high enough -> check jumpers
\r
879 407 // J400-J404, J407 and J408.
\r
880 408 if (!PWM_IncrementDutyCycle()) {
\r
882 \ 00000066 .... RCALL PWM_IncrementDutyCycle
\r
883 \ 00000068 2300 TST R16
\r
884 \ 0000006A F419 BRNE ??JumperCheck_4
\r
886 \ 0000006C .... RCALL PWM_Stop
\r
888 \ 0000006E E000 LDI R16, 0
\r
889 \ 00000070 9508 RET
\r
892 413 // Wait for ADC conversions to complete
\r
895 \ 00000072 .... RCALL ADC_Wait
\r
896 415 } while (Time_Left(TIMER_GEN));
\r
897 \ 00000074 E002 LDI R16, 2
\r
898 \ 00000076 .... RCALL Time_Left
\r
899 \ 00000078 2300 TST R16
\r
900 \ 0000007A F651 BRNE ??JumperCheck_0
\r
903 418 // If we end up here, the measurements took too long.
\r
905 \ 0000007C .... RCALL PWM_Stop
\r
907 \ 0000007E E000 LDI R16, 0
\r
908 \ 00000080 9508 RET
\r
911 Maximum stack usage in bytes:
\r
913 Function CSTACK RSTACK
\r
914 -------- ------ ------
\r
917 -> SetErrorFlag 3 2
\r
918 -> EnableBattery 3 2
\r
920 -> BatteryStatusRefresh 3 2
\r
921 -> BatteryDataRefresh 3 2
\r
922 -> DisableBatteries 3 2
\r
929 -> DisableBatteries 2 2
\r
934 -> DisableBatteries 4 2
\r
938 -> EnableBattery 4 2
\r
940 -> BatteryStatusRefresh 4 2
\r
941 -> DisableBatteries 4 2
\r
943 -> DisableBatteries 0 2
\r
951 -> PWM_IncrementDutyCycle 0 2
\r
959 -> EnableBattery 2 2
\r
961 -> BatteryStatusRefresh 2 2
\r
962 -> DisableBatteries 2 2
\r
965 Segment part sizes:
\r
967 Function/Label Bytes
\r
968 -------------- -----
\r
988 6 bytes in segment ABSOLUTE
\r
989 734 bytes in segment CODE
\r
990 6 bytes in segment INITTAB
\r
991 2 bytes in segment NEAR_Z
\r
993 734 bytes of CODE memory (+ 6 bytes shared)
\r
994 2 bytes of DATA memory (+ 6 bytes shared)
\r