diff --git a/components/display/display.c b/components/display/display.c index 788cc1f..1fd6af3 100644 --- a/components/display/display.c +++ b/components/display/display.c @@ -1,11 +1,9 @@ #include "display.h" #include +#include #include -#include -#include #include -#include #include #include "lcd.h" @@ -13,28 +11,24 @@ static const char *TAG = "display"; static void lcd_flush_cb(lv_display_t *disp, const lv_area_t *area, uint8_t *px_map) { - esp_lcd_panel_handle_t panel_handle = (esp_lcd_panel_handle_t)lv_display_get_user_data(disp); + lcd_t *lcd = (lcd_t *)lv_display_get_user_data(disp); int x1 = area->x1; int x2 = area->x2; int y1 = area->y1; int y2 = area->y2; - ESP_ERROR_CHECK(esp_lcd_panel_draw_bitmap(panel_handle, x1, y1, x2 + 1, y2 + 1, px_map)); ESP_LOGD(TAG, "lcd_flush_cb() x1=%d y1=%d x2=%d y2=%d", x1, y1, x2, y2); + lcd_draw_start(lcd, x1, y1, x2, y2, px_map); } -static uint32_t lcd_lvgl_tick_get_cb() { return esp_timer_get_time() / 1000; } - -bool color_trans_done_cb(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_io_event_data_t *edata, - void *user_ctx) { - lv_display_t *disp = (lv_display_t *)user_ctx; - lv_display_flush_ready(disp); - - return true; // TODO: not sure about this. +static void lcd_wait_cb(lv_display_t *disp) { + lcd_t *lcd = (lcd_t *)lv_display_get_user_data(disp); + lcd_draw_wait_finished(lcd); } -esp_err_t init_display(esp_lcd_panel_handle_t panel_handle, - esp_lcd_panel_io_handle_t panel_io_handle, lv_display_t **disp_out) { +static uint32_t lcd_lvgl_tick_get_cb() { return esp_timer_get_time() / 1000; } + +void init_display(lcd_t *lcd, lv_display_t **disp_out) { ESP_LOGI(TAG, "Initialize LVGL library"); lv_init(); lv_tick_set_cb(lcd_lvgl_tick_get_cb); @@ -52,19 +46,12 @@ esp_err_t init_display(esp_lcd_panel_handle_t panel_handle, lv_display_t *disp = lv_display_create(SMALLTV_LCD_H_RES, SMALLTV_LCD_V_RES); assert(disp != NULL); - lv_display_set_user_data(disp, (void *)panel_handle); + lv_display_set_user_data(disp, (void *)lcd); + lv_display_set_flush_wait_cb(disp, lcd_wait_cb); lv_display_set_flush_cb(disp, lcd_flush_cb); lv_display_set_buffers(disp, buf0, NULL, buf_sz, LV_DISPLAY_RENDER_MODE_PARTIAL); lv_display_set_color_format(disp, SMALLTV_LCD_COLOR_FORMAT); - // Register IO done callback. - const esp_lcd_panel_io_callbacks_t cbs = { - .on_color_trans_done = color_trans_done_cb, - }; - esp_lcd_panel_io_register_event_callbacks(panel_io_handle, &cbs, (void *)disp); - assert(disp_out != NULL); *disp_out = disp; - - return ESP_OK; } diff --git a/components/display/display.h b/components/display/display.h index e873720..e6b0ebd 100644 --- a/components/display/display.h +++ b/components/display/display.h @@ -1,9 +1,6 @@ #pragma once -#include -#include - +#include "lcd.h" #include "lvgl.h" -esp_err_t init_display(esp_lcd_panel_handle_t panel_handle, - esp_lcd_panel_io_handle_t panel_io_handle, lv_display_t **disp_out); +void init_display(lcd_t *lcd, lv_display_t **disp_out); diff --git a/components/display/lcd.c b/components/display/lcd.c index b42832d..aafb89e 100644 --- a/components/display/lcd.c +++ b/components/display/lcd.c @@ -7,10 +7,12 @@ #include #pragma GCC diagnostic pop #include +#include #include #include #include #include +#include static const char *TAG = "lcd"; @@ -42,7 +44,21 @@ static void setup_backlight_pwm() { ESP_ERROR_CHECK(ledc_update_duty(BL_LEDC_MODE, BL_LEDC_CHANNEL)); } -esp_err_t init_lcd(lcd_t *lcd_out) { +static bool io_done_cb(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_io_event_data_t *edata, + void *user_ctx) { + ESP_LOGD(TAG, "io_done_cb()"); + + lcd_t *lcd = (lcd_t *)user_ctx; + + BaseType_t result = xSemaphoreGive(lcd->drawing); + if (result != pdTRUE) { + ESP_ERROR_CHECK(ESP_ERR_INVALID_STATE); + } + + return true; // TODO: not sure about this. +} + +void init_lcd(lcd_t *lcd_out) { setup_backlight_pwm(); lcd_backlight_set_brightness(0); @@ -72,7 +88,6 @@ esp_err_t init_lcd(lcd_t *lcd_out) { }; ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)SMALLTV_LCD_SPI_HOST, &io_config, &panel_io_handle)); - assert(panel_io_handle != NULL); ESP_LOGI(TAG, "Create St7789 LCD panel"); esp_lcd_panel_dev_config_t panel_config = { @@ -85,7 +100,6 @@ esp_err_t init_lcd(lcd_t *lcd_out) { }; esp_lcd_panel_handle_t panel_handle; ESP_ERROR_CHECK(esp_lcd_new_panel_st7789(panel_io_handle, &panel_config, &panel_handle)); - assert(panel_handle != NULL); ESP_LOGI(TAG, "Initialize LCD panel"); ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_handle)); @@ -97,19 +111,41 @@ esp_err_t init_lcd(lcd_t *lcd_out) { lcd_backlight_set_brightness(255); + ESP_LOGI(TAG, "Assign outputs"); assert(lcd_out != NULL); memset(lcd_out, 0, sizeof(*lcd_out)); lcd_out->panel_handle = panel_handle; lcd_out->panel_io_handle = panel_io_handle; - return ESP_OK; + ESP_LOGI(TAG, "Register IO done callback"); + lcd_out->drawing = xSemaphoreCreateBinaryStatic(&lcd_out->drawing_buf); + assert(lcd_out->drawing != NULL); + const esp_lcd_panel_io_callbacks_t cbs = { + .on_color_trans_done = io_done_cb, + }; + ESP_ERROR_CHECK( + esp_lcd_panel_io_register_event_callbacks(panel_io_handle, &cbs, (void *)lcd_out)); } -esp_err_t lcd_backlight_set_brightness(uint8_t duty) { - ESP_LOGI(TAG, "Backlight duty cycle: %hhu", duty); +void lcd_draw_start(lcd_t *lcd, int x_start, int y_start, int x_end, int y_end, + const void *color_data) { + ESP_LOGD(TAG, "lcd_draw_start()"); + ESP_ERROR_CHECK(esp_lcd_panel_draw_bitmap(lcd->panel_handle, x_start, y_start, x_end + 1, + y_end + 1, color_data)); +} + +void lcd_draw_wait_finished(lcd_t *lcd) { + ESP_LOGD(TAG, "lcd_draw_wait_finished()"); - ledc_set_duty(BL_LEDC_MODE, BL_LEDC_CHANNEL, duty); - ledc_update_duty(BL_LEDC_MODE, BL_LEDC_CHANNEL); + BaseType_t result = xSemaphoreTake(lcd->drawing, portMAX_DELAY); + if (result != pdTRUE) { + ESP_ERROR_CHECK(ESP_ERR_INVALID_STATE); + } +} - return ESP_OK; +void lcd_backlight_set_brightness(uint8_t duty) { + ESP_LOGI(TAG, "lcd_backlight_set_brightness(%hhu)", duty); + + ESP_ERROR_CHECK(ledc_set_duty(BL_LEDC_MODE, BL_LEDC_CHANNEL, duty)); + ESP_ERROR_CHECK(ledc_update_duty(BL_LEDC_MODE, BL_LEDC_CHANNEL)); } diff --git a/components/display/lcd.h b/components/display/lcd.h index 5392066..3b65df8 100644 --- a/components/display/lcd.h +++ b/components/display/lcd.h @@ -1,8 +1,11 @@ #pragma once -#include #include #include +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wsign-compare" +#include +#pragma GCC diagnostic pop #include "lvgl.h" @@ -16,10 +19,17 @@ #define SMALLTV_LCD_CMD_BITS 8 #define SMALLTV_LCD_PARAM_BITS 8 +// All struct members are private to the implementation. typedef struct lcd_t { esp_lcd_panel_handle_t panel_handle; esp_lcd_panel_io_handle_t panel_io_handle; + + SemaphoreHandle_t drawing; + StaticSemaphore_t drawing_buf; } lcd_t; -esp_err_t init_lcd(lcd_t *lcd_out); -esp_err_t lcd_backlight_set_brightness(uint8_t duty); +void init_lcd(lcd_t *lcd_out); +void lcd_draw_start(lcd_t *lcd, int x_start, int y_start, int x_end, int y_end, + const void *color_data); +void lcd_draw_wait_finished(lcd_t *lcd); +void lcd_backlight_set_brightness(uint8_t duty); diff --git a/main/main.c b/main/main.c index 6d34a2d..c4e977b 100644 --- a/main/main.c +++ b/main/main.c @@ -9,6 +9,7 @@ #include #include #include +#include #include "display.h" #include "dns.h" @@ -73,12 +74,12 @@ void app_main(void) { ESP_LOGI(TAG, "Initialize LCD"); lcd_t lcd = {0}; - ESP_ERROR_CHECK(init_lcd(&lcd)); + init_lcd(&lcd); print_free_heap_stack(); ESP_LOGI(TAG, "Initialize display"); lv_display_t *disp = NULL; - ESP_ERROR_CHECK(init_display(lcd.panel_handle, lcd.panel_io_handle, &disp)); + init_display(&lcd, &disp); assert(disp != NULL); print_free_heap_stack();