Monday, February 4, 2013

Jumbo Digital Picture Frame

What do you do with a spare flat panel monitor?  If you are a Raspberry Pi hobbyist, you turn it into a jumbo size digital picture frame.  Photography is another of my hobbies and this is a great way to display my work.

Hardware Part 1 - Modify the Monitor Power Supply

This section requires some knowledge of power supplies and delicate soldering skills.  This step is totally optional and can be skipped.  I didn't want a second wire hanging from the picture frame for the Raspberry Pi power supply, so I tapped 5V off of the monitor's power supply.  You can power the Pi normally.  If you are really lucky you will have a monitor with a built in USB hub and you can power it from there.

I completely disassembled the monitor and located 5V and ground on the back side of the power supply where one of the connectors attached.  The wires in the lower right of this image show the power lines that I attached.

I shouldn't need to say this, but: DANGER.  Make sure the power supply is unplugged when you work on it.  Mains power can kill you!


Hardware Part 2 - The Control Panel

The monitor outputs 5V even if it is turned off, because it isn't really off - just in standby.  I added a power switch and LED as well as a push button to signal the Pi to shut down.  A simple script will monitor the pushpbutton and execute a halt when it is pressed.




If you only want to install the shutdown button, just connect it to a GPIO pin and to ground.  The pinouts that I used are shown here.  Don't be concerned about the inconsistency in the GPIO pin numbers.  This is explained below and is due to differences in the pin numbering used by the Raspberry Pi developers, the native pin numbers on the BCM chip, and the WiringPi library.



Hardware Part 3 -Build a case and put it all together

I used the plastic from the case to an old backup tape.  These are more flexible and a lot less brittle than most plastic CD cases.  I was able to use scissors to cut the plastic to fit the curved shape on the rear of the monitor.  Machine screws hold the case together tightly enough to keep the Raspberry Pi in place.  It is mounted so that the SD card extends a little bit below the monitor.  I would have liked to have it all hidden, but there wasn't room and this does make it easier to remove and insert the SD card.

Both the case and the control panel are held in place with Velcro   This allows me to peel the case loose so that I can plug a network cable in if needed.  Tie wraps are used to hold the HDMI cable and power cable neatly in place.  It is a very tight fit.

A added a short length of rope for hanging which is attached to the top two VESA mounting screws.  My frame is 21 inches and is quite a bit heavier than a typical painting, so I wanted something stronger than a typical picture hanger on the wall.   My work of art wouldn't be happy crashing to the floor.  I was very lucky and found a stud in the wall exactly where I wanted to mount the frame.  If you have to use drywall anchors, then I recommend using two about four inches apart and make the rope long enough to go over both.  If your walls are stucco, then I wish you luck.

System Preparation

Windows only recognizes the first partition on removable media and I wanted a large FAT partition to put the pictures on when the SD card is plugged in to my Windows laptop.  That means I had to use the /boot partition for this purpose.

  1. Load Raspbian as usual. Shut down the Pi and remove the sdcard.
  2. Install "Minitool Partition Wizard Home Edition" on a windows system with an sdcard slot. http://download.cnet.com/MiniTool-Partition-Wizard-Home-Edition/3000-2094_4-10962200.html
  3. Run the partition wizard and move the second partition (the system partition) all the way to the end of the disk space.  You could shrink the partition first but I didn't bother.
  4. Expand the first partition to fill the remaining space.
  5. Put the SD card back into the Pi, boot up, and log in.
  6. Update the apt database using:  sudo apt-get update
  7. Install the Linux Frame Buffer Interface using:  sudo apt-get install fbi
  8. Create a directory to hold the pictures that the frame will display:  sudo mkdir /boot/PICTURES 
  9. Create a new user named "slideshow" which is a member of the "video" group:  sudo adduser slideshow --ingroup video
  10. Change the inittab file to automatically log on the slideshow user:  sudo nano /etc/inittab   Find the line that begins 1:2345:respawn:/sbin/getty --noclear 38400 tty1  Comment out that line by placing a # in front of it and then add this line:  1:2345:respawn:/bin/login -f slideshow tty1 </dev/tty1 >/dev/tty1 2>&1
  11. Create a script to run the slideshow:  sudo nano /boot/slideshow.sh  which includes this one line: fbi -noverbose -m 1920x1080 -t 10 /boot/PICTURES/*.jpg   
  12. Some notes about the fbi command line:  The -m option specifies the resolution to use on the monitor.  This may need to be changed to display better for the monitor that you use.  The mode specified must be in the /etc/fb.modes  file.  I had to add the mode I needed, which is shown below.  The -t 10 option causes the program to run a slideshow with a 10 second period for each picture.  The -a option causes the program to automatically resize the images to fit the screen.  When I first tried this I was using 10 mega pixel images (about 3800 pixels across) and the Pi was taking 8-10 seconds to perform the resize.  To prevent this I removed the -a option and used FastStone Image Resizer to resize all the pictures for my slideshow to fit into a 1920x1080 screen.  You can find that utility here: http://www.faststone.org/FSResizerDownload.htm
  13. Make the script executable:  sudo chmod 775 /boot/slideshow.sh
  14. Edit the bash login script for the slideshow user:  sudo nano ~slideshow/.bashrc  and add this line to the end:   /boot/slideshow.sh
  15. Once all of the above has been done, you can reboot and the system will automatically run the slideshow.  You can stop it by pressing Control-C on the keyboard.
  16. Of course, you have to put some pictures in the pictures directory.  You can do this many ways, but I re-partitioned the sdcard so that I could plug it into my laptop and copy pictures directly to the sdcard.  The fbi command will support formats other than JPG, so don't feel that you are limited to that format.  You do need to realize that Linux is case sensitive with file names, so be sure to rename them all consistently. 

Here is the block that I added to the /etc/fb.modes file:


mode "1920x1080"
    geometry 1920 1080 1920 1080 32
    timings 0 0 0 0 0 0 0
    accel true
    rgba 8/16,8/8,8/0,0/0
endmode


The default fb.modes file did not include a 1920x1080 resolution so I had to find this example.  Fortunately it  works fine with my monitor.  More information about the fb.modes file can be found here:

Trigger Shutdown Script 

The drawing above shows the shutdown switch connected to GPIO-1.  I normally refer to the GPIO pins using the WiringPi numbering scheme.  However, I am not using WiringPi for this project.  We will access the GPIO pin via the /proc filesystem.  WiringPi GPIO-1 is GPIO-18 to the system.

Create a script to monitor the pin and perform a shutdown: sudo nano /etc/ini.d/wait-for-trigger.sh   
The contents of the script is this:


#!/bin/bash

# monitor GPIO pin 18 (wiringPi pin 1) for shutdown signal

# export GPIO pin 18 and set to input with pull-up
echo "18" > /sys/class/gpio/export
echo "in" > /sys/class/gpio/gpio18/direction
echo "high" > /sys/class/gpio/gpio18/direction

# wait for pin to go low
while [ true ]
do
if [ "$(cat /sys/class/gpio/gpio18/value)" == '0' ]
then
echo "SHUT DOWN NOW *****"
        halt &
        exit 1
fi
sleep 1
done


First, the GPIO pin is configured for input with a pull-up resistor enabled.  Then the scripts loops once a second and checks if the pin is pulled low from the push button being pressed.  If it is, then it executes the halt command and exits.

This script must be run at startup.  The easiest way to accomplish this is to add it to the end of the local startup script:  sudo nano /etc/rc.local
Add this line at the end of the file:
/etc/ini.d/wait-for-trigger.sh &
The & at the end of the line makes the command run in the background.  Without it, the local.rc script would not exit and the system would hang on startup.

All Completed:




Saturday, January 5, 2013

All cleaned up and re-mounted

A nice clean board (actually, i just flipped the old one over) and all components re-mounted.  System is up and running 24/7 now.
The Cleanly Re-Mounted Alarm/Automation System

Reading Temperature With Thermistors

My first interest for an analog input is a probe to read the temperature in my beer fridge. (I am a home brewer and occasionally need closely controlled temperature for fermenting lagers.) There were a couple of 10K ohm thermistors in my box of misc components, so I decided to try those. Something like the TMP36 sensor may be a better choice, and I will try some of those soon.

A thermistor is a special type of resistor that changes resistance with temperature.  A 10KΩ thermistor is 10KΩ at 25°C.  The first problem to solve is how to use the thermistor to produce a voltage that the MPC3008 analog to digital converter can read.  A simple voltage divider, as show in the diagram here, will do the trick.

The thermistor is R1, R2 is 10KΩ, and Vin is 5V.  This will make Vout = 2.5V at 25°C.  The chart for this thermistor shows that it should vary from 1.3V at 32°F to 2.9V at 95°F.  Setting the reference voltage on the MPC3008 to 3.3V will provide the best resolution for this range. I took test measurements by placing the thermistor in an insulated cup of water ranging from ice water to very warm.  Well, that was the plan anyway.  Reminder to self: when using a thermistor or other sensor in water, shrink tubing won't cut it.  I got a rude reminder of this when I first tried to do a calibration.


My solution to the waterproofing was to simply encase the thermistor and connecting wire in epoxy.  I formed a small mold using wax paper, filled it with freshly mixed epoxy, and pushed the sensor into the epoxy.  Once it dried, I trimmed it and it came out looking like this.














I took test measurements successfully and put the data into Excel. The plot of this data shows, as expected,  a very linear curve.  Putting this data into a Least Squares Fit function produced a slope of 0.13239 and an intercept of -14.402.  This gives me parameters to convert from counts to degrees with reasonable accuracy.  Once in use I will probably need to tweak the intercept value for individual sensors due to variations in the components.

The MPC3008 is a 10 bit ADC, meaning that it will output a value between 0 and 1023.  This corresponds to zero and reference volts.  For example, if the reference is 5V, an input of 2.5V would give an output of 512 counts.  To convert from counts to volts:

            V = Vref *counts/1024

Now that I have the data from my earlier calibration, I can simply use that to convert directly from counts to degrees F.

           Temp = -14.402 + (Counts * 0.13239)

My automation/alarm software has now been enhanced to read the analog data and convert it to real values using the provided conversion parameters.  I am now monitoring the temperature in my beer fridge and once I set up a large relay to control the power, I will be able to finely control the temperature and maybe brew a decent lager.

Saturday, December 22, 2012

Analog Interface

The capability to read analog inputs is a feature that is greatly missed on the Raspberry Pi, but I agree with the decision to omit this capability in order to keep the price down.  Besides, if they did include an analog interface, many would complain that it isn't adequate for their purpose.  How many input channels do you need?  What resolution? 8 bit, 10 bit, 12 bit 16 bit?  What throughput rate?

Fortunately, there are many analog input chips that use the SPI or I2C bus, making it almost trivial to add analog inputs to the Pi.  I chose the MCP3008, an 8 channel 10 bit ADC available from Adafruit.com.  Add a bi-directional logic level converter and some connectors and you're ready to go.

The level converter is on my main interface board which provides two SPI bus connectors.  The analog interface is a simple board which includes a connector for SPI, the MCP3008 chip, a jumper to choose the analog reference, and screw terminals for the inputs.  I ended up adding several more screw terminals connected to 5V in order to power thermistors. 

The SPI serial bus is full duplex, but the way it works may seems odd to a programmers point of view.  (It makes perfect sense if you understand how the hardware works.)  You may be familiar with how full duplex works on an RS-232 line: data can be sent and received at the same time, but independently.  That independence is due to the fact that RS-232 is an asynchronous protocol.  SPI is a synchronous protocol; meaning everything is driven by a clock pulse.
Data bits will be sent out the MISO line on each cycle of the CLOCK line.  At the same time data bits are being read in on the MOSI line.  The number of bits out is the number of bits you will read back in.  This means that you may have to write more bits than expected for a given command and you may read bits that are unused.

Fortunately, we don't have to worry much about the ugly details at the lower level.  There is a device driver for SPI that is included with the recent versions of Raspbian and the WiringPi library provides support for SPI I/O.  The functions wiringPiSPISetup and  wiringPiSPIDataRW are all that is needed.  Here is the source code for a program that I used when testing and calibrating sensors.


#include <stdio.h> #include <stdint.h> #include <wiringPi.h> #include <gertboard.h> // read SPI data from MCP3008 chip, 8 possible adc's (0 thru 7) int readadc(adcnum) { uint8_t buff[3]; int adc; if ((adcnum > 7) || (adcnum < 0)) return -1; buff[0] = 1; buff[1] = (8+adcnum)<<4; buff[2] = 0; wiringPiSPIDataRW(0, buff, 3); adc = ((buff[1]&3) << 8) + buff[2]; return adc; } int main(int argc, char *argv[]) { int i, chan; uint32_t x1, tot ; printf ("SPI test program\n") ; // initialize the WiringPi API if (wiringPiSPISetup (0, 1000000) < 0) return -1 ; // get the channel to read, default to 0 if (argc>1) chan = atoi(argv[1]); else chan = 0; // run until killed with Ctrl-C while (1) { tot = 0; for (i=0; i<100; i++) { // read data and add to total x1 = readadc(chan); tot += x1; delay(10); } // display the average value printf("chan %d: %d \n", chan, (tot/100)) ; } return 0 ; }

Note: The SPI device is not loaded by default.  The easy way to get it loaded is to used the "gpio" utility that comes with the WiringPi library.  Just enter
      gpio load spi
and the drivers will be loaded and ready to use.

Tuesday, December 4, 2012

Dual power supplies is the way to go

You may notice in the picture of my setup (in the previous post) that the Raspberry Pi is being powered normally via the USB power connector.  This was done because the Pi was failing to boot when powered through the GPIO port as I had planned.  While I did not do any tests, the obvious cause is a lack of sufficient current to power the Pi.  It really does want to have a solid 700mA of 5 volt juice.  My planned configuration worked fine on the workbench but failed once I mounted it on the wall and connected the alarm sensors.  The sensors require 12V power and I was using the same power supply to drive the sensors and the power adapter for the interface board.  That 12V power supply was only 2A and that was apparently too little for all of this.

I could have gotten a larger 12V power supply, but I already have several of these 2A supplies. Realization finally struck me that using a single power supply would be a mistake.  If any of the sensor lines was compromised, shorting the power to ground, it would cause the Pi to shut down suddenly.  So now I have one supply just for the alarm sensors and another that drives the interface board, and through that, the Pi.

The system is up and has been running for over a week with no major problems.  I spent several hours improving my code for driving the X10 interface to make it as reliable as possible.  It seems to work as well as it ever has when using heyu or ActiveHome to drive it.  X10 is inherently unreliable, but is usually good enough for casual use.  If you have a fairly new house that is wired properly, then it can work fairly well.  My house, unfortunately, is old and poorly wired.  I have made some improvements over the years, but there are still areas of my house that the X10 signals simply will not reach.  I will cover X10 in more detail in an future post.

Tuesday, November 27, 2012

Mounted and Testing Begun

The interface is complete now with all (well, most anyway) of the kinks out of it.  Here it is mounted on the wall in a utility area of the house.


I still need to install a few more sensors for the alarm system and I will soon add analog input using the SPI bus.  That worked just as expected on the breadboard.  You can see it connected in the blog post below.

There was some discussion on the forum about the serial connection for the X10 interface.  My CM11a works fine with just Tx, Rx, and GND connected.

The power supply was salvaged from a micro ATX PC case.  The 12V power supply that powers it is only 2A and I had trouble running the RasPi powered from my interface.  It worked fine on the bench with these same power supplies.  I assume that the motion detectors, which are wired to the same 12V supply are drawing too much current. This causes the ATX PS to fail to output adequate 5V current.  For the time being I have removed the power jumper (+1 for configurability) and just power it the normal way.  Once I get a beefier 12V PS, I will try powering the RasPi from the interface again.

Monday, November 5, 2012

Interface Completed

After yet another design change, I finally have the interface complete and ready to test.
Version 7 Finally Comes to Life



          ✓ Serial Port
          ✓ 8 Digital Inputs
          ✓ 4 Relay Outputs
          ✓ 2 SPI Ports
          ✓ 1 I2C Port
          ✓ Fused Power to Pi




Making the fuse involved the tiniest soldering I have ever done.  That is a surface mount poly-fuse soldered to two wires.  Once connectors are added, it is used for the jumper that connects the interface board 5V supply with the Raspberry Pi GPIO 5V pin.

The picture above shows one SPI port connected to an ADC chip on the bread board.  Once everything checks out, it will be time to mount it all.