Return to Robotics Tutorials
Installing tslib on Raspberry Pi for GUIslice
This page details the steps involved in installing the tslib touchscreen library for use with the GUIslice library and PiTFT 2.8" Capacitive display.
- Part 1: Tutorial for Installing PiTFT
- Part 2: Tutorial for Installing SDL1.2
- Part 3: Tutorial for Installing tslib
- Installing tslib
- Testing tslib
- Calibrating the touchscreen with ts_calibrate
- Troubleshooting tslib Installations & Fixing tslib errors
- SDL vs tslib for Touch Coordinates
It is possible to use the GUIslice library without tslib, but in my testing with the PiTFT, I found that the native SDL mouse emulation (from touchscreen) produced unreliable results, hence the recommendation for installing tslib here. If the touch coordinates returned by the SDL touch events appear to be working reliably in GUIslice, then there is no need for the tslib installation described here.
In addition to tslib, a couple other packages are also recommended for installation here, including evtest and i2c-tools. Of these, i2c-tools is an essential debug aide when trying to determine whether external I2C devices are connected correctly.
sudo apt-get install i2c-tools sudo apt-get install evtest tslib libts-bin
Note regarding i2c-tools: If you see an error regarding "Could not open file '/dev/i2c-1' or '/dev/i2c/1': No such file or directory", then you may need to enable the kernel I2C module. This can be done by running sudo raspi-config, selecting "Advanced Options", "A7 I2C", pressing Yes and Yes again and then finally rebooting (sudo shutdown -r now).
Installing tslib for C Programs
The above commands will install the binaries associated with the tslib (such as ts_test), but a few extra steps may be needed to enable access tslib APIs from your compiled C programs.
We start by ensuring we have git installed (which gives us access to source code repositories on the web):
sudo apt-get install git automake libtool
Now, we can fetch the tslib source code repository and build it as follows:
git clone git://github.com/kergoth/tslib.git cd tslib ./autogen.sh ./configure make sudo make install
After the above compilation has completed, we will see the "libts" library installed in /usr/local/lib and /usr/local/lib/ts.
In order for gcc or g++ to see this library when linking, it appears that we need to copy these libraries into another location as shown below. Without copying these libraries, you may see the following error during linking: "error while loading shared libraries: libts-1.0.so.0: cannot open shared object file: No such file or directory"). To copy the libts libraries into the /lib/arm-linux/gnueabihf/ directory we can issue the following:
sudo cp -P /usr/local/lib/libts* /lib/arm-linux-gnueabihf/
Test touchscreen from Command Line
The following tests are optional, but they help confirm that the touchscreen is operational in a number of ways. If the touchscreen input doesn't appear to be working correctly, then it may be worth running a few of these tests to see where you encounter differences.
Before we attempt to use tsllib from C we can check its function from the command line (CLI). Touchscreens such as the PiTFT implement an I2C slave interface allowing low-level communication between the CPU (Raspberry Pi) and the touchscreen controller. We can test that the touchscreen controller is accessible by using the i2cdetect command.
Note that many touchscreen devices don't use an I2C interface, so if this doesn't apply to your device the I2C test below can be skipped.
sudo i2cdetect -y 1
|i2cdetect with PiTFT|
The two-wire I2C interface is a simple communication protocol that enables the RPi to read or write a set of registers inside the touchscreen controller. At a high level, the protocol starts with a device address, followed by a register address and then the register data (read or written). The i2cdetect command attempts to read from 128 possible devices addresses (from 0x00 to 0x7F). If a device exists at that address, it can be detected (marked by its address in the readout), whereas all non-responsive addresses are marked by --.
Note that very old Raspberry Pi (ie revision 1) devices may need to use -y 0 instead of -y 1 in the command above.
If the PiTFT touchscreen controller's I2C interface is working correctly, you may see 0x38 or UU in the row and column corresponding to 0x38 in the list of responding addresses. If other I2C peripherals are also connected to the RPi, then you may see other addresses also listed (0x48 and 0x49 in my example here).
Now that we know that the electrical bus interface between the RPi and the touchscreen controller is operational, we can start to use other commands that are included in the tslib installation. We start by confirming that LINUX can see the touchscreen as a device:
ls -l /dev/input/touchscreen
You should see that the touchscreen is linked to a specific event (event2 in the above example). We can now use the evtest utility to watch for the low-level events from the touchscreen device:
sudo evtest /dev/input/touchscreen
After issuing the above and tapping at various locations on the PiTFT touchscreen, you should see a report of each coordinate (ABS_MT_POSITION_X, ABS_MT_POSITION_Y), its pressure (ABS_MT_PRESSURE) and a timestamp. Note that the "pressure" reading represents the touch state. Typically this will be a on / off value (0 for no touch, 127 for touch).
Included in the tslib package is a ts_print utility that simply outputs each coordinate and touch pressure:
sudo TSLIB_FBDEVICE=/dev/fb1 TSLIB_TSDEVICE=/dev/input/touchscreen ts_print
Testing tslib with Graphical ts_test utility
|ts_test Drag Mode|
A more advanced utility to test the touchscreen is ts_test, which provides a graphical interface enabling you to drag a cross-hair around the screen (Drag mode) or draw lines (Draw mode). In order to run ts_test, a few environment variables may need to be set (TSLIB_FBDEVICE specifies the LINUX framebuffer -- PiTFT will use /dev/fb1) and the touchscreen (TSLIB_TSDEVICE -- PiTFT will use /dev/input/touchscreen). These environment variables can be specified on the command-line before the ts_test command.
sudo TSLIB_FBDEVICE=/dev/fb1 TSLIB_TSDEVICE=/dev/input/touchscreen ts_test
|ts_test Draw Mode|
If everything works correctly, you will see a display with cross-hairs that you can drag around the screen (Drag mode). It is worth determining if the position of the cross-hair image lines up to where your finger presses occur. If they don't line up, then you may need to recalibrate your display (see below). Clicking on "Draw" changes the mode to one that leaves visible tracks below your touch-presses.
However, if after executing the above command it is possible that you may see an error referring to "No raw modules loaded":
No raw modules loaded. ts_config: No such file or directory
If this error is shown, then additional environment variable settings may need to be provided on the command-line as shown below. Note that these extra variables may be required in order to run other tslib binaries as well. When calling tslib from a C program, you may need to configure these same parameters via the C putenv() command in your initialization.
sudo TSLIB_FBDEVICE=/dev/fb1 TSLIB_TSDEVICE=/dev/input/touchscreen TSLIB_CALIBFILE=/etc/pointercal TSLIB_CONFFILE=/etc/ts.conf TSLIB_PLUGINDIR=/usr/local/lib/ts ts_test
Testing tslib with Compiled C code for ts_print
Lastly, one can also try building the ts_print utility that comes along with the ts_lib source. If you want to attempt the compilation, you can use the following commands:
gcc -Wall -W -c -o ts_print.o ts_print.c /bin/bash libtool --tag=CC --mode=link gcc -Wall -W -o ts_print ts_print.o tslib_src/libts.la -ldl
To run ts_print, we need to pass a number of environment variables in order for it to work. After much experimentation, I found the following to work with the PiTFT: (note that this should all be entered on one line)
sudo TSLIB_FBDEVICE=/dev/fb1 TSLIB_TSDEVICE=/dev/input/touchscreen TSLIB_CALIBFILE=/etc/pointercal TSLIB_CONFFILE=/etc/ts.conf TSLIB_PLUGINDIR=/usr/local/lib/ts ./ts_print
The above code will continuously output the state of the touchscreen input. Pressing on various parts of the screen should reveal the coordinates as expected. Note that the environment variables listed above can be initialized inside your C program with the putenv() function.
Calibrating the Touchscreen with ts_calibrate
If you are experiencing some misalignment between your touch position and the coordinates / cross-hairs shown above by the ts_test program, you may need to recalibrate your display.
sudo TSLIB_FBDEVICE=/dev/fb1 TSLIB_TSDEVICE=/dev/input/touchscreen TSLIB_CALIBFILE=/etc/pointercal TSLIB_CONFFILE=/etc/ts.conf TSLIB_PLUGINDIR=/usr/local/lib/ts ts_calibrate
After launching the ts_calibrate program, it will ask you to touch the cross-hairs at a few positions across the display. On the basis of your touch-input, a correlation between the TFT display X,Y coordinate and the touchscreen controller's X,Y coordinate can be drawn. The result is a set of calibration values that are written into /etc/pointercal.
The following is an example output from the calibration routine:
xres = 320, yres = 240 Took 13 samples... Top left : X = 176 Y = 61 Took 14 samples... Top right : X = 167 Y = 271 Took 18 samples... Bot right : X = 46 Y = 278 Took 11 samples... Bot left : X = 45 Y = 61 Took 18 samples... Center : X = 113 Y = 170 -16.278198 0.026873 1.030548 244.677582 -1.108725 -0.020114 Calibration constants: -1066808 1761 67537 16035190 -72661 -1318 65536
The actual values recorded to the pointercal calibration file were:
1761 67537 -1066808 -72661 -1318 16035190 65536 320 240
Troubleshooting tslib Installations & Fixing tslib errors
The following section details a few errors that may come up during installation and use of tslib and how to fix them.
- fatal error: tslib.h No such file or directory
This compiler message usually indicates that you have not installed the tslib source code package. See the kergoth git clone command above.
- undefined reference to 'ts_open' (or 'ts_config',
This linker error might suggest you are missing a -lts flag in your Makefile
- /usr/bin/ld: cannot find -lts | collect2: error: ld
returned 1 exit status
This linker error indicate that the tslib may not have been installed. See the autogen / configure / make commands above.
- error while loading shared libraries:
libts-1.0.so.0: cannot open shared object file: No such
file or directory
This runtime error may show up if you didn't copy the libts libraries into the /lib/arm-linux/ tree as shown above.
/lib/arm-linux-gnueabihf/libts-1.0.so.0 is not a
This warning message may come up at various times (eg. even when issuing unrelated apt-get install commands) if you didn't preserve the symbolic link (symlink) when copying from /usr/local/lib/libts* to /lib/arm-linux-gnueabihf/. This can be fixed by deleting the libts* files in /lib/arm-linux-gnueabihf/ and re-copying with the "-P" option (note the capital P, not lower-case).
- No raw modules loaded. ts_config: No such file or directory
This runtime error generally appears when running tslib binaries (such as ts_test) but not providing all of the necessary environment variables on the command-line. See the ts_test section above for the extra environment variables required.
- Could not open file '/dev/i2c-1' or '/dev/i2c/1': No such file or directory
This error message may come up when trying to run "i2cdetect -y 1 and indicates that access to the I2C device is not configured correctly. You may need to enable I2C in raspi-config (see the section above on i2c-tools).
SDL vs tslib for Touch Coordinates
Unreliable touch coordinates from SDL using Mouse functions
The SDL library provides support for touchscreens by making a touch appear like a mouse click. The function SDL_GetMouseState() can be used to fetch the mouse coordinates of a touch event. Unfortunately, I found that the coordinates returned by the SDL_GetMouseState() function were unreliable in that they caused all touch coordinates to be crammed into one corner of the display. It turns out that all touches appeared to be mapped to a coordinate range of (0..59) x (0..59)!
Using tslib to get touch coordinates
To avoid this issue, I decided to use tslib instead of SDL for fetching touchscreen presses. The tslib interacts directly with the PiTFT touchscreen controller via the I2C interface (already integrated into the PiTFT headers). A ts_read() function provides a structure that includes the X & Y coordinates in addition to the touch pressure.
Note that ts_read() is normally a blocking function unless you change the ts_open() call to set the last parameter to 1 (for non-blocking operation). If ts_read() is in blocking mode, then it won't return until a touch occurs, which would stall out your main event loop!
If we're going to use tslib to get the touch coordinates instead of SDL, one should disable the SDL mouse cursor with SDL_ShowCursor(SDL_DISABLE).
Example tslib usage for a GUI
Take a look at the GUIslice library for Raspberry Pi to see more advanced examples!