/////////////////////////////////////////////////////////////////////////////// // / // 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\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\s / // tatefunc.s90 / // / // / /////////////////////////////////////////////////////////////////////////////// NAME statefunc RSEG CSTACK:DATA:NOROOT(0) RSEG RSTACK:DATA:NOROOT(0) 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\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. // 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 { ST -Y, R24 // 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 R20, LOW(BattEEPROM) LDI R21, (BattEEPROM) >> 8 LDI R17, 128 // 100 for (i = 0; i < 32; i++) { // 101 BattEEPROM[page][i] = 0; ??Initialize_0: LDI R16, 0 RCALL __eeput8_16 // 102 } SUBI R20, 255 SBCI R21, 255 // 103 } DEC R17 BRNE ??Initialize_0 // 104 // 105 DDRB = (1<> 8 MOVW R21:R20, R25:R24 RCALL __eeget8_16 ANDI R16, 0x01 BRNE ??BatteryControl_3 MOVW R21:R20, R25:R24 SUBI R20, 255 SBCI R21, 255 RCALL __eeget8_16 ANDI R16, 0x01 BRNE ??BatteryControl_3 // 156 SetErrorFlag(ERR_NO_BATTERIES_ENABLED); LDI R30, LOW(ErrorFlags) LDI R31, (ErrorFlags) >> 8 LD R16, Z ORI R16, 0x02 ST Z, R16 LDS R16, CurrentState STD Z+1, R16 // 157 // 158 return(ST_ERROR); 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: LDI R26, 0 // 164 if (BattControl[i].Enabled) { ??BatteryControl_4: LDI R27, 0 MOVW R21:R20, R25:R24 ADD R20, R26 ADC R21, R27 RCALL __eeget8_16 ANDI R16, 0x01 BREQ ??BatteryControl_5 // 165 EnableBattery(i); MOV R16, R26 RCALL EnableBattery // 166 ADC_Wait(); RCALL ADC_Wait // 167 // 168 if (BatteryStatusRefresh()) { RCALL BatteryStatusRefresh TST R16 BREQ ??BatteryControl_5 // 169 if (!BattData.Charged) { LDS R16, BattData SBRC R16, 1 RJMP ??BatteryControl_5 // 170 BatteryDataRefresh(); RCALL BatteryDataRefresh // 171 // 172 return(ST_PREQUAL); LDI R16, 30 RJMP ??BatteryControl_2 // 173 } // 174 } // 175 } // 176 } ??BatteryControl_5: INC R26 CPI R26, 2 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(); RCALL DisableBatteries // 181 // 182 return(ST_SLEEP); LDI R16, 40 ??BatteryControl_2: LD R24, Y+ LD R25, Y+ LD R26, Y+ LD R27, Y+ 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 */ RSEG CODE:CODE:NOROOT(1) // 192 unsigned char Discharge(unsigned char inp) Discharge: // 193 { // 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 { // 210 unsigned char i; // 211 // 212 do { // 213 Doze(); // Take a nap (~8 seconds). RCALL ADC_Wait ??Sleep_0: RJMP ??Sleep_0 REQUIRE _A_MCUCR REQUIRE _A_MCUSR REQUIRE _A_WDTCR 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 */ 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; // 241 ADCS.Flag = FALSE; // 242 // 243 do { // 244 } while (ADCS.Flag == FALSE); ??Doze_0: RJMP ??Doze_0 REQUIRE _A_MCUCR REQUIRE _A_MCUSR REQUIRE _A_WDTCR REQUIRE _A_ADCSRA // 245 // 246 WDTCR = (1<> 8 LD R17, Z OR R17, R16 ST Z, R17 // 359 ErrorState = CurrentState; LDS R16, CurrentState STD Z+1, R16 // 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 { ST -Y, R27 ST -Y, R26 // 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 LDI R26, LOW(ADCS) LDI R27, (ADCS) >> 8 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: ADIW R27:R26, 12 LD R16, X+ LD R17, X SBIW R27:R26, 13 RCALL abs CPI R16, 101 SBCI R17, 0 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()) { RCALL PWM_IncrementDutyCycle TST R16 BREQ ??JumperCheck_2 // 409 PWM_Stop(); // 410 return(FALSE); // 411 } // 412 // 413 // Wait for ADC conversions to complete // 414 ADC_Wait(); RCALL ADC_Wait // 415 } while (Time_Left(TIMER_GEN)); LDI R16, 2 RCALL Time_Left TST R16 BREQ ??JumperCheck_2 ??JumperCheck_0: ADIW R27:R26, 6 LD R16, X+ LD R17, X SBIW R27:R26, 7 CPI R16, 255 SBCI R17, 3 BRNE ??JumperCheck_3 ??JumperCheck_2: RCALL PWM_Stop LDI R16, 0 RJMP ??JumperCheck_4 ??JumperCheck_3: ADIW R27:R26, 8 LD R16, X+ LD R17, X+ SUBI R16, 88 SBCI R17, 2 LD R18, X+ LD R19, X SBIW R27:R26, 11 SUB R16, R18 SBC R17, R19 RCALL abs CPI R16, 244 SBCI R17, 1 BRGE ??JumperCheck_1 RCALL PWM_Stop LDI R16, 1 ??JumperCheck_4: LD R26, Y+ LD R27, Y+ RET // 416 // 417 // 418 // If we end up here, the measurements took too long. // 419 PWM_Stop(); // 420 return(FALSE); // 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 // 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