Arduino project: Make your own digital photo frame

There’s no doubt Arduino has quickly become the world’s most popular do-it-yourself microcontroller board system, thanks to its simplicity, versatility and surprisingly low cost. But the key to that versatility is its Shield header that allows daughter boards or ‘shields’ to extend the Arduino’s functionality. In the last project, we built a digital clock project using the popular 1602 alphanumeric LCD shield and it’s hopefully had your mind ticking over with other ideas and possibilities. This month, we’re going a step further, introducing a new low-cost shield that incorporates a 320 x 240-pixel TFT LCD touchscreen.

2.4-inch touchscreen LCD shield

We’re all used to touchscreen LCD panels on our tablets and smartphones, so why shouldn’t Arduino get in on the act? We picked up this new 2.4-inch LCD touchscreen shield on eBay recently for $14 including shipping, but look around now and you’ll find it for under $8 (try searching on eBay). It delivers a 320 x 240-pixel (QVGA) display in a 2.4-inch panel with 16-bit colour and built-in touchscreen, all in a shield that plugs straight into an Arduino Uno board. Not only that, the shield also includes a MicroSD card slot, good for cards up to 32GB.


This 2.4-inch QVGA LCD shield sells for as little as $8 on eBay.

Using the Shield

Now TFT LCD panels for Arduino aren’t new — they’ve been around for a couple of years. But this is the first QVGA shield we’ve seen for under $10 and the first anywhere near that price that doesn’t need an LCD adapter board. (That’s where the adapter board plugs into the Arduino and the LCD panel plugs into the adapter board.)


An LCD panel adapter board is the most common option for Arduino.

Like all shields, this one needs a special code ‘library’ to enable you to program it. But unlike the more expensive alternatives, the library here didn’t come with example code or sketch (Arduino for app code) to make the panel display BMP images. So, we took it as a challenge and we’ve come up with our own BMP image viewer project. It takes any 320-pixel wide 24-bit BMP images located in the root of the MicroSD card, loads them up one at a time and displays them for five seconds, before loading up the next one. Once all of the images have been displayed, it loops again from the beginning.

All you need is an Arduino Uno controller board, the 2.4-inch ‘’ TFT LCD Shield and your own 320-pixel wide BMP images on a MicroSD card.


Unlike most LCD panels, this fits straight into an Arduino Uno board.


How the Shield works

If you think about it, a touchscreen LCD panel shield is the ultimate display and human-interface device — it’s compact, low-power, has enough resolution to display images and text and gives users feedback and control. With a touchscreen, you can do away with control buttons and switches. Well, at least in theory anyway.

If we pull the shield apart into its basic components, you’ve got the LCD panel, the touchscreen electrodes and the MicroSD card slot. Turn the shield over and you’ll see the silkscreen overlay detailing how the Arduino I/O pins are used. And the reality is that the shield uses just about every pin the Arduino Uno has to offer.


Its one major drawback is few I/O pins are left for other functions.

For starters, the LCD panel itself runs an 8-bit parallel data bus — LCD_D0 to LCD_D7, so eight of our I/O pins are gone right there. Next, the SD card needs another four — select, data in, data out and data clock. But the LCD panel needs another five pins to control the eight-bit data bus, taking up five of the six analog I/O pins. So in the end, there’s just one analog I/O and two digital I/O pins left for other uses in your project.


The Arduino Uno R3 microcontroller board runs this Shield happily.

How the sketch works

On your PC, loading up a BMP image is pretty simple — fire up Windows Explorer, select an image and bing — there it is on the screen. But setting up an Arduino Uno to do something similar will give you an appreciation of what your PC is doing.

The sketch is a mashup of code from different sources — some from Adafruit’s LCD library (for a different LCD panel), some from and the remainder our own code. In fact, Justin over at has created a modified library for our LCD shield that is a significant improvement with greater panel write speed.

Here’s a very rough workflow of what the sketch does:

  • Initialise the LCD panel and MicroSD card
  • Load up the first BMP image file
  • Decode the BMP fileheader
  • Read pixel information in three-byte array
  • Convert RGB888 pixel info into RGB565 format
  • Write the pixel data to the LCD panel controller
  • Go back to step 4 until file end is reached
  • Wait five seconds
  • Load up the next BMP image — if no more images, Step 2; otherwise, Step 3.

Most of the work happens in Steps 4 to 7, where the file is read and the individual pixels processed. The thing to remember is there’s no operating system here, no built-in BMP libraries, so the BMP file decoding has to be all done manually.


Our sketch turns the LCD shield into a rolling BMP image viewer.

BMP image fileheader

While an Arduino can easily read an 8-bit byte from a file on the MicroSD card, it’s worthwhile being able to read two-byte and four-byte chunks. These are carried out by the read16 and read32 procedures at the bottom of the sketch.

BMP files have a two-byte ‘BM’ signature at the start of the file — those bytes should read 0x4D42. Otherwise, it’s probably not a BMP image file. From there, the file includes basic information such as the horizontal and vertical resolution, the pixel depth and whether or not the image is compressed. Provided there is a 24-bit colour depth and no compression (0), we’re good to go.

RGB888 to RGB565

One reason why these LCD panels can be so relatively cheap, apart from being small, is that they only support 16-bit (65,536) colour, rather than 24-bit colour that most LCD monitors, new phones and tablets deliver. So in order to display a basic 24-bit BMP image, we need to either convert the image into 16-bit format before loading it onto the MicroSD card or we get the Arduino to convert it ‘on the fly’. Since few image editors support 16-bit colour BMP conversion, we decided to get the Arduino to do it instead.

Normal 24-bit-colour uncompressed BMP images have pixel data stored in a form known as RGB888. It means each pixel requires eight-bits of data for each of the three primary colours — red (R), green (G) and blue (B). But as we said earlier, the LCD shield supports only 16-bit, a format called RGB565 — five bits for red, six for green and five for blue.

Here’s how it works.

A green pixel in RGB888 format looks like this:


As you can see, the hexadecimal notation for this would be 0x00FF00. But in RGB565 format, the same pixel looks like this:


Remember, the first five bits are red, the next six are green and the final five are blue. Our converted RGB888 green pixel now becomes 0x07E0 in 16-bit hex notation. (If you’re new to hex notation, you count from 0 to 9 and A to F, covering four binary bits.)

Thankfully, the TFT LCD library has a command for this appropriately called RGB565. It uses clever low-level bit-shifting to convert RGB888 to RGB565 in pretty quick time, so we don’t have to do it manually. Still, understanding bit-level maths is really important when you get into deeper waters with Arduino — it’s not only the way you switch on advanced features in the ATMEGA328P chip, it’s also the way you get more speed.

Shield limitations

We’ve already looked at the major limitation this particular Shield has when it comes to leaving free I/O pins on your Arduino board, but there are a couple of others.

The first is the obvious banding. We’re not sure why but the panel has a distinct banding pattern that rather spoil colour photos. This isn’t just a one-off problem: other users are reporting the same pattern with this shield. It seems to fare much better when you feed it primary colours, so where possible, we’d stick to using 16-colours. Still, that’s not terrible — it’s perfectly useable for creating touch control buttons.

The other issue is speed — even with Justin’s library tweaks, it takes time for a 16MHz/8-bit microcontroller to convert 24-bit pixels into 16-bit ones and write them to the LCD controller video memory. You’ll find a 320 x 240-pixel BMP image will take around three seconds to load. That said, it’d be considerably faster if we didn’t have to do the RGB888 to RGB565 conversion for every pixel.


LCD panels up to 7-inches can run on some Arduino boards.

The touchscreen control

While it’s not clear from the pins, the touchscreen control information is delivered by the LCD I/O pins and eight-bit data bus. Because this shield is so low-cost, it uses the old resistive touchscreen technology. Here’s a brief run-down of how it works.

The touchscreen is made of up two polymer layers coated with a resistive material acting as electrodes. By pressing at a particular point, the resistive elements not only indicate where the screen was pressed but also the pressure applied. The layers are glued at the edges of the LCD panel and five wires (four conductors plus ground) connect via a thin ribbon cable bending back around to the LCD controller underneath the panel frame.


The touchscreen surface electrodes join the controller chip via this ribbon cable.

The idea is that you program your Arduino to continuously check or ‘poll’ the resistive elements to detect when the screen is being pressed. From the co-ordinates, you can then determine which screen control or ‘button’ was pressed and perform the appropriate action, whatever it is.

The resistive elements and LCD controller simply return a 10-bit number (0..1023) for each axis. You then use the map command to scale it to fit the resolution of the LCD screen.

Touchscreen example

While the BMP image viewer shows how to program the LCD panel, it doesn’t incorporate touch. So instead, we’ve come up with a simple touchscreen example that creates a phone keypad. Press the numbers and they’ll appear across the top, as if you’re typing a phone number.

The sketch adds the TouchScreen library to the TFTLCD library we used before. The key initialisation code is:

TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300);

The two touchpanel plates have two electrodes each: X+ and X- for the X-axis; Y+ and Y- for Y-axis. The ‘300’ is the nominal resistance of the panels in ohms. Using the getPoint() command, the library returns a three-point coordinate map indicating where the on the panel (x, y) is being pressed and with what amount of pressure (z).


Using the TouchScreen library, you can create a numeric keypad.

MicroSD card reader

The Shield’s MicroSD card slot is SDHC-ready, meaning it’ll handle cards up to 32GB in size. However, while the standard SD library that comes with the Arduino IDE includes support for FAT16 and FAT32 filesystems, it only allows the old DOS-style 8.3-character filenames (eight characters for the name, three for the extension). The reason? The Arduino’s limited 2KB RAM would be quickly chewed up if long filenames (up to 256 characters) were allowed.


The MicroSD card reader on the back is good for cards up to 32GB.

Arduino has two modes for accessing files on SD storage — you can name the file or you can simply load a file by its index using the SD.openNextFile() command. Each time you open a file, the file counter is incremented until you reach the last file in the directory. At that point, you issue an SD.rewindDirectory() command and you can start again. Our BMP image viewer sketch uses this method.

What’s next?

Touchscreen LCD panels are a great option for reducing the component count of your project, but remember they won’t suit every design (everything looks like a nail to a hammer). That said, hopefully you’ll be brimming with ideas that can make use of either the 1602 alphanumeric shield or this QVGA TFT LCD shield. We already have a couple of LCD projects on the go we hope to present in the not-too-distant future.

Where to get the sketch

You can download the sketch and libraries for the 2.4-inch TFT LCD Shield from our website at Unzip the archive and copy the contents of the /libraries folder into the /libraries folder of your Arduino 1.0.5 IDE. You can download the Arduino software from

  • cts_casemod

    “While it’s not clear from the pins, the touchscreen control information is delivered by the LCD I/O pins and eight-bit data bus. Because this shield is so low-cost, it uses the old resistive touchscreen technology.”

    90% of arduino shields (even if more expensive) use this same technology.
    Also the Touchscreen information is multiplexed with the control pins trough the Analog pins A0 to A4. It does not use the eight bit data bus.

  • ogdento

    where can you get the code for the keypad? it doesn’t seem to be in the zip. thanks!

    • It’s not in the zip file, because it’s not part of this project. (It’s, in fact, something I’m working on separately that isn’t finished – give you three guesses what it might be though…).

      • ogdento

        Fantastic!! I’ve been wanting a reverse polish arduino powered touch calculator! Actually I can think of lots of projects for this touch panel, thanks for the awesome writeups. Hope to see your new one on apcmag.

  • Venkat Raghavender

    hello sir! i m a beginner in using arduino,so can u please demonstrate the bmp viewer project in a video to my mail!!

  • Venkat Raghavender
  • Venkat Raghavender

    sir can u plz post the source code for photo frame using arduino!and how to implement the source code

  • Pauline Davis

    Great Article. analysis , I loved the analysis – Does anyone know where my business could get a blank IRS 1023 copy to fill in ?

  • Brandon La

    Will this source code work on Kedei taobao TFT LCD together with arduino MEGA

    • Probably not. Different Arduino, different LCD module and very likely different driver chip.