- Main Page
- Related Pages
- Data Structures
- Files

# chargefunc.c

Go to the documentation of this file.

    00001 /* This file has been prepared for Doxygen automatic documentation generation.*/
    00030 #include <ioavr.h>
    00031
    00032 #include "enums.h"
    00033 #include "structs.h"
    00034
    00035 #include "ADC.h"
    00036 #include "battery.h"
    00037 #include "chargefunc.h"
    00038 #include "main.h"
    00039 #include "menu.h"
    00040 #include "PWM.h"
    00041 #include "statefunc.h"
    00042 #include "time.h"
    00043
    00044 #ifdef NIMH
    00045 #include "NIMHspecs.h"
    00046 #endif // NIMH
    00047
    00048 #ifdef LIION
    00049 #include "LIIONspecs.h"
    00050 #endif // LIION
    00051
    00052
    00053 //******************************************************************************
    00054 // Variables
    00055 //******************************************************************************
    00057 ChargeParameters_t ChargeParameters;
    00058
    00060 HaltParameters_t HaltParameters;
    00061
    00062
    00063 //******************************************************************************
    00064 // Functions
    00065 //******************************************************************************
    00080 unsigned char ConstantCurrent(void)
    00081 {
    00082         unsigned char error = FALSE,
    00083                       wasStopped = FALSE;
    00084
    00085         do      {
    00086       // Wait for ADC conversions to complete.
    00087                 ADC_Wait();
    00088
    00089                 // If Master has flagged for a charge inhibit, pause charging.
    00090                 // (This is to prevent damage during prolonged serial communication.)
    00091                 if (BattControl[BattActive].ChargeInhibit) {
    00092                         wasStopped = TRUE;
    00093                         Time_Stop();
    00094                         OCR1B = 0;
    00095                 } else {
    00096                         // Continue charging!
    00097                         if (wasStopped) {
    00098                                 wasStopped = FALSE;
    00099
    00100                                 // Timer variables are not reset by this.
    00101                                 Time_Start();
    00102                         }
    00103
    00104                         // Adjust the charge current to within ChargeParameters.Current
    00105                         // +/- BAT_CURRENT_HYST.
    00106                         if ((ADCS.avgIBAT < 0) ||
    00107                             (ADCS.avgIBAT < (ChargeParameters.Current - BAT_CURRENT_HYST))) {
    00108
    00109                                 if(!PWM_IncrementDutyCycle()) {
    00110 #ifdef ABORT_IF_PWM_MAX
    00111                                 // If the duty cycle cannot be incremented, flag error and
    00112                                 // go to error state.
    00113                                         SetErrorFlag(ERR_PWM_CONTROL);
    00114                                         ChargeParameters.NextState = ST_ERROR;
    00115                                         error = TRUE;
    00116 #endif
    00117                                 }
    00118                         } else if ((ADCS.avgIBAT >= 0) &&
    00119                                  (ADCS.avgIBAT > (ChargeParameters.Current + BAT_CURRENT_HYST))) {
    00120
    00121                                 if(!PWM_DecrementDutyCycle()) {
    00122 #ifdef ABORT_IF_PWM_MIN
    00123                                         // If the duty cycle cannot be decremented, flag error and
    00124                                         // go to error state.
    00125                                         SetErrorFlag(ERR_PWM_CONTROL);
    00126                                         ChargeParameters.NextState = ST_ERROR;
    00127                                         error = TRUE;
    00128 #endif
    00129                                 }
    00130                         }
    00131                 }
    00132         } while (!HaltNow() && !error);
    00133
    00134         // Return the next state to Charge(). If an error has occured, this will
    00135         // point to some other state than the next state of charging.
    00136         return(ChargeParameters.NextState);
    00137 }
    00138
    00139
    00154 unsigned char ConstantVoltage(void)
    00155 {
    00156         unsigned char error = FALSE,
    00157                       wasStopped = FALSE;
    00158
    00159         do{
    00160
    00161                 // Wait for ADC conversions to complete.
    00162                 ADC_Wait();
    00163
    00164                 // If Master has flagged for a charge inhibit, pause charging.
    00165                 // (This is to prevent damage during prolonged serial communication.)
    00166                 if (BattControl[BattActive].ChargeInhibit) {
    00167                         wasStopped = TRUE;
    00168                         Time_Stop();
    00169                         OCR1B = 0;
    00170                 }
    00171
    00172                 else {
    00173                         // Continue charging!
    00174                         if (wasStopped) {
    00175                                 wasStopped = FALSE;
    00176
    00177                                 // Timer variables aren't reset by this.
    00178                                 Time_Start();
    00179                         }
    00180
    00181                         // Adjust the charge voltage to within ChargeParameters.Voltage
    00182                         // +/- BAT_VOLTAGE_HYST.
    00183                         if (ADCS.VBAT < (ChargeParameters.Voltage - BAT_VOLTAGE_HYST)) {
    00184
    00185                                 if(!PWM_IncrementDutyCycle()) {
    00186 #ifdef ABORT_IF_PWM_MAX
    00187                                 // Flag PWM control error and go to error-state if the duty
    00188                                 // cycle cannot be incremented.
    00189                                         SetErrorFlag(ERR_PWM_CONTROL);
    00190                                         ChargeParameters.NextState = ST_ERROR;
    00191                                         error = TRUE;
    00192 #endif
    00193                                 }
    00194                         } else if (ADCS.VBAT > (ChargeParameters.Voltage + BAT_VOLTAGE_HYST)) {
    00195
    00196                                 if(!PWM_DecrementDutyCycle()) {
    00197 #ifdef ABORT_IF_PWM_MIN
    00198                                         // Flag PWM control error and go to error-state if duty
    00199                                         // cycle cannot be decremented.
    00200                                         SetErrorFlag(ERR_PWM_CONTROL);
    00201                                         ChargeParameters.NextState = ST_ERROR;
    00202                                         error = TRUE;
    00203 #endif
    00204                                 }
    00205                         }
    00206                 }
    00207
    00208         } while (!HaltNow() && !error);
    00209
    00210         // Return the next state to Charge(). If an error has occured, this will
    00211         // point to some other state than the next state of charging.
    00212         return(ChargeParameters.NextState);
    00213 }
    00214
    00215
    00257 unsigned char MaxVoltageAndCurrent (void)
    00258 {
    00259         unsigned char error = FALSE,
    00260                       wasStopped = FALSE,
    00261                       tempRangeChange;
    00262
    00263         signed char lastTempRange = -1; // Must be set to an "illegal" temperature
    00264         // in the first iteration.
    00265
    00266         do {
    00267                 // Wait for ADC conversions to complete, then find the temperature.
    00268                 ADC_Wait();
    00269                 NTCLookUp();
    00270
    00271                 // If Master has flagged for a charge inhibit, pause charging.
    00272                 // (This is to prevent damage during prolonged serial communication.)
    00273                 if (BattControl[BattActive].ChargeInhibit) {
    00274                         wasStopped = TRUE;
    00275                         Time_Stop();
    00276                         OCR1B = 0;
    00277                 }
    00278                 else {
    00279                         // Continue charging!
    00280                         if (wasStopped) {
    00281                                 wasStopped = FALSE;
    00282
    00283                                 // Timer variables are not reset by this.
    00284                                 Time_Start();
    00285                         }
    00286
    00287          // Temperature hysteresis, allow some drift around the transitional values.
    00288          // (Compare the new temperature with the hysteresis boundaries of the
    00289          // previously set temperature range, and flag for a change if the new
    00290          // temperature deviates beyond the hysteresis.
    00291          tempRangeChange = FALSE;  // Start by assuming no change in temp. range.
    00292
    00293          // See if the temperature range has changed, flag if it has. Handle T0!
    00294          switch (lastTempRange) {
    00295             case T0 :
    00296                if ((BattData.Temperature - T0) > TEMP_HYST) {
    00297                   tempRangeChange = TRUE;
    00298                }
    00299                else {
    00300                   // We need to do this check if we're staying in this range:
    00301                   // If the battery voltage is below threshold #1 for T0, attempt to
    00302                   // regulate the charge current to max 1.0C and voltage to max 4.10 V.
    00303                   // If the battery voltage is above threshold #1 for T0, attempt to
    00304                   // regulate the charge current to max 0.5C and voltage to max 4.25 V.
    00305
    00306                   // This will cause a kind of "oscillation" starting when battery
    00307                   // voltage reaches 4.10 V, and ending once the battery voltage
    00308                   // surpasses 4.10 V for currents below 0.5 C, after which the
    00309                   // function will keep applying 4.25 V.
    00310                   // It will not cause any of the regulation limits to be crossed.
    00311                   if (ADCS.VBAT <= BAT_VOLTAGE_MAX_T0) {
    00312                      ChargeParameters.Voltage = BAT_VOLTAGE_MAX_T0;
    00313                      ChargeParameters.Current = BattData.MaxCurrent;
    00314                   }
    00315                   else {
    00316                      ChargeParameters.Voltage = BAT_VOLTAGE_MAX;
    00317                      ChargeParameters.Current = BattData.MaxCurrent/2;
    00318                   }
    00319                }
    00320             break;
    00321
    00322
    00323             case T1 :
    00324                if ((BattData.Temperature - T1) > TEMP_HYST
    00325                      || (T0 - BattData.Temperature) > TEMP_HYST) {
    00326                   tempRangeChange = TRUE;
    00327                }
    00328             break;
    00329
    00330
    00331             case T2 :
    00332                if ((BattData.Temperature - T2) > TEMP_HYST
    00333                      || (T1 - BattData.Temperature) >= TEMP_HYST) {
    00334                   tempRangeChange = TRUE;
    00335                }
    00336             break;
    00337
    00338
    00339             case T3 :
    00340                if ((T2 - BattData.Temperature) > TEMP_HYST) {
    00341                   tempRangeChange = TRUE;
    00342                }
    00343             break;
    00344
    00345
    00346             // This should only happen in first iteration.
    00347             default : tempRangeChange = TRUE;
    00348          }
    00349
    00350          // If a change in temperature range was flagged, update charge parameters.
    00351          if (tempRangeChange) {
    00352             // Find new temperature range, set maximum charge current and voltage.
    00353
    00354             if (BattData.Temperature <= T0) { // [-inf,T0] degrees C
    00355                if (ADCS.VBAT <= BAT_VOLTAGE_MAX_T0) {
    00356                   ChargeParameters.Voltage = BAT_VOLTAGE_MAX_T0;
    00357                   ChargeParameters.Current = BattData.MaxCurrent;
    00358                }
    00359                else {
    00360                   ChargeParameters.Voltage = BAT_VOLTAGE_MAX;
    00361                   ChargeParameters.Current = BattData.MaxCurrent/2;
    00362                }
    00363                lastTempRange = T0;
    00364             }
    00365
    00366             else {
    00367                // The other temperature ranges all allow charging at maximum 1.0 C,
    00368                // but have different maximum voltages.
    00369                ChargeParameters.Current = BattData.MaxCurrent;
    00370
    00371                if (BattData.Temperature <= T1) { // (T0,T1]
    00372                   ChargeParameters.Voltage = BAT_VOLTAGE_MAX;
    00373                   lastTempRange = T1;
    00374                }
    00375                else if (BattData.Temperature <= T2) { // (T1,T2]
    00376                   ChargeParameters.Voltage = BAT_VOLTAGE_MAX_T2;
    00377                   lastTempRange = T2;
    00378                }
    00379                else { // (T2,inf]
    00380                   ChargeParameters.Voltage = BAT_VOLTAGE_MAX_T3;
    00381                   lastTempRange = T3;
    00382                }
    00383             }
    00384          }
    00385
    00386                         // If both charge voltage and current are below limits, the PWM output may
    00387                         // be increased.
    00388                         if (ADCS.VBAT < (ChargeParameters.Voltage - BAT_VOLTAGE_HYST) &&
    00389                            ADCS.avgIBAT < (ChargeParameters.Current - BAT_CURRENT_HYST)) {
    00390
    00391                                 if(!PWM_IncrementDutyCycle()) {
    00392 #ifdef ABORT_IF_PWM_MAX
    00393                                         // If the duty cycle cannot be incremented, flag error and
    00394                                         // go to error state.
    00395                                         SetErrorFlag(ERR_PWM_CONTROL);
    00396                                         ChargeParameters.NextState = ST_ERROR;
    00397                                         error = TRUE;
    00398 #endif
    00399                                 }
    00400                                 // If either voltage or current is above limit + hysteresis, reduce output.
    00401                         }
    00402                         if (ADCS.VBAT > (ChargeParameters.Voltage + BAT_VOLTAGE_HYST) ||
    00403                             ADCS.avgIBAT > (ChargeParameters.Current + BAT_CURRENT_HYST)) {
    00404                                 if(!PWM_DecrementDutyCycle()) {
    00405 #ifdef ABORT_IF_PWM_MIN
    00406                                         // If the duty cycle cannot be decremented, flag error and
    00407                                         // go to error state.
    00408                                         SetErrorFlag(ERR_PWM_CONTROL);
    00409                                         ChargeParameters.NextState = ST_ERROR;
    00410                                         error = TRUE;
    00411 #endif
    00412                                 }
    00413                         }
    00414                 }
    00415         } while (!HaltNow() && !error);
    00416
    00417         // Return the next state to Charge(). If an error has occured, this will
    00418         // point to some other state than the next state of charging.
    00419         return(ChargeParameters.NextState);
    00420 }
    00421
    00422
    00445 unsigned char HaltNow(void)
    00446 {
    00447         unsigned char i, halt = FALSE;
    00448
    00449         // Wait for a full ADC-cycle to finish.
    00450         ADC_Wait();
    00451         NTCLookUp();
    00452
    00453         // Evaluate ADC readings according to HaltFlags. Flag errors if selected.
    00454         // If an error is flagged, ChargeParameters.NextState is set to ST_ERROR.
    00455         // (Gets overridden if either mains is failing, or the battery changes.)
    00456         for (i = 0x01; i != 0; i <<= 1) {
    00457                 if (HaltParameters.HaltFlags & i) {
    00458                         switch (i) {
    00459                         // Is VBAT less than the recorded maximum?
    00460                         case HALT_VOLTAGE_DROP:
    00461
    00462                                 // Update VBATMax if VBAT is higher or charge is inhibited by master.
    00463     // Evaluate for halt otherwise.
    00464                                 if (ADCS.VBAT > HaltParameters.VBATMax ||
    00465                                     BattControl[BattActive].ChargeInhibit) {
    00466                                         HaltParameters.VBATMax = ADCS.VBAT;
    00467                                 } else if((HaltParameters.VBATMax - ADCS.VBAT) >=
    00468                                           HaltParameters.VoltageDrop) {
    00469                                         halt = TRUE;
    00470                                 }
    00471                         break;
    00472
    00473
    00474                         // Has VBAT reached the maximum limit?
    00475                         case HALT_VOLTAGE_MAX:
    00476
    00477                                 if (ADCS.VBAT >= HaltParameters.VoltageMax) {
    00478                                         halt = TRUE;
    00479                                 }
    00480                                 break;
    00481
    00482
    00483                         // Has IBAT reached the minimum limit?
    00484                         case HALT_CURRENT_MIN:
    00485
    00486     // If the charging current has dropped below the minimum threshold and
    00487     // charging is not inhibited by master, flag a halt.
    00488                                 if (ADCS.avgIBAT <= HaltParameters.CurrentMin &&
    00489                                     !BattControl[BattActive].ChargeInhibit) {
    00490                                         halt = TRUE;
    00491                                 }
    00492                                 break;
    00493
    00494
    00495                         // Is the temperature rising too fast?
    00496                         case HALT_TEMPERATURE_RISE:
    00497
    00498                                 // If rawNTC has increased, the temperature has dropped.
    00499                                 // We can store this value for now, and start the timer.
    00500                                 // Otherwise, check if NTC has changed too fast.
    00501                                 if (ADCS.rawNTC > HaltParameters.LastNTC) {
    00502                                         HaltParameters.LastNTC = ADCS.rawNTC;
    00503                                         Time_Set(TIMER_TEMP,0,30,0);
    00504
    00505                                 // Is the increase in temperature greater than the set threshold?
    00506                                 } else  if ((HaltParameters.LastNTC - ADCS.rawNTC) >=
    00507                                   (BattData.ADCSteps * HaltParameters.TemperatureRise)) {
    00508
    00509                                         // If this happened within a timeframe of 30 seconds, the
    00510                                         // temperature is rising faster than we want.
    00511                                         // If not, update LastNTC and reset timer.
    00512                                         if (Time_Left(TIMER_TEMP))  {
    00513                                                 halt = TRUE;
    00514                                         } else {
    00515                                                 HaltParameters.LastNTC = ADCS.rawNTC;
    00516                                                 Time_Set(TIMER_TEMP,0,30,0);
    00517                                         }
    00518                                 }
    00519                         break;
    00520
    00521
    00522                         // Is there any time left?
    00523                         case HALT_TIME:
    00524
    00525                                 if (!Time_Left(TIMER_CHG)) {
    00526                                         halt = TRUE;
    00527
    00528                                         // If exhaustion flagging is selected, stop the PWM, disable the
    00529                                         // battery and flag it as exhausted. Make ST_ERROR next state.
    00530                                         if (HaltParameters.HaltFlags & HALT_FLAG_EXHAUSTION) {
    00531                                                         PWM_Stop();
    00532                                                         BattControl[BattActive].Enabled = FALSE;
    00533                                                         BattData.Exhausted = TRUE;
    00534                                                         SetErrorFlag(ERR_BATTERY_EXHAUSTED);
    00535                                                         ChargeParameters.NextState = ST_ERROR;
    00536                                         }
    00537                                 }
    00538                         break;
    00539
    00540
    00541                         default:  // Shouldn't end up here, but is needed for MISRA compliance.
    00542                         break;
    00543                         }
    00544                 }
    00545         }
    00546
    00547         // Standard checks:
    00548
    00549         // Battery too cold or hot?
    00550         if ((BattData.Temperature < HaltParameters.TemperatureMin) ||
    00551             (BattData.Temperature > HaltParameters.TemperatureMax)) {
    00552
    00553                 PWM_Stop();
    00554                 SetErrorFlag(ERR_BATTERY_TEMPERATURE);
    00555                 ChargeParameters.NextState = ST_ERROR;
    00556                 halt = TRUE;
    00557         }
    00558
    00559         // Battery not OK?
    00560         if (!BatteryCheck()) {
    00561                 PWM_Stop();
    00562                 ChargeParameters.NextState = ST_INIT;
    00563                 halt = TRUE;
    00564         }
    00565
    00566         // Is mains voltage OK?
    00567         if (!ADCS.Mains) {
    00568                 PWM_Stop();
    00569                 ChargeParameters.NextState = ST_SLEEP;
    00570                 halt = TRUE;
    00571         }
    00572
    00573         return(halt);
    00574 }