4008-04-07 Release
[avr_bc100.git] / BaseTinyFirmware / GCC / statefunc.c
index ef1464dcab714766f0addf4d6fb0261e04cec53b..9fc0ae5ae08669aecee4f6b6dfa13b1d2c4117c3 100644 (file)
  *      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
@@ -65,6 +65,9 @@ unsigned char ErrorFlags;  //!< \brief Holds error flags.
 //! \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
@@ -93,17 +96,20 @@ unsigned char Initialize(unsigned char inp)
 \r
        // Disable interrupts while setting prescaler.\r
        cli();\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
-                       eeprom_write_byte(&BattEEPROM[page][i], 0);\r
+                       // mthomas: avoid unneeded writes\r
+                       if ( eeprom_read_byte( &BattEEPROM[page][i] ) != 0 ) {\r
+                               eeprom_write_byte( &BattEEPROM[page][i], 0 );\r
+                       }\r
                }\r
        }\r
 \r
@@ -124,10 +130,10 @@ unsigned char Initialize(unsigned char inp)
        }\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
@@ -153,16 +159,16 @@ unsigned char Initialize(unsigned char inp)
 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 (!(eeprom_read_byte(&BattControl[0]) & BIT_BATTERY_ENABLED) && (!eeprom_read_byte(&BattControl[1]) & BIT_BATTERY_ENABLED)) {\r
                SetErrorFlag(ERR_NO_BATTERIES_ENABLED);\r
-               \r
+\r
                return(ST_ERROR);\r
        }\r
 \r
@@ -229,43 +235,72 @@ unsigned char Sleep(unsigned char inp)
                                return(ST_BATCON);\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
+ISR(WDT_vect)\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
+\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_cpu();                            // Go to sleep, wake up by WDT.\r
-       \r
-       wdt_reset();                            // Clear watchdog reset flag.\r
-       MCUSR &= ~(1<<WDRF);          \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_cpu();                            // Go to sleep, wake up by WDT.\r
+       }\r
+       else {\r
+               do {\r
+               } while ( !(WatchdogFlag) );\r
+       }\r
+\r
+       wdt_reset();           // Clear watchdog reset flag.\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
@@ -294,10 +329,10 @@ void Doze(void)
 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
@@ -306,7 +341,7 @@ unsigned char Error(unsigned char inp)
                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
@@ -341,7 +376,7 @@ unsigned char Error(unsigned char inp)
                                        ErrorFlags &= ~i;\r
                                break;\r
 \r
-                                       \r
+\r
                                default:\r
                                break;\r
                                }\r
@@ -386,12 +421,12 @@ unsigned char JumperCheck(void)
        signed int adcs_IBAT_tmp;\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
@@ -412,7 +447,7 @@ unsigned char JumperCheck(void)
                // typical value are below our set maximum, everything is OK.\r
                if (abs((signed int)(adcs_VIN_tmp - VIN_VBAT_DIFF_TYP - adcs_VBAT_tmp)) <\r
                                     VIN_VBAT_DIFF_MAX ) {\r
-                                \r
+\r
                        PWM_Stop();\r
                        return(TRUE);\r
                }\r
@@ -429,11 +464,11 @@ unsigned char JumperCheck(void)
                        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