User Tools

Site Tools


info:mighty_boost_sample_sketch

This is an old revision of the document!


* MightyBoost control sample sketch * Copyright (2015) Felix Rusu of http://lowpowerlab.com http://lowpowerlab.com/mightyboost MightyBoost is a smart backup PSU controllable by Moteino, and this sketch is a sample control sketch to run MightyBoost in this mode. Be sure to check back for code updates and patches * This sketch will provide control over the essential features of MightyBoost: - provide switched 5V power to a sensitive load like RaspberryPi which should not lose power instantly - Control the “5V*” output via Moteino+PowerButton (momentary tactile) - Monitor input supply and switch to battery backup when external power is lost - Monitor battery voltage and issue a shutdown/reboot signal when battery runs low This sketch may be extended to include integration with other LowPowerLab automation products * License * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Licence can be viewed at http://www.fsf.org/licenses/gpl.txt Please maintain this license information along with authorship and copyright notices in any redistribution of this code * #define LED 5 LED pin, should be analog for fading effect (PWM) #define BUTTON 3 Power button pin #define SIG_SHUTOFF 6 Signal to Pi to ask for a shutdown #define SIG_BOOTOK A0 Signal from Pi that it's OK to cutoff power !!NOTE!! Originally this was D7 but it was moved to A0 at least temporarily.

                                // On MightyBoost R1 you need to connect D7 and A0 with a jumper wire.
                                // The explanation for this is given here: http://lowpowerlab.com/mightyboost/#source

#define OUTPUT_5V 4 HIGH on this pin will switch the “5V*” output ON #define BATTERYSENSE A7 Sense VBAT_COND signal (when powered externally should read ~3.25v/3.3v (1000-1023), when external power is cutoff it should start reading around 2.85v/3.3v * 1023 ~= 880 (ratio given by 10k+4.7K divider from VBAT_COND = 1.47 multiplier)

                                // hence the actual input voltage = analogRead(A7) * 0.00322 (3.3v/1024) * 1.47 (10k+4.7k voltage divider ratio)
                                // when plugged in this should be 4.80v, nothing to worry about
                                // when on battery power this should decrease from 4.15v (fully charged Lipoly) to 3.3v (discharged Lipoly)
                                // trigger a shutdown to the target device once voltage is around 3.4v to allow 30sec safe shutdown

#define LOWBATTERYTHRESHOLD 3.5 a shutdown will be triggered to the target device when battery voltage drops below this (Volts) #define RESETHOLDTIME 500 Button must be hold this many mseconds before a reset is issued (should be much less than SHUTDOWNHOLDTIME) #define SHUTDOWNHOLDTIME 2000 Button must be hold this many mseconds before a shutdown sequence is started (should be much less than ForcedShutoffDelay) #define ShutoffTriggerDelay 6000 will start checking the SIG_BOOTOK line after this long #define RecycleTime 50000 window of time in which SIG_BOOTOK is expected to go HIGH should be at least 3000 more than Min

                                // if nothing happens after this window, if button is 
                                // still pressed, force cutoff power, otherwise switch back to normal ON state

#define RESETPULSETIME 500 When reset is issued, the SHUTOFF signal is held HIGH this many ms #define ForcedShutoffDelay 7500 when SIG_BOOTOK==0 (PI in unknown state): if button is held

                                // for this long, force shutdown (this should be less than RecycleTime)

#define ShutdownFinalDelay 4500 after shutdown signal is received, delay for this long to allow all PI LEDs to stop activity (pulse LED faster)

#define PRINTPERIOD 10000

int lastValidReading = 1; unsigned long lastValidReadingTime = 0; unsigned long NOW=0; int PowerState = 0; long lastPeriod = -1; float systemVoltage = 5;

void setup() {

Serial.begin(115200);
pinMode(BUTTON, INPUT_PULLUP);
pinMode(SIG_BOOTOK, INPUT);
pinMode(SIG_SHUTOFF, OUTPUT);
pinMode(LED, OUTPUT);
pinMode(OUTPUT_5V, OUTPUT);
pinMode(A7, INPUT);
digitalWrite(SIG_SHUTOFF, LOW);//added after sudden shutdown quirks, DO NOT REMOVE!
digitalWrite(OUTPUT_5V, LOW);//added after sudden shutdown quirks, DO NOT REMOVE!

}

void loop() {

int reading = digitalRead(BUTTON);
NOW = millis();
digitalWrite(SIG_SHUTOFF, LOW);//added after sudden shutdown quirks, DO NOT REMOVE!
boolean batteryLow = systemVoltage < LOWBATTERYTHRESHOLD;
if (batteryLow || reading != lastValidReading && NOW - lastValidReadingTime > 200)
{
  lastValidReading = reading;
  lastValidReadingTime = NOW;
  
  if (batteryLow || reading == 0)
  {
    //make sure the button is held down for at least 'RESETHOLDTIME' before taking action (this is to avoid accidental button presses and consequently Pi shutdowns)
    NOW = millis();
    while (!batteryLow && (PowerState == 1 && millis()-NOW < RESETHOLDTIME)) { delay(10); if (digitalRead(BUTTON) != 0) return; }
    //RESETHOLDTIME is satisfied, now check if button still held until SHUTDOWNHOLDTIME is satisfied
    analogWrite(LED, 128); //dim the LED to show something's going on
    while (!batteryLow && (PowerState == 1 && millis()-NOW < SHUTDOWNHOLDTIME))
    {
      if (digitalRead(BUTTON) != 0)
      {
        if (BOOTOK())       //SIG_BOOTOK is HIGH so Pi is running the shutdowncheck.sh script, ready to intercept the RESET PULSE
        {
          digitalWrite(SIG_SHUTOFF, HIGH);
          delay(RESETPULSETIME);
          digitalWrite(SIG_SHUTOFF, LOW);
          NOW = millis();
          boolean recycleDetected=false;
          while (millis()-NOW < RecycleTime) //blink LED while waiting for BOOTOK to go high
          {
            //blink 3 times and pause
            digitalWrite(LED, LOW);
            delay(100);
            digitalWrite(LED, HIGH);
            delay(100);
            digitalWrite(LED, LOW);
            delay(100);
            digitalWrite(LED, HIGH);
            delay(100);
            digitalWrite(LED, LOW);
            delay(100);
            digitalWrite(LED, HIGH);
            delay(500);
            if (!BOOTOK()) recycleDetected = true;
            else if (BOOTOK() && recycleDetected)
              return;
          }
          return; //reboot pulse sent but it appears a reboot failed; exit all checks
        }
        else return; //ignore everything else (button was held for RESETHOLDTIME, but SIG_BOOTOK was LOW)
      }
    }
    
    //SIG_BOOTOK must be HIGH when Pi is ON. During boot, this will take a while to happen (till it executes the "shutdowncheck" script)
    //so I dont want to cutoff power before it had a chance to fully boot up
    if (batteryLow || (PowerState == 1 && BOOTOK()))
    {
      // signal Pi to shutdown
      digitalWrite(SIG_SHUTOFF, HIGH);
      //now wait for the Pi to signal back
      NOW = millis();
      float in, out;
      boolean forceShutdown = true;
      
      while (millis()-NOW < RecycleTime)
      {
        if (in > 6.283) in = 0;
        in += .00628;
        
        out = sin(in) * 127.5 + 127.5;
        analogWrite(LED,out);
        delayMicroseconds(1500);
        
        //account for force-shutdown action (if button held for ForcedShutoffDelay, then force shutdown regardless)
        if (millis()-NOW <= (ForcedShutoffDelay-SHUTDOWNHOLDTIME) && digitalRead(BUTTON) != 0)
          forceShutdown = false;
        if (millis()-NOW >= (ForcedShutoffDelay-SHUTDOWNHOLDTIME) && forceShutdown)
        {
          PowerState = 0;
          digitalWrite(LED, PowerState); //turn off LED to indicate power is being cutoff
          digitalWrite(OUTPUT_5V, PowerState);
          break;
        }
        
        if (millis() - NOW > ShutoffTriggerDelay)
        {
          // Pi signaling OK to turn off
          if (!BOOTOK())
          {
            PowerState = 0;
            digitalWrite(LED, PowerState); //turn off LED to indicate power is being cutoff
            NOW = millis();
            while (millis()-NOW < ShutdownFinalDelay)
            {
              if (in > 6.283) in = 0;
              in += .00628;
              
              out = sin(in) * 127.5 + 127.5;
              analogWrite(LED,out);
              delayMicroseconds(300);
            }
            
            digitalWrite(OUTPUT_5V, PowerState);
            break;
          }
        }
      }
      
      // last chance: if power still on but button still pressed, force cutoff power
      if (PowerState == 1 && digitalRead(BUTTON) == 0)
      {
        PowerState = 0;
        digitalWrite(OUTPUT_5V, PowerState);
      }
      
      digitalWrite(SIG_SHUTOFF, LOW);
    }
    else if (PowerState == 1 && !BOOTOK())
    {
      NOW = millis();
      unsigned long NOW2 = millis();
      int analogstep = 255 / ((ForcedShutoffDelay-SHUTDOWNHOLDTIME)/100); //every 500ms decrease LED intensity
      while (digitalRead(BUTTON) == 0)
      {
        if (millis()-NOW2 > 100)
        {
          analogWrite(LED, 255 - ((millis()-NOW)/100)*analogstep);
          NOW2 = millis();
        }
        if (millis()-NOW > ForcedShutoffDelay-SHUTDOWNHOLDTIME)
        {
          //TODO: add blinking here to signal final shutdown delay
          PowerState = 0;
          digitalWrite(OUTPUT_5V, PowerState);
          break;
        }
      }
    }
    else if (PowerState == 0)
    {
      PowerState = 1;
      digitalWrite(OUTPUT_5V, PowerState); //digitalWrite(LED, PowerState);
    }
  }
  digitalWrite(LED, PowerState);
}
int currPeriod = millis()/PRINTPERIOD;
if (currPeriod != lastPeriod)
{
  lastPeriod=currPeriod;
  Serial.print("VIN: ");
  systemVoltage = analogRead(BATTERYSENSE) * 0.00322 * 1.47;
  Serial.print(systemVoltage);
  if (systemVoltage > 4.3)
    Serial.println("  (plugged in)");
  else Serial.println("  (running from battery!)");
}

}

boolean BOOTOK() {

return analogRead(SIG_BOOTOK) > 800;

}

info/mighty_boost_sample_sketch.1456237182.txt.gz · Last modified: 2016/02/23 09:19 by 75.177.137.2