Getting started with the Raspberry Pi 2 and a Adafruit PiTFT 2.8″ capacitive touchscreen display

“We live in an age when unnecessary things are our only necessities” (Oscar Wilde, “The Picture of Dorian Gray”)

Like many others, I bought another Raspberry Pi 2 to play around with, together with an
Adafruit 2.8″ PiTFT capacitive touchscreen
(note that Adafruit has various variants of displays that differ only in details such as resistive or capacitive touchscreen and Raspberry Pi 2 compatibility). Naturally one will like to use the display in both landscape and portrait orientations.

Adafruit has a pretty good tutorial online that covers the software installation part quite well. They offer both pre-built Raspbian images as well as installation scripts that install a custom kernel with special drivers and a device tree overlay that enables the loading of these drivers upon boot. One of the lines added to /boot/config.txt is this one:

dtoverlay=pitft28c,rotate=90,speed=32000000,fps=20

The rotate parameter is thus exactly what we’re looking for when we want to use the touchscreen display in different orientations. To quote:

The rotate= variable tells the driver to rotate the screen 0 90 180 or 270 degrees.
0 is portrait, with the bottom near the "Adafruit Logo"
90 is landscape, with the bottom of the screen near the buttons.
180 is portrait, with the top near the "Adafruit Logo"
270 is landscape, with the top of the screen near the buttons.

As for the actual using the display, it doesn’t really make sense to run X and a full desktop environment on it. Therefore Adafruit recommends PyGame, which is also the way I plan to go. Unlike their instructions I found no reason to downgrade to SDL 1.2 so far, however.

A simple PyGame-based test program looks like this:

import os
import pygame
import time

width,height=320,240

os.putenv('SDL_FBDEV', '/dev/fb1')
pygame.init()
#pygame.mouse.set_visible(False)
screen = pygame.display.set_mode((width, height))

font_big = pygame.font.Font(None, 100)

count = 0
newcount = 0
down_x, down_y = 0,0
old_delta_x = 0

def DrawNumber(nr):
    screen.fill((255, 255, 255))
    text_surface = font_big.render("{0}".format(count), True, (0,0,0))
    rect = text_surface.get_rect(center=(width/2,height/2))
    screen.blit(text_surface, rect)
    pygame.display.update()

DrawNumber(0)
while True:
    for event in pygame.event.get():
        if event.type is pygame.MOUSEBUTTONDOWN:
            down_x, down_y = pygame.mouse.get_pos()
            print "Touched at x: {0} y: {1}".format(down_x, down_y)
        elif event.type is pygame.MOUSEBUTTONUP:
            down_x, down_y = 0, 0
            print "Released"

    if down_x or down_y:
        cur_x, cur_y = pygame.mouse.get_pos()
        delta_x = cur_x - down_x
        if delta_x != old_delta_x:
            print "delta_x: {0}".format(delta_x)
            old_delta_x = delta_x

        if delta_x > 10:
            newcount = count + 1
        elif delta_x < -10:
            newcount = count - 1

        if newcount != count:
            count = newcount
            DrawNumber(count)

This displays a simple counter that increases when a swipe-right gesture is made and decrease when a swipe-left gesture is made. We don't really care about swiping up and down but as you'll notice when testing it is not possible to swipe up/down without also swiping slightly left or right. The code in the version above does very little to filter out this effect safe for only beginning to modify the counter when abs(delta_x) > 10.

For debugging purposes, the code prints the coordinates of the point where the touch gesture began and the current X offset. Furthermore, the line that disables the display of the mouse pointer PyGame usually shows is commented out by intent as we'll see in a follow-up post.

Go ahead and play a little bit with it :)