Archive for Raspberry Pi

Raspberry Pi console on a 128×160 TFT display

It can be really annoying if you want to connect to a headless Raspberry Pi which has been assigned a (yet) unknown DHCP address. In this posting, I will show how I added a 128×160 pixel TFT display to the Pi in order to display and even change the network configuration on the fly.

Hardware part

My primary intention was to find a display that would fit into my transparent RS Components Raspberry Pi case, such that the display could be mounted on the inside, which would give it some protection. Due to the case’s dimensions, the maximum display board height was approximately six centimeters. I did hence order a SainSmart 128×160 pixel TFT display from eBay, which turned out to use a ST7735 controller. The PCB is 5.0cm long and 3.4cm wide, and fits nicely into the case. Well, after changing the right angle pin headers for straight ones, that is.

Connecting the display was a straightforward task. I hooked the SPI pins up to MOSI and SCK (unidirectional – the MISO pin is left unconnected), and attached the Chip Select (CS) pin to CE0. The display has two further inputs that I attached to the Raspberry, namely the data/control pin (DC) and the reset (RES) signal, which I attached to GPIO pins 24 and 25. The display runs on 5V, so I used the supply voltage from pin 2 of the Raspberry’s P1 connector.

Software part

I actually needed several tries to get the display working seamlessly. If you are only interested in the outcome, click here to jump to the relevant part. Otherwise feel free to follow the full story.

Approach #1: Writing a daemon to display the IP address

My first thought was to do everything in userland and use the wiringPi library and existing Arduino code for the display’s initialization and pixel drawing from the Adafruit ST7735 library.

The following steps were required to accomplish this:

  • Installation of rpi-update by following the instructions on https://github.com/Hexxeh/rpi-update, and running it to update the Raspberry Pi’s firmware.
  • Installation of wiringPi by checking the latest version out from its git repository, and following its compilation instructions.
  • Adapting the code example that ships with the display to work on Raspbian. This basically included setting the GPIOs for Chip Select, Data/Control and Reset to outputs and wiring them accordingly.
  • I did also use the bitmap fonts provided by Benedikt K. on the mikrocontroller.net board in order to realize larger font sizes.

The result was that the display works, but updates very slowly. When writing text to the display, a complete screen takes more than three seconds to fill. This results from the fact that one pixel is painted at a time in the example application. Yet, in order to paint this pixel, the bounding box for the paining area must be set prior to transmitting the desired color information, which incurs a significant overhead.

The only solution to this issue would be to set the bounding box to the complete display size and send all pixels in a burst transfer, which motivated me to move to the kernel space and try the following approach.

Approach #2: Registering the display as a framebuffer device

When searching for support of the ST7735 in Linux, I came across a driver provided by ngreatorex, which is supposed to register the LCD display as a framebuffer device. The framebuffer offers higher flexibility with regard to the contents that shall be displayed (it can, e.g., also be used as output device for mplayer), and also uses aforementioned burst operation to draw the full screen at once. A first comparison of the source code against the previously mentioned Arduino library yielded only slight differences (apart from two errors in the control sequences for the ST7735_CASET and ST7735_RASET commands – a value of 0x00 is transmitted too often in both cases). Still, the solution appeared feasible and was worth trying.

In order to compile kernel modules like this framebuffer driver, both the kernel sources and the Module.symvers file are required. As none of them are shipped with Raspbian, I checked the kernel sources out (following these instructions), copied the kernel configuration file from the /boot/ partition, and compiled the kernel locally on the Pi. After approximately eight hours, the compilation of my brand new kernel was finished, and it was time to compile the modules as well. Once this has also completed, I backed up my old kernel and copied the new one (a file called Image) from the /arch/arm/boot subdirectory of the kernel tree to the /boot/ directory. I recommend to also copy the file System.map, which has been created in the root directory of the newly compiled kernel to /boot/. Finally (but this is my personal preference), copy .config to /boot in order to save the hassle of re-configuring the kernel should a recompilation become necessary. I did also install the kernel headers by running sudo make headers_install (although I figured later that this would not have been necessary).

When I tried to compile the ST7735 module now, an error message saying that “deferred IO for graphics” was required popped up. As I wasn’t sure if there would be further dependencies in the kernel configuration, I added the PicoLCD driver with framebuffer support as a kernel module. This module also relies on deferred graphics IO and thus inserts all required lines into the kernel configuration.

 Device Drivers --->  
    HID Devices (HID_SUPPORT [=y]) --->  
       Special HID drivers --->
          <M> PicoLCD (graphic version)
          [*]   Framebuffer support

The addition of the PicoLCD module in make menuconfig leads to the line

CONFIG_FB_DEFERRED_IO=y

being added to the kernel configuration in the graphics support section. Once the kernel and all modules have been compiled (again), the ST7735 module can be compiled without errors.

The library linked required some minor adaptation to reflect the GPIO pins used for the Reset and Data/Control pins. Once everything was set up and the ST7735 framebuffer module was compiled and installed using sudo make modules_install, the time was right to check whether it could be inserted into the running kernel by running sudo modprobe -v st7735fb. Although the module (and its dependencies) were loaded successfully, nothing changed on the TFT display. Loading the second module, rpi_st7735fb, which caters for defining the GPIO connections, failed with the message “ERROR: could not insert ‘rpi_st7735fb’: Invalid argument”. A look at dmesg yields the answer: “Driver [spidev] already registered for spi0.0”. My first though was if this was some relict from my wiringPi installation. In fact, however, when unloading the spidev module, the error message disappeared upon the insertion of the newly compiled module. Still, the display just stayed blank.

Third approach: Use the code provided by Kamal Mostafa

Kamal is a Ubuntu kernel developer, so he knows what he’s doing. In this particular case, he has connected an Adafruit display with ST7735 driver to his Raspberry Pi. The most convenient way would probably have been to just download his modified kernel source. I did, however, manually incorporate the changes to the kernel, namely removing the SPI port 0 binding in the file ./arch/arm/mach-bcm2708/bcm2708.c by eliminating lines 588-593:

  .chip_select = 0,
  .mode = SPI_MODE_0,
}, {
  .modalias = "spidev",
  .max_speed_hz = 500000,
  .bus_num = 0,

Again, a recompilation of the kernel is required, but as the SPI port 0 (i.e., the one where the LCD display is attached) is now free for use by the framebuffer, everything works nicely and dmesgnow reads

[   70.931883] fb1: ST7735 frame buffer device,
[   70.931894] 	using 40960 KiB of video memory
[   70.931901] 	rst_gpio=24 dc_gpio=25

After incorporating the other changes to /etc/inittab, as proposed on Kamal’s website, the Raspberry Pi now displays a login console after bootup, which can be used to directly check the network configuration and or adapt it using a keyboard connected to the Pi’s USB port.