############################################################################### # # # IAR Atmel AVR C/C++ Compiler V4.30F/W32 13/Mar/2008 04:52:01 # # Copyright 1996-2007 IAR Systems. All rights reserved. # # # # Source file = C:\home\kevin\pub\src\bc100\IAR\statefunc.c # # Command line = C:\home\kevin\pub\src\bc100\IAR\statefunc.c # # --cpu=tiny861 -ms -o C:\home\kevin\pub\src\bc10 # # 0\IAR\Release\Obj\ -D NDEBUG -lCN # # C:\home\kevin\pub\src\bc100\IAR\Release\List\ # # -lB C:\home\kevin\pub\src\bc100\IAR\Release\Lis # # t\ --initializers_in_flash -s9 --no_cross_call # # --no_tbaa -DENABLE_BIT_DEFINITIONS -e -I # # "C:\Program Files\IAR Systems\Embedded # # Workbench 4.0\avr\INC\" -I "C:\Program # # Files\IAR Systems\Embedded Workbench # # 4.0\avr\INC\CLIB\" --eeprom_size 512 # # --misrac=5-9,11-12,14,16-17,19-21,24-26,29-32, # # 34-35,38-39,42-43,46,50,52-54,56-59,61-62, # # 64-65,68-80,83-84,87-91,94-95,98-100,103-110, # # 112-126 # # Enabled MISRA C rules = 5-9,11-12,14,16-17,19-21,24-26,29-32,34-35, # # 38-39,42-43,46,50,52-54,56-59,61-62,64-65, # # 68-80,83-84,87-91,94-95,98-100,103-110,112-126 # # Checked = 5,7-9,11-12,14,17,19-21,24,29-32,34-35,38-39, # # 42,46,50,52-54,56-59,61-62,64,68-69,71-80, # # 83-84,87-89,91,94-95,98,100,104-105,108-109, # # 112-115,118-126 # # Not checked = 6,16,25-26,43,65,70,90,99,103,106-107,110, # # 116-117 # # List file = C:\home\kevin\pub\src\bc100\IAR\Release\List\st # # atefunc.lst # # Object file = C:\home\kevin\pub\src\bc100\IAR\Release\Obj\sta # # tefunc.r90 # # # # # ############################################################################### C:\home\kevin\pub\src\bc100\IAR\statefunc.c 1 /* This file has been prepared for Doxygen automatic documentation generation.*/ 2 /*! \file ********************************************************************* 3 * 4 * \brief 5 * State functions 6 * 7 * Contains the functions related to the states defined in menu.h.\n 8 * Also contains related functions, i.e. for checking jumpers, setting 9 * error flags and "dozing". 10 * 11 * \note The state function Charge() is in a separate file since it 12 * should easily be changed with regard to battery type. 13 * 14 * \par Application note: 15 * AVR458: Charging Li-Ion Batteries with BC100 \n 16 * AVR463: Charging NiMH Batteries with BC100 17 * 18 * \par Documentation 19 * For comprehensive code documentation, supported compilers, compiler 20 * settings and supported devices see readme.html 21 * 22 * \author 23 * Atmel Corporation: http://www.atmel.com \n 24 * Support email: avr@atmel.com 25 * 26 * 27 * $Name$ 28 * $Revision: 2299 $ 29 * $RCSfile$ 30 * $URL: http://svn.norway.atmel.com/AppsAVR8/avr458_Charging_Li-Ion_Batteries_with_BC100/tag/20070904_release_1.0/code/IAR/statefunc.c $ 31 * $Date: 2007-08-23 12:55:51 +0200 (to, 23 aug 2007) $\n 32 ******************************************************************************/ 33 34 #include \ In segment ABSOLUTE, at 0x55 \ volatile __io _A_MCUCR \ _A_MCUCR: \ 00000000 DS 1 \ In segment ABSOLUTE, at 0x54 \ volatile __io _A_MCUSR \ _A_MCUSR: \ 00000000 DS 1 \ In segment ABSOLUTE, at 0x48 \ volatile __io _A_CLKPR \ _A_CLKPR: \ 00000000 DS 1 \ In segment ABSOLUTE, at 0x41 \ volatile __io _A_WDTCR \ _A_WDTCR: \ 00000000 DS 1 \ In segment ABSOLUTE, at 0x37 \ volatile __io _A_DDRB \ _A_DDRB: \ 00000000 DS 1 \ In segment ABSOLUTE, at 0x26 \ volatile __io _A_ADCSRA \ _A_ADCSRA: \ 00000000 DS 1 35 #include 36 #include 37 38 #include "structs.h" 39 #include "enums.h" 40 41 #include "ADC.h" 42 #include "statefunc.h" 43 #include "battery.h" 44 #include "charge.h" 45 #include "main.h" 46 #include "menu.h" 47 #include "OWI.h" 48 #include "PWM.h" 49 #include "time.h" 50 #include "USI.h" 51 52 53 //****************************************************************************** 54 // Variables 55 //****************************************************************************** \ In segment NEAR_Z, align 1, keep-with-next \ 00000000 REQUIRE `?` 56 unsigned char ErrorFlags; //!< \brief Holds error flags. \ ErrorFlags: \ 00000000 DS 1 57 //!< \note See statefunc.h for definitions of flags. 58 59 //! \brief Holds the state in which latest error flag was set. 60 //! \note See menu.h for definitions of states. 61 unsigned char ErrorState; \ ErrorState: \ 00000001 DS 1 62 63 64 //****************************************************************************** 65 // Functions 66 //****************************************************************************** 67 /*! \brief Initialization 68 * 69 * - Sets the system clock prescaler to 1 (run at 8 MHz) 70 * - Initializes the one-wire interface 71 * - Clears on-chip EEPROM 72 * - Sets battery enable pins as outputs, then disables batteries 73 * - Initializes SPI according to \ref SPIMODE 74 * - Initializes ADC 75 * - Initializes timers 76 * - Reads battery data from both battery inputs (via ADC) 77 * - Disables batteries again 78 * - Sets battery A as the current one (\ref BattActive = 0) 79 * - Clears ErrorFlags 80 * 81 * \param inp Not used. 82 * 83 * \retval ST_BATCON Next state in the sequence. 84 */ \ In segment CODE, align 2, keep-with-next 85 unsigned char Initialize(unsigned char inp) \ Initialize: 86 { \ 00000000 938A ST -Y, R24 87 unsigned char i, page; 88 89 // Disable interrupts while setting prescaler. 90 __disable_interrupt(); \ 00000002 94F8 CLI 91 92 CLKPR = (1< 8 MHz clock frequency. \ 00000008 E000 LDI R16, 0 \ 0000000A BD08 OUT 0x28, R16 94 95 // Init 1-Wire(R) interface. 96 OWI_Init(OWIBUS); \ 0000000C E001 LDI R16, 1 \ 0000000E .... RCALL OWI_Init 97 98 // Clear on-chip EEPROM. 99 for (page = 0; page < 4; page++) { \ 00000010 .... LDI R20, LOW(BattEEPROM) \ 00000012 .... LDI R21, (BattEEPROM) >> 8 \ 00000014 E810 LDI R17, 128 100 for (i = 0; i < 32; i++) { 101 BattEEPROM[page][i] = 0; \ ??Initialize_0: \ 00000016 E000 LDI R16, 0 \ 00000018 .... RCALL __eeput8_16 102 } \ 0000001A 5F4F SUBI R20, 255 \ 0000001C 4F5F SBCI R21, 255 103 } \ 0000001E 951A DEC R17 \ 00000020 F7D1 BRNE ??Initialize_0 104 105 DDRB = (1<> 8 \ 00000016 01AC MOVW R21:R20, R25:R24 \ 00000018 .... RCALL __eeget8_16 \ 0000001A 7001 ANDI R16, 0x01 \ 0000001C F479 BRNE ??BatteryControl_3 \ 0000001E 01AC MOVW R21:R20, R25:R24 \ 00000020 5F4F SUBI R20, 255 \ 00000022 4F5F SBCI R21, 255 \ 00000024 .... RCALL __eeget8_16 \ 00000026 7001 ANDI R16, 0x01 \ 00000028 F449 BRNE ??BatteryControl_3 156 SetErrorFlag(ERR_NO_BATTERIES_ENABLED); \ 0000002A .... LDI R30, LOW(ErrorFlags) \ 0000002C .... LDI R31, (ErrorFlags) >> 8 \ 0000002E 8100 LD R16, Z \ 00000030 6002 ORI R16, 0x02 \ 00000032 8300 ST Z, R16 \ 00000034 9100.... LDS R16, CurrentState \ 00000038 8301 STD Z+1, R16 157 158 return(ST_ERROR); \ 0000003A CFE9 RJMP ??BatteryControl_1 159 } 160 161 // Get ADC-readings, try to read EPROM, and start prequalification 162 // of any uncharged battery. 163 for (i = 0; i < 2; i++) { \ ??BatteryControl_3: \ 0000003C E0A0 LDI R26, 0 164 if (BattControl[i].Enabled) { \ ??BatteryControl_4: \ 0000003E E0B0 LDI R27, 0 \ 00000040 01AC MOVW R21:R20, R25:R24 \ 00000042 0F4A ADD R20, R26 \ 00000044 1F5B ADC R21, R27 \ 00000046 .... RCALL __eeget8_16 \ 00000048 7001 ANDI R16, 0x01 \ 0000004A F069 BREQ ??BatteryControl_5 165 EnableBattery(i); \ 0000004C 2F0A MOV R16, R26 \ 0000004E .... RCALL EnableBattery 166 ADC_Wait(); \ 00000050 .... RCALL ADC_Wait 167 168 if (BatteryStatusRefresh()) { \ 00000052 .... RCALL BatteryStatusRefresh \ 00000054 2300 TST R16 \ 00000056 F039 BREQ ??BatteryControl_5 169 if (!BattData.Charged) { \ 00000058 9100.... LDS R16, BattData \ 0000005C FD01 SBRC R16, 1 \ 0000005E C003 RJMP ??BatteryControl_5 170 BatteryDataRefresh(); \ 00000060 .... RCALL BatteryDataRefresh 171 172 return(ST_PREQUAL); \ 00000062 E10E LDI R16, 30 \ 00000064 C005 RJMP ??BatteryControl_2 173 } 174 } 175 } 176 } \ ??BatteryControl_5: \ 00000066 95A3 INC R26 \ 00000068 30A2 CPI R26, 2 \ 0000006A F348 BRCS ??BatteryControl_4 177 178 // If we end up here, one or two batteries are found and fully charged. 179 // Disconnect, so we don't drain them, and go to sleep. 180 DisableBatteries(); \ 0000006C .... RCALL DisableBatteries 181 182 return(ST_SLEEP); \ 0000006E E208 LDI R16, 40 \ ??BatteryControl_2: \ 00000070 9189 LD R24, Y+ \ 00000072 9199 LD R25, Y+ \ 00000074 91A9 LD R26, Y+ \ 00000076 91B9 LD R27, Y+ \ 00000078 9508 RET 183 } 184 185 186 /*! \brief Start running on batteries 187 * 188 * \todo Run on batteries, if battery voltage high enough. 189 * \todo Jump here when mains voltage drops below threshold 190 * 191 */ \ In segment CODE, align 2, keep-with-next 192 unsigned char Discharge(unsigned char inp) \ Discharge: 193 { 194 return(ST_BATCON); // Supply voltage restored, start charging \ 00000000 E104 LDI R16, 20 \ 00000002 9508 RET 195 } 196 197 198 /*! \brief Sleeps until either battery needs charging 199 * 200 * Calls Doze(), then refreshes the status for both batteries on wakeup. If 201 * connected batteries are both charged, the function will loop. If not, it's 202 * back to ST_BATCON. 203 * 204 * \param inp Not used. 205 * 206 * \retval ST_BATCON Next state if a connected battery isn't fully charged. 207 */ \ In segment CODE, align 2, keep-with-next 208 unsigned char Sleep(unsigned char inp) \ `Sleep`: 209 { 210 unsigned char i; 211 212 do { 213 Doze(); // Take a nap (~8 seconds). \ 00000000 .... RCALL ADC_Wait \ ??Sleep_0: \ 00000002 CFFF RJMP ??Sleep_0 \ 00000004 REQUIRE _A_MCUCR \ 00000004 REQUIRE _A_MCUSR \ 00000004 REQUIRE _A_WDTCR \ 00000004 REQUIRE _A_ADCSRA 214 215 // If any batteries need charging, go to ST_BATCON. 216 // Otherwise, keep sleeping. 217 for (i = 0; i < 2; i++) { 218 EnableBattery(i); 219 ADC_Wait(); 220 if ((BatteryStatusRefresh()) && (!BattData.Charged)) { 221 return(ST_BATCON); 222 } 223 } 224 225 DisableBatteries(); // Disable both batteries before Doze()! 226 } while (TRUE); 227 } 228 229 230 /*! \brief Doze off for approx. 8 seconds (Vcc = 5 V) 231 * 232 * Waits for ADC-cycles to complete, disables the ADC, then sleeps for 233 * approx. 8 seconds (Vcc = 5 V) using the watchdog timer. 234 * On wakeup, ADC is re-enabled. 235 */ \ In segment CODE, align 2, keep-with-next 236 void Doze(void) \ Doze: 237 { 238 // Wait for this ADC cycle to complete, then halt after the next one. 239 ADC_Wait(); \ 00000000 .... RCALL ADC_Wait 240 ADCS.Halt = TRUE; 241 ADCS.Flag = FALSE; 242 243 do { 244 } while (ADCS.Flag == FALSE); \ ??Doze_0: \ 00000002 CFFF RJMP ??Doze_0 \ 00000004 REQUIRE _A_MCUCR \ 00000004 REQUIRE _A_MCUSR \ 00000004 REQUIRE _A_WDTCR \ 00000004 REQUIRE _A_ADCSRA 245 246 WDTCR = (1<> 8 \ 00000004 8110 LD R17, Z \ 00000006 2B10 OR R17, R16 \ 00000008 8310 ST Z, R17 359 ErrorState = CurrentState; \ 0000000A 9100.... LDS R16, CurrentState \ 0000000E 8301 STD Z+1, R16 360 } \ 00000010 9508 RET 361 362 363 /*! \brief Checks on-board jumpers. 364 * 365 * Checks on-board jumpers by disconnecting all loads, engaging the PWM and 366 * increasing the duty cycle until conditioned output voltage equals conditioned 367 * input voltage. At low PWM duty and no load buck output should be zero and, 368 * when increasing PWM duty, should quickly jump to steady state output roughly 369 * equal to input voltage. Will disable and leave disabled all batteries. 370 * 371 * \retval FALSE If jumper or load mismatch. 372 * \retval TRUE If everything OK. 373 */ \ In segment CODE, align 2, keep-with-next 374 unsigned char JumperCheck(void) \ JumperCheck: 375 { \ 00000000 93BA ST -Y, R27 \ 00000002 93AA ST -Y, R26 376 DisableBatteries(); // Disconnect, or loads may be destroyed! \ 00000004 .... RCALL DisableBatteries 377 378 PWM_Start(); // Start PWM (controls the buck charger). \ 00000006 .... RCALL PWM_Start 379 380 // Use general timer: shouldn't take longer than (6 x 255) / 2500 ~= 0.62s. 381 Time_Set(TIMER_GEN,0,1,0); \ 00000008 E040 LDI R20, 0 \ 0000000A E011 LDI R17, 1 \ 0000000C E020 LDI R18, 0 \ 0000000E E030 LDI R19, 0 \ 00000010 E002 LDI R16, 2 \ 00000012 .... RCALL Time_Set \ 00000014 .... LDI R26, LOW(ADCS) \ 00000016 .... LDI R27, (ADCS) >> 8 \ 00000018 C010 RJMP ??JumperCheck_0 382 383 do { 384 // If the PWM output voltage saturates the ADC, stop PWM output and 385 // report a failure. 386 if (ADCS.rawVBAT == 1023) { 387 PWM_Stop(); 388 return(FALSE); 389 } 390 391 // If the absolute difference between measured (VIN - VBAT) and the 392 // typical value are below our set maximum, everything is OK. 393 if (abs((signed int)(ADCS.VIN - VIN_VBAT_DIFF_TYP - ADCS.VBAT)) < 394 VIN_VBAT_DIFF_MAX ) { 395 396 PWM_Stop(); 397 return(TRUE); 398 } 399 400 // Charge current is too high -> check load and jumper J405 and J406. 401 if (abs(ADCS.IBAT) > 100) { \ ??JumperCheck_1: \ 0000001A 961C ADIW R27:R26, 12 \ 0000001C 910D LD R16, X+ \ 0000001E 911C LD R17, X \ 00000020 971D SBIW R27:R26, 13 \ 00000022 .... RCALL abs \ 00000024 3605 CPI R16, 101 \ 00000026 4010 SBCI R17, 0 \ 00000028 F47C BRGE ??JumperCheck_2 402 PWM_Stop(); 403 return(FALSE); 404 } 405 406 // If the PWM output can't be increased high enough -> check jumpers 407 // J400-J404, J407 and J408. 408 if (!PWM_IncrementDutyCycle()) { \ 0000002A .... RCALL PWM_IncrementDutyCycle \ 0000002C 2300 TST R16 \ 0000002E F061 BREQ ??JumperCheck_2 409 PWM_Stop(); 410 return(FALSE); 411 } 412 413 // Wait for ADC conversions to complete 414 ADC_Wait(); \ 00000030 .... RCALL ADC_Wait 415 } while (Time_Left(TIMER_GEN)); \ 00000032 E002 LDI R16, 2 \ 00000034 .... RCALL Time_Left \ 00000036 2300 TST R16 \ 00000038 F039 BREQ ??JumperCheck_2 \ ??JumperCheck_0: \ 0000003A 9616 ADIW R27:R26, 6 \ 0000003C 910D LD R16, X+ \ 0000003E 911C LD R17, X \ 00000040 9717 SBIW R27:R26, 7 \ 00000042 3F0F CPI R16, 255 \ 00000044 4013 SBCI R17, 3 \ 00000046 F419 BRNE ??JumperCheck_3 \ ??JumperCheck_2: \ 00000048 .... RCALL PWM_Stop \ 0000004A E000 LDI R16, 0 \ 0000004C C010 RJMP ??JumperCheck_4 \ ??JumperCheck_3: \ 0000004E 9618 ADIW R27:R26, 8 \ 00000050 910D LD R16, X+ \ 00000052 911D LD R17, X+ \ 00000054 5508 SUBI R16, 88 \ 00000056 4012 SBCI R17, 2 \ 00000058 912D LD R18, X+ \ 0000005A 913C LD R19, X \ 0000005C 971B SBIW R27:R26, 11 \ 0000005E 1B02 SUB R16, R18 \ 00000060 0B13 SBC R17, R19 \ 00000062 .... RCALL abs \ 00000064 3F04 CPI R16, 244 \ 00000066 4011 SBCI R17, 1 \ 00000068 F6C4 BRGE ??JumperCheck_1 \ 0000006A .... RCALL PWM_Stop \ 0000006C E001 LDI R16, 1 \ ??JumperCheck_4: \ 0000006E 91A9 LD R26, Y+ \ 00000070 91B9 LD R27, Y+ \ 00000072 9508 RET 416 417 418 // If we end up here, the measurements took too long. 419 PWM_Stop(); 420 return(FALSE); 421 } Maximum stack usage in bytes: Function CSTACK RSTACK -------- ------ ------ BatteryControl 4 4 -> JumperCheck 4 2 -> EnableBattery 4 2 -> ADC_Wait 4 2 -> BatteryStatusRefresh 4 2 -> BatteryDataRefresh 4 2 -> DisableBatteries 4 2 Discharge 0 2 Doze 0 2 -> ADC_Wait 0 2 Error 0 2 -> PWM_Stop 0 2 -> DisableBatteries 0 2 -> ADC_Wait 0 2 Initialize 1 4 -> OWI_Init 1 2 -> DisableBatteries 1 2 -> SPI_Init 1 2 -> ADC_Init 1 2 -> Time_Init 1 2 -> EnableBattery 1 2 -> ADC_Wait 1 2 -> BatteryStatusRefresh 1 2 -> DisableBatteries 1 2 JumperCheck 2 2 -> DisableBatteries 2 2 -> PWM_Start 2 2 -> Time_Set 2 2 -> abs 2 2 -> PWM_IncrementDutyCycle 2 2 -> ADC_Wait 2 2 -> Time_Left 2 2 -> PWM_Stop 2 2 -> abs 2 2 -> PWM_Stop 2 2 SetErrorFlag 0 2 Sleep 0 2 -> ADC_Wait 0 2 Segment part sizes: Function/Label Bytes -------------- ----- _A_MCUCR 1 _A_MCUSR 1 _A_CLKPR 1 _A_WDTCR 1 _A_DDRB 1 _A_ADCSRA 1 ErrorFlags 2 Initialize 82 BatteryControl 122 Discharge 4 Sleep 4 Doze 4 Error 8 SetErrorFlag 18 JumperCheck 116 Others 6 6 bytes in segment ABSOLUTE 358 bytes in segment CODE 6 bytes in segment INITTAB 2 bytes in segment NEAR_Z 358 bytes of CODE memory (+ 6 bytes shared) 2 bytes of DATA memory (+ 6 bytes shared) Errors: none Warnings: none