00001 /* This file has been prepared for Doxygen automatic documentation generation.*/ 00034 #include <ioavr.h> 00035 #include <inavr.h> 00036 #include <stdlib.h> 00037 00038 #include "structs.h" 00039 #include "enums.h" 00040 00041 #include "ADC.h" 00042 #include "statefunc.h" 00043 #include "battery.h" 00044 #include "charge.h" 00045 #include "main.h" 00046 #include "menu.h" 00047 #include "OWI.h" 00048 #include "PWM.h" 00049 #include "time.h" 00050 #include "USI.h" 00051 00052 00053 //****************************************************************************** 00054 // Variables 00055 //****************************************************************************** 00056 unsigned char ErrorFlags; 00057 00058 00061 unsigned char ErrorState; 00062 00063 00064 //****************************************************************************** 00065 // Functions 00066 //****************************************************************************** 00085 unsigned char Initialize(unsigned char inp) 00086 { 00087 unsigned char i, page; 00088 00089 // Disable interrupts while setting prescaler. 00090 __disable_interrupt(); 00091 00092 CLKPR = (1<<CLKPCE); // Enable CLKPS bit modification. 00093 CLKPR = 0; // Set prescaler 1 => 8 MHz clock frequency. 00094 00095 // Init 1-Wire(R) interface. 00096 OWI_Init(OWIBUS); 00097 00098 // Clear on-chip EEPROM. 00099 for (page = 0; page < 4; page++) { 00100 for (i = 0; i < 32; i++) { 00101 BattEEPROM[page][i] = 0; 00102 } 00103 } 00104 00105 DDRB = (1<<PB4) | (1<<PB5); // Set battery enable pins as outputs. 00106 DisableBatteries(); 00107 SPI_Init(SPIMODE); 00108 ADC_Init(); 00109 Time_Init(); 00110 00111 // Attempt to get ADC-readings (also gets RID-data) from both batteries. 00112 for (i = 0; i < 2; i++) { 00113 EnableBattery(i); 00114 ADC_Wait(); 00115 BatteryStatusRefresh(); 00116 } 00117 00118 DisableBatteries(); 00119 00120 BattActive = 0; // We have to start somewhere.. 00121 ErrorFlags = 0; 00122 00123 // Init complete! Go to ST_BATCON next. 00124 return(ST_BATCON); 00125 } 00126 00127 00145 unsigned char BatteryControl(unsigned char inp) 00146 { 00147 unsigned char i; 00148 00149 // Make sure ADC inputs are configured properly! (Will disables batteries.) 00150 if (!JumperCheck()) { 00151 return(ST_ERROR); // Error. Exit before damage is done! 00152 } 00153 00154 // If neither battery is valid, flag error and go to error state 00155 if ((!BattControl[0].Enabled) && (!BattControl[1].Enabled)) { 00156 SetErrorFlag(ERR_NO_BATTERIES_ENABLED); 00157 00158 return(ST_ERROR); 00159 } 00160 00161 // Get ADC-readings, try to read EPROM, and start prequalification 00162 // of any uncharged battery. 00163 for (i = 0; i < 2; i++) { 00164 if (BattControl[i].Enabled) { 00165 EnableBattery(i); 00166 ADC_Wait(); 00167 00168 if (BatteryStatusRefresh()) { 00169 if (!BattData.Charged) { 00170 BatteryDataRefresh(); 00171 00172 return(ST_PREQUAL); 00173 } 00174 } 00175 } 00176 } 00177 00178 // If we end up here, one or two batteries are found and fully charged. 00179 // Disconnect, so we don't drain them, and go to sleep. 00180 DisableBatteries(); 00181 00182 return(ST_SLEEP); 00183 } 00184 00185 00192 unsigned char Discharge(unsigned char inp) 00193 { 00194 return(ST_BATCON); // Supply voltage restored, start charging 00195 } 00196 00197 00208 unsigned char Sleep(unsigned char inp) 00209 { 00210 unsigned char i; 00211 00212 do { 00213 Doze(); // Take a nap (~8 seconds). 00214 00215 // If any batteries need charging, go to ST_BATCON. 00216 // Otherwise, keep sleeping. 00217 for (i = 0; i < 2; i++) { 00218 EnableBattery(i); 00219 ADC_Wait(); 00220 if ((BatteryStatusRefresh()) && (!BattData.Charged)) { 00221 return(ST_BATCON); 00222 } 00223 } 00224 00225 DisableBatteries(); // Disable both batteries before Doze()! 00226 } while (TRUE); 00227 } 00228 00229 00236 void Doze(void) 00237 { 00238 // Wait for this ADC cycle to complete, then halt after the next one. 00239 ADC_Wait(); 00240 ADCS.Halt = TRUE; 00241 ADCS.Flag = FALSE; 00242 00243 do { 00244 } while (ADCS.Flag == FALSE); 00245 00246 WDTCR = (1<<WDP3)|(1<<WDP0); // 8.0 seconds at 5 volts VCC. 00247 WDTCR |= (1<<WDIF)|(1<<WDIE)|(1<<WDE); // Clear flag and enable watchdog. 00248 MCUCR |= (1<<SE) | (1<<SM1)|(1<<SM0); // Sleep enable, mode = standby. 00249 __sleep(); // Go to sleep, wake up by WDT. 00250 00251 __watchdog_reset(); // Clear watchdog reset flag. 00252 MCUSR &= ~(1<<WDRF); 00253 WDTCR |= (1<<WDCE)|(1<<WDE); // Watchdog change enable. 00254 WDTCR = 0; // Turn off watchdog. 00255 00256 ADCS.Halt = FALSE; // Enable consecutive runs of ADC. 00257 ADCSRA |= (1<<ADEN)|(1<<ADSC); // Enable ADC & start conversion. 00258 00259 // Wait for this cycle to complete. 00260 ADC_Wait(); 00261 } 00262 00263 00286 unsigned char Error(unsigned char inp) 00287 { 00288 unsigned char i; 00289 00290 PWM_Stop(); // Stop charging. 00291 DisableBatteries(); // Disable all loads. 00292 00293 do { 00294 Doze(); // Take a nap. 00295 00296 // For each bit in ErrorFlags, starting with LSB, handle 00297 // associated error, if the flag is set. 00298 for (i = 0x01; i!=0; i<<=1) { 00299 if(i & ErrorFlags) { 00300 switch (i) { 00301 00302 case ERR_JUMPER_MISMATCH: 00303 // Clear flag & recheck. 00304 ErrorFlags &= ~i; 00305 JumperCheck(); 00306 break; 00307 00308 00309 case ERR_NO_BATTERIES_ENABLED: 00310 // Clear if any battery gets enabled. 00311 if ((BattControl[0].Enabled) || (BattControl[1].Enabled)) { 00312 ErrorFlags &= ~i; 00313 } 00314 break; 00315 00316 00317 case ERR_PWM_CONTROL: 00318 // Clear flag. 00319 ErrorFlags &= ~i; 00320 break; 00321 00322 00323 case ERR_BATTERY_TEMPERATURE: 00324 // Clear flag. 00325 ErrorFlags &= ~i; 00326 break; 00327 00328 00329 case ERR_BATTERY_EXHAUSTED: 00330 // Try the other battery. 00331 BattData.Exhausted = FALSE; 00332 BattActive = (BattActive + 1) % 2; 00333 ErrorFlags &= ~i; 00334 break; 00335 00336 00337 default: 00338 break; 00339 } 00340 } 00341 } 00342 } while (ErrorFlags); 00343 00344 return(ST_INIT); 00345 } 00346 00347 00356 void SetErrorFlag(unsigned char Flag) 00357 { 00358 ErrorFlags |= Flag; 00359 ErrorState = CurrentState; 00360 } 00361 00362 00374 unsigned char JumperCheck(void) 00375 { 00376 DisableBatteries(); // Disconnect, or loads may be destroyed! 00377 00378 PWM_Start(); // Start PWM (controls the buck charger). 00379 00380 // Use general timer: shouldn't take longer than (6 x 255) / 2500 ~= 0.62s. 00381 Time_Set(TIMER_GEN,0,1,0); 00382 00383 do { 00384 // If the PWM output voltage saturates the ADC, stop PWM output and 00385 // report a failure. 00386 if (ADCS.rawVBAT == 1023) { 00387 PWM_Stop(); 00388 return(FALSE); 00389 } 00390 00391 // If the absolute difference between measured (VIN - VBAT) and the 00392 // typical value are below our set maximum, everything is OK. 00393 if (abs((signed int)(ADCS.VIN - VIN_VBAT_DIFF_TYP - ADCS.VBAT)) < 00394 VIN_VBAT_DIFF_MAX ) { 00395 00396 PWM_Stop(); 00397 return(TRUE); 00398 } 00399 00400 // Charge current is too high -> check load and jumper J405 and J406. 00401 if (abs(ADCS.IBAT) > 100) { 00402 PWM_Stop(); 00403 return(FALSE); 00404 } 00405 00406 // If the PWM output can't be increased high enough -> check jumpers 00407 // J400-J404, J407 and J408. 00408 if (!PWM_IncrementDutyCycle()) { 00409 PWM_Stop(); 00410 return(FALSE); 00411 } 00412 00413 // Wait for ADC conversions to complete 00414 ADC_Wait(); 00415 } while (Time_Left(TIMER_GEN)); 00416 00417 00418 // If we end up here, the measurements took too long. 00419 PWM_Stop(); 00420 return(FALSE); 00421 }