Compare commits
	
		
			2 Commits
		
	
	
		
			4ac2bbba62
			...
			1d5853e91c
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 1d5853e91c | |||
| df62eb0fe6 | 
							
								
								
									
										2
									
								
								firmware/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								firmware/.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1,3 +1,5 @@ | ||||
| /build/ | ||||
| /managed_components/ | ||||
| sdkconfig | ||||
| sdkconfig.old | ||||
| *.swp | ||||
|   | ||||
							
								
								
									
										18
									
								
								firmware/dependencies.lock
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								firmware/dependencies.lock
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| dependencies: | ||||
|   idf: | ||||
|     source: | ||||
|       type: idf | ||||
|     version: 5.3.1 | ||||
|   lvgl/lvgl: | ||||
|     component_hash: 096c69af22eaf8a2b721e3913da91918c5e6bf1a762a113ec01f401aa61337a0 | ||||
|     dependencies: [] | ||||
|     source: | ||||
|       registry_url: https://components.espressif.com/ | ||||
|       type: service | ||||
|     version: 9.2.2 | ||||
| direct_dependencies: | ||||
| - idf | ||||
| - lvgl/lvgl | ||||
| manifest_hash: 5572feed6f42d829a5cb8a4d05d14bdccf26a3eea1ab283866a22e031aea011b | ||||
| target: esp32s3 | ||||
| version: 2.0.0 | ||||
| @@ -1,2 +1,3 @@ | ||||
| idf_component_register(SRCS "valconomy.c" | ||||
|                     INCLUDE_DIRS ".") | ||||
| idf_component_register( | ||||
|   SRCS "valconomy.c" "lvgl_demo_ui.c" | ||||
|   INCLUDE_DIRS ".") | ||||
|   | ||||
							
								
								
									
										17
									
								
								firmware/main/idf_component.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								firmware/main/idf_component.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | ||||
| ## IDF Component Manager Manifest File | ||||
| dependencies: | ||||
|   lvgl/lvgl: "^9.2.2" | ||||
|   ## Required IDF version | ||||
|   idf: | ||||
|     version: ">=4.1.0" | ||||
|   # # Put list of dependencies here | ||||
|   # # For components maintained by Espressif: | ||||
|   # component: "~1.0.0" | ||||
|   # # For 3rd party components: | ||||
|   # username/component: ">=1.0.0,<2.0.0" | ||||
|   # username2/component2: | ||||
|   #   version: "~1.0.0" | ||||
|   #   # For transient dependencies `public` flag can be set. | ||||
|   #   # `public` flag doesn't have an effect dependencies of the `main` component. | ||||
|   #   # All dependencies of `main` are public by default. | ||||
|   #   public: true | ||||
							
								
								
									
										152
									
								
								firmware/main/lvgl_demo_ui.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										152
									
								
								firmware/main/lvgl_demo_ui.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,152 @@ | ||||
| #include "lvgl.h" | ||||
|  | ||||
| static lv_style_t style_bullet; | ||||
| static lv_obj_t *scale1; | ||||
| static const lv_font_t *font_normal = &lv_font_montserrat_14; | ||||
|  | ||||
| static lv_obj_t *create_scale_box(lv_obj_t *parent, const char *text1, const char *text2, const char *text3) | ||||
| { | ||||
|     lv_obj_t *scale = lv_scale_create(parent); | ||||
|     lv_obj_center(scale); | ||||
|     lv_obj_set_size(scale, 300, 300); | ||||
|     lv_scale_set_mode(scale, LV_SCALE_MODE_ROUND_OUTER); | ||||
|     lv_scale_set_label_show(scale, false); | ||||
|     lv_scale_set_post_draw(scale, true); | ||||
|     lv_obj_set_width(scale, LV_PCT(100)); | ||||
|     lv_obj_set_style_pad_all(scale, 30, 0); | ||||
|  | ||||
|     lv_obj_t *bullet1 = lv_obj_create(parent); | ||||
|     lv_obj_set_size(bullet1, 13, 13); | ||||
|     lv_obj_remove_style(bullet1, NULL, LV_PART_SCROLLBAR); | ||||
|     lv_obj_add_style(bullet1, &style_bullet, 0); | ||||
|     lv_obj_set_style_bg_color(bullet1, lv_palette_main(LV_PALETTE_RED), 0); | ||||
|     lv_obj_t *label1 = lv_label_create(parent); | ||||
|     lv_label_set_text(label1, text1); | ||||
|  | ||||
|     lv_obj_t *bullet2 = lv_obj_create(parent); | ||||
|     lv_obj_set_size(bullet2, 13, 13); | ||||
|     lv_obj_remove_style(bullet2, NULL, LV_PART_SCROLLBAR); | ||||
|     lv_obj_add_style(bullet2, &style_bullet, 0); | ||||
|     lv_obj_set_style_bg_color(bullet2, lv_palette_main(LV_PALETTE_BLUE), 0); | ||||
|     lv_obj_t *label2 = lv_label_create(parent); | ||||
|     lv_label_set_text(label2, text2); | ||||
|  | ||||
|     lv_obj_t *bullet3 = lv_obj_create(parent); | ||||
|     lv_obj_set_size(bullet3, 13, 13); | ||||
|     lv_obj_remove_style(bullet3,  NULL, LV_PART_SCROLLBAR); | ||||
|     lv_obj_add_style(bullet3, &style_bullet, 0); | ||||
|     lv_obj_set_style_bg_color(bullet3, lv_palette_main(LV_PALETTE_GREEN), 0); | ||||
|     lv_obj_t *label3 = lv_label_create(parent); | ||||
|     lv_label_set_text(label3, text3); | ||||
|  | ||||
|     static int32_t grid_col_dsc[] = {LV_GRID_CONTENT, LV_GRID_FR(1), LV_GRID_TEMPLATE_LAST}; | ||||
|     static int32_t grid_row_dsc[] = {LV_GRID_CONTENT, LV_GRID_CONTENT, LV_GRID_CONTENT, LV_GRID_CONTENT, LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST}; | ||||
|     lv_obj_set_grid_dsc_array(parent, grid_col_dsc, grid_row_dsc); | ||||
|     lv_obj_set_grid_cell(scale, LV_GRID_ALIGN_START, 0, 2, LV_GRID_ALIGN_START, 1, 1); | ||||
|     lv_obj_set_grid_cell(bullet1, LV_GRID_ALIGN_START, 0, 1, LV_GRID_ALIGN_START, 2, 1); | ||||
|     lv_obj_set_grid_cell(bullet2, LV_GRID_ALIGN_START, 0, 1, LV_GRID_ALIGN_START, 3, 1); | ||||
|     lv_obj_set_grid_cell(bullet3, LV_GRID_ALIGN_START, 0, 1, LV_GRID_ALIGN_START, 4, 1); | ||||
|     lv_obj_set_grid_cell(label1, LV_GRID_ALIGN_STRETCH, 1, 1, LV_GRID_ALIGN_START, 2, 1); | ||||
|     lv_obj_set_grid_cell(label2, LV_GRID_ALIGN_STRETCH, 1, 1, LV_GRID_ALIGN_START, 3, 1); | ||||
|     lv_obj_set_grid_cell(label3, LV_GRID_ALIGN_STRETCH, 1, 1, LV_GRID_ALIGN_START, 4, 1); | ||||
|     return scale; | ||||
| } | ||||
|  | ||||
| static void scale1_indic1_anim_cb(void *var, int32_t v) | ||||
| { | ||||
|     lv_arc_set_value(var, v); | ||||
|  | ||||
|     lv_obj_t *card = lv_obj_get_parent(scale1); | ||||
|     lv_obj_t *label = lv_obj_get_child(card, -5); | ||||
|     lv_label_set_text_fmt(label, "Revenue: %"LV_PRId32" %%", v); | ||||
| } | ||||
|  | ||||
| static void scale1_indic2_anim_cb(void *var, int32_t v) | ||||
| { | ||||
|     lv_arc_set_value(var, v); | ||||
|  | ||||
|     lv_obj_t *card = lv_obj_get_parent(scale1); | ||||
|     lv_obj_t *label = lv_obj_get_child(card, -3); | ||||
|     lv_label_set_text_fmt(label, "Sales: %"LV_PRId32" %%", v); | ||||
| } | ||||
|  | ||||
| static void scale1_indic3_anim_cb(void *var, int32_t v) | ||||
| { | ||||
|     lv_arc_set_value(var, v); | ||||
|  | ||||
|     lv_obj_t *card = lv_obj_get_parent(scale1); | ||||
|     lv_obj_t *label = lv_obj_get_child(card, -1); | ||||
|     lv_label_set_text_fmt(label, "Costs: %"LV_PRId32" %%", v); | ||||
| } | ||||
|  | ||||
| void example_lvgl_demo_ui(lv_display_t *disp) | ||||
| { | ||||
|     // init default theme | ||||
|     lv_theme_default_init(disp, lv_palette_main(LV_PALETTE_BLUE), lv_palette_main(LV_PALETTE_RED), LV_THEME_DEFAULT_DARK, | ||||
|                           font_normal); | ||||
|     // lv_sysmon_hide_performance(disp); | ||||
|  | ||||
|     // bullet style | ||||
|     lv_style_init(&style_bullet); | ||||
|     lv_style_set_border_width(&style_bullet, 0); | ||||
|     lv_style_set_radius(&style_bullet, LV_RADIUS_CIRCLE); | ||||
|  | ||||
|     lv_obj_t *parent = lv_display_get_screen_active(disp); | ||||
|  | ||||
|     // create scale widget | ||||
|     scale1 = create_scale_box(parent, "Revenue", "Sales", "Costs"); | ||||
|  | ||||
|     // create arc indicators | ||||
|     lv_obj_t *arc; | ||||
|     arc = lv_arc_create(scale1); | ||||
|     lv_obj_remove_style(arc, NULL, LV_PART_KNOB); | ||||
|     lv_obj_remove_style(arc, NULL, LV_PART_MAIN); | ||||
|     lv_obj_set_size(arc, lv_pct(100), lv_pct(100)); | ||||
|     lv_obj_set_style_arc_opa(arc, 0, 0); | ||||
|     lv_obj_set_style_arc_width(arc, 15, LV_PART_INDICATOR); | ||||
|     lv_obj_set_style_arc_color(arc, lv_palette_main(LV_PALETTE_BLUE), LV_PART_INDICATOR); | ||||
|     lv_obj_remove_flag(arc, LV_OBJ_FLAG_CLICKABLE); | ||||
|  | ||||
|     // animation | ||||
|     lv_anim_t a; | ||||
|     lv_anim_init(&a); | ||||
|     lv_anim_set_values(&a, 20, 100); | ||||
|     lv_anim_set_repeat_count(&a, LV_ANIM_REPEAT_INFINITE); | ||||
|     lv_anim_set_exec_cb(&a, scale1_indic1_anim_cb); | ||||
|     lv_anim_set_var(&a, arc); | ||||
|     lv_anim_set_duration(&a, 4100); | ||||
|     lv_anim_set_playback_duration(&a, 2700); | ||||
|     lv_anim_start(&a); | ||||
|  | ||||
|     arc = lv_arc_create(scale1); | ||||
|     lv_obj_remove_style(arc, NULL, LV_PART_KNOB); | ||||
|     lv_obj_set_size(arc, lv_pct(100), lv_pct(100)); | ||||
|     lv_obj_set_style_margin_all(arc, 20, 0); | ||||
|     lv_obj_set_style_arc_opa(arc, 0, 0); | ||||
|     lv_obj_set_style_arc_width(arc, 15, LV_PART_INDICATOR); | ||||
|     lv_obj_set_style_arc_color(arc, lv_palette_main(LV_PALETTE_RED), LV_PART_INDICATOR); | ||||
|     lv_obj_remove_flag(arc, LV_OBJ_FLAG_CLICKABLE); | ||||
|     lv_obj_center(arc); | ||||
|  | ||||
|     lv_anim_set_exec_cb(&a, scale1_indic2_anim_cb); | ||||
|     lv_anim_set_var(&a, arc); | ||||
|     lv_anim_set_duration(&a, 2600); | ||||
|     lv_anim_set_playback_duration(&a, 3200); | ||||
|     lv_anim_start(&a); | ||||
|  | ||||
|     arc = lv_arc_create(scale1); | ||||
|     lv_obj_remove_style(arc, NULL, LV_PART_KNOB); | ||||
|     lv_obj_set_size(arc, lv_pct(100), lv_pct(100)); | ||||
|     lv_obj_set_style_margin_all(arc, 40, 0); | ||||
|     lv_obj_set_style_arc_opa(arc, 0, 0); | ||||
|     lv_obj_set_style_arc_width(arc, 15, LV_PART_INDICATOR); | ||||
|     lv_obj_set_style_arc_color(arc, lv_palette_main(LV_PALETTE_GREEN), LV_PART_INDICATOR); | ||||
|     lv_obj_remove_flag(arc, LV_OBJ_FLAG_CLICKABLE); | ||||
|     lv_obj_center(arc); | ||||
|  | ||||
|     lv_anim_set_exec_cb(&a, scale1_indic3_anim_cb); | ||||
|     lv_anim_set_var(&a, arc); | ||||
|     lv_anim_set_duration(&a, 2800); | ||||
|     lv_anim_set_playback_duration(&a, 1800); | ||||
|     lv_anim_start(&a); | ||||
| } | ||||
| @@ -1,46 +1,237 @@ | ||||
| #include <stdio.h> | ||||
| #include <inttypes.h> | ||||
| #include <stdio.h> | ||||
|  | ||||
| #include "sdkconfig.h" | ||||
| #include "freertos/FreeRTOS.h" | ||||
| #include "freertos/task.h" | ||||
| #include "esp_chip_info.h" | ||||
| #include "esp_flash.h" | ||||
| #include "esp_system.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 "lvgl.h" | ||||
|  | ||||
| #define LCD_HRES        800 | ||||
| #define LCD_VRES        480 | ||||
| #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 i2c_master_bus_handle_t i2c_bus_handle; | ||||
| static 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 example_lvgl_demo_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_i2c_master_init(void) { | ||||
|   ESP_LOGI(TAG, "Init I2C"); | ||||
|   i2c_master_bus_config_t i2c_mst_config = { | ||||
|     .clk_source = I2C_CLK_SRC_DEFAULT, | ||||
|     .i2c_port = I2C_NUM_0, | ||||
|     .scl_io_num = 9, | ||||
|     .sda_io_num = 8, | ||||
|     .glitch_ignore_cnt = 7, | ||||
|     .flags.enable_internal_pullup = true, | ||||
|   }; | ||||
|  | ||||
|   ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_mst_config, &i2c_bus_handle)); | ||||
|  | ||||
|   i2c_device_config_t exio_dev_cfg = { | ||||
|     .dev_addr_length = I2C_ADDR_BIT_LEN_7, | ||||
|     .device_address = 0x24, // CH422G config register | ||||
|     .scl_speed_hz = 100000, | ||||
|   }; | ||||
|  | ||||
|   ESP_ERROR_CHECK(i2c_master_bus_add_device(i2c_bus_handle, &exio_dev_cfg, &exio_cfg_handle)); | ||||
|   exio_dev_cfg.device_address = 0x38; | ||||
|   ESP_ERROR_CHECK(i2c_master_bus_add_device(i2c_bus_handle, &exio_dev_cfg, &exio_o_handle)); | ||||
| } | ||||
|  | ||||
| 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 = 0x08; // Pull LCD 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 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_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)); | ||||
|  | ||||
|   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)); | ||||
|   example_lvgl_demo_ui(display); | ||||
|   val_lvgl_unlock(); | ||||
| } | ||||
|  | ||||
| void app_main(void) { | ||||
|   printf("Hello world!\n"); | ||||
|   val_i2c_master_init(); | ||||
|  | ||||
|   /* Print chip information */ | ||||
|   esp_chip_info_t chip_info; | ||||
|   uint32_t flash_size; | ||||
|   esp_chip_info(&chip_info); | ||||
|   printf("This is %s chip with %d CPU core(s), %s%s%s%s, ", | ||||
|          CONFIG_IDF_TARGET, | ||||
|          chip_info.cores, | ||||
|          (chip_info.features & CHIP_FEATURE_WIFI_BGN) ? "WiFi/" : "", | ||||
|          (chip_info.features & CHIP_FEATURE_BT) ? "BT" : "", | ||||
|          (chip_info.features & CHIP_FEATURE_BLE) ? "BLE" : "", | ||||
|          (chip_info.features & CHIP_FEATURE_IEEE802154) ? ", 802.15.4 (Zigbee/Thread)" : ""); | ||||
|   esp_lcd_panel_handle_t lcd_panel = val_setup_lcd(); | ||||
|   assert(lcd_panel); | ||||
|  | ||||
|   unsigned major_rev = chip_info.revision / 100; | ||||
|   unsigned minor_rev = chip_info.revision % 100; | ||||
|   printf("silicon revision v%d.%d, ", major_rev, minor_rev); | ||||
|   if(esp_flash_get_size(NULL, &flash_size) != ESP_OK) { | ||||
|     printf("Get flash size failed"); | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   printf("%" PRIu32 "MB %s flash\n", flash_size / (uint32_t)(1024 * 1024), | ||||
|          (chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded" : "external"); | ||||
|  | ||||
|   printf("Minimum free heap size: %" PRIu32 " bytes\n", esp_get_minimum_free_heap_size()); | ||||
|  | ||||
|   for (int i = 10; i >= 0; i--) { | ||||
|     printf("Restarting in %d seconds...\n", i); | ||||
|     vTaskDelay(1000 / portTICK_PERIOD_MS); | ||||
|   } | ||||
|   printf("Restarting now.\n"); | ||||
|   fflush(stdout); | ||||
|   esp_restart(); | ||||
|   val_setup_lvgl(lcd_panel); | ||||
| } | ||||
|   | ||||
| @@ -1,4 +1,21 @@ | ||||
| # This file was generated using idf.py save-defconfig. It can be edited manually. | ||||
| # Espressif IoT Development Framework (ESP-IDF) 5.3.1 Project Minimal Configuration | ||||
| # | ||||
| CONFIG_IDF_TARGET="esp32s3" | ||||
| CONFIG_ESPTOOLPY_FLASH_MODE_AUTO_DETECT=n | ||||
| CONFIG_ESPTOOLPY_FLASHMODE_QIO=y | ||||
| CONFIG_ESPTOOLPY_FLASHFREQ_120M=y | ||||
| CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y | ||||
| CONFIG_SPIRAM=y | ||||
| CONFIG_SPIRAM_MODE_OCT=y | ||||
| CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y | ||||
| CONFIG_SPIRAM_RODATA=y | ||||
| CONFIG_SPIRAM_SPEED_120M=y | ||||
| CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y | ||||
| CONFIG_ESP32S3_DATA_CACHE_LINE_64B=y | ||||
| CONFIG_ESP_WIFI_DPP_SUPPORT=y | ||||
| CONFIG_FREERTOS_HZ=1000 | ||||
| CONFIG_LV_DEF_REFR_PERIOD=24 | ||||
| CONFIG_LV_USE_SYSMON=y | ||||
| CONFIG_LV_USE_PERF_MONITOR=y | ||||
| CONFIG_IDF_EXPERIMENTAL_FEATURES=y | ||||
|   | ||||
		Reference in New Issue
	
	Block a user