186 lines
5.2 KiB
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;
|
|
} |