Raspberry Pi Photo Frame


Our last digital photo frame died a little while ago.  I did some research for a replacement and decided that none really did what I wanted.  Plus, this sounded like a perfect project. The most obvious candidate for the heart of the project is the Raspberry Pi.  There are lots of options for suitable screen from small to large TFT panels.  However, this version is intended as a proof of concept & so keep the costs down in case it turns out to be a disaster.  Adafruit do a fantastic little 2.8″ touch screen TFT panel that nicely mounts onto the Raspberry Pi GPIO.  Both can be enclosed in a variant of the lovely PiBow case. Finally, the project needed to run over WiFi so it could be positioned anywhere in the house.  If this project proved successful a larger screen could be purchased and this little touchscreen could be used for all sorts of other things.


The bill of parts is as follows:

  • Raspberry Pi
  • Adafruit PiTFT 2.8″ Touchscreen
  • Pack of 3mm Tactile Switches (Optional)
  • PiTFT Pibow
  • Edimax EW-7811UN 150Mbps Wireless Nano USB Adapter


Rather than re-inventing the wheel, Adafruit provide a great set of guides for installing & configuring the Raspberry Pi  For this project, follow the first 3 as follows to get as far as a working system with a WiFi network connection:

  1. Adafruit’s Raspberry Pi Lesson 1. Preparing an SD Card for your Raspberry Pi | PDF
  2. Adafruit’s Raspberry Pi Lesson 2. First Time Configuration | PDF
  3. Adafruit’s Raspberry Pi Lesson 3. Network Setup | PDF

Next, assemble & mount the PiTFT board, then install & configure the supporting software:

  1. Adafruit PiTFT – 2.8″ Touchscreen Display for Raspberry Pi | PDF

The configuration of the touchscreen & push buttons are not required for this phase of the project, but are fun to play with.  So go ahead and get them working if you like. This should get you to the stage where the messages are displayed to the PiTFT when you boot the computer.


and you can display an image using the frame buffer image command included in the instructions:


To create a very simple slide show:

# fbi -T 2 -d /dev/fb1 -noverbose -a -t 2 -u *.JPG


-T 2 (required if running over ssh)
-d /dev/fb1 (send the images to the PiTFT) 
-noverbose (don't display onscreen menu) 
-a (automatically resize the image) 
-t 2 (display as slideshow with 2 second transition 
-u (randomise the order of the filenames) 
*.jpg (all the JPEG images in the current directory)

Run as a Service

To make the slideshow start when the Raspberry Pi boots, the frame buffer command needs to be wrapped in an init script and installed as a service. The script included here is a copy of the skeleton init script installed by default & located in /etc/init.d.  This is modified to run the frame buffer command with the options required for the slideshow.  In this example, all the photos are stored in /frame.

Run the following commands logged in as root or use sudo.

Copy the skeleton init script file

# cd /etc/init.d
# cp skeleton fbi

Edit the file so it is similar to my version below.  Then make the script executable and install it as a service.

# chmod +x fbi
# update-rc.d fbi defaults

To start the service:

# service fbi start

The service can be stopped as follows:

# service fbi stop

Below is the fbi init script from my setup:

#! /bin/sh
# Provides: fbi
# Required-Start: $remote_fs $syslog
# Required-Stop: $remote_fs $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: starts fb image viewer
# Description: starts fb image viewer as a slideshow

# Author: Jamie Jackson

# Do NOT "set -e"

# PATH should only include /usr/* if it runs after the mountnfs.sh script
DESC="start frame buffer slideshow"
DAEMON_ARGS="-T 2 -d /dev/fb1 -noverbose -a -t 2 -u /frame/*.JPG"

# Exit if the package is not installed
[ -x "$DAEMON" ] || exit 0

# Read configuration variable file if it is present
[ -r /etc/default/$NAME ] && . /etc/default/$NAME

# Load the VERBOSE setting and other rcS variables
. /lib/init/vars.sh

# Define LSB log_* functions.
# Depend on lsb-base (>= 3.2-14) to ensure that this file is present
# and status_of_proc is working.
. /lib/lsb/init-functions

# Function that starts the daemon/service
    # Return
    # 0 if daemon has been started
    # 1 if daemon was already running
    # 2 if daemon could not be started
    start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \
        || return 1
    start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- \
        $DAEMON_ARGS \
        || return 2
    # Add code here, if necessary, that waits for the process to be ready
    # to handle requests from services started subsequently which depend
    # on this one. As a last resort, sleep for some time.

# Function that stops the daemon/service
    # Return
    # 0 if daemon has been stopped
    # 1 if daemon was already stopped
    # 2 if daemon could not be stopped
    # other if a failure occurred
    start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME
    [ "$RETVAL" = 2 ] && return 2
    # Wait for children to finish too if this is a daemon that forks
    # and if the daemon is only ever run from this initscript.
    # If the above conditions are not satisfied then add some other code
    # that waits for the process to drop all resources that could be
    # needed by services started subsequently. A last resort is to
    # sleep for some time.
    start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON
    [ "$?" = 2 ] && return 2
    # Many daemons don't delete their pidfiles when they exit.
    rm -f $PIDFILE
    return "$RETVAL"

# Function that sends a SIGHUP to the daemon/service
do_reload() {
    # If the daemon can reload its configuration without
    # restarting (for example, when it is sent a SIGHUP),
    # then implement that here.
    start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME
    return 0

case "$1" in
        [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
        case "$?" in
            0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
            2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
        [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
        case "$?" in
            0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
            2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
        status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
        # If the "reload" option is implemented then remove the
        # 'force-reload' alias
        log_daemon_msg "Restarting $DESC" "$NAME"
        case "$?" in
            case "$?" in
                0) log_end_msg 0 ;;
                1) log_end_msg 1 ;; # Old process is still running
                *) log_end_msg 1 ;; # Failed to start
        # Failed to stop
        log_end_msg 1
    #echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2
    echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2
    exit 3



The end result turned out pretty well.  Future improvements would obviously be a bigger screen.  This 2.8″ one works fine on my desk, but would be too small in the living room.  There are quite a few larger options, many of which connect via HDMI.  Using a HDMI connected screen would be more flexible.  Instead of using the frame buffer tool (fbi) to display images, XBMC could be used instead.  This would allow the streaming of video & music also.

I have successfully had XBMC working on a Raspberry Pi with a HDMI connected monitor.  This is straight forward as it is the way it is intended to work.  I tried to get XBMC to display on this screen using the frame buffer but with no success.  Nothing but kernel panic on boot.

An issue with the current set up is that the list of images to display is enumerated once when the fbi command is first called.  If new images are added to the directory, the service needs to be restarted before these new images will be displayed.

An improvement on the current project would be to make use of the touch screen interface to change settings such as refreshing the images list.  The touch screen interface looks fun, so will probably have a go at making it work at some point.

3 thoughts on “Raspberry Pi Photo Frame

  1. I have been looking around for info/pics on getting XBMC to run and operate on the PiTFT screens and I have not found anyone that has been successful. I noticed you attempted it and just wanted to see if you had any luck? Thanks for the help!

Leave a Reply

Your email address will not be published. Required fields are marked *