What do you want to achieve?
I want to simply display “Hello World” on a screen.
What have you tried so far?
I have it running with nrfConnect (Nordic’s VS Code Addin) 2.9.1 which used lvgl 8.*. I moved to 3.1.0 which is lvgl 9.3.0 and the screen shows “Hello World” three times starting in the center (where I expect it to be) and then twice below it.
Code to reproduce
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/display.h>
#include <zephyr/pm/device.h>
#include <zephyr/drivers/pwm.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/logging/log.h>
#include <stdio.h>
#include <app_version.h>
#include <lvgl.h>
LOG_MODULE_REGISTER(app, LOG_LEVEL_DBG);
int count = 0;
// BACKLIGHT MANAGER CODE
#define PWM_LED0 DT_ALIAS(pwm_led0)
static const struct pwm_dt_spec pwm_led0 = PWM_DT_SPEC_GET(PWM_LED0);
int backlight_manager_init(void)
{
LOG_DBG("Starting backlight PWM");
if (!pwm_is_ready_dt(&pwm_led0)) {
LOG_ERR("Error: PWM device %s is not ready", pwm_led0.dev->name);
return -1;
}
return 0;
}
static void set_pwm(const struct pwm_dt_spec *pwmdev, uint8_t percent) {
LOG_DBG("Setting PWM to %d%%", percent);
int ret;
uint32_t step = pwmdev->period / 100;
uint32_t pulse_width = step * percent;
if (!device_is_ready(pwmdev->dev)) {
LOG_ERR("PWM device not ready");
return;
}
ret = pwm_set_pulse_dt(pwmdev, pulse_width);
if (ret < 0) {
LOG_ERR("Failed to set pulse width: %i", ret);
return;
}
}
void backlight_manager_wake()
{
set_pwm(&pwm_led0, 100);
//set_pwm(&backlight_spec, 1);
}
void backlight_manager_sleep()
{
set_pwm(&pwm_led0, 0);
}
// DISPLAY MANAGER CODE
static const struct device *display_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_display));
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;
}
display_blanking_off(display_dev);
return 0;
}
// VOLTAGE CODE
int change_gpio_voltage(uint32_t target_voltage)
{
int err = 0;
uint32_t regout = NRF_UICR->VREGHVOUT;
LOG_INF("change_gpio_voltage: REGOUT = 0x%08x", regout);
LOG_INF("change_gpio_voltage: target voltage is %d", target_voltage);
if ((regout & UICR_VREGHVOUT_VREGHVOUT_Msk) != target_voltage) {
LOG_INF("Target voltage not set. Configuring");
// Set NVMC in write mode:
NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos;
while (NRF_NVMC->CONFIG != NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos) {
// Wait...
}
// Write the actual UICR Register:
NRF_UICR->VREGHVOUT = (target_voltage | ~UICR_VREGHVOUT_VREGHVOUT_Msk);
while (NRF_NVMC->READY == NVMC_READY_READY_Busy) {
// Wait...
}
// Set NVMC back in read mode:
NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos;
while (NRF_NVMC->CONFIG != NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos) {
// Wait...
}
// Check whether it was set successfully:
if ((NRF_UICR->VREGHVOUT & UICR_VREGHVOUT_VREGHVOUT_Msk) != target_voltage) {
err = 0;
}
// Reset if success. Config will remain on future reboots.
if (err == 0) {
NVIC_SystemReset();
}
} else {
LOG_INF("Target voltage already set. No action needed.");
err = 0;
}
return err;
}
// SCREEN HELLO WORLD CODE
static lv_obj_t *scr_home;
int screen_helloworld_init()
{
LOG_DBG("Creating home screen");
scr_home = lv_obj_create(NULL);
// Used this function as it automatically deletes previous screen.
// Should work as you did also I think. But have not used lv_scr_load_xxx before
//lv_screen_load_anim(scr_home, LV_SCR_LOAD_ANIM_NONE, 0, 0, true);
lv_screen_load(scr_home);
lv_obj_t *hello_world_label;
lv_obj_set_style_bg_color(lv_scr_act(), lv_palette_main(LV_PALETTE_GREEN), LV_PART_MAIN);
lv_obj_set_style_text_color(lv_scr_act(), lv_color_white(), LV_PART_MAIN);
hello_world_label = lv_label_create(lv_scr_act());
lv_label_set_text(hello_world_label, "Hello World!");
lv_obj_align(hello_world_label, LV_ALIGN_CENTER, 0, 0);
lv_obj_set_style_text_font(hello_world_label, &lv_font_montserrat_16, LV_PART_MAIN);
return 0;
}
int main(void)
{
LOG_DBG("Hello World! %s (%s)", CONFIG_BOARD, APP_VERSION_EXTENDED_STRING);
change_gpio_voltage(UICR_VREGHVOUT_VREGHVOUT_3V0);
display_manager_init();
backlight_manager_init();
screen_helloworld_init();
backlight_manager_wake();
while (count < 100) {
count++;
LOG_DBG("looping %d", count);
k_sleep(K_MSEC(1000));
lv_timer_handler();
}
backlight_manager_sleep();
return 0;
}
and this in the dts/overlay:
/ {
mipi_dbi {
compatible = "zephyr,mipi-dbi-spi";
spi-dev = <&spi4>;
dc-gpios = <&gpio0 19 GPIO_ACTIVE_HIGH>;
reset-gpios = <&gpio0 23 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>;
mipi-mode = "MIPI_DBI_MODE_SPI_4WIRE";
};
};
};
I also simply have this in the main while loop:
lv_timer_handler();
Environment
- MCU/MPU/Board: nrf5340 board
- LVGL version: 9.3.0
- nrfConnect: 3.0.1
- Zephyr: 4.0.99 (maybe a Nordic patch level)
- Display: st7789, SPI, mipi_dbi