148 lines
4.7 KiB
C
148 lines
4.7 KiB
C
#include "lvgl_port.h"
|
|
|
|
#include "board_config.h"
|
|
|
|
#include "draw/sw/lv_draw_sw.h"
|
|
#include "driver/spi_master.h"
|
|
#include "esp_lcd_panel_ops.h"
|
|
#include "esp_log.h"
|
|
#include "esp_timer.h"
|
|
#include "freertos/FreeRTOS.h"
|
|
#include "freertos/task.h"
|
|
#include "sys/lock.h"
|
|
#include "sys/param.h"
|
|
#include "unistd.h"
|
|
|
|
#include <assert.h>
|
|
|
|
static const char *TAG = "lvgl_port";
|
|
static _lock_t s_lvgl_api_lock;
|
|
|
|
static bool notify_flush_ready(esp_lcd_panel_io_handle_t panel_io,
|
|
esp_lcd_panel_io_event_data_t *edata,
|
|
void *user_ctx)
|
|
{
|
|
(void)panel_io;
|
|
(void)edata;
|
|
lv_display_t *disp = (lv_display_t *)user_ctx;
|
|
lv_display_flush_ready(disp);
|
|
return false;
|
|
}
|
|
|
|
static void flush_cb(lv_display_t *disp, const lv_area_t *area, uint8_t *px_map)
|
|
{
|
|
esp_lcd_panel_handle_t panel_handle = lv_display_get_user_data(disp);
|
|
const lv_area_t *draw_area = area;
|
|
uint8_t *draw_buf = px_map;
|
|
|
|
static uint8_t rotated_buf[BOARD_LCD_H_RES * BOARD_LVGL_DRAW_BUF_LINES *
|
|
sizeof(lv_color16_t)];
|
|
|
|
lv_display_rotation_t rotation = lv_display_get_rotation(disp);
|
|
lv_area_t rotated_area;
|
|
if (rotation != LV_DISPLAY_ROTATION_0) {
|
|
lv_color_format_t cf = lv_display_get_color_format(disp);
|
|
rotated_area = *area;
|
|
lv_display_rotate_area(disp, &rotated_area);
|
|
|
|
int32_t src_w = lv_area_get_width(area);
|
|
int32_t src_h = lv_area_get_height(area);
|
|
uint32_t src_stride = lv_draw_buf_width_to_stride(src_w, cf);
|
|
uint32_t dest_stride =
|
|
lv_draw_buf_width_to_stride(lv_area_get_width(&rotated_area), cf);
|
|
|
|
lv_draw_sw_rotate(px_map, rotated_buf, src_w, src_h, src_stride,
|
|
dest_stride, rotation, cf);
|
|
|
|
draw_area = &rotated_area;
|
|
draw_buf = rotated_buf;
|
|
}
|
|
|
|
int offsetx1 = draw_area->x1;
|
|
int offsetx2 = draw_area->x2;
|
|
int offsety1 = draw_area->y1;
|
|
int offsety2 = draw_area->y2;
|
|
lv_draw_sw_rgb565_swap(draw_buf,
|
|
(offsetx2 + 1 - offsetx1) * (offsety2 + 1 - offsety1));
|
|
esp_lcd_panel_draw_bitmap(panel_handle, offsetx1, offsety1, offsetx2 + 1,
|
|
offsety2 + 1, draw_buf);
|
|
}
|
|
|
|
static void increase_lvgl_tick(void *arg)
|
|
{
|
|
(void)arg;
|
|
lv_tick_inc(BOARD_LVGL_TICK_PERIOD_MS);
|
|
}
|
|
|
|
static void lvgl_port_task(void *arg)
|
|
{
|
|
(void)arg;
|
|
ESP_LOGI(TAG, "Starting LVGL task");
|
|
uint32_t time_till_next_ms = 0;
|
|
while (1) {
|
|
_lock_acquire(&s_lvgl_api_lock);
|
|
time_till_next_ms = lv_timer_handler();
|
|
_lock_release(&s_lvgl_api_lock);
|
|
time_till_next_ms = MAX(time_till_next_ms, BOARD_LVGL_TASK_MIN_DELAY_MS);
|
|
time_till_next_ms = MIN(time_till_next_ms, BOARD_LVGL_TASK_MAX_DELAY_MS);
|
|
usleep(1000 * time_till_next_ms);
|
|
}
|
|
}
|
|
|
|
void lvgl_port_lock(void)
|
|
{
|
|
_lock_acquire(&s_lvgl_api_lock);
|
|
}
|
|
|
|
void lvgl_port_unlock(void)
|
|
{
|
|
_lock_release(&s_lvgl_api_lock);
|
|
}
|
|
|
|
lv_display_t *lvgl_port_init(esp_lcd_panel_io_handle_t io_handle,
|
|
esp_lcd_panel_handle_t panel_handle)
|
|
{
|
|
ESP_LOGI(TAG, "Initialize LVGL library");
|
|
lv_init();
|
|
|
|
lv_display_t *display =
|
|
lv_display_create(BOARD_LCD_H_RES, BOARD_LCD_V_RES);
|
|
lv_display_set_rotation(display, LV_DISPLAY_ROTATION_270);
|
|
|
|
size_t draw_buffer_sz = BOARD_LCD_H_RES * BOARD_LVGL_DRAW_BUF_LINES *
|
|
sizeof(lv_color16_t);
|
|
void *buf1 = spi_bus_dma_memory_alloc(BOARD_LCD_HOST, draw_buffer_sz, 0);
|
|
assert(buf1);
|
|
void *buf2 = spi_bus_dma_memory_alloc(BOARD_LCD_HOST, draw_buffer_sz, 0);
|
|
assert(buf2);
|
|
|
|
lv_display_set_buffers(display, buf1, buf2, draw_buffer_sz,
|
|
LV_DISPLAY_RENDER_MODE_PARTIAL);
|
|
lv_display_set_user_data(display, panel_handle);
|
|
lv_display_set_color_format(display, LV_COLOR_FORMAT_RGB565);
|
|
lv_display_set_flush_cb(display, flush_cb);
|
|
|
|
ESP_LOGI(TAG, "Install LVGL tick timer");
|
|
const esp_timer_create_args_t lvgl_tick_timer_args = {
|
|
.callback = &increase_lvgl_tick,
|
|
.name = "lvgl_tick",
|
|
};
|
|
esp_timer_handle_t lvgl_tick_timer = NULL;
|
|
ESP_ERROR_CHECK(esp_timer_create(&lvgl_tick_timer_args, &lvgl_tick_timer));
|
|
ESP_ERROR_CHECK(esp_timer_start_periodic(lvgl_tick_timer,
|
|
BOARD_LVGL_TICK_PERIOD_MS * 1000));
|
|
|
|
ESP_LOGI(TAG, "Register flush ready callback");
|
|
const esp_lcd_panel_io_callbacks_t cbs = {
|
|
.on_color_trans_done = notify_flush_ready,
|
|
};
|
|
ESP_ERROR_CHECK(
|
|
esp_lcd_panel_io_register_event_callbacks(io_handle, &cbs, display));
|
|
|
|
ESP_LOGI(TAG, "Create LVGL task");
|
|
xTaskCreate(lvgl_port_task, "LVGL", BOARD_LVGL_TASK_STACK_SIZE, NULL,
|
|
BOARD_LVGL_TASK_PRIORITY, NULL);
|
|
|
|
return display;
|
|
}
|