In a previous article, I explained how I set up a TFT LCD screen on my Raspberry Pi. Because I had been previously using my Pi as a headless server, I hadn’t installed a desktop environment. I wanted to add a lightweight heads-up display to the server, and I wanted a graphical application that could operate without X, the usual graphical system on Linux.

Writing such a lightweight application required understanding how to interact more directly with my new screen, the learnings from which I’ll share here. This article is a summary of multiple sources I pieced together.

Set up framebuffers

Linux provides the concept of a framebuffer, a virtual device that can be read from and written to in order to display graphics. The contents of a framebuffer are then typically displayed on a screen.

On a Raspberry Pi, the HDMI output corresponds to Framebuffer 0, represented by the /dev/fb0 file. If you connected your Pi to a regular monitor or TV, or you’re using another type of HDMI-based screen, you can display graphics by writing to this file.

If you have an SPI-based screen and you followed my previous tutorial, then you have a second framebuffer, /dev/fb1 . With the fbcon=map:10 setting from the tutorial, your console is set to display on Framebuffer 1, which is what shows the console on your LCD screen.

In this section, we will configure the framebuffers to allow for some convenient functionality. Don’t follow these instructions blindly. The goal is to understand what tools are available to you so you can use the ones that make sense for your application.

First, it’s possible the console is not displaying at the right resolution, in which case we can force a particular resolution. In /boot/config.txt , change the following values, which may need to be uncommented. Choose the right resolution for your screen.

framebuffer_width=480

framebuffer_height=320

Next, we will also force the HDMI output to display at the same resolution as the LCD screen. My current understanding is that Framebuffer 0 is the only one that can take advantage of hardware acceleration, so we’ll typically want to display to this framebuffer, then copy the output over to Framebuffer 1. To do so, we want the resolutions to match.

In /boot/config.txt , we create a custom HDMI mode and set the resolution. Again, choose the right resolution for your screen. I like to leave an explanatory comment in the configuration file for my own benefit.

# There are two framebuffers when the LCD is attached:

#

# - /dev/fb0 - represents the HDMI output. This output is hardware-accelerated,

# and therefore should be the target of GUIs.

# - /dev/fb1 - represents the LCD output.

#

# The following settings enable a custom mode (mode 87) that sets the HDMI

# output to the same resolution as the LCD. This is useful so an application

# can target the hardware-accelerated output, and the raspi2fb tool can be used

# to mirror the output to the LCD.

#

# The HDMI group forces DMT output even on the HDMI output. DMT is the standard

# for monitors, in contrast to CEA, the standard for TVs.

hdmi_cvt 480 320 60 1 0 0 0

hdmi_mode=87

hdmi_group=2

Note that you definitely don’t want to do this if you want to display on both the LCD screen and an external monitor at the same time, at different resolutions.

Displaying graphics via the framebuffer