stm32plus: A full photoframe application

The code presented in this article requires a minimum of version 2.0.0 of my stm32plus library.

About this article

For this next article in the series of stm32plus C++ demonstrations using the STM32F103 series of ARM Cortex M3 microcontrollers I thought that I’d take a break from showcasing LCD drivers and present a fully functional graphical photoframe application.

This one application will allow me to demonstrate several STM32 peripherals and capabilities in a series of upcoming articles. In particular, I will demonstrate:

  • The 4-bit SDIO peripheral.
  • FAT32/FAT16 file systems.
  • Bitmaps.
  • Fonts, proportional and fixed.
  • Hardware LCD scrolling.
  • Animation based on timers and interrupts.

The photoframe application

The goals of this simple application are as follows:

  • Run on a QVGA (240×320) display. To save time we will only support the portrait orientation.
  • Have a touch screen interface.
  • Support hundreds of images.
  • All transitions must be smooth to the eye and all graphical updates should be effectively instantaneous. Users today expect this level of responsiveness.
  • Must not require any external memory or peripherals not included on the STM32F103.
  • Must work on the lowest 72Mhz STM32 that sports the FSMC peripheral. This means the code and anything we compile in with it must fit into 128Kb of flash.

With all that lot in mind, let’s see how we get on.

Handling the graphics

Our primary (and indeed only) mass storage medium in this project is the SD card. Thankfully even the smallest cards these days have gigabytes of storage so no problems there.

Our app requires 240×320 images and 44×58 thumbnails in 18-bit (262K colours) format. Technically we could do the conversion from a format such as JPEG or PNG on the STM32 but that would be a waste of flash space when we’re going to be copying these across from the PC anyway. I do the resizing in Photoshop (which is overkill but I’m familiar with Photoshop) and stm32plus includes a format conversion utility.

The images below are a small selection of my own photographs that we’ll use in this demo.

The bm2rgbi utility

In the utils directory of the stm32plus package there is a PC utility bm2rgbi.exe. This utility will convert an image in any of the main formats (PNG, BMP, JPEG, GIF) to a format suitable for directly sending to the controller of an LCD panel supported by stm32plus.

Usage: bm2rgbi input-image-file output-image-file target-device target-colour-depth [-c]

-c : compress the output in LZG format
Supported devices and colours:
  ili9325 64
  ili9325 262
  ili9327 64
  ili9327 262
  ili9481 64
  ili9481 262
  hx8347a 64
  mc2pa8201 64
  mc2pa8201 262
  mc2pa8201 16
  lds285 64
  lds285 262
  lds285 16

Using the bm2rgi utility I created the necessary full size bitmaps and thumbnails from the resized images saved from Photoshop.

[insert pic of transfer process]

File system

A screenshot of the file system on the SD card is shown below. The images are numbered sequentially from zero and stored in the img subdirectory. The corresponding thumbnails are named similarly and stored in the thumb subdirectory.

The filesystem on the card showing two images

The user interface is controlled by the touch screen on the LCD. When the user starts up the app for the first time the screen must be calibrated. stm32plus contains the routines for doing this, as demonstrated in my earlier article.

After calibration the calibration parameters are serialised to the SD card via an output stream attached to a file called ‘touchcal.bin’. Upon subsequent restarts of the application the calibration data is deserialised and the user is given five seconds to tap the screen if he wants to recalibrate.

High performance SDIO

We have a requirement for high performance. No-one is going to be impressed by images that visibly crawl down to fill the screen from the on-board storage. To achieve maximum performance we use a unique feature of the stm32plus FAT filesystem driver.

The stm32plus FAT file system driver contains a unique function that allows us to find a contiguous stretch of free blocks on the block device that the file system is created on (the SD card here). Since we are embedded and no-one else can pre-empt us and allocate this space to files we can use this free space as we see fit, and I’m going to use it as a fast cache for images.

Images are stored raw on the SD card without corrupting the file system

Reading blocks directly and sequentially from the device is much faster than having to deal with navigating the file system structure at the same time as reading the data. This feature is used by our app to create a cache of the images on startup in the unallocated space that can be dumped directly to the LCD on demand. Cool eh?

The main loop

During the main loop each image is read from the special cache described above and dumped to the LCD. We then pause for a configurable number of seconds before animating the transition to the next image using hardware scrolling. Hardware scrolling is a bit of an exaggeration on the part of the LCD controller manufacturers since all it does is change the position of scan line zero to somewhere other than the top but it does the job for us here.


stm32plus contains a number of animation transitions, known as easing functions, in the fx directory. Animation will be covered in a future blog article, for now you can see the bounce easing function in action in this application. The timing for the animation is controlled by a timer interrupt that triggers actions attached to a timeline.

Control GUI

Tapping the screen at any time gets you the control GUI. Using the GUI the user can go directly to any image using a scrolling windows of up to 8 thumbnails. These thumbnails are small graphic files so I don’t bother storing them in the free space image cache. They are opened and blitted in to the display interactively as the user uses the application.

The controls used in the GUI

The control GUI also allows the user to configure the time between automatic image transitions using an up/down control (sometimes known as a spinner). The stop and play icons offer overall control over whether automatic image transitions are enabled at all.

All of the GUI elements in the control GUI, including each of the numeric ‘seconds’ indicators, were created in Photoshop before being resized down, converted with bm2rgbi and stored on the SD card. All I need to do at run-time is blit them into the display at the appropriate position at the right time.

Watch the video

Here’s a video that shows the app in action. As usual I can rely on my videography and post-production skills to make a slick application look completely terrible.

Get the source code

stm32plus contains the complete source code in the examples directory. it’s open source, have fun.

  • Babu

    Great project.

  • ECL

    Hi Andy, your site definitely rocks! Keep the good work. I want to ask you a little question: in your project you mention this "Reading blocks directly and sequentially from the device is much faster than having to deal with navigating the file system structure at the same time as reading the data. This feature is used by our app to create a cache of the images on startup in the unallocated space that can be dumped directly to the LCD on demand." – Can you do this with standard .bmp files also? or only with .262 files?.

    Also the photoframe video is loading images very quickly has something to do with the .262 format?, I mean, if you change/modify code to read standard .bmp files instead of .262 files, loading speed would be the same? how much does it decrease?

    Best Regards!

    • I can only do it so fast with images that have been converted to the native panel format. When working in this way I can read blocks of data and just pass them straight through to the panel. If I had to convert from a generic file format such as BMP then the data would have to be processed as a stream, uncompressed (if it's compressed) and the pixel format would have to be converted to the native panel format and then written out a pixel at a time. It would be *much* slower.

      If you wanted to create a user-friendly application that allowed users to play common formats from an SD card then I'd do it by pre-processing and caching their files into the native format before the app starts running. Ideally you'd do this on a PC in an "uploader" application, but it could be done on the MCU.

  • Newbie

    Thank your for great project.

    I'm new in embedded programming. Tried to download to my board but result is blank LCD.
    The board I got from here,
    Do you have idea why the screen is blank? From the sample, I'm sure that LCD from this board is ILI9325.


    • I would start by trying one of the simpler projects first, for example the one in examples/ili9325. That one just requires the LCD to work and doesn't bring in lots of other stuff like the touch screen, SDIO and file system. If the LCD still remains blank then check the pin mappings for the backlight and reset line.

  • Kyle Williams

    Where Can I find the simple connection diagram

    • There is no addition wiring – the development board is used as-is. The peripherals used are the FSMC (connected to the 2.4″ ILI9325), SPI for the touch screen and the SDIO peripheral for the data. They’re all directly connected on the dev board.

      • Kyle Williams

        Thank you for the quick reply I know from the past that on the f407 the SPI would be connected as: T_IRQ -> PB6
        T_DO -> PA7
        T_DIN -> PA6
        T_CS -> PB5
        T_CLK -> PA5
        , however; I am unsure of the connection to the SDIO peripheral
        SD_CS -> PC11
        SD_DO ->PC8

        • Yes, in the pframe example I’m using PB6 for the pen IRQ and SPI1 for the ADS7843 controller.

          The SDIO peripheral pinout is given in the comments at the top of this example.

          • Kyle Williams

            Yes, the I/O described in sdio.cpp, i.e. SDIO_CLK, SDIO_D0-D3 and SDIO_CMD, is the Common SDIO I/O I am familair with and the one indicated for my board, homever; on the panel ili9327 or hx8352a the the only ports for the SDIO perhipheral are CS, DIN, CLK and DO