1 /* This file has been prepared for Doxygen automatic documentation generation.*/
\r
2 /*! \file *********************************************************************
\r
7 * Contains the functions for charging with constant current and voltage,
\r
8 * and for deciding when to halt.
\r
10 * \par Application note:
\r
11 * AVR458: Charging Li-Ion Batteries with BC100 \n
\r
12 * AVR463: Charging NiMH Batteries with BC100
\r
14 * \par Documentation
\r
15 * For comprehensive code documentation, supported compilers, compiler
\r
16 * settings and supported devices see readme.html
\r
19 * Atmel Corporation: http://www.atmel.com \n
\r
20 * Support email: avr@atmel.com
\r
26 * $URL: http://svn.norway.atmel.com/AppsAVR8/avr458_Charging_Li-Ion_Batteries_with_BC100/tag/20070904_release_1.0/code/IAR/chargefunc.c $
\r
27 * $Date: 2007-08-23 12:55:51 +0200 (to, 23 aug 2007) $\n
\r
28 ******************************************************************************/
\r
33 #include "structs.h"
\r
36 #include "battery.h"
\r
37 #include "chargefunc.h"
\r
41 #include "statefunc.h"
\r
45 #include "NIMHspecs.h"
\r
49 #include "LIIONspecs.h"
\r
53 //******************************************************************************
\r
55 //******************************************************************************
\r
56 //! Struct that holds parameters for ConstantCurrent() and ConstantVoltage().
\r
57 ChargeParameters_t ChargeParameters;
\r
59 //! Struct that holds parameters for HaltNow().
\r
60 HaltParameters_t HaltParameters;
\r
63 //******************************************************************************
\r
65 //******************************************************************************
\r
66 /*! \brief Charges battery with a constant current.
\r
68 * This function applies a constant current (set in ChargeParameters.Current)
\r
69 * to the battery until HaltNow() returns TRUE, or a PWM error occurs and
\r
70 * \ref ABORT_IF_PWM_MIN or \ref ABORT_IF_PWM_MAX is defined.\n
\r
71 * The charge current can vary with +/- \ref BAT_CURRENT_HYST.\n
\r
72 * If the Master inhibits charging, timers are stopped and PWM output dropped.
\r
73 * Once the battery is no longer flagged for charge inhibit, timers are
\r
74 * started again and charging resumed.
\r
76 * \retval ChargeParameters.NextState Next state once this stage is done.
\r
77 * If no errors occured, this will be whatever was set in Charge(). Otherwise,
\r
78 * HaltNow() will have set a new next state.
\r
80 unsigned char ConstantCurrent(void)
\r
82 unsigned char error = FALSE,
\r
86 // Wait for ADC conversions to complete.
\r
89 // If Master has flagged for a charge inhibit, pause charging.
\r
90 // (This is to prevent damage during prolonged serial communication.)
\r
91 if (BattControl[BattActive].ChargeInhibit) {
\r
96 // Continue charging!
\r
100 // Timer variables are not reset by this.
\r
104 // Adjust the charge current to within ChargeParameters.Current
\r
105 // +/- BAT_CURRENT_HYST.
\r
106 if ((ADCS.avgIBAT < 0) ||
\r
107 (ADCS.avgIBAT < (ChargeParameters.Current - BAT_CURRENT_HYST))) {
\r
109 if(!PWM_IncrementDutyCycle()) {
\r
110 #ifdef ABORT_IF_PWM_MAX
\r
111 // If the duty cycle cannot be incremented, flag error and
\r
112 // go to error state.
\r
113 SetErrorFlag(ERR_PWM_CONTROL);
\r
114 ChargeParameters.NextState = ST_ERROR;
\r
118 } else if ((ADCS.avgIBAT >= 0) &&
\r
119 (ADCS.avgIBAT > (ChargeParameters.Current + BAT_CURRENT_HYST))) {
\r
121 if(!PWM_DecrementDutyCycle()) {
\r
122 #ifdef ABORT_IF_PWM_MIN
\r
123 // If the duty cycle cannot be decremented, flag error and
\r
124 // go to error state.
\r
125 SetErrorFlag(ERR_PWM_CONTROL);
\r
126 ChargeParameters.NextState = ST_ERROR;
\r
132 } while ((!HaltNow()) && (!error));
\r
134 // Return the next state to Charge(). If an error has occured, this will
\r
135 // point to some other state than the next state of charging.
\r
136 return(ChargeParameters.NextState);
\r
140 /*! \brief Charges battery with a constant voltage
\r
142 * This function applies a constant voltage (set in ChargeParameters.Voltage)
\r
143 * to the battery until HaltNow() returns TRUE, or a PWM error occurs and
\r
144 * \ref ABORT_IF_PWM_MIN or \ref ABORT_IF_PWM_MAX is defined.\n
\r
145 * The charge voltage can vary with +/- \ref BAT_VOLTAGE_HYST.\n
\r
146 * If the Master inhibits charging, timers are stopped and PWM output dropped.
\r
147 * Once the battery is no longer flagged for charge inhibit, timers are
\r
148 * started again and charging resumed.
\r
150 * \retval ChargeParameters.NextState Next state once this stage is done.
\r
151 * If no errors occured, this will be whatever was set in Charge(). Otherwise,
\r
152 * HaltNow() will have set a new next state.
\r
154 unsigned char ConstantVoltage(void)
\r
156 unsigned char error = FALSE,
\r
157 wasStopped = FALSE;
\r
161 // Wait for ADC conversions to complete.
\r
164 // If Master has flagged for a charge inhibit, pause charging.
\r
165 // (This is to prevent damage during prolonged serial communication.)
\r
166 if (BattControl[BattActive].ChargeInhibit) {
\r
173 // Continue charging!
\r
175 wasStopped = FALSE;
\r
177 // Timer variables aren't reset by this.
\r
181 // Adjust the charge voltage to within ChargeParameters.Voltage
\r
182 // +/- BAT_VOLTAGE_HYST.
\r
183 if (ADCS.VBAT < (ChargeParameters.Voltage - BAT_VOLTAGE_HYST)) {
\r
185 if(!PWM_IncrementDutyCycle()) {
\r
186 #ifdef ABORT_IF_PWM_MAX
\r
187 // Flag PWM control error and go to error-state if the duty
\r
188 // cycle cannot be incremented.
\r
189 SetErrorFlag(ERR_PWM_CONTROL);
\r
190 ChargeParameters.NextState = ST_ERROR;
\r
194 } else if (ADCS.VBAT > (ChargeParameters.Voltage + BAT_VOLTAGE_HYST)) {
\r
196 if(!PWM_DecrementDutyCycle()) {
\r
197 #ifdef ABORT_IF_PWM_MIN
\r
198 // Flag PWM control error and go to error-state if duty
\r
199 // cycle cannot be decremented.
\r
200 SetErrorFlag(ERR_PWM_CONTROL);
\r
201 ChargeParameters.NextState = ST_ERROR;
\r
208 } while ((!HaltNow()) && (!error));
\r
210 // Return the next state to Charge(). If an error has occured, this will
\r
211 // point to some other state than the next state of charging.
\r
212 return(ChargeParameters.NextState);
\r
216 /*! \brief Determines when to halt charging.
\r
218 * This function evaluates parameters depending on what has been flagged in
\r
219 * HaltParameters.HaltFlags, and returns TRUE or FALSE if the charging should
\r
221 * In addition, error flagging on timeout (battery exhaustion) can be set.\n
\r
223 * The function also checks if the battery temperature is within limits,
\r
224 * if mains is OK, and if BatteryCheck() returns TRUE.
\r
225 * If an error is detected, the associated errorflag is set and
\r
226 * ChargeParameters.NextState is changed to an appropriate state.
\r
228 * \retval TRUE Halt now.
\r
229 * \retval FALSE Don't halt now.
\r
231 * \note See chargefunc.h for definitions of halt flags.
\r
232 * \note It is generally a bad idea not to halt on a timeout.
\r
233 * \note If HALT_ON_VOLTAGE_DROP is set, HaltParameters.VBATMax should be
\r
234 * reset in Charge() before calling a charging-function.
\r
236 * \todo "Priorities" of standard error checks OK?
\r
238 unsigned char HaltNow(void)
\r
240 unsigned char i, halt = FALSE;
\r
242 // Wait for a full ADC-cycle to finish.
\r
245 // Evaluate ADC readings according to HaltFlags. Flag errors if selected.
\r
246 // If an error is flagged, ChargeParameters.NextState is set to ST_ERROR.
\r
247 // (Gets overridden if either mains is failing, or the battery changes.)
\r
248 for (i = 0x01; i != 0; i <<= 1) {
\r
249 if (HaltParameters.HaltFlags & i) {
\r
251 // Is VBAT less than the recorded maximum?
\r
252 case HALT_VOLTAGE_DROP:
\r
254 // Update VBATMax if VBAT is higher. Evaluate for halt otherwise.
\r
255 if (ADCS.VBAT > HaltParameters.VBATMax) {
\r
256 HaltParameters.VBATMax = ADCS.VBAT;
\r
257 } else if((HaltParameters.VBATMax - ADCS.VBAT) >=
\r
258 HaltParameters.VoltageDrop) {
\r
264 // Has VBAT reached the maximum limit?
\r
265 case HALT_VOLTAGE_MAX:
\r
267 if (ADCS.VBAT >= HaltParameters.VoltageMax) {
\r
273 // Has IBAT reached the minimum limit?
\r
274 case HALT_CURRENT_MIN:
\r
276 if (ADCS.avgIBAT <= HaltParameters.CurrentMin) {
\r
282 // Is the temperature rising too fast?
\r
283 case HALT_TEMPERATURE_RISE:
\r
285 // If rawNTC has increased, the temperature has dropped.
\r
286 // We can store this value for now, and start the timer.
\r
287 // Otherwise, check if NTC has changed too fast.
\r
288 if (ADCS.rawNTC > HaltParameters.LastNTC) {
\r
289 HaltParameters.LastNTC = ADCS.rawNTC;
\r
290 Time_Set(TIMER_TEMP,0,30,0);
\r
292 // Is the increase in temperature greater than the set threshold?
\r
293 } else if ((HaltParameters.LastNTC - ADCS.rawNTC) >=
\r
294 (BattData.ADCSteps * HaltParameters.TemperatureRise)) {
\r
296 // If this happened within a timeframe of 30 seconds, the
\r
297 // temperature is rising faster than we want.
\r
298 // If not, update LastNTC and reset timer.
\r
299 if (Time_Left(TIMER_TEMP)) {
\r
302 HaltParameters.LastNTC = ADCS.rawNTC;
\r
303 Time_Set(TIMER_TEMP,0,30,0);
\r
309 // Is there any time left?
\r
312 if (!Time_Left(TIMER_CHG)) {
\r
315 // If exhaustion flagging is selected, stop the PWM, disable the
\r
316 // battery and flag it as exhausted. Make ST_ERROR next state.
\r
317 if (HaltParameters.HaltFlags & HALT_FLAG_EXHAUSTION) {
\r
319 BattControl[BattActive].Enabled = FALSE;
\r
320 BattData.Exhausted = TRUE;
\r
321 SetErrorFlag(ERR_BATTERY_EXHAUSTED);
\r
322 ChargeParameters.NextState = ST_ERROR;
\r
328 default: // Shouldn't end up here, but is needed for MISRA compliance.
\r
334 // Standard checks:
\r
336 // Battery too cold or hot?
\r
337 if ((BattData.Temperature <= HaltParameters.TemperatureMin) ||
\r
338 (BattData.Temperature >= HaltParameters.TemperatureMax)) {
\r
341 SetErrorFlag(ERR_BATTERY_TEMPERATURE);
\r
342 ChargeParameters.NextState = ST_ERROR;
\r
347 if (!BatteryCheck()) {
\r
349 ChargeParameters.NextState = ST_INIT;
\r
353 // Is mains voltage OK?
\r
356 ChargeParameters.NextState = ST_SLEEP;
\r