LVGL on a TFT LCD Display with the nRF9160 DK

This blog post demonstrates how to get a LVGL sample up and running on the nRF9160 DK using Adafruit 1.3" 240x240 Wide Angle TFT LCD Display with MicroSD - ST7789. Follow the wiring guide and the steps in the blog post and get your display going! In an ideal world, we would be able to use the st7789v shield for waveshare 240x240, but since the nRF9160 DK does not have a device tree node label for arduino_spi, we need to implement a workaround. For the details on how the project configuration and overlay files were derived, check out my other blog post.

guide_result

Hardware

Components

Wiring

Important: The display operates with 3.3V logic, so on the nRF9160 DK, you must ensure that a tiny switch, SW9 (which sets VDD IO) is set at 3V!

Following the generic ST7789V shield pin assignment, we wire the connection as such:

nRF9160 DK pin Display pin
P0.08 RST
P0.09 D/C
P0.10 TCS
P0.11 SI
P0.12 SO
P0.13 SCK
GND GND
5V Vin


Software

After having wired up your DK, we need to perform some steps on the software side!

Prerequisites

nRF Connect SDK (NCS) installation. The attached project contains working files for both NCS v1.6.0 and NCS v2.2.0.

No guarantees can be made for other versions of NCS but it might work.

Steps

  1. Download the attached project
  2. Extract it into a valid west workspace (that is, a folder from which you can call the command west build from command line)
  3. Connect your nRF9160 DK (with the screen already wired up) to your computer
  4. Build and flash the project to the DK

Incorporating this into other projects

The process of making this display work with your own project is a bit different if you NCS v1.6.0 or NCS v2.2.0. The steps are given for each of the SDK versions below.

For reference, the new project you want to configure the display for is named YourProject.

Using the ncs v1.6.0 sample

  1. Ensure that the LVGL and display-specific settings from the provided ZIP's config file (prj.conf) is in YourProject's config file
  2. Ensure that the overlay from the provided ZIP is also included (that is, boards/nrf9160dk_nrf9160ns.overlay)
    1. If YourProject already has an overlay file (nrf9160dk_nrf9160ns.overlay), you could copy-paste the contents of the provided overlay file to YourProject's nrf9160dk_nrf9160ns.overlay
    2. If YourProject does not have an overlay file, then you could copy the whole file into YourProject folder. This will automatically be detected by CMake when you hit build!
  3. Be sure to include device.h, drivers/display.h and lvgl.h in the C-file in which you want to program using LVGL.

Using the NCS v2.2.0 sample

  1. Ensure that the LVGL and display-specific settings from the provided ZIP's config file (prj.conf) is in YourProject's config file
  2. Set the SHIELD variable for building by doing one of these things:
    1. Place the line set(SHIELD st7789v_waveshare_240x240) into YourProject's CMakeLists.txt
    2. Pass the st7789v shield as an argument to the build like this: 
      west build -- -DSHIELD=st7789v_waveshare_240x240

Note on the source code structure

The source code might not look like ordinary LVGL code (which uses lv_init, lv_disp_draw_buf_init etc) because this part of LVGL is abstracted away by Zephyr, as seen in lvgl.c in Zephyr. The source code is also based on the LVGL sample provided by Zephyr, with changes made so that it works with the nRF9160 DK when following this tutorial.

Attached files

lvgl_logo_sample_for_nrf9160_DK.zip
  • Thank you for advice!

    I changed st7789v_set_orientation function to:

    static int st7789v_set_orientation(const struct device *dev,
    			    const enum display_orientation orientation)
    {
    	struct st7789v_data *data = (struct st7789v_data *)dev->data;
    
    	uint8_t tx_data = ST7789V_MADCTL_RBG;
    
    	if (orientation == DISPLAY_ORIENTATION_NORMAL) {
    		tx_data |= ST7789V_MADCTL_MX_LEFT_TO_RIGHT | ST7789V_MADCTL_MY_TOP_TO_BOTTOM;
    	} else if (orientation == DISPLAY_ORIENTATION_ROTATED_90) {
    		tx_data |= ST7789V_MADCTL_MV_REVERSE_MODE | ST7789V_MADCTL_MX_RIGHT_TO_LEFT;
    	} else if (orientation == DISPLAY_ORIENTATION_ROTATED_180) {
    		tx_data |= ST7789V_MADCTL_MX_RIGHT_TO_LEFT | ST7789V_MADCTL_MY_BOTTOM_TO_TOP;
    	} else if (orientation == DISPLAY_ORIENTATION_ROTATED_270) {
    		tx_data |= ST7789V_MADCTL_MY_BOTTOM_TO_TOP | ST7789V_MADCTL_MV_REVERSE_MODE;
    	}
    
    	st7789v_transmit(data, ST7789V_CMD_MADCTL, &tx_data, 1);
    
    	return 0;
    }


    And it works. I can rotate display, but there is problem. Only rotation by 90 degrees works correct. 

    If I rotate by 180 or 270, display is shifted by 80 pixels down. 
    I am not sure, but I think it is because ST7789_Datasheet.pdf page 124, 8.12 Address control, where it is written, that: The address ranges are X=0 to X=239 (Efh) and Y=0 to Y=319 (13Fh).
    So, instead of 240px, it uses 320, but I am not sure 100%. I have no idea, how to check that.

    I tried to to use:
    lv_obj_align(img1, lv_scr_act(), LV_ALIGN_CENTER, 0, 80);


    And it shifted image up in correct position, so starting point of coordinate frame was correct, but it did not display the whole picture.

    Here is the result from display:



    When I shift image, it crops its upper side. 

    Any advice will be appreciated!

  • Hello!

     

    The error message originates from the driver for the st7789v display itself. By navigating to line 256 in  zephyr/drivers/display/display_st7789v.c (also found here online), you can see the function st7789v_set_orientation which gives you trouble. The driver has not been implemented to support screen orientation.

     

    At a glance it seems that orientation should be possible to implement. Displays that implement orientation such as display_ili9xxx.c line 255 (seen here) seems to be using some MADCTL_MX/MV/MY values. Coincidentally, there is also a part in the ST7789V datasheet (p167) that seems to address the same values. Again, this is just my first-glance assumption but I think it should be possible to implement orientation in much the same way as has been done in display_ili9xxx.c.

     

    If you want, I will take a closer look at this on Friday and hopefully be able to come up with a working solution for you. If you need it more urgently I encourage you to either seek help in the Nordic Q&A or try to implement the st7789v_set_orientation yourself. Let me know what it will be :)

  • Did somebody manage to rotate display using this driver?
    I tried 

    display_set_orientation(display_dev, DISPLAY_ORIENTATION_ROTATED_180);


    But got error:
    <err> display_st7789v: Changing display orientation not implemented


    I tried to change display driver inside lvgl.c file:
    disp_drv.rotated = ??



  • I'm not offended. Your earlier comment was taken down by a moderator for unprofessional behaviour. LVGL was initially named LittlevGL but was later renamed to Light and Versatile Graphics Library. Check out the Zephyr LVGL codebase readme if you haven't already.