"Device ST7789V not found" with ST7789V Waveshare 240x240 display under Zephyr

Hi,

Has anyone got a ST7789V Waveshare 240x240 display to work under PlatformIO/Zephyr on a nRF52840, STM32 or another similar MCU?

I’ve tried to get a ST7789V running on nRF52840 (Particle Xenon) and
STM32 (blackpill_f411ce) boards but ran into a problem. I’m not sure if it is an error in
configuration or possibly a bug associated with the ST7789V driver.

An earlier version of Zephyr had a sample code for ST87789V display but the sample got removed in the recent releases.

I’ve found that although I have the correct devicetree label for the ST7789V and
the physical display hookup matches the overlay, a call to device_get_binding() from main.c fails to bind correctly. A NULL display device handle gets returned with a
“app: Device ST7789V not found. Aborting test.”

Below is my setup and Zephyr configuration for review.

Can someone please chime in and suggest what I may be doing incorrectly or possibly missing?

I thought I may share the info before following up with the Zephyr folks, in case someone has used a ST7789V with Zephyr and ran into similar issues.

Any assistance would be much appreciated! Thank you.

Development Environment:

PlatformIO Core: 5.0.4
VSC: 1.52.1
Host: macOS Mojave 10.14.6

PlatformIO Framework: Zephyr
Target: Particle Xenon
Debug: Segger Edu Mini J-Link

particle_xenon.overlay:

/*
 * Particle Xenon with Waveshare ST7789V (240x240)
 * 
 * Xenon 				ST7789V
 * P0.18 (RESET)		RST
 * P1.15 (SPI_SCK)		SPI_SCK
 * P1.14 (SPI_MISO)		-
 * P1.13 (SPI_MOSI) 	SPI_MOSI
 * P1.10 (D5)			DC (DATA/CMD)
 * P1.08 (D4)			CS 
 * GND					GND
 * 3V3					VCC
 * 
 */

/ {
	aliases {
		wave = &waveshare_device;
	};
};

&spi0 {
	status = "okay";
	sck-pin =  <47>;
	mosi-pin = <45>;
	miso-pin = <46>;
	cs-gpios = <&gpio1 8 GPIO_ACTIVE_LOW>; /* D4 */ 

    waveshare_device: st7789v@0 {
		compatible = "sitronix,st7789v";
		label = "ST7789V";
		spi-max-frequency = <20000000>;
		reg = <0>;
		cmd-data-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>;  /* D5 */
		reset-gpios = <&gpio0 18 GPIO_ACTIVE_LOW>; /* RESET */
		width = <240>;
		height = <240>;
		x-offset = <0>;
		y-offset = <0>;
		vcom = <0x19>;
		gctrl = <0x35>;
		vrhs = <0x12>;
		vdvs = <0x20>;
		mdac = <0x00>;
		lcm = <0x2c>;
		colmod = <0x05>;
		gamma = <0x01>;
		porch-param = [0c 0c 00 33 33];
		cmd2en-param = [5a 69 02 01];
		pwctrl1-param = [a4 a1];
		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];
		ram-param = [00 F0];
		rgb-param = [CD 08 14];
	};

};

prj.conf:

CONFIG_HEAP_MEM_POOL_SIZE=16384
CONFIG_MAIN_STACK_SIZE=2048

CONFIG_STDOUT_CONSOLE=y
CONFIG_PRINTK=y
CONFIG_GPIO=y
CONFIG_SPI_0=y

CONFIG_ST7789V=y
CONFIG_ST7789V_RGB565=y

CONFIG_LOG=y

CONFIG_LOG_PRINTK=y
CONFIG_LOG_IMMEDIATE=y

CONFIG_DISPLAY=y
CONFIG_DISPLAY_LOG_LEVEL_DBG=y

platformio.ini:

[platformio]
default_envs = xenon

[env:xenon]
platform = nordicnrf52
framework = zephyr
board = particle_xenon
build_flags = -DSHIELD_ST7789V_WAVESHARE_240X240
upload_protocol = jlink
debug_tool = jlink
debug_init_break = tbreak main
monitor_speed = 115200

From main.c:

...
...

display_dev = device_get_binding(DT_INST_0_SITRONIX_ST7789_LABEL)
if (display_dev == NULL) {
		LOG_ERR("Device %s not found. Aborting test.", label);
		return;
}

...
...

From z_impl_device_get_binding():

In the call to /framework-zephyr/kernel/device.c/z_impl_device_get_binding()/:

- search for device names doesn't see any ST7789V device

- only the following devices are found
  UART0
  CLOCK
  sys_clock
  GPIO_0
  GPIO_1

- No ST7789V is found and returns a NULL display_dev pointer
- LOG_ERR printed to UART0

Serial UART0 output

10:43:00.891 -> *** Booting Zephyr OS build zephyr-v20400  ***
10:43:00.891 -> 
[00:00:12.298,065] e[0m<inf> app: Waveshare ST7789V display samplee[0m
10:43:14.012 -> Particle Xenon with Waveshare ST7789V...
10:43:14.012 -> 
[00:05:15.421,020] e[1;31m<err> app: Device ST7789V not found. Aborting test.e[0m

From the generated devicetree_unfixed.h

/* Node parent (/soc/spi@40003000) identifier: */
#define DT_N_S_soc_S_spi_40003000_S_st7789v_0_PARENT DT_N_S_soc_S_spi_40003000
#define DT_N_S_soc_S_spi_40003000_S_st7789v_0_FOREACH_CHILD(fn)

/* Existence and alternate IDs: */
#define DT_N_S_soc_S_spi_40003000_S_st7789v_0_EXISTS 1
#define DT_N_ALIAS_wave DT_N_S_soc_S_spi_40003000_S_st7789v_0
#define DT_N_INST_0_sitronix_st7789v DT_N_S_soc_S_spi_40003000_S_st7789v_0
#define DT_N_NODELABEL_waveshare_device DT_N_S_soc_S_spi_40003000_S_st7789v_0

/* Special property macros: /
#define DT_N_S_soc_S_spi_40003000_S_st7789v_0_REG_NUM 1
#define DT_N_S_soc_S_spi_40003000_S_st7789v_0_REG_IDX_0_EXISTS 1
#define DT_N_S_soc_S_spi_40003000_S_st7789v_0_REG_IDX_0_VAL_ADDRESS 0 /
0x0 */
#define DT_N_S_soc_S_spi_40003000_S_st7789v_0_IRQ_NUM 0
#define DT_N_S_soc_S_spi_40003000_S_st7789v_0_COMPAT_MATCHES_sitronix_st7789v 1
#define DT_N_S_soc_S_spi_40003000_S_st7789v_0_STATUS_okay 1

/* Generic property macros: /
#define DT_N_S_soc_S_spi_40003000_S_st7789v_0_P_compatible {“sitronix,st7789v”}
#define DT_N_S_soc_S_spi_40003000_S_st7789v_0_P_compatible_IDX_0 “sitronix,st7789v”
#define DT_N_S_soc_S_spi_40003000_S_st7789v_0_P_compatible_LEN 1
#define DT_N_S_soc_S_spi_40003000_S_st7789v_0_P_compatible_EXISTS 1
#define DT_N_S_soc_S_spi_40003000_S_st7789v_0_P_label “ST7789V”
#define DT_N_S_soc_S_spi_40003000_S_st7789v_0_P_label_EXISTS 1
#define DT_N_S_soc_S_spi_40003000_S_st7789v_0_P_reg {0 /
0x0 */}
#define DT_N_S_soc_S_spi_40003000_S_st7789v_0_P_reg_IDX_0 0
#define DT_N_S_soc_S_spi_40003000_S_st7789v_0_P_reg_EXISTS 1

I think you must not do that in build_flags but in the prj.conf, since it’s a KConfig setting

So try and do a CONFIG_SHIELD_ST7789V_WAVESHARE_240X240=y in the prj.conf. THe other SPI and ST7789V settings etc should then follow automatically.

EDIT: per

the option is turned on automatically when the shield lists contain the macro st7789v_waveshare_240x240 which should be addable via build_flags = -DSHIELD=st7789v_waveshare_240x240, see refernce with west in link below.

The used Zephyr v2.4 version definitely supports the display shield per Generic ST7789V Display Shield — Zephyr Project Documentation.

If we follow that doc you should try and use the platformio.ini

[env:particle_xenon]
platform = nordicnrf52
board = particle_xenon
framework = zephyr
build_flags = -DSHIELD=st7789v_waveshare_240x240

and as prj.conf

and as main.c

Without any other files / overflays.

The expected pinout is described in the doc link above – try and follow that at first before trying to use your own overlay.

Hi maxgerhardt,

Thank you for the quick response. It’s much appreciated.

The reason I use a custom overlay is because the ST7789 Waveshare 240x240 display that I have doesn’t have the standard Arduino connector pins. It’s a standalone display that is hooked up to a Particle Xenon board, using the SPI MOSI/SCK & GPIOs for CS/DC.

The Generic ST7789 display shield can only be used with a board that provides a configuration for Arduino connectors and defines node aliases for SPI and GPIO interfaces, as per Generic ST7789V Display Shield — Zephyr Project Documentation

If I build the lvgl sample for nrf52840dk_nrf52840, which has an Arduino connector, the generated devicetree has entries for the ST7789V device.

west build -b nrf52840dk_nrf52840 . -- -DSHIELD=st7789v_waveshare_240x240

I tried using

  • zephyr/samples/display/lvgl/prj.conf
  • build_flags = -DSHIELD=st7789v_waveshare_240x240
  • zephyr/samples/display/lvgl/src/main.c
  • with and without particle_xenon.overlay

Results

Without the particle_xenon.overlay

Under debug, the call in main.c to device_get_binding(CONFIG_LVGL_DISPLAY_DEV_NAME) has CONFIG_LVGL_DISPLAY_DEV_NAME = “DISPLAY”

The devicetree (devicetree_unfixed.h) shows

  • No entries for ST7789v
  • SPI_0, SPI_1 and SPI_3 have status = “disabled”
  • SPI_2 has status = “okay”, details below.
  • LVGL_DISPLAY_DEV_NAME set to “DISPLAY”
  • SSPI MOSI/SCK, etc set to Arduino Connector Pins (expected default for the Generic ST7789V shield)

/* Generic property macros: /
#define DT_N_S_soc_S_spi_40023000_P_miso_pull_up 0
#define DT_N_S_soc_S_spi_40023000_P_miso_pull_up_EXISTS 1
#define DT_N_S_soc_S_spi_40023000_P_miso_pull_down 0
#define DT_N_S_soc_S_spi_40023000_P_miso_pull_down_EXISTS 1
#define DT_N_S_soc_S_spi_40023000_P_reg {1073885184 /
0x40023000 /, 4096 / 0x1000 /}
#define DT_N_S_soc_S_spi_40023000_P_reg_IDX_0 1073885184
#define DT_N_S_soc_S_spi_40023000_P_reg_IDX_1 4096
#define DT_N_S_soc_S_spi_40023000_P_reg_EXISTS 1
#define DT_N_S_soc_S_spi_40023000_P_interrupts {35 /
0x23 /, 1 / 0x1 */}
#define DT_N_S_soc_S_spi_40023000_P_interrupts_IDX_0 35
#define DT_N_S_soc_S_spi_40023000_P_interrupts_IDX_1 1
#define DT_N_S_soc_S_spi_40023000_P_interrupts_EXISTS 1
#define DT_N_S_soc_S_spi_40023000_P_sck_pin 19
#define DT_N_S_soc_S_spi_40023000_P_sck_pin_EXISTS 1
#define DT_N_S_soc_S_spi_40023000_P_mosi_pin 20
#define DT_N_S_soc_S_spi_40023000_P_mosi_pin_EXISTS 1
#define DT_N_S_soc_S_spi_40023000_P_miso_pin 21
#define DT_N_S_soc_S_spi_40023000_P_miso_pin_EXISTS 1
#define DT_N_S_soc_S_spi_40023000_P_label “SPI_2
#define DT_N_S_soc_S_spi_40023000_P_label_EXISTS 1
#define DT_N_S_soc_S_spi_40023000_P_cs_gpios_IDX_0_PH
#define DT_N_S_soc_S_spi_40023000_P_cs_gpios_IDX_0_VAL_pin 17
#define DT_N_S_soc_S_spi_40023000_P_cs_gpios_IDX_0_VAL_pin_EXISTS 1
#define DT_N_S_soc_S_spi_40023000_P_cs_gpios_IDX_0_VAL_flags 1
#define DT_N_S_soc_S_spi_40023000_P_cs_gpios_IDX_0_VAL_flags_EXISTS 1
#define DT_N_S_soc_S_spi_40023000_P_cs_gpios_LEN 1
#define DT_N_S_soc_S_spi_40023000_P_cs_gpios_EXISTS 1
#define DT_N_S_soc_S_spi_40023000_P_status “okay”
#define DT_N_S_soc_S_spi_40023000_P_status_ENUM_IDX 1
#define DT_N_S_soc_S_spi_40023000_P_status_EXISTS 1

Serial UART0 Output:

17:07:59.067 -> *** Booting Zephyr OS build zephyr-v20400  ***
17:07:59.067 -> [00:00:00.254,760] e[1;31m<err> lvgl: Display device not found.e[0m
17:07:59.067 -> [00:00:00.254,791] e[1;31m<err> app: Device DISPLAY not found. Aborting test.e[0m

With the particle_xenon.overlay

The devicetree (devicetree_unfixed.h) shows

  • SPI_2 has status = “okay”

  • Correct GPIO entries for the Xenon SPI MOSI, SPI SCK, and CS

  • Correct entries for ST7789v, including DC & RST match the overlay values

  • According to the zephyr/boards/shields/st7789v_generic/Kconfig.defconfig,
    if (DISPLAY && LVGL && SHIELD_ST7789V_WAVESHARE_240X240) CONFIG_LVGL_DISPLAY_DEV_NAME = “ST7789V”

  • However, find that CONFIG_LVGL_DISPLAY_DEV_NAME = “DISPLAY”

  • Call to device_get_binding(CONFIG_LVGL_DISPLAY_DEV_NAME) return a NULL pointer.

  • Call to device_get_binding(DT_LABEL(DT_INST(0, sitronix_st7789v)) gets the ST7789V device but the call to device_get_binding() still returns a NULL pointer.

    21:02:52.168 → *** Booting Zephyr OS build zephyr-v20400 ***
    21:02:52.168 → [00:00:00.254,760] e[1;31m lvgl: Display device not found.e[0m
    21:02:52.168 → [00:00:00.254,791] e[1;31m app: Device ST7789V not found. Aborting test.e[0m

It seems that something is still not quite right with the configuration.

Anything else I should try, before I reach out to the Zephyr folks?

It looks like the ST7789V display perhaps isn’t working because I’m not using an Arduino Connector definitions that would map the generic display Arduino pins to the GPIO pins applicable to my board.

I may try defining an Arduino Connector overlay, similar to the Feather connector definitions for the Particle Xenon, and also reach out to the Zephyr folks.

Hi maxgerhardt,

I’ve resolved the issues with the ST7789V.

In a fresh review of the particle_xenon.overlay, I noticed a silly oversight on my part!

I forgot to include the vendor hardware property for the SPI node. It isn’t set in the nrf52840.dtsi but is a required property, and can be “nordic,nrf-spi”, or “nordic,nrf-spim”, or “nordic,nrf-spis”.

Here is the revised particle_xenon.overlay definition.

&spi0 {
	compatible = "nordic,nrf-spi";
	status = "okay";
	sck-pin =  <47>;
	mosi-pin = <45>;
	miso-pin = <46>;
	cs-gpios = <&gpio1 8 GPIO_ACTIVE_LOW>; /* D4 */ 

	st7789v@0 {
		compatible = "sitronix,st7789v";
		label = "ST7789V";
		spi-max-frequency = <20000000>;
		reg = <0>;
		cmd-data-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>;  /* D5 */
		reset-gpios = <&gpio0 18 GPIO_ACTIVE_LOW>; /* RESET */
		width = <240>;
		height = <240>;
		x-offset = <0>;
		y-offset = <0>;
		vcom = <0x19>;
		gctrl = <0x35>;
		vrhs = <0x12>;
		vdvs = <0x20>;
		mdac = <0x00>;
		gamma = <0x01>;
		colmod = <0x05>;
		lcm = <0x2c>;
		porch-param = [0c 0c 00 33 33];
		cmd2en-param = [5a 69 02 01];
		pwctrl1-param = [a4 a1];
		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];
		ram-param = [00 F0];
		rgb-param = [CD 08 14];
	};
};

and prj.conf

CONFIG_HEAP_MEM_POOL_SIZE=16384
CONFIG_MAIN_STACK_SIZE=2048

CONFIG_GPIO=y
CONFIG_SPI=y

CONFIG_DISPLAY=y
CONFIG_DISPLAY_LOG_LEVEL_ERR=y
CONFIG_ST7789V=y
CONFIG_ST7789V_RGB565=y

CONFIG_LVGL=y
CONFIG_LVGL_USE_LABEL=y
CONFIG_LVGL_DISPLAY_DEV_NAME="ST7789V"
CONFIG_LVGL_BITS_PER_PIXEL=16
CONFIG_LVGL_USE_CONT=y
CONFIG_LVGL_USE_BTN=y

CONFIG_LOG=y
CONFIG_PRINTK=y

and platformio.ini

[platformio]
default_envs = xenon

[env:xenon]
platform = nordicnrf52
framework = zephyr
board = particle_xenon
build_flags = -DSHIELD=st7789v_waveshare_240x240
upload_protocol = jlink
debug_tool = jlink
debug_init_break = tbreak main
monitor_speed = 115200

I have some reading to do on lvgl API, and also get the stt7789v display to run with stm32 (blackpill_f411ce).

Once again, thank you for the assistance. It’ much appreciated!

1 Like