Post

ENG | Pimoroni 2.8 inch display

Exploring Pimoroni 2.8" display with Raspberry Pi Pico.

ENG | Pimoroni 2.8 inch display

I have tried several displays already and came to the conclusion that ILI9xxx displays have rather unattractive colors. For the weather-station project, another disadvantage is the 20 cm flat cable, which is not very flexible and takes too much space.

I ordered an IPS display and an E-Ink display which are both basically Raspberry Pi Pico shields. E-Ink display is sort of black box, when it comes to documentation, but it has some poorly written code examples.

So back to one from Pimoroni. It’s quite well documented and comes with prebuilt MicroPython and drivers source code. Let’s explore it.

Description

The shield contains not only the display, but also four buttons, an RGB LED controlled by PWM, and a Qwiic/Stemma/LaskaKit connector for sensors. Unfortunately, the pin headers are on the same side as the USB connector and point outward, which complicates the design of a 3D-printed enclosure.

The display itself has rich, vivid colors—more saturated than those on a Lenovo T480s.

Pinout

PinDescription
GP6SDA
GP7SCL
GP12Button-A
GP13Button-B
GP14Button-X
GP15Button-Y
GP16LCD_DC
GP17LCD_CS
GP18LCD_SCLK
GP19LCD_MOSI
GP20LCD_BACKLIGHT
GP21LCD_TE
GP 26LED_RED
GP 27LED_GREEN
GP 28LED_BLUE

NOTES

  • When a button is pressed, the corresponding pin is grounded.
  • To turn the LEDs off, use PWM at full duty cycle.

Getting started with MicroPython

The straightforward approach is:

  • Download the MicroPython for your variant of Raspberry Pi Pico with drivers for Piromoni boards already included
  • Copy it to Raspberry Pico in bootloader mode, for example
    1
    2
    3
    
    $ udisksctl mount -b /dev/sdb1
    Mounted /dev/sdb1 at /run/media/pavel/RP2350
    $ cp ~/Downloads/rpi_pico2_w-v1.26.1-micropython.uf2 /run/media/pavel/RP2350
    
  • Clone git repository with examples:
    1
    
    git clone https://github.com/pimoroni/pimoroni-pico.git
    
  • Go to the display examples:
    1
    
    cd pimoroni-pico/micropython/examples/pico_display
    
  • Modify some file(s) for use with 2.8” display and experiment, like
    1
    2
    
    $ mpremote fs cp pencil.png :
    $ mpremote run display_png.py
    

Some examples are already set up for the 2.8” model, while others require adjusting the pin mapping or display initialization according to comments.

Using file from previous experiments, I modified PNG example to this by removing comments and changing color mode, filename and position:

1
2
3
4
5
6
7
8
9
10
11
12
13
from picographics import PicoGraphics, DISPLAY_PICO_DISPLAY_2, PEN_RGB565
import pngdec
display = PicoGraphics(display=DISPLAY_PICO_DISPLAY_2, pen_type=PEN_RGB565)
display.set_backlight(1.0)
png = pngdec.PNG(display)
try:
    png.open_file("holedna.png")
    png.decode(0, 0, scale=1)
except OSError:
    print("Error: PNG File missing!")
display.update()
while True:
    pass

Zephyr RTOS

Expectations

This will be fun, because in device tree definition, there are many initialization parameters required. Hopefully initialization code can be copied from Pimoroni driver linked above and article will be expanded if I find time and will power to do so. Also I have to find out what might be TE pin and if/how reset pin is used.

So far, displays had SPI pins (MOSI, SCK, CS), MIPI-DBI pins (RESET, DC), but this one has TE (tearing effect) instead of reset.

Ok. Let’s try to modify examples from ILI9341 display - this article contains some progressively more complicated code examples.

Reality

I took the framebuffer example from ILI9341 and tried to modify device tree overlay, expecting that the C code can remain unchanged. This would be true, but in the end code needed merging with blinky example to turn on backlight. Nonetheless here is device tree overlay for Raspberry Pi Pico 2 W.

It merges Pimoroni driver with device tree for some 240x240 display shield - Pimoroni driver has different gamma tables and few parameters for 240x240 and 320x240 displays, but there may be differences between IPS and TN displays from various manufacturers. Hard to say.

Sadly, at the time of writing, the ST7789V driver does not support rotation. There were pull requests, but they cannot be merged due to major changes caused by the introduction of the MIPI layer.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
/ {
    chosen {
        zephyr,display = &st7789;
        zephyr,console = &usb_cdc;
    };

    aliases {
        backlight = &backlight;
    };

    leds {
        // TODO: RGB are GP26-28, BL is GP20
        compatible = "gpio-leds";
        // label: node name
        backlight: backlight-led {
            gpios = <&gpio0 20 GPIO_ACTIVE_HIGH>;
        };
    };

    pwmleds {
        compatible = "pwm-leds";
    };

    mipi_dbi {
        compatible      = "zephyr,mipi-dbi-spi";
        spi-dev         = <&spi0>;
        dc-gpios        = <&gpio0 16 GPIO_ACTIVE_HIGH>;
        //te-gpios        = <&gpio0 21>;
        write-only;
        #address-cells  = <1>;
        #size-cells     = <0>;

        st7789: st7789@0 {
            compatible          = "sitronix,st7789v";
            mipi-max-frequency  = <15000000>;
            reg                 = <0>;      // Uses cs-gpios[0]
            // https://shop.pimoroni.com/products/pico-display-pack-2-8?variant=42047194005587
            // https://cdn.shopify.com/s/files/1/0174/1800/files/pico_display_2_8_schematic.pdf?v=1728314048
            // https://docs.zephyrproject.org/latest/build/dts/api/bindings/display/sitronix%2Cst7789v.html
            // https://github.com/pimoroni/pimoroni-pico/blob/main/drivers/st7789/st7789.cpp
            // https://github.com/zephyrproject-rtos/zephyr/blob/9da1b3cba1a2a8a448c8650fb30b38b570a9b9de/boards/fanke/fk750m1_vbt6/fk750m1_vbt6.dts#L23
            x-offset    = <0>;
            y-offset    = <0>;
            width       = <240>;
            height      = <320>;
            gctrl       = <0x35>; // Gate control
            vcom        = <0x1f>; // VCOM Setting
            pvgam-param = [D0 04 0D 11 13 2B 3F 54 4C 18 0D 0B 1F 23];
            nvgam-param = [D0 04 0C 11 13 2C 3F 44 51 2F 1F 1F 20 23];
            // TODO: te-on -> likely not supported by driver
            colmod      = <5>; // 16bpp hicolor

            porch-param = [0c 0c 00 33 33];
            lcm         = <0x2c>;
            // vdvvrhen 0x01 - maybe set by driver?
            vrhs = <0x12>;
            vdvs = <0x20>;
            pwctrl1-param = [a4 a1];
            // these commands are copied from random 240x240 board
            mdac = <0x00>;
            gamma = <0x01>;
            cmd2en-param = [5a 69 02 01];
            ram-param = [00 F0];
            rgb-param = [CD 08 14];
            mipi-mode = "MIPI_DBI_MODE_SPI_4WIRE";

            // Rotation is not supported by driver
            //rotation            = <90>;     // Default, portait 240x320, 90 landscape ...
            status              = "okay";
        };

    };
};

&spi0 {
    status          = "okay";
    clock-frequency = <15000000>;
    // Note: multiple devices can have CS pins configured here, separated by ","
    // They are referenced via reg=<n>;
    cs-gpios        = <&gpio0 17 GPIO_ACTIVE_LOW>;
};

&zephyr_udc0 {
    usb_cdc: usb_cdc_0 {
        compatible = "zephyr,cdc-acm-uart";
    };
};

Project configuration requires enabling the driver and removing the ILI9341 settings:

1
2
CONFIG_ST7789V=y
CONFIG_ST7789V_BGR565=y

To control the backlight, the source code needs an extra section with GPIO:

1
#include <zephyr/drivers/gpio.h>
1
2
3
4
5
6
7
8
    /* Backlight on */
    const struct gpio_dt_spec backlight_led = GPIO_DT_SPEC_GET(DT_ALIAS(backlight), gpios);
    if (!gpio_is_ready_dt(&backlight_led)) {
        LOG_ERR("LED GPIO not ready.");
        return -1;
    }
    gpio_pin_configure_dt(&backlight_led, GPIO_OUTPUT_ACTIVE);
    gpio_pin_set_dt(&backlight_led, 1);

And possibly some adjustments for portrait orientation.

Building code for Raspberry Pi Pico 2 W is easy (once command is in shell history)

1
2
west build -p auto -b rpi_pico2/rp2350a/m33/w
disksctl mount -b /dev/sdb1 && west flash -r uf2

LVGL image example

This example requires rotating the image by 90° prior to conversion to a header file, enabling CONFIG_LV_USE_ST7789=y in prj.conf, and applying the same changes as in the raw framebuffer example.

Summary

Using this shield in Python is super easy.

Zephyr RTOS is kind of disappointing here. These displays seem very common, but there are no default parameters. Some settings which are not included in driver from Pimoroni are required here and I have no clue what default values should be - they might be excessive. Documentation of these parameters is not included in source code (or rather YAML binding file). Display rotation is not supported.

This was simply an experiment to see whether I could get it working. It took one evening.

This post is licensed under CC BY 4.0 by the author.