This article is a work in progress to create a power-controller for the Raspberry Pi based on a PIC microcontroller and MOSFET. The PIC implements an I2C slave to allow power control, and also to approximate the registers of a PCF8563 Real Time Clock (RTC) chip, to allow timed wake-up of the Pi.
- Power the Raspberry Pi off and on with a push-button.
- Fully shut down the Raspberry Pi on ‘shutdown -h’.
- Wake-up at a specified time (one-off or periodic).
- Monitor the supply voltage.
- Log glitches in the power-supply (e.g. caused by USB device activity).
- Maintains the time from a CR2032 button cell.
During power-down, the circuit currently consumes around 5μA of power, useful where a battery is being used to power the Pi (remote solar-power applications, or in-car systems, for example).
The Pi is able to instruct the PIC to power it down using a short I2C command sequence. Wake up events include a push-button, or other voltage-sense on an input pin.
It’s only on a breadboard at the moment, the firmware is very much still a work-in-progress, and the schematics have only been roughly sketched out. I’ll likely paste in another circuit I have to add the options of an LCD display and multi-button inputs using IO expanders.
The PIC chip I’ve chosen is the PIC18F27J13, which has 128K of program memory and over 3K of RAM. This means there’s plenty of room left for custom programs on the PIC to intercept inputs and buffer data while the Pi boots up, and a CR2032 battery backup prevents data-loss in the PIC in the event of power failure.
I’m hoping that the low-voltage programming feature of the ‘J’ family of PIC chips will allow custom firmware to be developed on the Pi and deployed directly to the PIC, but I’ve yet to read up on the implications of this.
The schematic below implements enough to implement a RTC, implement an I2C slave that can be driven by the Pi to turn the power off, and to power the Pi on and off with a push-button.
The 26-way connector used is a female receptacle rather than a 26-way pin-header. This will probably change initially, because there’s no easy way for me to solder a female connector to the copper side of a home-made PCB. Therefore, I’ll likely use pins and a ribbon connector to hook up the board.
Note that Q1 is not the MOSFET used – it’s actually an STU95N2LH5 from ST Microelectronics. This has a much lower Vgs threshold and a very low Rds, which means it switches on fully with 3.3V and drops very little voltage between the drain and the source.
I’ve chosen a USB type A socket (the big ones) for ease of assembly in hand made PCBs. This could be substituted for the same socket as is on the Pi, but it’s a lot more fiddly. A +5V sense pin is probably required so that the PIC can detect when the main power is disconnected.
Beyond this, I’ll probably bring out 5V, 3V3, and some ADC/GPIO pins to external connectors so they can be used to interface with the PIC. The MCP1700 voltage regulator can deliver up to 250mA, which could be useful to external circuits, and the PIC chip has a 12 bit ADC.
The schematic above is a slight modification of the previous circuit that includes a potentiometer to set a voltage threshold to alarm if the voltage goes below (or above, I suppose) the pre-set value.
Firmware and details on integrating with Debian to follow… If you’re in a hurry, then you could implement a push-button just by handling PORTB interrupt on change and toggling LATC7 (after software de-bounce), and perhaps even additionally hooking RB7 to a GPIO on the Pi.
PIC18F47J13 Family Datasheet – details on the PIC18F27J13 used in this project.
Microchip AN734 – Using the PIC Devices for Slave I2C Communication, gives a fairly clear definition of the possible states that need to be handled to implement slave devices.
I’m planning to read out up-to 12 pulses (S0-pulses from kWh meters) using the CCP-modules of two PIC18F27J13’s. The PIC’s need to communicate with the Raspberry using I2C. I’m hoping you can help me out a bit.
There’s a discussion on the Raspberry forum about the topic.
Maybe you can shed some light, as it seems you’ve got some expertise with the PIC’s.
NB: what program are using for the circuit-diagrams?
I had a quick skim over the thread (I recall reading your original post on the forum). My approach would be to use the Interrupt On Change (IOC) feature of PORTB in the PIC18F27J13 and then simply increment counters for low->high or high->low transitions on pins that change (old_PORTB XOR current_PORTB gives you the bits that have changed). Implement an I2C slave device on the PIC to access your counters.
Alternatively use a timer interrupt to poll PORTB for changes every 1ms (for example), assuming the S0 pulses are long enough – I read 50ms mentioned elsewhere. Polling will allow you to count on more than the four PORTB pins that have IOC.
The PORTB or polling-timer interrupt should be serviced as high-priority, and the I2C interrupt as low priority, which means no pulses will be missed during I2C communications. In an I2C interrupt service routine (ISR), you should read counters twice to ensure they’re the same both times before sending back over I2C (because your counters will typically be unsigned long, and reads are not atomic).
I used Cadsoft Eagle to draw the schematic, but created a custom component for the PIC18F27J13 – I intend to post the C code and Eagle library when I get the time to pull it all together. The code will give you a ready-made I2C slave that you can modify for your project, but it’s not too difficult to implement.
Awesome work! I made something similar a while back for my RPI game console but I use an ATTiny85 instead – c code and fritzing files https://github.com/gamaral/rpi-pwrbtn
I’m finishing off another version with a built in RTC and other goodies. 🙂 (but this time using SMT)
I’d found your work from a link from the forum I think, and learned about fritzing in the process. I might add mine there too – I need to learn about how to do Creative Commons hardware.
Anyway nice work, I’ll look out for your new board. I’m thinking of adding IR wake-up support to mine, and then writing the firmware so that sections of the circuit can be left out, with corresponding software configured with #defines. On the other hand, taking it to a bare minimum (e.g. power on button and off via GPIO) would probably warrant a much simpler chip.
Nice workaround. I think you can reduce the complexity a lil’ bit by setting the PIC to use the internal RC oscillator. It should work fine for low speed i2c communications.
Note that the crystal is 32.768kHz specifically for the realtime clock. The problem with INTRC is that it’s not accurately tuned to a frequency like INTOSC, so the the clock would drift. It could be software calibrated, but it may also drift with temperature, for example. However there are doubtless applications that don’t need an accurate clock, or even a clock at all.
I am curious about the statement you made that said “The Pi is able to instruct the PIC to power it down using a short I2C command sequence. ” Does the Pi send a shutdown command to the PIC, which then just cuts the power to the PIC? Or do you somehow determine that the Pi has actually finished shutting down before the PIC turns off your mosfet? I would assume that once the Pi OS has turned off, it obviously can’t send an I2C packet. Just curious about the actual implementation of this.
Yes, the modified ‘halt’ operation in /etc/init.d/halt pushes a specific sequence over I2C – the PIC will delay a few seconds then power off the MOSFET’s gate. It could be signalled with a GPIO pin too, I suppose, but since the I2C bus is shared, we don’t lose any pins using it for shutdown.
Based on your extremely helpful post on driving relays through RPi GPIO, I was able to build something useful.
For my next project, I want to see if I can build a CNC m/c – with heavy duty (24VDC, 4A per phase steppers). If you could post something on making stepper motor drivers, it would be awesome. I have read up sufficiently online & on youtube, to understand stepper motors ( uni/bipolar , pulses, step resolution ), how to make a DIY cnc.
I have also posted on RPi forum asking for help – http://www.raspberrypi.org/phpBB3/viewtopic.php?f=37&t=33124
I think a RPi+PIC + HexBuffer +TIP120 seems to be the best bet – as described http://www.imagesco.com/articles/picstepper/04.html. Does that sound right? Would love to see a post by you on doing something like that. Any other resources you could point me to would be helpful.
I have been looking for doing something similar but why don’t you use a transistor like the TIP120? I have seen that people uses to switch devices from GPIO and it is much cheaper.
What do you think?
Hi, almost a year to discover this … will you plan to continue on this as you say “details on integrating with Debian to follow…”
This site seems stopped in time? sorry to ask but it is TOO interesting
Thanks and regards 🙂
Thanks Hector. I lost interest in Raspberry Pi after the foundation fiddled around so much with the hardware just to get a camera working – they introduced a lot of ‘if-then-else’ blocks in the learning process for no significant gain (in terms of stated aims of the foundation). Still, it’s done now, and at least it happened early on.
Integrating with Debian should be little more than replacing the halt command – providing full PCF8563 emulation would allow the standard RTC driver to be used.
great work, two things I would like to comment on your schematics,
– You can save one resistor for the pushbutton, remove R2 and connect R1 to GND instead. You can then enable the weak-pull-up in the PIC configuration. You will need to change the software though, as the button is now inverted (i.e. button pushed is 0, button open is 1)
– Generally it is considered best practise to switch the positive power rail instead of GND, for that you would need a (more expensive) Low RDS P-Channel Mosfet though.
(working at MSL, check out our RemotePi Board )
Thanks Alex, I’d assumed the power controller would only be of practical use in battery-critical applications (hence peripherals powered directly from the Pi), so was willing to switch ground with a cheaper N-Channel FET that I could buy locally. Perhaps a bit short-sighted of me.
What FET did you choose for your board?
We mostly use the IRFU5305 ( http://www.irf.com/product-info/datasheets/data/irfr5305.pdf ) or similar depending on availability, that P-Channel Mosfet can be driven with 5v logic and has a very low Rds of typically only 0.065 Ohm, i.e. the theoretical voltage drop at 1A is only about 0.07 V (in practise it is a bit higher, about 0.1 V).
It is a bit expensive though (around USD 1.50 at Digikey or RS Components).
Because you use 3.3V logic, which is not enough to drive the Mosfet directly from the microcontroller, in your case you would have to use a second N-Channel Mosfet to drive the IRFU.
So actually it would be quite a bit more effort for your project to use high side switching.