firmware: Split LCD logic into separate file
This commit is contained in:
		@@ -1,3 +1,3 @@
 | 
				
			|||||||
idf_component_register(
 | 
					idf_component_register(
 | 
				
			||||||
  SRCS "valconomy.c" "ui.c" "usb.c"
 | 
					  SRCS "valconomy.c" "ui.c" "lcd.c" "usb.c"
 | 
				
			||||||
  INCLUDE_DIRS ".")
 | 
					  INCLUDE_DIRS ".")
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										13
									
								
								firmware/main/common.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								firmware/main/common.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
				
			|||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <inttypes.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "driver/i2c_master.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define SCL_SPEED 100000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define LCD_HRES        800
 | 
				
			||||||
 | 
					#define LCD_VRES        480
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern i2c_master_bus_handle_t i2c_bus_handle;
 | 
				
			||||||
 | 
					extern i2c_master_dev_handle_t exio_cfg_handle, exio_o_handle;
 | 
				
			||||||
							
								
								
									
										255
									
								
								firmware/main/lcd.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										255
									
								
								firmware/main/lcd.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,255 @@
 | 
				
			|||||||
 | 
					#include <inttypes.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "sdkconfig.h"
 | 
				
			||||||
 | 
					#include "freertos/FreeRTOS.h"
 | 
				
			||||||
 | 
					#include "freertos/task.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "esp_err.h"
 | 
				
			||||||
 | 
					#include "esp_log.h"
 | 
				
			||||||
 | 
					#include "esp_timer.h"
 | 
				
			||||||
 | 
					#include "esp_lcd_panel_ops.h"
 | 
				
			||||||
 | 
					#include "esp_lcd_panel_rgb.h"
 | 
				
			||||||
 | 
					#include "driver/i2c_master.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "esp_lcd_touch_gt911.h"
 | 
				
			||||||
 | 
					#include "lvgl.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "common.h"
 | 
				
			||||||
 | 
					#include "lcd.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define LCD_PIXEL_SIZE    2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// in ms
 | 
				
			||||||
 | 
					#define LVGL_TICK_PERIOD     2
 | 
				
			||||||
 | 
					#define LVGL_TASK_MAX_DELAY  500
 | 
				
			||||||
 | 
					#define LVGL_TASK_MIN_DELAY  1
 | 
				
			||||||
 | 
					#define LVGL_TASK_PRIORITY   2
 | 
				
			||||||
 | 
					#define LVGL_TASK_STACK_SIZE (8 * 1024)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const char *TAG = "valconomy-lcd";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// LVGL library is not thread-safe, we will call LVGL APIs from different tasks, so use a mutex to protect it
 | 
				
			||||||
 | 
					static SemaphoreHandle_t lvgl_mtx = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool val_on_vsync(esp_lcd_panel_handle_t panel, const esp_lcd_rgb_panel_event_data_t *event_data, void *user_ctx) {
 | 
				
			||||||
 | 
					  return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void val_lvgl_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);
 | 
				
			||||||
 | 
					  // pass the draw buffer to the driver
 | 
				
			||||||
 | 
					  esp_lcd_panel_draw_bitmap(panel_handle, area->x1, area->y1, area->x2 + 1, area->y2 + 1, px_map);
 | 
				
			||||||
 | 
					  lv_disp_flush_ready(disp);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void val_increase_lvgl_tick(void *arg) {
 | 
				
			||||||
 | 
					  /* Tell LVGL how many milliseconds has elapsed */
 | 
				
			||||||
 | 
					  lv_tick_inc(LVGL_TICK_PERIOD);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void val_lvgl_port_task(void *arg) {
 | 
				
			||||||
 | 
					  ESP_LOGI(TAG, "Starting LVGL task");
 | 
				
			||||||
 | 
					  uint32_t task_delay_ms = LVGL_TASK_MAX_DELAY;
 | 
				
			||||||
 | 
					  while (1) {
 | 
				
			||||||
 | 
					    // Lock the mutex due to the LVGL APIs are not thread-safe
 | 
				
			||||||
 | 
					    if (val_lvgl_lock(-1)) {
 | 
				
			||||||
 | 
					      task_delay_ms = lv_timer_handler();
 | 
				
			||||||
 | 
					      // Release the mutex
 | 
				
			||||||
 | 
					      val_lvgl_unlock();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (task_delay_ms > LVGL_TASK_MAX_DELAY) {
 | 
				
			||||||
 | 
					      task_delay_ms = LVGL_TASK_MAX_DELAY;
 | 
				
			||||||
 | 
					    } else if (task_delay_ms < LVGL_TASK_MIN_DELAY) {
 | 
				
			||||||
 | 
					      task_delay_ms = LVGL_TASK_MIN_DELAY;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    vTaskDelay(pdMS_TO_TICKS(task_delay_ms));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void val_lvgl_touch_read(lv_indev_t *indev, lv_indev_data_t *data) {
 | 
				
			||||||
 | 
					  uint16_t touchpad_x[1] = {0};
 | 
				
			||||||
 | 
					  uint16_t touchpad_y[1] = {0};
 | 
				
			||||||
 | 
					  uint8_t touchpad_cnt = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Read touch controller data
 | 
				
			||||||
 | 
					  esp_lcd_touch_handle_t touch_panel = lv_indev_get_user_data(indev);
 | 
				
			||||||
 | 
					  esp_lcd_touch_read_data(touch_panel);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Get coordinates
 | 
				
			||||||
 | 
					  bool touchpad_pressed = esp_lcd_touch_get_coordinates(touch_panel, touchpad_x, touchpad_y, NULL, &touchpad_cnt, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (touchpad_pressed && touchpad_cnt > 0) {
 | 
				
			||||||
 | 
					    data->point.x = touchpad_x[0];
 | 
				
			||||||
 | 
					    data->point.y = touchpad_y[0];
 | 
				
			||||||
 | 
					    data->state = LV_INDEV_STATE_PR;
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    data->state = LV_INDEV_STATE_REL;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool val_lvgl_lock(int timeout_ms) {
 | 
				
			||||||
 | 
					  // Convert timeout in milliseconds to FreeRTOS ticks
 | 
				
			||||||
 | 
					  // If `timeout_ms` is set to -1, the program will block until the condition is met
 | 
				
			||||||
 | 
					  const TickType_t timeout_ticks = (timeout_ms == -1) ? portMAX_DELAY : pdMS_TO_TICKS(timeout_ms);
 | 
				
			||||||
 | 
					  return xSemaphoreTakeRecursive(lvgl_mtx, timeout_ticks) == pdTRUE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void val_lvgl_unlock(void) {
 | 
				
			||||||
 | 
					  xSemaphoreGiveRecursive(lvgl_mtx);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					esp_lcd_touch_handle_t val_setup_touch(void) {
 | 
				
			||||||
 | 
					  ESP_LOGI(TAG, "Install touch panel driver");
 | 
				
			||||||
 | 
					  esp_lcd_panel_io_i2c_config_t io_config = ESP_LCD_TOUCH_IO_I2C_GT911_CONFIG();
 | 
				
			||||||
 | 
					  io_config.scl_speed_hz = SCL_SPEED;
 | 
				
			||||||
 | 
					  esp_lcd_panel_io_handle_t io_handle = NULL;
 | 
				
			||||||
 | 
					  ESP_ERROR_CHECK(esp_lcd_new_panel_io_i2c(i2c_bus_handle, &io_config, &io_handle));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  esp_lcd_touch_io_gt911_config_t gt911_config = {
 | 
				
			||||||
 | 
					    .dev_addr = io_config.dev_addr,
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  esp_lcd_touch_config_t tp_cfg = {
 | 
				
			||||||
 | 
					    .x_max = LCD_HRES,
 | 
				
			||||||
 | 
					    .y_max = LCD_VRES,
 | 
				
			||||||
 | 
					    .rst_gpio_num = -1,
 | 
				
			||||||
 | 
					    .int_gpio_num = 4,
 | 
				
			||||||
 | 
					    .levels = {
 | 
				
			||||||
 | 
					      .reset = 0,
 | 
				
			||||||
 | 
					      .interrupt = 0,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    .flags = {
 | 
				
			||||||
 | 
					      .swap_xy = 0,
 | 
				
			||||||
 | 
					      .mirror_x = 0,
 | 
				
			||||||
 | 
					      .mirror_y = 0,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    .driver_data = >911_config,
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  esp_lcd_touch_handle_t tp;
 | 
				
			||||||
 | 
					  ESP_ERROR_CHECK(esp_lcd_touch_new_i2c_gt911(io_handle, &tp_cfg, &tp));
 | 
				
			||||||
 | 
					  return tp;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					esp_lcd_panel_handle_t val_setup_lcd(void) {
 | 
				
			||||||
 | 
					  uint8_t i2c_b;
 | 
				
			||||||
 | 
					  i2c_b = 0x01; // Output enable
 | 
				
			||||||
 | 
					  ESP_ERROR_CHECK(i2c_master_transmit(exio_cfg_handle, &i2c_b, 1, -1));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  i2c_b = 0x00; // Reset everything
 | 
				
			||||||
 | 
					  ESP_ERROR_CHECK(i2c_master_transmit(exio_o_handle, &i2c_b, 1, -1));
 | 
				
			||||||
 | 
					  vTaskDelay(pdMS_TO_TICKS(10));
 | 
				
			||||||
 | 
					  i2c_b = 0x0c; // Pull LCD + touch out of reset
 | 
				
			||||||
 | 
					  ESP_ERROR_CHECK(i2c_master_transmit(exio_o_handle, &i2c_b, 1, -1));
 | 
				
			||||||
 | 
					  vTaskDelay(pdMS_TO_TICKS(100));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ESP_LOGI(TAG, "Install RGB LCD panel driver");
 | 
				
			||||||
 | 
					  esp_lcd_panel_handle_t panel_handle = NULL;
 | 
				
			||||||
 | 
					  esp_lcd_rgb_panel_config_t panel_config = {
 | 
				
			||||||
 | 
					    .data_width = 16, // RGB565
 | 
				
			||||||
 | 
					    .psram_trans_align = 64,
 | 
				
			||||||
 | 
					    .num_fbs = 2,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .clk_src = LCD_CLK_SRC_DEFAULT,
 | 
				
			||||||
 | 
					    .disp_gpio_num = -1, // Only accessible via GPIO expander
 | 
				
			||||||
 | 
					    .pclk_gpio_num = 7,
 | 
				
			||||||
 | 
					    .vsync_gpio_num = 3,
 | 
				
			||||||
 | 
					    .hsync_gpio_num = 46,
 | 
				
			||||||
 | 
					    .de_gpio_num = 5,
 | 
				
			||||||
 | 
					    .data_gpio_nums = {
 | 
				
			||||||
 | 
					      14, // B3
 | 
				
			||||||
 | 
					      38, // B4
 | 
				
			||||||
 | 
					      18, // B5
 | 
				
			||||||
 | 
					      17, // B6
 | 
				
			||||||
 | 
					      10, // B7
 | 
				
			||||||
 | 
					      39, // G2
 | 
				
			||||||
 | 
					       0, // G3
 | 
				
			||||||
 | 
					      45, // G4
 | 
				
			||||||
 | 
					      48, // G5
 | 
				
			||||||
 | 
					      47, // G6
 | 
				
			||||||
 | 
					      21, // G7
 | 
				
			||||||
 | 
					       1, // R3
 | 
				
			||||||
 | 
					       2, // R4
 | 
				
			||||||
 | 
					      42, // R5
 | 
				
			||||||
 | 
					      41, // R6
 | 
				
			||||||
 | 
					      40, // R7
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    .timings = {
 | 
				
			||||||
 | 
					      .pclk_hz = 18 * 1000 * 1000, // 18000000 / (hs+hbp+hfp+hres) / (vs+vbp+hfp+vres) = ~42Hz
 | 
				
			||||||
 | 
					      .h_res = LCD_HRES,
 | 
				
			||||||
 | 
					      .v_res = LCD_VRES,
 | 
				
			||||||
 | 
					      .hsync_back_porch = 8,
 | 
				
			||||||
 | 
					      .hsync_front_porch = 8,
 | 
				
			||||||
 | 
					      .hsync_pulse_width = 4,
 | 
				
			||||||
 | 
					      .vsync_back_porch = 16,
 | 
				
			||||||
 | 
					      .vsync_front_porch = 16,
 | 
				
			||||||
 | 
					      .vsync_pulse_width = 4,
 | 
				
			||||||
 | 
					      .flags = {
 | 
				
			||||||
 | 
					        .pclk_active_neg = true,
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    .flags.fb_in_psram = true, // allocate frame buffer in PSRAM
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  ESP_ERROR_CHECK(esp_lcd_new_rgb_panel(&panel_config, &panel_handle));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ESP_LOGI(TAG, "Initialize RGB LCD panel");
 | 
				
			||||||
 | 
					  ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_handle));
 | 
				
			||||||
 | 
					  ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ESP_LOGI(TAG, "Turn on LCD backlight");
 | 
				
			||||||
 | 
					  i2c_b = 0x0e; // LCD + touch out of reset, backlight on
 | 
				
			||||||
 | 
					  ESP_ERROR_CHECK(i2c_master_transmit(exio_o_handle, &i2c_b, 1, -1));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return panel_handle;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					lv_display_t *val_setup_lvgl(esp_lcd_panel_handle_t lcd_panel, esp_lcd_touch_handle_t touch_panel) {
 | 
				
			||||||
 | 
					  ESP_LOGI(TAG, "Initialize LVGL library");
 | 
				
			||||||
 | 
					  lv_init();
 | 
				
			||||||
 | 
					  // create a lvgl display
 | 
				
			||||||
 | 
					  lv_display_t *display = lv_display_create(LCD_HRES, LCD_VRES);
 | 
				
			||||||
 | 
					  // associate the rgb panel handle to the display
 | 
				
			||||||
 | 
					  lv_display_set_user_data(display, lcd_panel);
 | 
				
			||||||
 | 
					  // set color depth
 | 
				
			||||||
 | 
					  lv_display_set_color_format(display, LV_COLOR_FORMAT_RGB565);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // create draw buffers
 | 
				
			||||||
 | 
					  void *buf1 = NULL;
 | 
				
			||||||
 | 
					  void *buf2 = NULL;
 | 
				
			||||||
 | 
					  ESP_LOGI(TAG, "Use frame buffers as LVGL draw buffers");
 | 
				
			||||||
 | 
					  ESP_ERROR_CHECK(esp_lcd_rgb_panel_get_frame_buffer(lcd_panel, 2, &buf1, &buf2));
 | 
				
			||||||
 | 
					  // set LVGL draw buffers and direct mode
 | 
				
			||||||
 | 
					  lv_display_set_buffers(display, buf1, buf2, LCD_HRES * LCD_VRES * LCD_PIXEL_SIZE, LV_DISPLAY_RENDER_MODE_DIRECT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // set the callback which can copy the rendered image to an area of the display
 | 
				
			||||||
 | 
					  lv_display_set_flush_cb(display, val_lvgl_flush_cb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ESP_LOGI(TAG, "Register event callbacks");
 | 
				
			||||||
 | 
					  esp_lcd_rgb_panel_event_callbacks_t cbs = {
 | 
				
			||||||
 | 
					    .on_vsync = val_on_vsync,
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  ESP_ERROR_CHECK(esp_lcd_rgb_panel_register_event_callbacks(lcd_panel, &cbs, display));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  lv_indev_t *indev = lv_indev_create();
 | 
				
			||||||
 | 
					  lv_indev_set_user_data(indev, touch_panel);
 | 
				
			||||||
 | 
					  lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER);
 | 
				
			||||||
 | 
					  lv_indev_set_read_cb(indev, val_lvgl_touch_read);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ESP_LOGI(TAG, "Install LVGL tick timer");
 | 
				
			||||||
 | 
					  // Tick interface for LVGL (using esp_timer to generate 2ms periodic event)
 | 
				
			||||||
 | 
					  const esp_timer_create_args_t lvgl_tick_timer_args = {
 | 
				
			||||||
 | 
					    .callback = &val_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, LVGL_TICK_PERIOD * 1000));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  lvgl_mtx = xSemaphoreCreateRecursiveMutex();
 | 
				
			||||||
 | 
					  assert(lvgl_mtx);
 | 
				
			||||||
 | 
					  ESP_LOGI(TAG, "Create LVGL task");
 | 
				
			||||||
 | 
					  xTaskCreate(val_lvgl_port_task, "LVGL", LVGL_TASK_STACK_SIZE, NULL, LVGL_TASK_PRIORITY, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return display;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										16
									
								
								firmware/main/lcd.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								firmware/main/lcd.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
				
			|||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <inttypes.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "esp_lcd_panel_ops.h"
 | 
				
			||||||
 | 
					#include "esp_lcd_panel_rgb.h"
 | 
				
			||||||
 | 
					#include "esp_lcd_touch_gt911.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "lvgl.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool val_lvgl_lock(int timeout_ms);
 | 
				
			||||||
 | 
					void val_lvgl_unlock(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					esp_lcd_touch_handle_t val_setup_touch(void);
 | 
				
			||||||
 | 
					esp_lcd_panel_handle_t val_setup_lcd(void);
 | 
				
			||||||
 | 
					lv_display_t *val_setup_lvgl(esp_lcd_panel_handle_t lcd_panel, esp_lcd_touch_handle_t touch_panel);
 | 
				
			||||||
@@ -1,5 +1,7 @@
 | 
				
			|||||||
#include "lvgl.h"
 | 
					#include "lvgl.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "ui.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const lv_font_t *font_normal = &lv_font_montserrat_14;
 | 
					static const lv_font_t *font_normal = &lv_font_montserrat_14;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void b_cfg_cb(lv_event_t *e) {
 | 
					static void b_cfg_cb(lv_event_t *e) {
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										5
									
								
								firmware/main/ui.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								firmware/main/ui.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "lvgl.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void val_lvgl_ui(lv_display_t *disp);
 | 
				
			||||||
@@ -6,6 +6,9 @@
 | 
				
			|||||||
#include "tinyusb.h"
 | 
					#include "tinyusb.h"
 | 
				
			||||||
#include "class/hid/hid_device.h"
 | 
					#include "class/hid/hid_device.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "common.h"
 | 
				
			||||||
 | 
					#include "usb.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define TUSB_DESC_TOTAL_LEN (TUD_CONFIG_DESC_LEN + CFG_TUD_HID * TUD_HID_DESC_LEN)
 | 
					#define TUSB_DESC_TOTAL_LEN (TUD_CONFIG_DESC_LEN + CFG_TUD_HID * TUD_HID_DESC_LEN)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const char *TAG = "valconomy-usb";
 | 
					static const char *TAG = "valconomy-usb";
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										5
									
								
								firmware/main/usb.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								firmware/main/usb.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "tinyusb_types.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void val_usb_init(void);
 | 
				
			||||||
@@ -6,106 +6,20 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "esp_err.h"
 | 
					#include "esp_err.h"
 | 
				
			||||||
#include "esp_log.h"
 | 
					#include "esp_log.h"
 | 
				
			||||||
#include "esp_timer.h"
 | 
					 | 
				
			||||||
#include "driver/i2c_master.h"
 | 
					 | 
				
			||||||
#include "esp_lcd_panel_ops.h"
 | 
					#include "esp_lcd_panel_ops.h"
 | 
				
			||||||
#include "esp_lcd_panel_rgb.h"
 | 
					#include "driver/i2c_master.h"
 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "esp_lcd_touch_gt911.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "lvgl.h"
 | 
					#include "lvgl.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define SCL_SPEED 100000
 | 
					#include "common.h"
 | 
				
			||||||
 | 
					#include "usb.h"
 | 
				
			||||||
#define LCD_HRES        800
 | 
					#include "lcd.h"
 | 
				
			||||||
#define LCD_VRES        480
 | 
					#include "ui.h"
 | 
				
			||||||
#define LCD_PIXEL_SIZE    2
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// in ms
 | 
					 | 
				
			||||||
#define LVGL_TICK_PERIOD     2
 | 
					 | 
				
			||||||
#define LVGL_TASK_MAX_DELAY  500
 | 
					 | 
				
			||||||
#define LVGL_TASK_MIN_DELAY  1
 | 
					 | 
				
			||||||
#define LVGL_TASK_PRIORITY   2
 | 
					 | 
				
			||||||
#define LVGL_TASK_STACK_SIZE (8 * 1024)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const char *TAG = "valconomy";
 | 
					static const char *TAG = "valconomy";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static i2c_master_bus_handle_t i2c_bus_handle;
 | 
					i2c_master_bus_handle_t i2c_bus_handle;
 | 
				
			||||||
static i2c_master_dev_handle_t exio_cfg_handle, exio_o_handle;
 | 
					i2c_master_dev_handle_t exio_cfg_handle, exio_o_handle;
 | 
				
			||||||
 | 
					 | 
				
			||||||
// LVGL library is not thread-safe, we will call LVGL APIs from different tasks, so use a mutex to protect it
 | 
					 | 
				
			||||||
static SemaphoreHandle_t lvgl_mtx = NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
extern void val_usb_init(void);
 | 
					 | 
				
			||||||
extern void val_lvgl_ui(lv_display_t *disp);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool val_lvgl_lock(int timeout_ms) {
 | 
					 | 
				
			||||||
  // Convert timeout in milliseconds to FreeRTOS ticks
 | 
					 | 
				
			||||||
  // If `timeout_ms` is set to -1, the program will block until the condition is met
 | 
					 | 
				
			||||||
  const TickType_t timeout_ticks = (timeout_ms == -1) ? portMAX_DELAY : pdMS_TO_TICKS(timeout_ms);
 | 
					 | 
				
			||||||
  return xSemaphoreTakeRecursive(lvgl_mtx, timeout_ticks) == pdTRUE;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void val_lvgl_unlock(void) {
 | 
					 | 
				
			||||||
  xSemaphoreGiveRecursive(lvgl_mtx);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static bool val_on_vsync(esp_lcd_panel_handle_t panel, const esp_lcd_rgb_panel_event_data_t *event_data, void *user_ctx) {
 | 
					 | 
				
			||||||
  return false;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void val_lvgl_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);
 | 
					 | 
				
			||||||
  // pass the draw buffer to the driver
 | 
					 | 
				
			||||||
  esp_lcd_panel_draw_bitmap(panel_handle, area->x1, area->y1, area->x2 + 1, area->y2 + 1, px_map);
 | 
					 | 
				
			||||||
  lv_disp_flush_ready(disp);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void val_increase_lvgl_tick(void *arg) {
 | 
					 | 
				
			||||||
  /* Tell LVGL how many milliseconds has elapsed */
 | 
					 | 
				
			||||||
  lv_tick_inc(LVGL_TICK_PERIOD);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void val_lvgl_port_task(void *arg) {
 | 
					 | 
				
			||||||
  ESP_LOGI(TAG, "Starting LVGL task");
 | 
					 | 
				
			||||||
  uint32_t task_delay_ms = LVGL_TASK_MAX_DELAY;
 | 
					 | 
				
			||||||
  while (1) {
 | 
					 | 
				
			||||||
    // Lock the mutex due to the LVGL APIs are not thread-safe
 | 
					 | 
				
			||||||
    if (val_lvgl_lock(-1)) {
 | 
					 | 
				
			||||||
      task_delay_ms = lv_timer_handler();
 | 
					 | 
				
			||||||
      // Release the mutex
 | 
					 | 
				
			||||||
      val_lvgl_unlock();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (task_delay_ms > LVGL_TASK_MAX_DELAY) {
 | 
					 | 
				
			||||||
      task_delay_ms = LVGL_TASK_MAX_DELAY;
 | 
					 | 
				
			||||||
    } else if (task_delay_ms < LVGL_TASK_MIN_DELAY) {
 | 
					 | 
				
			||||||
      task_delay_ms = LVGL_TASK_MIN_DELAY;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    vTaskDelay(pdMS_TO_TICKS(task_delay_ms));
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void val_lvgl_touch_read(lv_indev_t *indev, lv_indev_data_t *data) {
 | 
					 | 
				
			||||||
  uint16_t touchpad_x[1] = {0};
 | 
					 | 
				
			||||||
  uint16_t touchpad_y[1] = {0};
 | 
					 | 
				
			||||||
  uint8_t touchpad_cnt = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Read touch controller data
 | 
					 | 
				
			||||||
  esp_lcd_touch_handle_t touch_panel = lv_indev_get_user_data(indev);
 | 
					 | 
				
			||||||
  esp_lcd_touch_read_data(touch_panel);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Get coordinates
 | 
					 | 
				
			||||||
  bool touchpad_pressed = esp_lcd_touch_get_coordinates(touch_panel, touchpad_x, touchpad_y, NULL, &touchpad_cnt, 1);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (touchpad_pressed && touchpad_cnt > 0) {
 | 
					 | 
				
			||||||
    data->point.x = touchpad_x[0];
 | 
					 | 
				
			||||||
    data->point.y = touchpad_y[0];
 | 
					 | 
				
			||||||
    data->state = LV_INDEV_STATE_PR;
 | 
					 | 
				
			||||||
  } else {
 | 
					 | 
				
			||||||
    data->state = LV_INDEV_STATE_REL;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void val_i2c_master_init(void) {
 | 
					static void val_i2c_master_init(void) {
 | 
				
			||||||
  ESP_LOGI(TAG, "Init I2C");
 | 
					  ESP_LOGI(TAG, "Init I2C");
 | 
				
			||||||
@@ -131,165 +45,6 @@ static void val_i2c_master_init(void) {
 | 
				
			|||||||
  ESP_ERROR_CHECK(i2c_master_bus_add_device(i2c_bus_handle, &exio_dev_cfg, &exio_o_handle));
 | 
					  ESP_ERROR_CHECK(i2c_master_bus_add_device(i2c_bus_handle, &exio_dev_cfg, &exio_o_handle));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static esp_lcd_touch_handle_t val_setup_touch(void) {
 | 
					 | 
				
			||||||
  ESP_LOGI(TAG, "Install touch panel driver");
 | 
					 | 
				
			||||||
  esp_lcd_panel_io_i2c_config_t io_config = ESP_LCD_TOUCH_IO_I2C_GT911_CONFIG();
 | 
					 | 
				
			||||||
  io_config.scl_speed_hz = SCL_SPEED;
 | 
					 | 
				
			||||||
  esp_lcd_panel_io_handle_t io_handle = NULL;
 | 
					 | 
				
			||||||
  ESP_ERROR_CHECK(esp_lcd_new_panel_io_i2c(i2c_bus_handle, &io_config, &io_handle));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  esp_lcd_touch_io_gt911_config_t gt911_config = {
 | 
					 | 
				
			||||||
    .dev_addr = io_config.dev_addr,
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  esp_lcd_touch_config_t tp_cfg = {
 | 
					 | 
				
			||||||
    .x_max = LCD_HRES,
 | 
					 | 
				
			||||||
    .y_max = LCD_VRES,
 | 
					 | 
				
			||||||
    .rst_gpio_num = -1,
 | 
					 | 
				
			||||||
    .int_gpio_num = 4,
 | 
					 | 
				
			||||||
    .levels = {
 | 
					 | 
				
			||||||
      .reset = 0,
 | 
					 | 
				
			||||||
      .interrupt = 0,
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    .flags = {
 | 
					 | 
				
			||||||
      .swap_xy = 0,
 | 
					 | 
				
			||||||
      .mirror_x = 0,
 | 
					 | 
				
			||||||
      .mirror_y = 0,
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    .driver_data = >911_config,
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  esp_lcd_touch_handle_t tp;
 | 
					 | 
				
			||||||
  ESP_ERROR_CHECK(esp_lcd_touch_new_i2c_gt911(io_handle, &tp_cfg, &tp));
 | 
					 | 
				
			||||||
  return tp;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static esp_lcd_panel_handle_t val_setup_lcd(void) {
 | 
					 | 
				
			||||||
  uint8_t i2c_b;
 | 
					 | 
				
			||||||
  i2c_b = 0x01; // Output enable
 | 
					 | 
				
			||||||
  ESP_ERROR_CHECK(i2c_master_transmit(exio_cfg_handle, &i2c_b, 1, -1));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  i2c_b = 0x00; // Reset everything
 | 
					 | 
				
			||||||
  ESP_ERROR_CHECK(i2c_master_transmit(exio_o_handle, &i2c_b, 1, -1));
 | 
					 | 
				
			||||||
  vTaskDelay(pdMS_TO_TICKS(10));
 | 
					 | 
				
			||||||
  i2c_b = 0x0c; // Pull LCD + touch out of reset
 | 
					 | 
				
			||||||
  ESP_ERROR_CHECK(i2c_master_transmit(exio_o_handle, &i2c_b, 1, -1));
 | 
					 | 
				
			||||||
  vTaskDelay(pdMS_TO_TICKS(100));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  ESP_LOGI(TAG, "Install RGB LCD panel driver");
 | 
					 | 
				
			||||||
  esp_lcd_panel_handle_t panel_handle = NULL;
 | 
					 | 
				
			||||||
  esp_lcd_rgb_panel_config_t panel_config = {
 | 
					 | 
				
			||||||
    .data_width = 16, // RGB565
 | 
					 | 
				
			||||||
    .psram_trans_align = 64,
 | 
					 | 
				
			||||||
    .num_fbs = 2,
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    .clk_src = LCD_CLK_SRC_DEFAULT,
 | 
					 | 
				
			||||||
    .disp_gpio_num = -1, // Only accessible via GPIO expander
 | 
					 | 
				
			||||||
    .pclk_gpio_num = 7,
 | 
					 | 
				
			||||||
    .vsync_gpio_num = 3,
 | 
					 | 
				
			||||||
    .hsync_gpio_num = 46,
 | 
					 | 
				
			||||||
    .de_gpio_num = 5,
 | 
					 | 
				
			||||||
    .data_gpio_nums = {
 | 
					 | 
				
			||||||
      14, // B3
 | 
					 | 
				
			||||||
      38, // B4
 | 
					 | 
				
			||||||
      18, // B5
 | 
					 | 
				
			||||||
      17, // B6
 | 
					 | 
				
			||||||
      10, // B7
 | 
					 | 
				
			||||||
      39, // G2
 | 
					 | 
				
			||||||
       0, // G3
 | 
					 | 
				
			||||||
      45, // G4
 | 
					 | 
				
			||||||
      48, // G5
 | 
					 | 
				
			||||||
      47, // G6
 | 
					 | 
				
			||||||
      21, // G7
 | 
					 | 
				
			||||||
       1, // R3
 | 
					 | 
				
			||||||
       2, // R4
 | 
					 | 
				
			||||||
      42, // R5
 | 
					 | 
				
			||||||
      41, // R6
 | 
					 | 
				
			||||||
      40, // R7
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    .timings = {
 | 
					 | 
				
			||||||
      .pclk_hz = 18 * 1000 * 1000, // 18000000 / (hs+hbp+hfp+hres) / (vs+vbp+hfp+vres) = ~42Hz
 | 
					 | 
				
			||||||
      .h_res = LCD_HRES,
 | 
					 | 
				
			||||||
      .v_res = LCD_VRES,
 | 
					 | 
				
			||||||
      .hsync_back_porch = 8,
 | 
					 | 
				
			||||||
      .hsync_front_porch = 8,
 | 
					 | 
				
			||||||
      .hsync_pulse_width = 4,
 | 
					 | 
				
			||||||
      .vsync_back_porch = 16,
 | 
					 | 
				
			||||||
      .vsync_front_porch = 16,
 | 
					 | 
				
			||||||
      .vsync_pulse_width = 4,
 | 
					 | 
				
			||||||
      .flags = {
 | 
					 | 
				
			||||||
        .pclk_active_neg = true,
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    .flags.fb_in_psram = true, // allocate frame buffer in PSRAM
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
  ESP_ERROR_CHECK(esp_lcd_new_rgb_panel(&panel_config, &panel_handle));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  ESP_LOGI(TAG, "Initialize RGB LCD panel");
 | 
					 | 
				
			||||||
  ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_handle));
 | 
					 | 
				
			||||||
  ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  ESP_LOGI(TAG, "Turn on LCD backlight");
 | 
					 | 
				
			||||||
  i2c_b = 0x0e; // LCD + touch out of reset, backlight on
 | 
					 | 
				
			||||||
  ESP_ERROR_CHECK(i2c_master_transmit(exio_o_handle, &i2c_b, 1, -1));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return panel_handle;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void val_setup_lvgl(esp_lcd_panel_handle_t lcd_panel, esp_lcd_touch_handle_t touch_panel) {
 | 
					 | 
				
			||||||
  ESP_LOGI(TAG, "Initialize LVGL library");
 | 
					 | 
				
			||||||
  lv_init();
 | 
					 | 
				
			||||||
  // create a lvgl display
 | 
					 | 
				
			||||||
  lv_display_t *display = lv_display_create(LCD_HRES, LCD_VRES);
 | 
					 | 
				
			||||||
  // associate the rgb panel handle to the display
 | 
					 | 
				
			||||||
  lv_display_set_user_data(display, lcd_panel);
 | 
					 | 
				
			||||||
  // set color depth
 | 
					 | 
				
			||||||
  lv_display_set_color_format(display, LV_COLOR_FORMAT_RGB565);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // create draw buffers
 | 
					 | 
				
			||||||
  void *buf1 = NULL;
 | 
					 | 
				
			||||||
  void *buf2 = NULL;
 | 
					 | 
				
			||||||
  ESP_LOGI(TAG, "Use frame buffers as LVGL draw buffers");
 | 
					 | 
				
			||||||
  ESP_ERROR_CHECK(esp_lcd_rgb_panel_get_frame_buffer(lcd_panel, 2, &buf1, &buf2));
 | 
					 | 
				
			||||||
  // set LVGL draw buffers and direct mode
 | 
					 | 
				
			||||||
  lv_display_set_buffers(display, buf1, buf2, LCD_HRES * LCD_VRES * LCD_PIXEL_SIZE, LV_DISPLAY_RENDER_MODE_DIRECT);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // set the callback which can copy the rendered image to an area of the display
 | 
					 | 
				
			||||||
  lv_display_set_flush_cb(display, val_lvgl_flush_cb);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  ESP_LOGI(TAG, "Register event callbacks");
 | 
					 | 
				
			||||||
  esp_lcd_rgb_panel_event_callbacks_t cbs = {
 | 
					 | 
				
			||||||
    .on_vsync = val_on_vsync,
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
  ESP_ERROR_CHECK(esp_lcd_rgb_panel_register_event_callbacks(lcd_panel, &cbs, display));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  lv_indev_t *indev = lv_indev_create();
 | 
					 | 
				
			||||||
  lv_indev_set_user_data(indev, touch_panel);
 | 
					 | 
				
			||||||
  lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER);
 | 
					 | 
				
			||||||
  lv_indev_set_read_cb(indev, val_lvgl_touch_read);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  ESP_LOGI(TAG, "Install LVGL tick timer");
 | 
					 | 
				
			||||||
  // Tick interface for LVGL (using esp_timer to generate 2ms periodic event)
 | 
					 | 
				
			||||||
  const esp_timer_create_args_t lvgl_tick_timer_args = {
 | 
					 | 
				
			||||||
    .callback = &val_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, LVGL_TICK_PERIOD * 1000));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  lvgl_mtx = xSemaphoreCreateRecursiveMutex();
 | 
					 | 
				
			||||||
  assert(lvgl_mtx);
 | 
					 | 
				
			||||||
  ESP_LOGI(TAG, "Create LVGL task");
 | 
					 | 
				
			||||||
  xTaskCreate(val_lvgl_port_task, "LVGL", LVGL_TASK_STACK_SIZE, NULL, LVGL_TASK_PRIORITY, NULL);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  ESP_LOGI(TAG, "Display LVGL UI");
 | 
					 | 
				
			||||||
  // Lock the mutex due to the LVGL APIs are not thread-safe
 | 
					 | 
				
			||||||
  assert(val_lvgl_lock(-1));
 | 
					 | 
				
			||||||
  val_lvgl_ui(display);
 | 
					 | 
				
			||||||
  val_lvgl_unlock();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void app_main(void) {
 | 
					void app_main(void) {
 | 
				
			||||||
  val_i2c_master_init();
 | 
					  val_i2c_master_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -300,5 +55,12 @@ void app_main(void) {
 | 
				
			|||||||
  esp_lcd_touch_handle_t touch_panel = val_setup_touch();
 | 
					  esp_lcd_touch_handle_t touch_panel = val_setup_touch();
 | 
				
			||||||
  assert(touch_panel);
 | 
					  assert(touch_panel);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  val_setup_lvgl(lcd_panel, touch_panel);
 | 
					  lv_display_t *display = val_setup_lvgl(lcd_panel, touch_panel);
 | 
				
			||||||
 | 
					  assert(display);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ESP_LOGI(TAG, "Display LVGL UI");
 | 
				
			||||||
 | 
					  // Lock the mutex due to the LVGL APIs are not thread-safe
 | 
				
			||||||
 | 
					  assert(val_lvgl_lock(-1));
 | 
				
			||||||
 | 
					  val_lvgl_ui(display);
 | 
				
			||||||
 | 
					  val_lvgl_unlock();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user