• Great Success!

    Christoph11/18/2017 at 21:06 2 comments

    It works!

    The initial goal was to have a simple push button to

    • power up a teensy
    • let the application that's running on the teensy know if the button is pressed at runtime
    • let the application itself turn off power when necessary

    My breadboard is populated with:

    • a #LiFePO4wered/18650 
    • this power button
    • a pololu 5V step up/down regulator
    • and a Teensy 3.6 with VUSB cut, so it's powered via VIN from the pololu regulator.

    The basic routing is battery -> power button -> reg -> teensy, and the teensy keeps an eye on the power button's sense output and controls the keep_alive signal (active high):

    And here's the sketch:

    #define SENSE_PIN 34
    #define KEEP_ALIVE_PIN 33
    #define LED_PIN LED_BUILTIN
    
    bool power_button_pressed()
    {
      return !digitalRead(SENSE_PIN);
    }
    
    void setup() {
      // put your setup code here, to run once:
      pinMode(SENSE_PIN, INPUT_PULLUP);
      pinMode(KEEP_ALIVE_PIN, OUTPUT);
      pinMode(LED_PIN, OUTPUT);
      digitalWrite(LED_PIN, 1);
      digitalWrite(KEEP_ALIVE_PIN, 1);
      while(power_button_pressed());
      Serial.println("Starting up");
    }
    
    void loop() {
      static bool power_wait_off = false;
      static const uint16_t power_off_time = 2000;
      static elapsedMillis power_off_timer;
    
      if((!power_wait_off) && power_button_pressed())
      {
        Serial.println("Starting power button timeout");
        power_wait_off = true;
        power_off_timer = 0;
      }
      else if(power_wait_off && (!power_button_pressed()))
      {
        Serial.println("Aborting power button timeout");
        power_wait_off = false;
      }
      else if(power_wait_off && (power_off_timer > power_off_time))
      {
        digitalWrite(LED_PIN, 0);
        Serial.print("powering down, let go of that button.");
        while(power_button_pressed());
        delay(500);
        digitalWrite(KEEP_ALIVE_PIN, 0);
        while(1); // loop until power is gone
      }
    }

     The sketch not only implements the "sense and keep_alive thing", but also takes care of two caveats:

    • Once the board is powered up, the button is still pressed. Before waiting for the long power-off button press, setup() waits until the button is released again
    • When the long button press has been detected, it waits until the button is released again before de-asserting keep_alive. Otherwise, the circuit would power up again as the button is still pressed, and enter an endless on-off loop.

  • Boards and stencil from Aisler arrived, first test

    Christoph11/15/2017 at 00:19 1 comment

    This was in the mail two days ago:

    There were a second sticker and a third board but I just wanted to show top and bottom here.

    The board cuts aren't really clean:

    The result after soldering (the Aisler stencil did a good job!) and adding a teensy:

    In that circuit, I just use the teensy to

    • supply power to the power button board
    • measure the sense output (pin D0 with an internal pullup)
    • measure the output voltage (pin D1)
    • control the keep_alive pin (pin D2)

    Here's the sketch, which

    • prints some state output on Serial
    • when the button is pressed, keeps the output alive for seconds
      #define SENSE_PIN 0
      #define POWER_PIN 1
      #define KEEP_ALIVE_PIN 2
      
      void setup() {
        pinMode(SENSE_PIN, INPUT_PULLUP);
        pinMode(POWER_PIN, INPUT_PULLDOWN);
        pinMode(KEEP_ALIVE_PIN, OUTPUT);
        digitalWrite(KEEP_ALIVE_PIN, 0);
      }
      
      void loop() {
        static const uint16_t on_time = 2000;
        static elapsedMillis on_timer;
        static bool on = false;
        static const uint16_t print_time = 250;
        static elapsedMillis print_timer = print_time;
        if(!digitalRead(SENSE_PIN))
        {
          on_timer = 0;
          on = true;
          digitalWrite(KEEP_ALIVE_PIN, 1);
        }
        else if(on && (on_timer == on_time))
        {
          digitalWrite(KEEP_ALIVE_PIN, 0);
          on = false;
        }
        if(print_timer >= print_time)
        {
          Serial.printf("sense: %01d | power: %01d | on: %01d\n", digitalRead(SENSE_PIN), digitalRead(POWER_PIN), on);
          print_timer = 0;
        }
      }

     This worked as expected.

    I also tried to modify the circuit to make it latch by itself. It just needed a strong enough pullup resistor (I had 2k7 at hand) from Q2's base to Vbat_out and once the button was pressed, power stayed on by itself.

    Next: Test with a Teensy that can shut itself off with this circuit, because that's waht I had in mind when I started this project.

  • Revised a bit, boards ordered

    Christoph11/02/2017 at 20:48 3 comments

    So this is what I'll try:

    There's only one modification compared to the schematic in the previous log: A cap between Q1's gate and Vbat_in. When the button is pressed, this cap will be charged and keep the mosfet open should the switch bounce.

    One of the headers has the same pinout as standard TO-220 MOSFET (G-D-S) so Q1 can be replaced by an external larger transistor, even on a breadboard.

    The PCB:

    The switch is centered so the board won't lean over when pressing the switch while breadboarded.

    A pack of these is ordered from both oshpark and aisler, I'll compare, solder and test them when they're here.

  • First version (untested)

    Christoph10/28/2017 at 19:52 4 comments

    I'll start with this one and write about how I (partially) understand it. It's basically the third schematic from the previous log plus a pull-down resistor for Q2's gate:

    • Vbat_in goes from 3 to 8 V, allowing me to use one or two LiFePO4 cells in series plus some headroom.
    • Q1 is a P-channel MOSFET IRLML6401. The allowed V_GS is 8 V so this part is at its maximum rating. I have it in my parts bin mainly for its low gate threshold voltage, a feature which doesn't come into play here. The gate is pulled high by R1, so it's not conducting if not actively pulled down by Q2 or SW1
    • SW1 is used to enable power to the regulator and subsequently the MCU.
    • Q2 is an N-channel MOSFET IRLML6344. V_GS,th is 1.1 V (max) so it should work well with low-voltage logic input from the keep alive input. The gate is pulled low so it will not conduct if not pulled high actively.
    • D1 and D2 (both SB120) because I had those at hand) make sure that, while Q2 is pulling down Q1's gate, the switch state can still be determined by an MCU connected to the sense output.

    As soon as SW1 is pressed and the MCU is supplied with power, the MCU has to pull up Q2's gate to keep power enabled. The application can use the sense signal to get input from the push button. If, for example, the button is pressed for more than 1 second, the MCU can run some cleanup code and let go of the keep alive signal.

    So much for the theory as I understand it. If you spot any serious flaws in this (especially component choice, since the basic circuit seems to be one that has been proven to work) please leave a comment.

    I might remove R4. If this is built as a breadboardable pcb, the user can then choose to either pull Q2's base up or down depending on the application's needs.

  • Some existing work to start with

    Christoph10/27/2017 at 20:25 0 comments

    Since there are many circuits which do something very similar to what this circuit should do, I'll have a look at some of those first.

    From https://electronics.stackexchange.com/a/140416/18496

    This one seems to be a bit minimalistic, but doesn't have anything I don't need. There's no "press and hold button to switch off again" for example. OTOH, it doesn't feature a sense output to be read by an MCU.

    Next one is again from stack exchange:

    • Different approach without a shottky in the way when compared to the previous one
    • there is a sense output that didn't get the love it needs.
    • Unnamed R (below the push button) must be matched to battery voltage and whatever should be connected to sense
    • Q4 is used to use an active "switch off" pulse rather than a constant "keep alive" and it would need a current limiting resistor for the base.

    There was a lot to find in the eevblog forums. This thread for example. From that one:

    That looks simple enough and it might do what I need. Some things to consider:

    • "switch" (or "sense" in the above notes) is active low and will need a pull-up. No big deal, and that can even be an mcu's internal pull-up.
    • There might be a voltage regulator downstream of "cpu power"
    • There will be large caps downstream of "cpu power"
    • "power" can probably be turned from constant active-high keep-alive to pulse active-low shutdown, but that might come with some delicate timing issues
    • I think the "power" transistor needs a gate pulldown resistor for the keep-alive configuration
    • Is the upper diode really necessary? Wouldn't the lower one suffice?