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
31 #include <avr/interrupt.h>
\r
34 #include "structs.h"
\r
37 #include "battery.h"
\r
38 #include "chargefunc.h"
\r
42 #include "statefunc.h"
\r
46 #include "NIMHspecs.h"
\r
50 #include "LIIONspecs.h"
\r
54 //******************************************************************************
\r
56 //******************************************************************************
\r
57 //! Struct that holds parameters for ConstantCurrent() and ConstantVoltage().
\r
58 ChargeParameters_t ChargeParameters;
\r
60 //! Struct that holds parameters for HaltNow().
\r
61 HaltParameters_t HaltParameters;
\r
64 //******************************************************************************
\r
66 //******************************************************************************
\r
67 /*! \brief Charges battery with a constant current.
\r
69 * This function applies a constant current (set in ChargeParameters.Current)
\r
70 * to the battery until HaltNow() returns TRUE, or a PWM error occurs and
\r
71 * \ref ABORT_IF_PWM_MIN or \ref ABORT_IF_PWM_MAX is defined.\n
\r
72 * The charge current can vary with +/- \ref BAT_CURRENT_HYST.\n
\r
73 * If the Master inhibits charging, timers are stopped and PWM output dropped.
\r
74 * Once the battery is no longer flagged for charge inhibit, timers are
\r
75 * started again and charging resumed.
\r
77 * \retval ChargeParameters.NextState Next state once this stage is done.
\r
78 * If no errors occured, this will be whatever was set in Charge(). Otherwise,
\r
79 * HaltNow() will have set a new next state.
\r
81 unsigned char ConstantCurrent(void)
\r
83 unsigned char error = FALSE,
\r
85 unsigned char sreg_saved;
\r
86 signed int adcs_avgIBAT_tmp;
\r
89 // Wait for ADC conversions to complete.
\r
92 // If Master has flagged for a charge inhibit, pause charging.
\r
93 // (This is to prevent damage during prolonged serial communication.)
\r
94 if (eeprom_read_byte(&BattControl[BattActive]) & BIT_BATTERY_CHARGE_INHIBIT) {
\r
99 // Continue charging!
\r
101 wasStopped = FALSE;
\r
103 // Timer variables are not reset by this.
\r
109 adcs_avgIBAT_tmp = ADCS.avgIBAT;
\r
112 // Adjust the charge current to within ChargeParameters.Current
\r
113 // +/- BAT_CURRENT_HYST.
\r
114 if ((adcs_avgIBAT_tmp < 0) ||
\r
115 (adcs_avgIBAT_tmp < (ChargeParameters.Current - BAT_CURRENT_HYST))) {
\r
117 if(!PWM_IncrementDutyCycle()) {
\r
118 #ifdef ABORT_IF_PWM_MAX
\r
119 // If the duty cycle cannot be incremented, flag error and
\r
120 // go to error state.
\r
121 SetErrorFlag(ERR_PWM_CONTROL);
\r
122 ChargeParameters.NextState = ST_ERROR;
\r
126 } else if ((adcs_avgIBAT_tmp >= 0) &&
\r
127 (adcs_avgIBAT_tmp > (ChargeParameters.Current + BAT_CURRENT_HYST))) {
\r
129 if(!PWM_DecrementDutyCycle()) {
\r
130 #ifdef ABORT_IF_PWM_MIN
\r
131 // If the duty cycle cannot be decremented, flag error and
\r
132 // go to error state.
\r
133 SetErrorFlag(ERR_PWM_CONTROL);
\r
134 ChargeParameters.NextState = ST_ERROR;
\r
140 } while (!HaltNow() && !error);
\r
142 // Return the next state to Charge(). If an error has occured, this will
\r
143 // point to some other state than the next state of charging.
\r
144 return(ChargeParameters.NextState);
\r
148 /*! \brief Charges battery with a constant voltage
\r
150 * This function applies a constant voltage (set in ChargeParameters.Voltage)
\r
151 * to the battery until HaltNow() returns TRUE, or a PWM error occurs and
\r
152 * \ref ABORT_IF_PWM_MIN or \ref ABORT_IF_PWM_MAX is defined.\n
\r
153 * The charge voltage can vary with +/- \ref BAT_VOLTAGE_HYST.\n
\r
154 * If the Master inhibits charging, timers are stopped and PWM output dropped.
\r
155 * Once the battery is no longer flagged for charge inhibit, timers are
\r
156 * started again and charging resumed.
\r
158 * \retval ChargeParameters.NextState Next state once this stage is done.
\r
159 * If no errors occured, this will be whatever was set in Charge(). Otherwise,
\r
160 * HaltNow() will have set a new next state.
\r
162 unsigned char ConstantVoltage(void)
\r
164 unsigned char error = FALSE,
\r
165 wasStopped = FALSE;
\r
166 unsigned char sreg_saved;
\r
167 unsigned int adcs_VBAT_tmp;
\r
171 // Wait for ADC conversions to complete.
\r
174 // If Master has flagged for a charge inhibit, pause charging.
\r
175 // (This is to prevent damage during prolonged serial communication.)
\r
176 if (eeprom_read_byte(&BattControl[BattActive]) & BIT_BATTERY_CHARGE_INHIBIT) {
\r
183 // Continue charging!
\r
185 wasStopped = FALSE;
\r
187 // Timer variables aren't reset by this.
\r
193 adcs_VBAT_tmp = ADCS.VBAT;
\r
196 // Adjust the charge voltage to within ChargeParameters.Voltage
\r
197 // +/- BAT_VOLTAGE_HYST.
\r
198 if (adcs_VBAT_tmp < (ChargeParameters.Voltage - BAT_VOLTAGE_HYST)) {
\r
200 if(!PWM_IncrementDutyCycle()) {
\r
201 #ifdef ABORT_IF_PWM_MAX
\r
202 // Flag PWM control error and go to error-state if the duty
\r
203 // cycle cannot be incremented.
\r
204 SetErrorFlag(ERR_PWM_CONTROL);
\r
205 ChargeParameters.NextState = ST_ERROR;
\r
209 } else if (adcs_VBAT_tmp > (ChargeParameters.Voltage + BAT_VOLTAGE_HYST)) {
\r
211 if(!PWM_DecrementDutyCycle()) {
\r
212 #ifdef ABORT_IF_PWM_MIN
\r
213 // Flag PWM control error and go to error-state if duty
\r
214 // cycle cannot be decremented.
\r
215 SetErrorFlag(ERR_PWM_CONTROL);
\r
216 ChargeParameters.NextState = ST_ERROR;
\r
223 } while (!HaltNow() && !error);
\r
225 // Return the next state to Charge(). If an error has occured, this will
\r
226 // point to some other state than the next state of charging.
\r
227 return(ChargeParameters.NextState);
\r
231 /*! \brief Determines when to halt charging.
\r
233 * This function evaluates parameters depending on what has been flagged in
\r
234 * HaltParameters.HaltFlags, and returns TRUE or FALSE if the charging should
\r
236 * In addition, error flagging on timeout (battery exhaustion) can be set.\n
\r
238 * The function also checks if the battery temperature is within limits,
\r
239 * if mains is OK, and if BatteryCheck() returns TRUE.
\r
240 * If an error is detected, the associated errorflag is set and
\r
241 * ChargeParameters.NextState is changed to an appropriate state.
\r
243 * \retval TRUE Halt now.
\r
244 * \retval FALSE Don't halt now.
\r
246 * \note See chargefunc.h for definitions of halt flags.
\r
247 * \note It is generally a bad idea not to halt on a timeout.
\r
248 * \note If HALT_ON_VOLTAGE_DROP is set, HaltParameters.VBATMax should be
\r
249 * reset in Charge() before calling a charging-function.
\r
251 * \todo "Priorities" of standard error checks OK?
\r
253 unsigned char HaltNow(void)
\r
255 unsigned char i, halt = FALSE;
\r
256 unsigned int adcs_rawNTC_tmp, adcs_VBAT_tmp;
\r
257 signed int adcs_avgIBAT_tmp;
\r
258 unsigned char sreg_saved;
\r
260 // Wait for a full ADC-cycle to finish.
\r
263 // Evaluate ADC readings according to HaltFlags. Flag errors if selected.
\r
264 // If an error is flagged, ChargeParameters.NextState is set to ST_ERROR.
\r
265 // (Gets overridden if either mains is failing, or the battery changes.)
\r
266 for (i = 0x01; i != 0; i <<= 1) {
\r
267 if (HaltParameters.HaltFlags & i) {
\r
271 adcs_VBAT_tmp = ADCS.VBAT;
\r
272 adcs_avgIBAT_tmp = ADCS.avgIBAT;
\r
276 // Is VBAT less than the recorded maximum?
\r
277 case HALT_VOLTAGE_DROP:
\r
278 // Update VBATMax if VBAT is higher. Evaluate for halt otherwise.
\r
279 if (adcs_VBAT_tmp > HaltParameters.VBATMax) {
\r
280 HaltParameters.VBATMax = adcs_VBAT_tmp;
\r
281 } else if((HaltParameters.VBATMax - adcs_VBAT_tmp) >=
\r
282 HaltParameters.VoltageDrop) {
\r
288 // Has VBAT reached the maximum limit?
\r
289 case HALT_VOLTAGE_MAX:
\r
291 if (adcs_VBAT_tmp >= HaltParameters.VoltageMax) {
\r
297 // Has IBAT reached the minimum limit?
\r
298 case HALT_CURRENT_MIN:
\r
300 if (adcs_avgIBAT_tmp <= HaltParameters.CurrentMin) {
\r
306 // Is the temperature rising too fast?
\r
307 case HALT_TEMPERATURE_RISE:
\r
311 adcs_rawNTC_tmp = ADCS.rawNTC;
\r
313 // If rawNTC has increased, the temperature has dropped.
\r
314 // We can store this value for now, and start the timer.
\r
315 // Otherwise, check if NTC has changed too fast.
\r
316 if (adcs_rawNTC_tmp > HaltParameters.LastNTC) {
\r
317 HaltParameters.LastNTC = adcs_rawNTC_tmp;
\r
318 Time_Set(TIMER_TEMP,0,30,0);
\r
320 // Is the increase in temperature greater than the set threshold?
\r
321 } else if ((HaltParameters.LastNTC - adcs_rawNTC_tmp) >=
\r
322 (BattData.ADCSteps * HaltParameters.TemperatureRise)) {
\r
324 // If this happened within a timeframe of 30 seconds, the
\r
325 // temperature is rising faster than we want.
\r
326 // If not, update LastNTC and reset timer.
\r
327 if (Time_Left(TIMER_TEMP)) {
\r
330 HaltParameters.LastNTC = adcs_rawNTC_tmp;
\r
331 Time_Set(TIMER_TEMP,0,30,0);
\r
337 // Is there any time left?
\r
340 if (!Time_Left(TIMER_CHG)) {
\r
343 // If exhaustion flagging is selected, stop the PWM, disable the
\r
344 // battery and flag it as exhausted. Make ST_ERROR next state.
\r
345 if (HaltParameters.HaltFlags & HALT_FLAG_EXHAUSTION) {
\r
347 Battery_t tmp = eeprom_read_byte(&BattControl[BattActive]);
\r
348 tmp &= ~BIT_BATTERY_ENABLED; // Enabled = FALSE;
\r
349 eeprom_write_byte(&BattControl[BattActive], tmp);
\r
350 BattData.Exhausted = TRUE;
\r
351 SetErrorFlag(ERR_BATTERY_EXHAUSTED);
\r
352 ChargeParameters.NextState = ST_ERROR;
\r
358 default: // Shouldn't end up here, but is needed for MISRA compliance.
\r
364 // Standard checks:
\r
366 // Battery too cold or hot?
\r
367 if ((BattData.Temperature <= HaltParameters.TemperatureMin) ||
\r
368 (BattData.Temperature >= HaltParameters.TemperatureMax)) {
\r
371 SetErrorFlag(ERR_BATTERY_TEMPERATURE);
\r
372 ChargeParameters.NextState = ST_ERROR;
\r
377 if (!BatteryCheck()) {
\r
379 ChargeParameters.NextState = ST_INIT;
\r
383 // Is mains voltage OK?
\r
386 ChargeParameters.NextState = ST_SLEEP;
\r