/////////////////////////////////////////////////////////////////////////////// // / // IAR Atmel AVR C/C++ Compiler V4.30F/W32 12/Mar/2008 23:01:39 / // Copyright 1996-2007 IAR Systems. All rights reserved. / // / // Source file = C:\home\kevin\pub\src\bc100_cal\IAR\statefunc.c / // Command line = C:\home\kevin\pub\src\bc100_cal\IAR\statefunc.c / // --cpu=tiny861 -ms -o C:\home\kevin\pub\src\bc100_cal\IA / // R\Debug\Obj\ -lC C:\home\kevin\pub\src\bc100_cal\IAR\De / // bug\List\ -lB C:\home\kevin\pub\src\bc100_cal\IAR\Debug / // \List\ --initializers_in_flash -z2 --no_cse / // --no_inline --no_code_motion --no_cross_call / // --no_clustering --no_tbaa --debug / // -DENABLE_BIT_DEFINITIONS -e --require_prototypes -I / // "C:\Program Files\IAR Systems\Embedded Workbench / // 4.0\avr\INC\" -I "C:\Program Files\IAR / // Systems\Embedded Workbench 4.0\avr\INC\CLIB\" / // --eeprom_size 512 / // List file = C:\home\kevin\pub\src\bc100_cal\IAR\Debug\List\statefun / // c.s90 / // / // / /////////////////////////////////////////////////////////////////////////////// NAME statefunc RSEG CSTACK:DATA:NOROOT(0) RSEG RSTACK:DATA:NOROOT(0) EXTERN ?EPILOGUE_B2_L09 EXTERN ?EPILOGUE_B3_L09 EXTERN ?EPILOGUE_B4_L09 EXTERN ?PROLOGUE2_L09 EXTERN ?PROLOGUE3_L09 EXTERN ?PROLOGUE4_L09 EXTERN ?SS_DIVMOD_L02 EXTERN ?S_MUL_L02 EXTERN ?need_segment_init EXTERN __eeget8_16 EXTERN __eeput8_16 PUBWEAK `?` PUBLIC BatteryControl PUBLIC Discharge PUBLIC Doze PUBLIC Error PUBLIC ErrorFlags PUBLIC ErrorState PUBLIC Initialize PUBLIC JumperCheck PUBLIC SetErrorFlag PUBLIC `Sleep` PUBWEAK _A_ADCSRA PUBWEAK _A_CLKPR PUBWEAK _A_DDRB PUBWEAK _A_MCUCR PUBWEAK _A_MCUSR PUBWEAK _A_WDTCR PUBWEAK __?EEARH PUBWEAK __?EEARL PUBWEAK __?EECR PUBWEAK __?EEDR EXTERN OWI_Init EXTERN DisableBatteries EXTERN SPI_Init EXTERN ADC_Init EXTERN Time_Init EXTERN EnableBattery EXTERN ADC_Wait EXTERN BatteryStatusRefresh EXTERN BatteryDataRefresh EXTERN PWM_Stop EXTERN PWM_Start EXTERN Time_Set EXTERN abs EXTERN PWM_IncrementDutyCycle EXTERN Time_Left EXTERN ADCS EXTERN BattActive EXTERN BattControl EXTERN BattData EXTERN BattEEPROM EXTERN CurrentState // C:\home\kevin\pub\src\bc100_cal\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 ASEGN ABSOLUTE:DATA:NOROOT,055H // volatile __io _A_MCUCR _A_MCUCR: DS 1 ASEGN ABSOLUTE:DATA:NOROOT,054H // volatile __io _A_MCUSR _A_MCUSR: DS 1 ASEGN ABSOLUTE:DATA:NOROOT,048H // volatile __io _A_CLKPR _A_CLKPR: DS 1 ASEGN ABSOLUTE:DATA:NOROOT,041H // volatile __io _A_WDTCR _A_WDTCR: DS 1 ASEGN ABSOLUTE:DATA:NOROOT,037H // volatile __io _A_DDRB _A_DDRB: DS 1 ASEGN ABSOLUTE:DATA:NOROOT,026H // volatile __io _A_ADCSRA _A_ADCSRA: 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 //****************************************************************************** RSEG NEAR_Z:DATA:NOROOT(0) REQUIRE `?` // 56 unsigned char ErrorFlags; //!< \brief Holds error flags. ErrorFlags: 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. RSEG NEAR_Z:DATA:NOROOT(0) REQUIRE `?` // 61 unsigned char ErrorState; ErrorState: 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 */ RSEG CODE:CODE:NOROOT(1) // 85 unsigned char Initialize(unsigned char inp) Initialize: // 86 { RCALL ?PROLOGUE4_L09 MOV R27, R16 // 87 unsigned char i, page; // 88 // 89 // Disable interrupts while setting prescaler. // 90 __disable_interrupt(); CLI // 91 // 92 CLKPR = (1< 8 MHz clock frequency. LDI R16, 0 OUT 0x28, R16 // 94 // 95 // Init 1-Wire(R) interface. // 96 OWI_Init(OWIBUS); LDI R16, 1 RCALL OWI_Init // 97 // 98 // Clear on-chip EEPROM. // 99 for (page = 0; page < 4; page++) { LDI R25, 0 ??Initialize_0: CPI R25, 4 BRCC ??Initialize_1 // 100 for (i = 0; i < 32; i++) { LDI R24, 0 ??Initialize_2: CPI R24, 32 BRCC ??Initialize_3 // 101 BattEEPROM[page][i] = 0; LDI R26, 0 MOV R20, R25 LDI R21, 0 LDI R16, 32 LDI R17, 0 RCALL ?S_MUL_L02 LDI R20, LOW(BattEEPROM) LDI R21, (BattEEPROM) >> 8 ADD R20, R16 ADC R21, R17 MOV R16, R24 LDI R17, 0 ADD R20, R16 ADC R21, R17 MOV R16, R26 RCALL __eeput8_16 // 102 } INC R24 RJMP ??Initialize_2 // 103 } ??Initialize_3: INC R25 RJMP ??Initialize_0 // 104 // 105 DDRB = (1<> 8 RCALL __eeget8_16 ANDI R16, 0x01 TST R16 BRNE ??BatteryControl_2 LDI R20, LOW((BattControl + 1)) LDI R21, HIGH((BattControl + 1)) RCALL __eeget8_16 ANDI R16, 0x01 TST R16 BRNE ??BatteryControl_2 // 156 SetErrorFlag(ERR_NO_BATTERIES_ENABLED); LDI R16, 2 RCALL SetErrorFlag // 157 // 158 return(ST_ERROR); LDI R16, 90 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_2: LDI R24, 0 ??BatteryControl_3: CPI R24, 2 BRCC ??BatteryControl_4 // 164 if (BattControl[i].Enabled) { LDI R25, 0 LDI R20, LOW(BattControl) LDI R21, (BattControl) >> 8 ADD R20, R24 ADC R21, R25 RCALL __eeget8_16 ANDI R16, 0x01 TST R16 BREQ ??BatteryControl_5 // 165 EnableBattery(i); MOV R16, R24 RCALL EnableBattery // 166 ADC_Wait(); RCALL ADC_Wait // 167 // 168 if (BatteryStatusRefresh()) { RCALL BatteryStatusRefresh TST R16 BREQ ??BatteryControl_5 // 169 if (!BattData.Charged) { LDI R30, LOW(BattData) LDI R31, (BattData) >> 8 LD R16, Z SBRC R16, 1 RJMP ??BatteryControl_5 // 170 BatteryDataRefresh(); RCALL BatteryDataRefresh // 171 // 172 return(ST_PREQUAL); LDI R16, 30 RJMP ??BatteryControl_1 // 173 } // 174 } // 175 } // 176 } ??BatteryControl_5: INC R24 RJMP ??BatteryControl_3 // 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(); ??BatteryControl_4: RCALL DisableBatteries // 181 // 182 return(ST_SLEEP); LDI R16, 40 ??BatteryControl_1: LDI R30, 3 RJMP ?EPILOGUE_B3_L09 // 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 */ RSEG CODE:CODE:NOROOT(1) // 192 unsigned char Discharge(unsigned char inp) Discharge: // 193 { MOV R17, R16 // 194 return(ST_BATCON); // Supply voltage restored, start charging LDI R16, 20 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 */ RSEG CODE:CODE:NOROOT(1) // 208 unsigned char Sleep(unsigned char inp) `Sleep`: // 209 { RCALL ?PROLOGUE2_L09 MOV R25, R16 // 210 unsigned char i; // 211 // 212 do { // 213 Doze(); // Take a nap (~8 seconds). ??Sleep_0: RCALL Doze // 214 // 215 // If any batteries need charging, go to ST_BATCON. // 216 // Otherwise, keep sleeping. // 217 for (i = 0; i < 2; i++) { LDI R24, 0 ??Sleep_1: CPI R24, 2 BRCC ??Sleep_2 // 218 EnableBattery(i); MOV R16, R24 RCALL EnableBattery // 219 ADC_Wait(); RCALL ADC_Wait // 220 if ((BatteryStatusRefresh()) && (!BattData.Charged)) { RCALL BatteryStatusRefresh TST R16 BREQ ??Sleep_3 LDI R30, LOW(BattData) LDI R31, (BattData) >> 8 LD R16, Z SBRC R16, 1 RJMP ??Sleep_3 // 221 return(ST_BATCON); LDI R16, 20 RJMP ??Sleep_4 ??Sleep_3: INC R24 RJMP ??Sleep_1 // 222 } // 223 } // 224 // 225 DisableBatteries(); // Disable both batteries before Doze()! ??Sleep_2: RCALL DisableBatteries // 226 } while (TRUE); RJMP ??Sleep_0 ??Sleep_4: LDI R30, 2 RJMP ?EPILOGUE_B2_L09 // 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 */ RSEG CODE:CODE:NOROOT(1) // 236 void Doze(void) Doze: // 237 { // 238 // Wait for this ADC cycle to complete, then halt after the next one. // 239 ADC_Wait(); RCALL ADC_Wait // 240 ADCS.Halt = TRUE; LDI R30, LOW(ADCS) LDI R31, (ADCS) >> 8 LD R16, Z ORI R16, 0x80 ST Z, R16 // 241 ADCS.Flag = FALSE; LDI R30, LOW(ADCS) LDI R31, (ADCS) >> 8 LD R16, Z ANDI R16, 0xDF ST Z, R16 // 242 // 243 do { // 244 } while (ADCS.Flag == FALSE); ??Doze_0: LDI R30, LOW(ADCS) LDI R31, (ADCS) >> 8 LD R16, Z SBRS R16, 5 RJMP ??Doze_0 // 245 // 246 WDTCR = (1<> 8 LD R16, Z ANDI R16, 0x7F ST Z, R16 // 257 ADCSRA |= (1<> 8 LD R17, Z AND R17, R16 ST Z, R17 // 305 JumperCheck(); RCALL JumperCheck RJMP ??Error_3 // 306 break; // 307 // 308 // 309 case ERR_NO_BATTERIES_ENABLED: // 310 // Clear if any battery gets enabled. // 311 if ((BattControl[0].Enabled) || (BattControl[1].Enabled)) { ??Error_5: LDI R20, LOW(BattControl) LDI R21, (BattControl) >> 8 RCALL __eeget8_16 ANDI R16, 0x01 TST R16 BRNE ??Error_9 LDI R20, LOW((BattControl + 1)) LDI R21, HIGH((BattControl + 1)) RCALL __eeget8_16 ANDI R16, 0x01 TST R16 BREQ ??Error_3 // 312 ErrorFlags &= ~i; ??Error_9: MOV R16, R24 COM R16 LDI R30, LOW(ErrorFlags) LDI R31, (ErrorFlags) >> 8 LD R17, Z AND R17, R16 ST Z, R17 RJMP ??Error_3 // 313 } // 314 break; // 315 // 316 // 317 case ERR_PWM_CONTROL: // 318 // Clear flag. // 319 ErrorFlags &= ~i; ??Error_6: MOV R16, R24 COM R16 LDI R30, LOW(ErrorFlags) LDI R31, (ErrorFlags) >> 8 LD R17, Z AND R17, R16 ST Z, R17 RJMP ??Error_3 // 320 break; // 321 // 322 // 323 case ERR_BATTERY_TEMPERATURE: // 324 // Clear flag. // 325 ErrorFlags &= ~i; ??Error_7: MOV R16, R24 COM R16 LDI R30, LOW(ErrorFlags) LDI R31, (ErrorFlags) >> 8 LD R17, Z AND R17, R16 ST Z, R17 RJMP ??Error_3 // 326 break; // 327 // 328 // 329 case ERR_BATTERY_EXHAUSTED: // 330 // Try the other battery. // 331 BattData.Exhausted = FALSE; ??Error_8: LDI R30, LOW(BattData) LDI R31, (BattData) >> 8 LD R16, Z ANDI R16, 0xF7 ST Z, R16 // 332 BattActive = (BattActive + 1) % 2; LDS R30, BattActive LDI R31, 0 ADIW R31:R30, 1 MOVW R17:R16, R31:R30 LDI R20, 2 LDI R21, 0 RCALL ?SS_DIVMOD_L02 STS BattActive, R20 // 333 ErrorFlags &= ~i; MOV R16, R24 COM R16 LDI R30, LOW(ErrorFlags) LDI R31, (ErrorFlags) >> 8 LD R17, Z AND R17, R16 ST Z, R17 // 334 break; // 335 // 336 // 337 default: // 338 break; // 339 } // 340 } // 341 } ??Error_3: LSL R24 RJMP ??Error_1 // 342 } while (ErrorFlags); ??Error_2: LDS R16, ErrorFlags TST R16 BREQ $+2+2 RJMP ??Error_0 // 343 // 344 return(ST_INIT); LDI R16, 10 LDI R30, 2 RJMP ?EPILOGUE_B2_L09 // 345 } // 346 // 347 // 348 /*! \brief Sets the specified error-flag and saves the current state // 349 * // 350 * Updates \ref ErrorFlags and \ref ErrorState. // 351 * // 352 * \note Error flags are specified in statefunc.h. // 353 * // 354 * \param Flag Specifies what error to flag. // 355 */ RSEG CODE:CODE:NOROOT(1) // 356 void SetErrorFlag(unsigned char Flag) SetErrorFlag: // 357 { // 358 ErrorFlags |= Flag; LDI R30, LOW(ErrorFlags) LDI R31, (ErrorFlags) >> 8 LD R17, Z OR R17, R16 ST Z, R17 // 359 ErrorState = CurrentState; LDS R17, CurrentState STS ErrorState, R17 // 360 } 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 */ RSEG CODE:CODE:NOROOT(1) // 374 unsigned char JumperCheck(void) JumperCheck: // 375 { // 376 DisableBatteries(); // Disconnect, or loads may be destroyed! RCALL DisableBatteries // 377 // 378 PWM_Start(); // Start PWM (controls the buck charger). 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); LDI R20, 0 LDI R17, 1 LDI R18, 0 LDI R19, 0 LDI R16, 2 RCALL Time_Set // 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) { ??JumperCheck_0: LDI R30, LOW(ADCS) LDI R31, (ADCS) >> 8 LDD R16, Z+6 LDD R17, Z+7 CPI R16, 255 LDI R18, 3 CPC R17, R18 BRNE ??JumperCheck_1 // 387 PWM_Stop(); RCALL PWM_Stop // 388 return(FALSE); LDI R16, 0 RET // 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 ) { ??JumperCheck_1: LDI R30, LOW(ADCS) LDI R31, (ADCS) >> 8 LDD R16, Z+8 LDD R17, Z+9 SUBI R16, 88 SBCI R17, 2 LDI R30, LOW(ADCS) LDI R31, (ADCS) >> 8 LDD R18, Z+10 LDD R19, Z+11 SUB R16, R18 SBC R17, R19 RCALL abs CPI R16, 244 LDI R18, 1 CPC R17, R18 BRGE ??JumperCheck_2 // 395 // 396 PWM_Stop(); RCALL PWM_Stop // 397 return(TRUE); LDI R16, 1 RET // 398 } // 399 // 400 // Charge current is too high -> check load and jumper J405 and J406. // 401 if (abs(ADCS.IBAT) > 100) { ??JumperCheck_2: LDI R30, LOW(ADCS) LDI R31, (ADCS) >> 8 LDD R16, Z+12 LDD R17, Z+13 RCALL abs CPI R16, 101 LDI R18, 0 CPC R17, R18 BRLT ??JumperCheck_3 // 402 PWM_Stop(); RCALL PWM_Stop // 403 return(FALSE); LDI R16, 0 RET // 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()) { ??JumperCheck_3: RCALL PWM_IncrementDutyCycle TST R16 BRNE ??JumperCheck_4 // 409 PWM_Stop(); RCALL PWM_Stop // 410 return(FALSE); LDI R16, 0 RET // 411 } // 412 // 413 // Wait for ADC conversions to complete // 414 ADC_Wait(); ??JumperCheck_4: RCALL ADC_Wait // 415 } while (Time_Left(TIMER_GEN)); LDI R16, 2 RCALL Time_Left TST R16 BRNE ??JumperCheck_0 // 416 // 417 // 418 // If we end up here, the measurements took too long. // 419 PWM_Stop(); RCALL PWM_Stop // 420 return(FALSE); LDI R16, 0 RET // 421 } 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 END // // 6 bytes in segment ABSOLUTE // 734 bytes in segment CODE // 6 bytes in segment INITTAB // 2 bytes in segment NEAR_Z // // 734 bytes of CODE memory (+ 6 bytes shared) // 2 bytes of DATA memory (+ 6 bytes shared) // //Errors: none //Warnings: none