Introduction
Raspberry Pi is an amazing device, packing so much power into a small form factor with such a cheap cost.
Unfortunately, it does not comes with its own power supply. Shutting down involves running the shutdown command and unplugging the USB power.
A video demonstration of the implementation can be found here.
Design
This power supply consists of:
- Push Button - To trigger on, off and forced power off function
- LED light - To show status of, ON (light up), Turning off (blinking), OFF (light off)
- Relay - Driving the power into the Pi using Attiny85 (5V USB power)
- Transistors x 2 (2N2222 or any similar NPN Transistor)
- One for driving the Relay to feed power into Pi
- One for trigging the shutdown command of Pi (using GPIO12 / Pin32 in this example)
- Attiny85 (I used Digispark USB development board for development) - Main controller
Here's how the switch is designed to work:
When power is connected, the attiny85 is powered up, relay is in OFF state and Pi is NOT powered. The attiny85 is waiting for button to be pressed.
- When button is pressed, relay is switched on. Pi is powered and boots up.
- When button is pressed again, the program sends a signal to Pi to shutdown. The Pi has a python script running and listening to signal on the GPIO port. When signal is received, Pi will run shutdown command.
- The program waits until Pi is fully shutdown by monitoring GPIO14 (UART TX) (voltage <0.1).
- Once confirmed Pi is fully shutdown, the program turns the relay to OFF and Pi's power will be cut.
Circuit Diagram
- Circuit diagram also attached:
- P0 of digispark drives the relay to power to Pi
- P1 of digispark drives the status LED
- P2 of digispark takes input from button for power on / off button
- P3 of digispark trigger shutdown of Pi via GPIO12
- P4 of digispark detects if Pi is shutdown via GPIO14 (UART TX)
Using the Code
- Install the sketch into attiny85. I am using Digispark USB development board (
sketch_pi_switch.ino
)
- Run the shutdown script in Raspberry Pi (ShutdownDetect.py)
Points of Interest
int SHUTDOWN_PIN = 3;
int RELAY_PIN = 0;
int BUTTON_PIN = 2;
int LED_PIN = 1;
The powerstatus
variable is used to keep track of the power status of pi.
int powerstatus = 0;
Each loop is delayed by 50ms, making timing a bit easy (e.g., how long the button has been pressed).
If button is pressed for a long time (60 * 50ms) = 3s, force to power down.
if(buttondowncount>=60 && buttonupcount >2)
{ buttondowncount = 0;
buttonupcount = 0;
powerstatus = 5;
}
If button is pressed for a short time (3 * 50ms) = 150ms. Either move from power off (powerstatus
0 to 1) or start power off sequence (powerstatus
2 to 3).
else if(buttondowncount>=3 && buttonupcount >2)
{ buttondowncount = 0;
buttonupcount = 0;
if(powerstatus==0)
powerstatus=2;
else if(powerstatus==2)
powerstatus=3;
}
The next section of the code is where the actions are for each powerstatus
.
if(powerstatus==2)
{
digitalWrite(SHUTDOWN_PIN, LOW);
digitalWrite(LED_PIN, HIGH);
digitalWrite(RELAY_PIN, HIGH);
}
else if(powerstatus==3)
{
digitalWrite(SHUTDOWN_PIN, HIGH);
delay(100);
digitalWrite(SHUTDOWN_PIN, LOW);
powerstatus=4;
checkOffCount = 0;
}
else if(powerstatus==4)
{
digitalWrite(LED_PIN, LOW);
delay(300);
digitalWrite(LED_PIN, HIGH);
delay(200);
if(checkPiOff())
checkOffCount = checkOffCount + 1;
else
checkOffCount=0;
if(checkOffCount==10)
{
digitalWrite(LED_PIN, LOW);
digitalWrite(RELAY_PIN, LOW);
powerstatus = 0;
checkOffCount = 0;
}
}
else if(powerstatus==5) {
digitalWrite(LED_PIN, LOW);
digitalWrite(RELAY_PIN, LOW);
powerstatus = 0;
checkOffCount = 0;
}
The most interesting section would be powerstatus==3
and 4
. Below triggers the pi and runs the shutdown command and sets the powerstatus to 4
(waiting for Safe Shutdown to finish).
digitalWrite(SHUTDOWN_PIN, HIGH);
delay(100);
digitalWrite(SHUTDOWN_PIN, LOW);
powerstatus=4;
Then in powerstatus == 4
, it blinks the LED light and monitors whether the pi is fully in shutdown state.
else if(powerstatus==4)
{
digitalWrite(LED_PIN, LOW);
delay(300);
digitalWrite(LED_PIN, HIGH);
delay(200);
if(checkPiOff())
checkOffCount = checkOffCount + 1;
else
checkOffCount=0;
if(checkOffCount==5)
{
digitalWrite(LED_PIN, LOW);
digitalWrite(RELAY_PIN, LOW);
powerstatus = 0;
checkOffCount = 0;
}
}
Points of Interest
- Digispark does draw some power, even when the PI is shutdown. I am running it in 1Mhz mode so that it draws the minimum power.
- This project can be easily improved to remotely control the Pi's power via Infrared. Let me know your thoughts!