准备

使用windows espidf + vscode

移植:

通过组件管理器安装最新lvgl库和lvgl port库。

ESP32 底层相关配置

void setup_gpio_init(void)
{
    gpio_config_t gpio_cfg = {};
    gpio_cfg.mode = GPIO_MODE_OUTPUT;
    gpio_cfg.pin_bit_mask = 1ULL << LCD_BLK_NUM;
    gpio_cfg.pull_down_en = GPIO_PULLUP_DISABLE;
    gpio_cfg.pull_up_en = GPIO_PULLUP_DISABLE;
    gpio_cfg.intr_type = GPIO_INTR_DISABLE;
    ESP_ERROR_CHECK(gpio_config(&gpio_cfg));
}
void setup_spi_init(void)
{
    spi_bus_config_t spi_cfg = {};
    spi_cfg.sclk_io_num = LCD_SCLK_NUM;
    spi_cfg.mosi_io_num = LCD_MOSI_NUM;
    spi_cfg.miso_io_num = LCD_MISO_NUM;

    spi_cfg.quadwp_io_num = GPIO_NUM_NC;
    spi_cfg.quadhd_io_num = GPIO_NUM_NC;
    //spi_cfg.max_transfer_sz应当比显存容量大,避免刷新失败,计算时应将像素点总数乘以每个像素点的字节数
    spi_cfg.max_transfer_sz = LCD_H_RES_DATA * LCD_BUFFER_H_DATA * sizeof(uint16_t);
    ESP_ERROR_CHECK(spi_bus_initialize(LCD_SPI2_HOST, &spi_cfg, SPI_DMA_CH_AUTO));
}

lcd面板

void device_lcd_init(void)
{
    esp_lcd_panel_io_spi_config_t io_config = {};
    io_config.dc_gpio_num = LCD_DC_NUM;
    io_config.cs_gpio_num = LCD_CS_NUM;
    io_config.pclk_hz = LCD_PIXEL_CLK_HZ;
    io_config.lcd_cmd_bits = LCD_CMD_BITS;
    io_config.lcd_param_bits = LCD_PARAM_BITS;
    io_config.spi_mode = 0;
    io_config.trans_queue_depth = 10;
    ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)LCD_SPI2_HOST, &io_config, &lcd_io));
    esp_lcd_panel_dev_config_t panel_config = {};

    panel_config.reset_gpio_num = LCD_RST_NUM;
    panel_config.rgb_ele_order = LCD_COLOR_SPACE;
    panel_config.bits_per_pixel = LCD_BITS_PER_PIXEL;
    ESP_ERROR_CHECK(esp_lcd_new_panel_st7789(lcd_io, &panel_config, &lcd_panel));

    esp_lcd_panel_reset(lcd_panel);
    esp_lcd_panel_init(lcd_panel);
    esp_lcd_panel_set_gap(lcd_panel, 0, 0);
    //_设置偏移
    esp_lcd_panel_invert_color(lcd_panel,true);
    // esp_lcd_panel_mirror(lcd_panel,false,_true);
    esp_lcd_panel_disp_on_off(lcd_panel, true);
}

实例一个lvgl输入设备

lv_indev_t * init_button_event_mode(void)
{
    // create indev
    indev_button = lv_indev_create();
    lv_indev_set_type(indev_button, LV_INDEV_TYPE_KEYPAD);
    lv_indev_set_mode(indev_button, LV_INDEV_MODE_EVENT);      // event-driven
    lv_indev_set_read_cb(indev_button, lv_event_button_read_cb);
    lv_indev_set_driver_data(indev_button, &ctx);
    lv_indev_set_display(indev_button, lv_display_get_default()); // or your disp handle

    ctx.indev = indev_button;
    ctx.pressed = false;
    return indev_button;
}

lvgl输入设备回调

static void lv_event_button_read_cb(lv_indev_t * indev, lv_indev_data_t * data)
{
    printf("got\n");
    
    btn_ctx_t *ctx = (btn_ctx_t *)lv_indev_get_driver_data(indev);
    // read and clear the pressed flag (do not block)
    data->key = ctx->lv_key;
    
    bool pressed = ctx->pressed;
    if (pressed) {
        data->state = LV_INDEV_STATE_PRESSED;
    } else {
        data->state = LV_INDEV_STATE_RELEASED;
    }
    // printf("focused=%p\n", lv_group_get_focused(lv_indev_get_act()));
    lv_obj_t *f = lv_group_get_focused(lv_indev_get_group(indev));
    printf("focused=%p ", f);
    printf("read_cb key=%lu state=%d\n", data->key, data->state);
}

实际lv_event_button_read_cb的事件来源(注意pseudo,其实由于没有实际输入设备,这个将交给控制台,由命令行控制伪装输入):

/*
* @para btnx:0:left,1:enter,2:right
*/
void pseudo_button_gpio_isr(uint8_t btnX,uint8_t click)
{
    switch (btnX)
    {
    case 0:
        ctx.lv_key = LV_KEY_LEFT;
        break;
    case 1:
        ctx.lv_key = LV_KEY_ENTER;
        break;
    case 2:
        ctx.lv_key = LV_KEY_RIGHT;
        break;
    
    default:
        break;
    }
    ctx.pressed = (click != 0);
    // esp_lvgl_port provides this ISR-safe wake. It will set event bits and yield from ISR if needed.
    lvgl_port_task_wake(LVGL_PORT_EVENT_TOUCH, ctx.indev);
}

正式建立lvgl与硬件lcd的联系;

void soft_drv_lvgl_port_init(void)
{
    /*_LCD_backlight_on_*/
    ESP_ERROR_CHECK(gpio_set_level(LCD_BLK_NUM, LCD_BL_NO_LEVEL));

    // encoder_init_todo
    lvgl_port_cfg_t lvgl_cfg = {};
    lvgl_cfg.task_priority = 4;     /*_LVGL_task_priority_*/
    lvgl_cfg.task_stack = 12 * 1024; /*LVGL_task_stack_size_*/
    lvgl_cfg.task_affinity = -1;    /*LVGL_task_pinned_to_core(-l_is_no_affinity)*/

    lvgl_cfg.task_max_sleep_ms = 500; /*_Maximum_sleep_in_LVGL_task*/
    lvgl_cfg.timer_period_ms = 5;    /*LVGL_timer_tick_period_in_ms_ */

    ESP_ERROR_CHECK(lvgl_port_init(&lvgl_cfg));

    lvgl_port_display_cfg_t disp_cfg = {};
    disp_cfg.io_handle = lcd_io;

    disp_cfg.panel_handle = lcd_panel;
    //disp_cfg.buffer_size应该小于spi_cfg.max_transfer_sz
    disp_cfg.buffer_size = LCD_H_RES * LCD_DRAW_BUFF_HEIGHT;
    disp_cfg.double_buffer = LCD_DEAW_BUFF_DOUBLE;
    disp_cfg.hres = LCD_H_RES;
    disp_cfg.vres = LCD_V_RES;
    disp_cfg.monochrome = false;
#if LVGL_VERSION_MAJOR >= 9
    disp_cfg.color_format  = LV_COLOR_FORMAT_RGB565;
#endif
    disp_cfg.rotation.swap_xy = false;
    disp_cfg.rotation.mirror_x = false;
    disp_cfg.rotation.mirror_y = false;
    disp_cfg.flags.buff_dma = true;

#if LVGL_VERSION_MAJOR >= 9
    disp_cfg.flags.swap_bytes = true;
#endif
    lvgl_disp = lvgl_port_add_disp(&disp_cfg);
}

移植更多细节可以参考:“https://www.bilibili.com/video/BV1rNPjeEE34/?vd_source=8a28106cecc10670fe9dc17e05c6226f”

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐