I will show you how to measure the 5V supply voltage as an example application, but you can easily change this setup to do other things.
There have been so many issues reported with the 5V supply for the Pi that on the latest models the designers added a visual indication for the accepted voltage level. However, this has not really resulted in a much improved situation, judging from the many comments and related problems in the forums.
As we all (should) know by now, the 5V supply is rather critical for the Pi itself, but even more so when peripherals like WIFI adapters are added to the USB ports.
To properly and precisely measure the 5V supply by the Pi itself, additional hardware is needed, because the Pi lacks analog inputs and outputs.
There are several add-ons available that can be used to measure the 5V supply, but I will use this post to go to the basics with a minimum setup. In another set of posts, I will also explain how to add analog output capabilities to the Pi.
Here are these posts:
Output with PWM : viewtopic.php?f=37&t=124130
Output with DAC : viewtopic.php?f=37&t=124184
So, here we go.
I’ll try to make this solution as simple as possible, and I will not go into much details here. In any case, we need a true (there are other tricks) analog input, and we will use a readily available chip to implement that. The MCP3002 is such a device. It provides 10bit resolution on the conversion, has two input channels, and has an SPI interface to communicate with it.
Here is a link to the datasheet: http://ww1.microchip.com/downloads/en/D ... 21294E.pdf
This chip can even be ordered through Amazon for around $4,00 for the 8pin DIP version, which is easy to use with breadboards.
The supply voltage for the MCP3002 is also the reference voltage that is used for the conversion circuits. I won’t go in details here, but that is an important reference for the measurements it makes. In our case, we want to measure the 5V supply, so we can’t use that. It would distort the level and precision of the measurements we want to make because this supply is depending on the chargers or supplies we need to check. However, we also have the 3V3 supply of the Pi available to us, and that is much more stable and precise. We could also use another chip/method to provide a stable and precise reference voltage, but the 3V3 will do fine for this application. Unfortunately, with most ADC’s, they can only measure up to their reference voltage, so we need to apply a trick to measure 5V with a 3V3 reference/supply. The solution is rather simple, we can just use a resistor voltage divider to bring the input voltage below the 3V3 reference voltage.
Let’s examine the precision of what we will be able to measure, and how that works. With a 3V3 reference voltage, and a 10-bit resolution, we will get a precision of 3V3 divided by 10-bits or 1024 different values. 3V3 is 3300 mV, and 3300mV / 1024 gives a 3.22mV resolution for every bit, and that gives a theoretical measurement precision of 3.22mV / 3300mV = 0.097% This is more than enough.
If we use a voltage divider of 1:2, we just need to multiply the measured value by 2 to get the “real” input back. We will use two 10K resistors to create a 1:2 divider, and that allows us to measure up to 6V6 at the input.
You can use higher resistor values, but you may start to influence the conversion process. Let me explain this in simple terms. The ADC works by letting the input voltage charge a capacitor within a certain time period. If you start to limit the charging current by using high value resistors, the capacitor will not charge quickly enough, and you will get lower results than you actually supply because you are fooling the ADC chip.
To tell the chip what to do, and to read back the results, we’ll use the SPI interface. This only uses a few of the pins of the P1 connector, and are readily available. We’ll need a clock signal (SCLK) to send/receive the data and control information. We’ll need the data and control input and output pins (MOSI and MISO), and we need a way to select the proper device, because the Pi can accommodate two SPI devices. We’ll use the CE0 pin for that purpose.
The following schematic shows the connections of the MCP3002 to the P1 connector of the Pi, and also the voltage divider that connects the 5V to the ADC. If you use a breadboard to wire this up initially, I recommend you to use at least a 100nF by-pass capacitor on the reference/voltage pin of the ADC. Better even would be the addition of an electrolyte (C2). The value is not really important, it acts like a simple voltage buffer or reservoir for the chip. OK, that’s it for the hardware. Now what and how do we tell the ADC what to do, and how do we get the results back and interpret those into meaningful measurement results?
This also is rather simple, once you have prepared the Pi, so we’ll go through all the steps.
I am now using the latest firmware (Jessie) as a reference because things changed since we moved to that version of the Debian OS. Keep that in mind.
My OS version is:
First we need to import the SPI drivers so we can communicate over the SPI bus, and some tools to install them.pi@raspberrypi ~ $ uname -a
Linux raspberrypi 4.1.7+ #815 PREEMPT Thu Sep 17 17:59:24 BST 2015 armv6l GNU/Linux
pi@raspberrypi ~ $
Install spidev:
Code: Select all
sudo apt-get install python-setuptools
sudo apt-get install python-dev
sudo apt-get install git
git clone git://github.com/doceme/py-spidev
cd py-spidev/
sudo python setup.py install
Code: Select all
sudo nano /boot/config.txt
Code: Select all
dtparam=spi=on
Code: Select all
sudo reboot
Code: Select all
#!/usr/bin/python
#-------------------------------------------------------------------------------
# Name: MCP3002 Measure 5V
# Purpose: Measure the 5V Supply of the Raspberry Pi
#
# Author: paulv
#
# Created: 22-10-2015
# Copyright: (c) paulv 2015
# Licence: <your licence>
#-------------------------------------------------------------------------------
import spidev # import the SPI driver
from time import sleep
DEBUG = False
vref = 3.3 * 1000 # V-Ref in mV (Vref = VDD for the MCP3002)
resolution = 2**10 # for 10 bits of resolution
calibration = 38 # in mV, to make up for the precision of the components
# MCP3002 Control bits
#
# 7 6 5 4 3 2 1 0
# X 1 S O M X X X
#
# bit 6 = Start Bit
# S = SGL or \DIFF SGL = 1 = Single Channel, 0 = \DIFF is pseudo differential
# O = ODD or \SIGN
# in Single Ended Mode (SGL = 1)
# ODD 0 = CH0 = + GND = - (read CH0)
# 1 = CH1 = + GND = - (read CH1)
# in Pseudo Diff Mode (SGL = 0)
# ODD 0 = CH0 = IN+, CH1 = IN-
# 1 = CH0 = IN-, CH1 = IN+
#
# M = MSBF
# MSBF = 1 = LSB first format
# 0 = MSB first format
# ------------------------------------------------------------------------------
# SPI setup
spi_max_speed = 1000000 # 1 MHz (1.2MHz = max for 2V7 ref/supply)
# reason is that the ADC input cap needs time to get charged to the input level.
CE = 0 # CE0 | CE1, selection of the SPI device
spi = spidev.SpiDev()
spi.open(0,CE) # Open up the communication to the device
spi.max_speed_hz = spi_max_speed
#
# create a function that sets the configuration parameters and gets the results
# from the MCP3002
#
def read_mcp3002(channel):
# see datasheet for more information
# 8 bit control :
# X, Strt, SGL|!DIFF, ODD|!SIGN, MSBF, X, X, X
# 0, 1, 1=SGL, 0 = CH0 , 0 , 0, 0, 0 = 96d
# 0, 1, 1=SGL, 1 = CH1 , 0 , 0, 0, 0 = 112d
if channel == 0:
cmd = 0b01100000
else:
cmd = 0b01110000
if DEBUG : print"cmd = ", cmd
spi_data = spi.xfer2([cmd,0]) # send hi_byte, low_byte; receive hi_byte, low_byte
if DEBUG : print("Raw ADC (hi-byte, low_byte) = {}".format(spi_data))
# receive data range: 000..3FF (10 bits)
# MSB first: (set control bit in cmd for LSB first)
# spidata[0] = X, X, X, X, X, 0, B9, B8
# spidata[1] = B7, B6, B5, B4, B3, B2, B1, B0
# LSB: mask all but B9 & B8, shift to left and add to the MSB
adc_data = ((spi_data[0] & 3) << 8) + spi_data[1]
return adc_data
try:
print("MCP3002 Single Ended CH0 Read of the 5V Pi Supply")
print("SPI max sampling speed = {}".format(spi_max_speed))
print("V-Ref = {0}, Resolution = {1}".format(vref, resolution))
print("SPI device = {0}".format(CE))
print("-----------------------------\n")
while True:
# average three readings to get a more stable one
channeldata_1 = read_mcp3002(0) # get CH0 input
sleep(2)
channeldata_2 = read_mcp3002(0) # get CH0 input
sleep(2)
channeldata_3 = read_mcp3002(0) # get CH0 input
channeldata = (channeldata_1+channeldata_2+channeldata_3)/3
#
# Voltage = (CHX data * (V-ref [= 3300 mV] * 2 [= 1:2 input divider]) / 1024 [= 10bit resolution]
#
voltage = int(round(((channeldata * vref * 2) / resolution),0))+ calibration
if DEBUG : print("Data (bin) {0:010b}".format(channeldata))
print("Voltage (mV): {}".format(voltage))
if DEBUG : print("-----------------")
except KeyboardInterrupt: # Ctrl-C
if DEBUG : print "Closing SPI channel"
spi.close()
def main():
pass
if __name__ == '__main__':
main()
The datasheet of the ADC and the comments in the source should give you a good idea on how this works. If you want to use another ADC, this code should be relatively easy to adapt.
Once downloaded to your Pi, you start the program with:
Code: Select all
python Measure_5V.py
I used a DMM to set the calibration constant in the code, and I use a very stable variable supply with 2.5Amps, set to 5V21 before it goes through a short and solid USB cable. The voltage drop is still about 150mV by the time you measure it at the P1 connector.MCP3002 Single Ended CH0 Read of the 5V Pi Supply
SPI max sampling speed = 1000000
V-Ref = 3300.0, Resolution = 1024
SPI device = 0
-----------------------------
Voltage (mV): 5052
Voltage (mV): 5072
Voltage (mV): 5078
Voltage (mV): 5065
Voltage (mV): 5059
Voltage (mV): 5065
Voltage (mV): 5059
Voltage (mV): 5072
Voltage (mV): 5072
Voltage (mV): 5072
Voltage (mV): 5078
Voltage (mV): 5072
Voltage (mV): 5065
Voltage (mV): 5072
Because I use the "old" Pi, it also has the poly fuse in the circuit. Still, despite the solid supply, there is still a variation in the 5V as you can see. (I use my Pi headless with a WIFI adapter)
I hope this will help you to trace and monitor your supply problems, and that we will see a lot fewer issues with this, now that you have a simple way to measure what voltage actually reaches the Pi. At the same time, I hope you learned how easy it actually is to add analog inputs to the Pi. I hope to do the same in a while to add analog outputs as well, so stay tuned.
With this program as the basis, it should now be easy for you to add data logging, warnings and other bells and whistles, to keep an eye on that dreaded 5V supply, all to your harts delight.
Enjoy!