I'm moving to 2.9.1 and trying to get mipi working with a st7789 display. I have it working with 2.6.1 without mipi, but can't seem to get it working with mipi on a nrf5340dk. Backlight is working on both. Here is the relevant overlay configuration:
#include <zephyr/dt-bindings/mipi_dbi/mipi_dbi.h> &pinctrl { spi4_default: spi4_default { group1 { psels = <NRF_PSEL(SPIM_SCK, 0, 6)>, <NRF_PSEL(SPIM_MOSI, 0, 25)>; }; }; spi4_sleep: spi4_sleep { group1 { psels = <NRF_PSEL(SPIM_SCK, 0, 6)>, <NRF_PSEL(SPIM_MOSI, 0, 25)>; low-power-enable; }; }; }; &spi4 { status = "okay"; cs-gpios = <&gpio0 11 GPIO_ACTIVE_LOW>; }; / { chosen { zephyr,display = &st7789v_st7789v_tl019fqv01; }; mipi_dbi { compatible = "zephyr,mipi-dbi-spi"; spi-dev = <&spi4>; dc-gpios = < &gpio1 11 GPIO_ACTIVE_HIGH>; reset-gpios = < &gpio1 10 GPIO_ACTIVE_LOW>; write-only; #address-cells = <1>; #size-cells = <0>; st7789v_st7789v_tl019fqv01: st7789v@0 { compatible = "sitronix,st7789v"; mipi-max-frequency = <20000000>; reg = <0>; width = <240>; height = <280>; x-offset = <0>; y-offset = <20>; 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]; mipi-mode = <MIPI_DBI_MODE_SPI_4WIRE>; }; }; };
The configuration which was working for 2.6.1:
&pinctrl { spi4_default: spi4_default { group1 { psels = <NRF_PSEL(SPIM_SCK, 0, 6)>, <NRF_PSEL(SPIM_MOSI, 0, 25)>; }; }; spi4_sleep: spi4_sleep { group1 { psels = <NRF_PSEL(SPIM_SCK, 0, 6)>, <NRF_PSEL(SPIM_MOSI, 0, 25)>; low-power-enable; }; }; }; &spi4 { compatible = "nordic,nrf-spim"; status = "okay"; pinctrl-0 = <&spi4_default>; pinctrl-1 = <&spi4_sleep>; pinctrl-names = "default", "sleep"; cs-gpios = <&gpio0 11 GPIO_ACTIVE_LOW>; st7789v_st7789v_tl019fqv01: st7789v@0 { compatible = "sitronix,st7789v"; spi-max-frequency = <20000000>; reg = <0>; cmd-data-gpios = < &gpio1 11 GPIO_ACTIVE_LOW>; reset-gpios = < &gpio1 10 GPIO_ACTIVE_LOW>; width = <240>; height = <280>; x-offset = <0>; y-offset = <20>; 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]; }; }; / { chosen { zephyr,display = &st7789v_st7789v_tl019fqv01; }; };
The code is very simple, these are the key calls:
#include <zephyr/kernel.h> #include <zephyr/drivers/gpio.h> #include <zephyr/drivers/pwm.h> #include <zephyr/logging/log.h> #include <lvgl.h> #include <app_version.h> #include <zephyr/drivers/display.h> #include <zephyr/pm/device.h> LOG_MODULE_REGISTER(app, LOG_LEVEL_DBG); #define BUTTON1_NODE DT_NODELABEL(button1) static const struct device *display_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_display)); static const struct gpio_dt_spec button1 = GPIO_DT_SPEC_GET_OR(BUTTON1_NODE, gpios, {0}); static struct gpio_callback button1_cb_data; /* 1000 msec = 1 sec */ #define SLEEP_TIME_MS 2000 static const struct pwm_dt_spec screen_backlight = PWM_DT_SPEC_GET(DT_ALIAS(screenblk)); bool pwm_on = true; int pwm_value = 0; static lv_obj_t *screen_helloworld; int display_manager_init(void) { LOG_DBG("Initializing display manager"); if (!device_is_ready(display_dev)) { LOG_ERR("Device not ready, aborting test"); return 0; } //LOG_DBG("Display name: %d", display_dev->name); //LOG_DBG("Display driver name: %d", display_dev->driver_api->name); //LOG_DBG("Display driver version: %d", display_dev->driver_api->version); display_blanking_off(display_dev); return 0; } static void screen_backlight_pulse(uint8_t percent) { LOG_DBG("Backlight pwm set to %d%%", percent); int ret; uint32_t step = screen_backlight.period / 100; uint32_t pulse_width = step * percent; if (!device_is_ready(screen_backlight.dev)) { LOG_ERR("Screen backlight is not ready"); return; } ret = pwm_set_pulse_dt(&screen_backlight, pulse_width); if (ret < 0) { LOG_ERR("Failed to set pulse width: %i", ret); return; } } //static void button_isr_callback(const struct device *port,struct gpio_callback *cb,uint32_t pins) void button1_pressed(const struct device *dev, struct gpio_callback *cb,uint32_t pins) { LOG_DBG("Button pressed at %" PRIu32, k_cycle_get_32()); ARG_UNUSED(dev); ARG_UNUSED(cb); ARG_UNUSED(pins); LOG_DBG("Button pressed"); if (pwm_on) { pwm_value = !pwm_value; LOG_DBG("pwm_value: %d", pwm_value); if (pwm_value) { screen_backlight_pulse(100); } else { screen_backlight_pulse(0); } } } int button_manager_init(void) { LOG_DBG("Initializing button manager"); int ret; if (!gpio_is_ready_dt(&button1)) { LOG_ERR("Error: button device %s is not ready",button1.port->name); return 0; } ret = gpio_pin_configure_dt(&button1, GPIO_INPUT); if (ret != 0) { LOG_ERR("Error %d: failed to configure %s pin %d", ret, button1.port->name, button1.pin); return 0; } ret = gpio_pin_interrupt_configure_dt(&button1,GPIO_INT_EDGE_TO_ACTIVE); if (ret != 0) { LOG_ERR("Error %d: failed to configure interrupt on %s pin %d", ret, button1.port->name, button1.pin); return 0; } gpio_init_callback(&button1_cb_data, button1_pressed, BIT(button1.pin)); gpio_add_callback(button1.port, &button1_cb_data); LOG_DBG("Set up button at %s pin %d", button1.port->name, button1.pin); return 0; } void screen_helloworld_init() { LOG_DBG("Starting..."); static lv_obj_t *helloworld_label; screen_helloworld = lv_obj_create(NULL); LOG_DBG("Setting text and back color"); lv_obj_set_style_bg_color(screen_helloworld, lv_color_black(), LV_PART_MAIN); lv_obj_set_style_text_color(screen_helloworld, lv_color_white(), LV_PART_MAIN); LOG_DBG("Creating label"); helloworld_label = lv_label_create(screen_helloworld); lv_label_set_text(helloworld_label, "Hello World"); lv_obj_align(helloworld_label, LV_ALIGN_CENTER, 0, 0); lv_obj_set_style_text_font(helloworld_label, &lv_font_montserrat_16, LV_PART_MAIN); } void display_test(){ LOG_DBG("Display test"); if (!device_is_ready(display_dev)) { LOG_ERR("Device not ready, aborting test"); return; } display_blanking_off(display_dev); } int main(void) { int count = 0; LOG_DBG("Display Hello World! %s (%s)", CONFIG_BOARD, APP_VERSION_EXTENDED_STRING); button_manager_init(); if (!device_is_ready(screen_backlight.dev)) { LOG_WRN("Screen backlight pwm device is not ready"); return -ENODEV; } display_manager_init(); if (pwm_on) { screen_backlight_pulse(100); } else { screen_backlight_pulse(0); } screen_helloworld_init(); LOG_DBG("calling lv_task_handler"); lv_task_handler(); LOG_DBG("Starting loop"); while (1) { count++; LOG_DBG("count = %d", count); lv_task_handler(); k_msleep(SLEEP_TIME_MS); if (count > 1000) { count = 0; } } }