* AVR463: Charging NiMH Batteries with BC100\r
*\r
* \par Documentation\r
- * For comprehensive code documentation, supported compilers, compiler \r
+ * For comprehensive code documentation, supported compilers, compiler\r
* settings and supported devices see readme.html\r
*\r
* \author\r
* Atmel Corporation: http://www.atmel.com \n\r
* Support email: avr@atmel.com\r
*\r
- * \r
+ *\r
* $Name$\r
* $Revision: 2299 $\r
* $RCSfile$\r
//! \note See menu.h for definitions of states.\r
unsigned char ErrorState;\r
\r
+//! \brief Set to 1 by the watchdog-timeout-ISR\r
+//! \note added by Martin Thomas\r
+volatile unsigned char WatchdogFlag;\r
\r
//******************************************************************************\r
// Functions\r
\r
// Disable interrupts while setting prescaler.\r
__disable_interrupt();\r
- \r
+\r
CLKPR = (1<<CLKPCE); // Enable CLKPS bit modification.\r
CLKPR = 0; // Set prescaler 1 => 8 MHz clock frequency.\r
- \r
+\r
// Init 1-Wire(R) interface.\r
OWI_Init(OWIBUS);\r
- \r
+\r
// Clear on-chip EEPROM.\r
- for (page = 0; page < 4; page++) {\r
+ for (page = 0; page < 4; page++) {\r
for (i = 0; i < 32; i++) {\r
- BattEEPROM[page][i] = 0;\r
+ // From mthomas GCC addition\r
+ if (BattEEPROM[page][i] != 0) {\r
+ BattEEPROM[page][i] = 0;\r
+ }\r
}\r
}\r
\r
Time_Init();\r
\r
// Attempt to get ADC-readings (also gets RID-data) from both batteries.\r
- for (i = 0; i < 2; i++) {\r
+ for (i = 0; i < BATCONN; i++) {\r
EnableBattery(i);\r
ADC_Wait();\r
BatteryStatusRefresh();\r
}\r
- \r
+\r
DisableBatteries();\r
- \r
+\r
BattActive = 0; // We have to start somewhere..\r
ErrorFlags = 0;\r
- \r
+\r
// Init complete! Go to ST_BATCON next.\r
return(ST_BATCON);\r
}\r
unsigned char BatteryControl(unsigned char inp)\r
{\r
unsigned char i;\r
- \r
+\r
// Make sure ADC inputs are configured properly! (Will disables batteries.)\r
if (!JumperCheck()) {\r
return(ST_ERROR); // Error. Exit before damage is done!\r
}\r
- \r
+\r
// If neither battery is valid, flag error and go to error state\r
if ((!BattControl[0].Enabled) && (!BattControl[1].Enabled)) {\r
SetErrorFlag(ERR_NO_BATTERIES_ENABLED);\r
- \r
+\r
return(ST_ERROR);\r
}\r
\r
// Get ADC-readings, try to read EPROM, and start prequalification\r
// of any uncharged battery.\r
- for (i = 0; i < 2; i++) {\r
- if (BattControl[i].Enabled) { \r
+ for (i = 0; i < BATCONN; i++) {\r
+ if (BattControl[i].Enabled) {\r
EnableBattery(i);\r
ADC_Wait();\r
\r
if (!BattData.Charged) {\r
BatteryDataRefresh();\r
\r
- return(ST_PREQUAL); \r
+ return(ST_PREQUAL);\r
}\r
}\r
}\r
\r
// If any batteries need charging, go to ST_BATCON.\r
// Otherwise, keep sleeping.\r
- for (i = 0; i < 2; i++) {\r
+ for (i = 0; i < BATCONN; i++) {\r
EnableBattery(i);\r
ADC_Wait();\r
- if ((BatteryStatusRefresh()) && (!BattData.Charged)) {\r
- return(ST_BATCON);\r
+ if ( BatteryStatusRefresh() ) {\r
+ if ( !BattData.Charged ) {\r
+ return(ST_BATCON);\r
+ }\r
}\r
}\r
- \r
+\r
DisableBatteries(); // Disable both batteries before Doze()!\r
} while (TRUE);\r
}\r
\r
+/*! \brief Watchdog interrupt-service-routine\r
+ *\r
+ * Called on watchdog timeout, added by Martin Thomas\r
+ */\r
+#pragma vector = WDT_vect\r
+__interrupt void WDT_ISR(void)\r
+{\r
+ WatchdogFlag = 1;\r
+}\r
+\r
\r
/*! \brief Doze off for approx. 8 seconds (Vcc = 5 V)\r
*\r
* Waits for ADC-cycles to complete, disables the ADC, then sleeps for\r
* approx. 8 seconds (Vcc = 5 V) using the watchdog timer.\r
* On wakeup, ADC is re-enabled.\r
+ * Modification by Martin Thomas:\r
+ * Do not enter standby mode if PB6 is low (MASTER_INT on BC100)\r
+ * so SPI communication with the master-controller is still possible\r
+ * during "doze".\r
*/\r
void Doze(void)\r
{\r
+ uint8_t sreg_saved;\r
// Wait for this ADC cycle to complete, then halt after the next one.\r
ADC_Wait();\r
ADCS.Halt = TRUE;\r
ADCS.Flag = FALSE;\r
- \r
+\r
do {\r
- } while (ADCS.Flag == FALSE); \r
- \r
+ } while (ADCS.Flag == FALSE);\r
+\r
WDTCR = (1<<WDP3)|(1<<WDP0); // 8.0 seconds at 5 volts VCC.\r
WDTCR |= (1<<WDIF)|(1<<WDIE)|(1<<WDE); // Clear flag and enable watchdog.\r
- MCUCR |= (1<<SE) | (1<<SM1)|(1<<SM0); // Sleep enable, mode = standby.\r
- __sleep(); // Go to sleep, wake up by WDT.\r
- \r
+\r
+ DDRB &= ~(1<<PB6); // MASTER_INT as input\r
+ PORTB |= (1<<PB6); // enabled internal pullup\r
+ WatchdogFlag = 0;\r
+ if ( PINB & (1<<PB6) ) {\r
+ MCUCR |= (1<<SE) | (1<<SM1) | (1<<SM0); // Sleep enable, mode = standby.\r
+ __sleep(); // Go to sleep, wake up by WDT.\r
+ }\r
+ else {\r
+ // stay awake if PB6 is pulled low by master\r
+ do {\r
+ } while ( !(WatchdogFlag) );\r
+ }\r
+\r
__watchdog_reset(); // Clear watchdog reset flag.\r
- MCUSR &= ~(1<<WDRF); \r
+ PORTB &= ~(1<<PB6); // disabled internal pullup\r
+ MCUSR &= ~(1<<WDRF);\r
+\r
+ sreg_saved = SREG;\r
+ cli();\r
WDTCR |= (1<<WDCE)|(1<<WDE); // Watchdog change enable.\r
WDTCR = 0; // Turn off watchdog.\r
- \r
+ SREG = sreg_saved;\r
+\r
ADCS.Halt = FALSE; // Enable consecutive runs of ADC.\r
ADCSRA |= (1<<ADEN)|(1<<ADSC); // Enable ADC & start conversion.\r
- \r
+\r
// Wait for this cycle to complete.\r
- ADC_Wait(); \r
+ ADC_Wait();\r
}\r
\r
\r
unsigned char Error(unsigned char inp)\r
{\r
unsigned char i;\r
- \r
+\r
PWM_Stop(); // Stop charging.\r
DisableBatteries(); // Disable all loads.\r
- \r
+\r
do {\r
Doze(); // Take a nap.\r
\r
for (i = 0x01; i!=0; i<<=1) {\r
if(i & ErrorFlags) {\r
switch (i) {\r
- \r
+\r
case ERR_JUMPER_MISMATCH:\r
// Clear flag & recheck.\r
ErrorFlags &= ~i;\r
ErrorFlags &= ~i;\r
break;\r
\r
- \r
+\r
default:\r
break;\r
}\r
unsigned char JumperCheck(void)\r
{\r
DisableBatteries(); // Disconnect, or loads may be destroyed!\r
- \r
+\r
PWM_Start(); // Start PWM (controls the buck charger).\r
- \r
+\r
// Use general timer: shouldn't take longer than (6 x 255) / 2500 ~= 0.62s.\r
Time_Set(TIMER_GEN,0,1,0);\r
- \r
+\r
do {\r
// If the PWM output voltage saturates the ADC, stop PWM output and\r
// report a failure.\r
// typical value are below our set maximum, everything is OK.\r
if (abs((signed int)(ADCS.VIN - VIN_VBAT_DIFF_TYP - ADCS.VBAT)) <\r
VIN_VBAT_DIFF_MAX ) {\r
- \r
+\r
PWM_Stop();\r
return(TRUE);\r
}\r
PWM_Stop();\r
return(FALSE);\r
}\r
- \r
+\r
// Wait for ADC conversions to complete\r
ADC_Wait();\r
} while (Time_Left(TIMER_GEN));\r
- \r
+\r
\r
// If we end up here, the measurements took too long.\r
PWM_Stop();\r