ESP32S2_Cal/main/impl/impl_lvgl.c

186 lines
5.2 KiB
C

#include "impl_lvgl.h"
#include "esp_log.h"
#include "impl_epd.h"
#define EPD_DISPLAY_PIXEL_COUNT 400 * 300
#define EPD_DISPLAY_FRAME_SIZE (EPD_DISPLAY_PIXEL_COUNT * 2 / 8)
#define EPD_DISPLAY_GS 0
#define EPD_DISPLAY_MAX_PARTIAL 6
static impl_epd_handle_t s_epd_impl;
static epd_gdew042t2_t s_gd_epd = {
.cb =
{
.reset_cb = impl_epd_reset,
.write_command_cb = impl_epd_write_command,
.write_data_cb = impl_epd_write_data,
.poll_busy_cb = impl_epd_poll_busy,
.delay_cb = impl_epd_delay,
},
#if EPD_DISPLAY_GS
.mode = EPD_GDEW042T2_MODE_GS,
#else
.mode = EPD_GDEW042T2_MODE_BW,
#endif
.user_data = &s_epd_impl,
};
#if !EPD_DISPLAY_GS
static uint8_t s_epd_partial_counter = EPD_DISPLAY_MAX_PARTIAL - 1;
#endif
static lv_disp_draw_buf_t s_disp_buf;
static lv_color_t s_disp_store[EPD_DISPLAY_FRAME_SIZE];
static lv_disp_drv_t s_disp_drv;
static TaskHandle_t s_lv_tick_handle;
static TaskHandle_t s_lv_task_handle;
static SemaphoreHandle_t s_lv_semphr_handle;
static void impl_lvgl_epd_set_px_cb(lv_disp_drv_t *disp_drv, uint8_t *buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y,
lv_color_t color, lv_opa_t opa) {
uint32_t byte_index = (buf_w * y + x) / 8;
uint8_t bit_index = 7 - (x % 8);
uint8_t brightness = lv_color_brightness(color);
#if EPD_DISPLAY_GS
if (brightness < 64) {
buf[byte_index] &= ~(1 << bit_index);
buf[15000 + byte_index] &= ~(1 << bit_index);
} else if (brightness < 128) {
buf[byte_index] &= ~(1 << bit_index);
buf[15000 + byte_index] |= (1 << bit_index);
} else if (brightness < 192) {
buf[byte_index] |= (1 << bit_index);
buf[15000 + byte_index] &= ~(1 << bit_index);
} else {
buf[byte_index] |= (1 << bit_index);
buf[15000 + byte_index] |= (1 << bit_index);
}
#else
uint8_t current_frame = 0;
if ((s_epd_partial_counter % 2) == 1) {
current_frame = 1;
}
if (brightness > 128) {
buf[current_frame * 15000 + byte_index] |= (1 << bit_index);
} else {
buf[current_frame * 15000 + byte_index] &= ~(1 << bit_index);
}
#endif
}
static void impl_lvgl_epd_flush_cb(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p) {
epd_coord_t coord = {
.x_start = 0,
.x_end = 399,
.y_start = 0,
.y_end = 299,
};
#if EPD_DISPLAY_GS
epd_gdew042t2_upload(&s_gd_epd, &coord, (uint8_t *)color_p, (uint8_t *)&color_p[15000]);
#else
if (s_epd_partial_counter == 0) {
s_epd_partial_counter = EPD_DISPLAY_MAX_PARTIAL - 1;
s_gd_epd.mode = EPD_GDEW042T2_MODE_BW;
// Flush to full
epd_gdew042t2_upload(&s_gd_epd, &coord, (uint8_t *)color_p, (uint8_t *)color_p);
} else {
s_gd_epd.mode = EPD_GDEW042T2_MODE_BW_PART;
// Even: buffer 0, odd: buffer 1
if ((s_epd_partial_counter % 2) == 1) {
epd_gdew042t2_upload(&s_gd_epd, &coord, (uint8_t *)color_p, (uint8_t *)&color_p[15000]);
} else {
epd_gdew042t2_upload(&s_gd_epd, &coord, (uint8_t *)&color_p[15000], (uint8_t *)color_p);
}
s_epd_partial_counter--;
}
#endif
lv_disp_flush_ready(disp_drv);
}
static void impl_lvgl_epd_rounder_cb(lv_disp_drv_t *disp_drv, lv_area_t *area) {
area->x1 = 0;
area->x2 = 399;
}
static void impl_lvgl_log_cb(const char *buf) { ESP_LOGI("LVGL", "%s", buf); }
void impl_lvgl_timer_task(void *pvParameters) {
for (;;) {
impl_lvgl_lock();
lv_timer_handler();
impl_lvgl_unlock();
vTaskDelay(pdMS_TO_TICKS(100));
}
}
void impl_lvgl_tick_task(void *pvParameters) {
for (;;) {
impl_lvgl_lock();
lv_tick_inc(50);
impl_lvgl_unlock();
vTaskDelay(pdMS_TO_TICKS(50));
}
}
esp_err_t impl_lvgl_lock(void) {
if (xSemaphoreTake(s_lv_semphr_handle, portMAX_DELAY) != pdTRUE) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t impl_lvgl_unlock(void) {
xSemaphoreGive(s_lv_semphr_handle);
return ESP_OK;
}
esp_err_t impl_lvgl_init(void) {
ESP_ERROR_CHECK(impl_epd_init(&s_epd_impl));
lv_init();
lv_disp_draw_buf_init(&s_disp_buf, s_disp_store, NULL, EPD_DISPLAY_PIXEL_COUNT);
lv_disp_drv_init(&s_disp_drv);
s_disp_drv.set_px_cb = impl_lvgl_epd_set_px_cb;
s_disp_drv.flush_cb = impl_lvgl_epd_flush_cb;
s_disp_drv.rounder_cb = impl_lvgl_epd_rounder_cb;
s_disp_drv.hor_res = 400;
s_disp_drv.ver_res = 300;
s_disp_drv.draw_buf = &s_disp_buf;
s_disp_drv.full_refresh = 1;
printf("Buffer start: %p\r\n", s_disp_store);
lv_disp_t *disp = lv_disp_drv_register(&s_disp_drv);
if (disp == NULL) {
return ESP_FAIL;
}
s_lv_semphr_handle = xSemaphoreCreateBinary();
if (s_lv_semphr_handle == NULL) {
return ESP_FAIL;
}
xSemaphoreGive(s_lv_semphr_handle);
xTaskCreate(impl_lvgl_tick_task, "LV_TICK", 1024, NULL, 5, &s_lv_tick_handle);
xTaskCreate(impl_lvgl_timer_task, "LV_TMR", 4096, NULL, 4, &s_lv_task_handle);
// TODO: Launch LVGL tasks below.
return ESP_OK;
}