From 7d465641a34d6540acece730f6f599b8e7d268bc Mon Sep 17 00:00:00 2001 From: Lorenzo Gasparini Date: Tue, 23 Sep 2025 00:37:55 +0200 Subject: [PATCH] Add support for 8048s070 --- .github/actions/build-esp/action.yaml | 10 +- .github/workflows/ci.yaml | 23 +- .vscode/c_cpp_properties.sample.json | 38 +++- CLAUDE.md | 17 +- CMakeLists.txt | 6 +- README.md | 2 +- dependencies.lock => dependencies.lock.esp32 | 6 +- dependencies.lock.esp32s3 | 76 +++++++ esp/CMakeLists.txt | 11 +- esp/idf_component.yml | 17 +- esp/{lcd.cpp => lcd_3248s035c.cpp} | 2 +- esp/lcd_3248s035c.hpp | 3 + esp/lcd_8048s070c.cpp | 219 +++++++++++++++++++ esp/lcd_8048s070c.hpp | 3 + esp/{lcd.hpp => lcd_common.hpp} | 2 + esp/main.cpp | 2 +- package.json | 3 +- partitions.csv => partitions_esp32.csv | 0 partitions_esp32s3.csv | 7 + platformio.ini | 14 +- scripts/merge_firmware.sh | 57 ++++- sdkconfig.defaults | 2 - sdkconfig.defaults.esp32 | 3 + sdkconfig.defaults.esp32s3 | 8 + simulator/include/lvgl_sdl.h | 4 +- 25 files changed, 488 insertions(+), 47 deletions(-) rename dependencies.lock => dependencies.lock.esp32 (93%) create mode 100644 dependencies.lock.esp32s3 rename esp/{lcd.cpp => lcd_3248s035c.cpp} (99%) create mode 100644 esp/lcd_3248s035c.hpp create mode 100644 esp/lcd_8048s070c.cpp create mode 100644 esp/lcd_8048s070c.hpp rename esp/{lcd.hpp => lcd_common.hpp} (82%) rename partitions.csv => partitions_esp32.csv (100%) create mode 100644 partitions_esp32s3.csv create mode 100644 sdkconfig.defaults.esp32 create mode 100644 sdkconfig.defaults.esp32s3 diff --git a/.github/actions/build-esp/action.yaml b/.github/actions/build-esp/action.yaml index 58fec6a..48b5a6b 100644 --- a/.github/actions/build-esp/action.yaml +++ b/.github/actions/build-esp/action.yaml @@ -6,6 +6,10 @@ inputs: description: 'ESP-IDF version to use' required: false default: 'v5.5.1' + idf_target: + description: 'ESP-IDF target to use (esp32, esp32s3)' + required: false + default: 'esp32' runs: using: 'composite' @@ -30,13 +34,13 @@ runs: uses: actions/cache@v4 with: path: .ccache - key: ccache-${{ runner.os }}-esp32-${{ inputs.idf_version }}-${{ hashFiles('**/CMakeLists.txt', 'sdkconfig.defaults', 'dependencies.lock') }} + key: ccache-${{ runner.os }}-${{ inputs.idf_target }}-${{ inputs.idf_version }}-${{ hashFiles('**/CMakeLists.txt', 'sdkconfig.defaults', format('sdkconfig.defaults.{0}', inputs.idf_target), format('dependencies.lock.{0}', inputs.idf_target)) }} - name: Cache managed components uses: actions/cache@v4 with: path: managed_components - key: managed_components-${{ runner.os }}-${{ hashFiles('dependencies.lock') }} + key: managed_components-${{ runner.os }}-${{ inputs.idf_target }}-${{ hashFiles(format('dependencies.lock.{0}', inputs.idf_target)) }} - name: esp-idf build and merge firmware shell: bash @@ -45,7 +49,7 @@ runs: IMAGE="espressif/idf:${{ inputs.idf_version }}" docker run --rm -t \ - -e IDF_TARGET="esp32" \ + -e IDF_TARGET="${{ inputs.idf_target }}" \ -e IDF_CCACHE_ENABLE=1 \ -e CCACHE_DIR="/app/${{ github.repository }}/.ccache" \ -e GITHUB_ACTIONS=true \ diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 6cea775..698c222 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -112,21 +112,26 @@ jobs: build_esp: name: Build and archive ESP firmware runs-on: ubuntu-latest + strategy: + matrix: + idf_target: [esp32, esp32s3] steps: - name: Checkout uses: actions/checkout@v5 - name: Build ESP binaries uses: ./.github/actions/build-esp + with: + idf_target: ${{ matrix.idf_target }} - name: Archive build output artifacts uses: actions/upload-artifact@v4 with: - name: merged-firmware + name: merged-firmware-${{ matrix.idf_target }} path: build/merged-firmware.bin compression-level: 0 build_simulator: - name: Build and archive simulator binary + name: Build and archive simulator binaries timeout-minutes: 10 runs-on: ubuntu-latest container: joined/sdl2:latest @@ -138,7 +143,7 @@ jobs: path: | ~/.cache/pip ~/.platformio/.cache - key: ${{ runner.os }}-pio-v2 + key: pio-${{ runner.os }}-${{ hashFiles('platformio.ini') }} - uses: actions/setup-python@v6 with: python-version: '3.12' @@ -147,9 +152,15 @@ jobs: - name: Build PlatformIO Project run: | pio run - - name: Archive build output artifacts + - name: Archive 480x320 simulator build + uses: actions/upload-artifact@v4 + with: + name: simulator_480x320 + path: .pio/build/3248s035c/program + compression-level: 0 + - name: Archive 800x480 simulator build uses: actions/upload-artifact@v4 with: - name: simulator - path: .pio/build/emulator/program + name: simulator_800x480 + path: .pio/build/8048s070c/program compression-level: 0 diff --git a/.vscode/c_cpp_properties.sample.json b/.vscode/c_cpp_properties.sample.json index 2b75257..6ea7f77 100644 --- a/.vscode/c_cpp_properties.sample.json +++ b/.vscode/c_cpp_properties.sample.json @@ -25,14 +25,48 @@ } }, { - "name": "Simulator", + "name": "Simulator 3248s035c", "cStandard": "c23", "cppStandard": "c++23", "defines": [ "PLATFORMIO=60118", "USE_SDL", "LV_CONF_INCLUDE_SIMPLE", - "LV_LVGL_H_INCLUDE_SIMPLE" + "LV_LVGL_H_INCLUDE_SIMPLE", + "SDL_HOR_RES=480", + "SDL_VER_RES=320" + ], + "compilerPath": "/usr/bin/gcc", + "includePath": [ + "${workspaceFolder}/esp/ui", + "${workspaceFolder}/simulator/src", + "${workspaceFolder}/simulator/include", + "${workspaceFolder}/.pio/libdeps/emulator/lv_drivers", + "${workspaceFolder}/.pio/libdeps/emulator/lvgl", + "${workspaceFolder}/.pio/libdeps/emulator/lvgl/src" + ], + "browse": { + "limitSymbolsToIncludedHeaders": true, + "path": [ + "${workspaceFolder}/esp/ui", + "${workspaceFolder}/simulator/src", + "${workspaceFolder}/simulator/include", + "${workspaceFolder}/.pio/libdeps/emulator/lvgl", + "${workspaceFolder}/.pio/libdeps/emulator/lvgl/src" + ] + } + }, + { + "name": "Simulator 8048s070c", + "cStandard": "c23", + "cppStandard": "c++23", + "defines": [ + "PLATFORMIO=60118", + "USE_SDL", + "LV_CONF_INCLUDE_SIMPLE", + "LV_LVGL_H_INCLUDE_SIMPLE", + "SDL_HOR_RES=800", + "SDL_VER_RES=480" ], "compilerPath": "/usr/bin/gcc", "includePath": [ diff --git a/CLAUDE.md b/CLAUDE.md index 89c4434..eeeb3df 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -4,7 +4,8 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co ## Project Overview -SunTransit is an ESP32-based IoT project that displays Berlin public transport (BVG) departure information on Sunton 3.5" LCD displays. The project consists of three main components: +SunTransit is an ESP32-based IoT project that displays Berlin public transport (BVG) departure information on Sunton LCD displays. +The project consists of three main components: 1. **ESP32 Firmware** - ESP-IDF based C++ application 2. **React Frontend** - Web interface for configuration @@ -27,12 +28,12 @@ SunTransit is an ESP32-based IoT project that displays Berlin public transport ( - `idf.py monitor` - Open serial monitor - `idf.py flash monitor` - Flash and immediately start monitoring - `idf.py menuconfig` - Configure project settings -- `pip install -r requirements.txt` - Install Python dependencies ### Simulator Development - Install libsdl2 dependency: `sudo apt-get install libsdl2-dev` - `pio run` - Build simulator (runs from project root, includes UI from `esp/ui/` directly) -- `pio run -t upload` - Build and run simulator +- `pio run -t upload -e 3248s035c` - Build and run simulator for 480x320px screen +- `pio run -t upload -e 8048s070c` - Build and run simulator for 800x480px screen ### Code Quality - `clang-format -i esp/**/*.{c,cpp,h,hpp}` - Format C++ code @@ -51,23 +52,19 @@ SunTransit is an ESP32-based IoT project that displays Berlin public transport ( - **Time Management** (`time.*`) - SNTP synchronization and timezone handling ### Frontend Structure (`frontend/` directory) -- React 18 SPA with Material-UI components +- React 19 SPA with Material-UI components - Uses SWR for API state management - TypeScript throughout -- Parcel v2.11.0 for bundling +- Parcel for bundling - Automatically gzipped during build for ESP32 embedding ### Development Workflow Notes - The frontend is built first and embedded into ESP32 firmware -- VSCode C++ extension conflicts require simulator to be separate workspace - Copy `.vscode/c_cpp_properties.sample.json` to `.vscode/c_cpp_properties.json` for ESP-IDF development - Pre-commit hooks enforce formatting and linting ### Hardware Target -- Sunton 3248S035C boards (ESP32 + 3.5" LCD) -- 480x320px ST7796 display controller -- GT911 touch controller -- 4MB flash with custom partition table +Sunton 3248S035C (ESP32 + 3.5" LCD 480x320px) and 8048S070C (ESP32-S3 + 7.0" LCD 800x480px) ### Memory and Performance Considerations - LVGL configuration optimized for ESP32 memory constraints diff --git a/CMakeLists.txt b/CMakeLists.txt index 4c4dcc7..aa7cb34 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,9 +12,6 @@ set(EXTRA_COMPONENT_DIRS esp) # For the LCD/Touch initializers in `lcd.h` idf_build_set_property(COMPILE_OPTIONS "-Wno-missing-field-initializers" APPEND) -# TODO Fix deprecated enum conversion warning -# Seems like it's fixed on `master`, but not in the latest release (v8.3) - # TODO The following should be handled via menuconfig, but they're missing in the KConfig # TODO These cause warnings like: # `warning: ignoring attribute 'section (".iram1.4")' because it conflicts with previous 'section (".iram1.1")' [-Wattributes]` @@ -25,4 +22,7 @@ idf_build_set_property(COMPILE_OPTIONS "-DLV_ATTRIBUTE_TICK_INC=IRAM_ATTR" APPEN # For the fonts idf_build_set_property(COMPILE_OPTIONS "-DLV_LVGL_H_INCLUDE_SIMPLE" APPEND) +# Target-specific lockfile +idf_build_set_property(DEPENDENCIES_LOCK "dependencies.lock.${IDF_TARGET}") + project(suntransit) diff --git a/README.md b/README.md index 57462e1..2eaca38 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ An [ESP32](https://www.espressif.com/en/products/socs/esp32) project to monitor ## Features -- Based on Sunton [3248S035C](https://www.openhasp.com/0.7.0/hardware/sunton/esp32-3248s035/) boards (3.5", 480x320px). In the future, support for other boards is planned. +- Supports Sunton [3248S035C](https://www.openhasp.com/0.7.0/hardware/sunton/esp32-3248s035/) (3.5", 480x320px) and [8048S070C](https://www.openhasp.com/0.7.0/hardware/sunton/esp32-8048s0xx/) (7.0", 800x480px). - WiFi 🛜 provisioning via the "ESP SoftAP Provisioning" app 📱 - Web based configuration - Selection of station to show departures from (BVG) diff --git a/dependencies.lock b/dependencies.lock.esp32 similarity index 93% rename from dependencies.lock rename to dependencies.lock.esp32 index 8c0006c..09378ef 100644 --- a/dependencies.lock +++ b/dependencies.lock.esp32 @@ -60,7 +60,7 @@ dependencies: type: service version: 1.1.3 espressif/esp_lvgl_port: - component_hash: e720c95cf0667554a204591bb5fade4655fb2990465557041200fa44b5bc7556 + component_hash: a3db8fedba9f474dac24f1e0cd5bc5e560224e51bb5fa30bb2aa5470d49048db dependencies: - name: idf require: private @@ -72,7 +72,7 @@ dependencies: source: registry_url: https://components.espressif.com/ type: service - version: 2.6.0 + version: 2.6.1 espressif/mdns: component_hash: 3ec0af5f6bce310512e90f482388d21cc7c0e99668172d2f895356165fc6f7c5 dependencies: @@ -101,6 +101,6 @@ direct_dependencies: - espressif/esp_lvgl_port - espressif/mdns - idf -manifest_hash: 82a45dec557a424f3c86f9c60f44fb777ddfb5fc973db799d2d6b8f5d19baac8 +manifest_hash: c7e0a3e71168efcfe4914077ad130cf2087cff65f10aee88a2b5081658952861 target: esp32 version: 2.0.0 diff --git a/dependencies.lock.esp32s3 b/dependencies.lock.esp32s3 new file mode 100644 index 0000000..a4aa9ac --- /dev/null +++ b/dependencies.lock.esp32s3 @@ -0,0 +1,76 @@ +dependencies: + bblanchon/arduinojson: + component_hash: b1c2f0b0bc26969af19809cee80b220fb882481d59cc75f8e79ebceecdc69f06 + dependencies: [] + source: + registry_url: https://components.espressif.com/ + type: service + version: 7.4.2 + espressif/esp_lcd_touch: + component_hash: 779b4ba2464a3ae85681e4b860caa5fdc35801458c23f3039ee761bae7f442a4 + dependencies: + - name: idf + require: private + version: '>=4.4.2' + source: + registry_url: https://components.espressif.com + type: service + version: 1.1.2 + espressif/esp_lcd_touch_gt911: + component_hash: acc1c184358aa29ef72506f618c9c76a8cc2bf12af38a2bff3d44d84f3a08857 + dependencies: + - name: espressif/esp_lcd_touch + registry_url: https://components.espressif.com + require: public + version: ^1.1.0 + - name: idf + require: private + version: '>=4.4.2' + source: + registry_url: https://components.espressif.com/ + type: service + version: 1.1.3 + espressif/esp_lvgl_port: + component_hash: a3db8fedba9f474dac24f1e0cd5bc5e560224e51bb5fa30bb2aa5470d49048db + dependencies: + - name: idf + require: private + version: '>=4.4' + - name: lvgl/lvgl + registry_url: https://components.espressif.com + require: public + version: '>=8,<10' + source: + registry_url: https://components.espressif.com/ + type: service + version: 2.6.1 + espressif/mdns: + component_hash: 3ec0af5f6bce310512e90f482388d21cc7c0e99668172d2f895356165fc6f7c5 + dependencies: + - name: idf + require: private + version: '>=5.0' + source: + registry_url: https://components.espressif.com/ + type: service + version: 1.8.2 + idf: + source: + type: idf + version: 5.5.1 + lvgl/lvgl: + component_hash: b702d642e03e95928046d5c6726558e6444e112420c77efa5fdb6650b0a13c5d + dependencies: [] + source: + registry_url: https://components.espressif.com + type: service + version: 9.3.0 +direct_dependencies: +- bblanchon/arduinojson +- espressif/esp_lcd_touch_gt911 +- espressif/esp_lvgl_port +- espressif/mdns +- idf +manifest_hash: c7e0a3e71168efcfe4914077ad130cf2087cff65f10aee88a2b5081658952861 +target: esp32s3 +version: 2.0.0 diff --git a/esp/CMakeLists.txt b/esp/CMakeLists.txt index b0c0977..e728450 100644 --- a/esp/CMakeLists.txt +++ b/esp/CMakeLists.txt @@ -1,7 +1,16 @@ file(GLOB_RECURSE FONT_SRCS ui/fonts/*.c) +# Select LCD implementation based on target +if(IDF_TARGET STREQUAL "esp32") + set(LCD_IMPL "lcd_3248s035c.cpp") +elseif(IDF_TARGET STREQUAL "esp32s3") + set(LCD_IMPL "lcd_8048s070c.cpp") +else() + message(FATAL_ERROR "Unsupported target: ${IDF_TARGET}") +endif() + idf_component_register( - SRCS "nvs_engine.cpp" "utils.cpp" "bvg_api_client.cpp" "lcd.cpp" "main.cpp" "http_server.cpp" "ui/ui.cpp" "time.cpp" ${FONT_SRCS} + SRCS "nvs_engine.cpp" "utils.cpp" "bvg_api_client.cpp" ${LCD_IMPL} "main.cpp" "http_server.cpp" "ui/ui.cpp" "time.cpp" ${FONT_SRCS} INCLUDE_DIRS "." "ui" PRIV_REQUIRES esp_app_format esp_http_client esp_http_server esp_timer esp_wifi json nvs_flash spiffs vfs wifi_provisioning lwip ) diff --git a/esp/idf_component.yml b/esp/idf_component.yml index 6417a4e..694170e 100644 --- a/esp/idf_component.yml +++ b/esp/idf_component.yml @@ -1,10 +1,21 @@ ## IDF Component Manager Manifest File +targets: + - esp32 + - esp32s3 + dependencies: bblanchon/arduinojson: "^7.0.0" + espressif/mdns: "^1.2.1" - espressif/esp_lcd_st7796: "^1.0.0" + + espressif/esp_lcd_st7796: + version: "^1.0.0" + rules: + - if: target == "esp32" + espressif/esp_lcd_touch_gt911: "^1.0.7~1" + espressif/esp_lvgl_port: "^2.6.0" - ## Required IDF version + idf: - version: ">=4.1.0" + version: ">=5.5.1" diff --git a/esp/lcd.cpp b/esp/lcd_3248s035c.cpp similarity index 99% rename from esp/lcd.cpp rename to esp/lcd_3248s035c.cpp index af055b1..318ecb0 100644 --- a/esp/lcd.cpp +++ b/esp/lcd_3248s035c.cpp @@ -14,7 +14,7 @@ #include #include -#include "lcd.hpp" +#include "lcd_3248s035c.hpp" /* LCD size */ #define LCD_ST7796_H_RES (480) diff --git a/esp/lcd_3248s035c.hpp b/esp/lcd_3248s035c.hpp new file mode 100644 index 0000000..81df6f7 --- /dev/null +++ b/esp/lcd_3248s035c.hpp @@ -0,0 +1,3 @@ +#pragma once + +#include "lcd_common.hpp" diff --git a/esp/lcd_8048s070c.cpp b/esp/lcd_8048s070c.cpp new file mode 100644 index 0000000..22fecc0 --- /dev/null +++ b/esp/lcd_8048s070c.cpp @@ -0,0 +1,219 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lcd_8048s070c.hpp" + +/* LCD size */ +#define LCD_HRES 800 +#define LCD_VRES 480 + +/* LCD pins */ +#define PIN_LCD_HSYNC (GPIO_NUM_39) +#define PIN_LCD_VSYNC (GPIO_NUM_40) +#define PIN_LCD_DE (GPIO_NUM_41) +#define PIN_LCD_PCLK (GPIO_NUM_42) +#define PIN_BL (GPIO_NUM_2) + +/* Touch settings */ +#define TOUCH_GT911_I2C_NUM (I2C_NUM_0) +#define TOUCH_GT911_I2C_CLK_HZ (400000) + +/* LCD touch pins */ +#define TOUCH_GT911_I2C_SCL (GPIO_NUM_20) +#define TOUCH_GT911_I2C_SDA (GPIO_NUM_19) +#define PIN_TOUCH_RST (GPIO_NUM_38) + +static const char *TAG = "LCD"; + +/* LCD IO and panel */ +static esp_lcd_panel_handle_t lcd_panel = NULL; +static esp_lcd_touch_handle_t touch_handle = NULL; + +/* LVGL display and touch */ +static lv_disp_t *lvgl_disp = NULL; +static lv_indev_t *lvgl_touch_indev = NULL; + +namespace LVGL_LCD { + +static void backlight_init(int gpio, uint32_t duty_percent) { + ledc_timer_config_t tcfg = { + .speed_mode = LEDC_LOW_SPEED_MODE, + .duty_resolution = LEDC_TIMER_10_BIT, + .timer_num = LEDC_TIMER_0, + .freq_hz = 20000, + .clk_cfg = LEDC_AUTO_CLK, + }; + ESP_ERROR_CHECK(ledc_timer_config(&tcfg)); + + ledc_channel_config_t c = { + .gpio_num = gpio, + .speed_mode = LEDC_LOW_SPEED_MODE, + .channel = LEDC_CHANNEL_0, + .timer_sel = LEDC_TIMER_0, + .duty = 0, + .hpoint = 0, + .flags = {.output_invert = 0}, + }; + ESP_ERROR_CHECK(ledc_channel_config(&c)); + + uint32_t duty = (duty_percent * ((1 << 10) - 1)) / 100; + ESP_ERROR_CHECK(ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, duty)); + ESP_ERROR_CHECK(ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0)); +} + +static esp_err_t app_lcd_init(void) { + /* LCD backlight */ + backlight_init(PIN_BL, 50); + + ESP_LOGD(TAG, "Install LCD driver"); + // See e.g. https://github.com/MMlodzinski/Sunton_ESP32-8048S070c_ESP_IDF_LVGL_example/blob/main/example/main/bsp.h + const esp_lcd_rgb_panel_config_t panel_config = { + .clk_src = LCD_CLK_SRC_PLL160M, + .timings = + { + .pclk_hz = 20 * 1000 * 1000, + .h_res = LCD_HRES, + .v_res = LCD_VRES, + .hsync_pulse_width = 30, + .hsync_back_porch = 16, + .hsync_front_porch = 20, + .vsync_pulse_width = 13, + .vsync_back_porch = 10, + .vsync_front_porch = 22, + .flags = + { + .pclk_active_neg = 1, + }, + }, + .data_width = 16, + .bits_per_pixel = 16, + .num_fbs = 2, // double buffer for RGB displays + .bounce_buffer_size_px = LCD_HRES * 10, // small bounce buffer for 800x480 + .dma_burst_size = 64, + .hsync_gpio_num = PIN_LCD_HSYNC, + .vsync_gpio_num = PIN_LCD_VSYNC, + .de_gpio_num = PIN_LCD_DE, + .pclk_gpio_num = PIN_LCD_PCLK, + .disp_gpio_num = -1, + .data_gpio_nums = {15, 7, 6, 5, 4, 9, 46, 3, 8, 16, 1, 14, 21, 47, 48, 45}, + .flags = + { + .fb_in_psram = 1, + }, + }; + + ESP_ERROR_CHECK(esp_lcd_new_rgb_panel(&panel_config, &lcd_panel)); + ESP_ERROR_CHECK(esp_lcd_panel_reset(lcd_panel)); + ESP_ERROR_CHECK(esp_lcd_panel_init(lcd_panel)); + return ESP_OK; +} + +static esp_err_t app_touch_init(void) { + /* Initialize I2C */ + const i2c_config_t i2c_conf = {.mode = I2C_MODE_MASTER, + .sda_io_num = TOUCH_GT911_I2C_SDA, + .scl_io_num = TOUCH_GT911_I2C_SCL, + .sda_pullup_en = GPIO_PULLUP_DISABLE, + .scl_pullup_en = GPIO_PULLUP_DISABLE, + .master = {.clk_speed = TOUCH_GT911_I2C_CLK_HZ}}; + ESP_RETURN_ON_ERROR(i2c_param_config(TOUCH_GT911_I2C_NUM, &i2c_conf), TAG, "I2C configuration failed"); + ESP_RETURN_ON_ERROR(i2c_driver_install(TOUCH_GT911_I2C_NUM, i2c_conf.mode, 0, 0, 0), TAG, + "I2C initialization failed"); + + /* Initialize touch HW */ + const esp_lcd_touch_config_t tp_cfg = { + .x_max = LCD_HRES, + .y_max = LCD_VRES, + .rst_gpio_num = PIN_TOUCH_RST, + // Touch interrupt is unusable due to routing mistake, see https://esp3d.io/ESP3D-TFT/Version_1.X/hardware/esp32-s3/sunton-70-8048/ + .int_gpio_num = GPIO_NUM_NC, + .levels = + { + .reset = 0, + .interrupt = 0, + }, + .flags = + { + .swap_xy = 0, + .mirror_x = 0, + .mirror_y = 0, + }, + }; + esp_lcd_panel_io_handle_t tp_io_handle = NULL; + const esp_lcd_panel_io_i2c_config_t tp_io_config = ESP_LCD_TOUCH_IO_I2C_GT911_CONFIG(); + ESP_RETURN_ON_ERROR(esp_lcd_new_panel_io_i2c((uint32_t)TOUCH_GT911_I2C_NUM, &tp_io_config, &tp_io_handle), TAG, ""); + return esp_lcd_touch_new_i2c_gt911(tp_io_handle, &tp_cfg, &touch_handle); +} + +static esp_err_t app_lvgl_init(void) { + lvgl_port_cfg_t lvgl_cfg = ESP_LVGL_PORT_INIT_CONFIG(); + ESP_RETURN_ON_ERROR(lvgl_port_init(&lvgl_cfg), TAG, "LVGL port initialization failed"); + + /* Add LCD screen */ + ESP_LOGD(TAG, "Add LCD screen"); + const lvgl_port_display_cfg_t disp_cfg = { + .panel_handle = lcd_panel, + .buffer_size = LCD_HRES * LCD_VRES, + .hres = LCD_HRES, + .vres = LCD_VRES, + .monochrome = false, + /* Rotation values must be same as used in esp_lcd for initial settings of the screen */ + .rotation = + { + .swap_xy = false, + .mirror_x = false, + .mirror_y = false, + }, + .color_format = LV_COLOR_FORMAT_RGB565, + .flags = + { + .buff_dma = true, + .buff_spiram = false, + .swap_bytes = false, + .direct_mode = true, + }, + }; + + const lvgl_port_display_rgb_cfg_t rgb_cfg = {.flags = { + .bb_mode = true, + .avoid_tearing = true, + }}; + + lvgl_disp = lvgl_port_add_disp_rgb(&disp_cfg, &rgb_cfg); + + /* Add touch input (for selected screen) */ + ESP_LOGD(TAG, "Add touch input"); + const lvgl_port_touch_cfg_t touch_cfg = { + .disp = lvgl_disp, + .handle = touch_handle, + }; + + lvgl_touch_indev = lvgl_port_add_touch(&touch_cfg); + + return ESP_OK; +} + +esp_err_t init(void) { + /* LCD HW initialization */ + ESP_ERROR_CHECK(app_lcd_init()); + + /* Touch initialization */ + ESP_ERROR_CHECK(app_touch_init()); + + /* LVGL initialization */ + ESP_ERROR_CHECK(app_lvgl_init()); + + // TODO We probably need some locking mechanism when accessing the NVS for this board + // At the moment, when writing it the NVS, the screen flickers + + return ESP_OK; +} +} // namespace LVGL_LCD diff --git a/esp/lcd_8048s070c.hpp b/esp/lcd_8048s070c.hpp new file mode 100644 index 0000000..81df6f7 --- /dev/null +++ b/esp/lcd_8048s070c.hpp @@ -0,0 +1,3 @@ +#pragma once + +#include "lcd_common.hpp" diff --git a/esp/lcd.hpp b/esp/lcd_common.hpp similarity index 82% rename from esp/lcd.hpp rename to esp/lcd_common.hpp index 6efe17f..c50ef4a 100644 --- a/esp/lcd.hpp +++ b/esp/lcd_common.hpp @@ -1,3 +1,5 @@ +#pragma once + #include namespace LVGL_LCD { diff --git a/esp/main.cpp b/esp/main.cpp index 7f8fcd6..c11b199 100644 --- a/esp/main.cpp +++ b/esp/main.cpp @@ -16,7 +16,7 @@ #include "bvg_api_client.hpp" #include "http_server.hpp" -#include "lcd.hpp" +#include "lcd_common.hpp" #include "nvs_engine.hpp" #include "time.hpp" #include "ui.hpp" diff --git a/package.json b/package.json index a3b9592..f0ee1ab 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,8 @@ "scripts": { "simulator:fullclean": "pio run -t fullclean", "simulator:clean": "pio run -t clean", - "simulator:run": "pio run -t upload", + "simulator:run:3": "pio run -e 3248s035c -t upload", + "simulator:run:8": "pio run -e 8048s070c -t upload", "esp:erase-config": "parttool.py erase_partition --partition-name=app_nvs", "lint:frontend": "concurrently 'pnpm lint:frontend:eslint' 'pnpm lint:frontend:ts' 'pnpm lint:prettier'", "lint:frontend:eslint": "eslint .", diff --git a/partitions.csv b/partitions_esp32.csv similarity index 100% rename from partitions.csv rename to partitions_esp32.csv diff --git a/partitions_esp32s3.csv b/partitions_esp32s3.csv new file mode 100644 index 0000000..ef28577 --- /dev/null +++ b/partitions_esp32s3.csv @@ -0,0 +1,7 @@ +# Name, Type, SubType, Offset, Size, Flags +# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap +nvs, data, nvs, 0x9000, 0x6000, +app_nvs, data, nvs, , 0x4000, +phy_init, data, phy, , 0x1000, +factory, app, factory, , 15232K, +www, data, spiffs, , 1024K, diff --git a/platformio.ini b/platformio.ini index ea4b10d..08fd67a 100644 --- a/platformio.ini +++ b/platformio.ini @@ -3,7 +3,7 @@ src_dir = . include_dir = simulator/include lib_dir = simulator/lib -[env:emulator] +[env] platform = native lib_deps = lvgl/lvgl@^9.3.0 @@ -19,3 +19,15 @@ build_flags = ; in simulator/include/. Without this, library C files can't find configuration headers. -I simulator/include -I esp/ui + +[env:3248s035c] +build_flags = + ${env.build_flags} + -D SDL_HOR_RES=480 + -D SDL_VER_RES=320 + +[env:8048s070c] +build_flags = + ${env.build_flags} + -D SDL_HOR_RES=800 + -D SDL_VER_RES=480 diff --git a/scripts/merge_firmware.sh b/scripts/merge_firmware.sh index 9517e06..fbbfbe2 100755 --- a/scripts/merge_firmware.sh +++ b/scripts/merge_firmware.sh @@ -1,11 +1,56 @@ #!/usr/bin/env bash -esptool.py --chip esp32 merge_bin \ +# Detect target - priority: command line arg > IDF_TARGET env var > sdkconfig fallback +if [ $# -gt 0 ]; then + TARGET="$1" + echo "Using target from command line: $TARGET" +elif [ -n "$IDF_TARGET" ]; then + TARGET="$IDF_TARGET" + echo "Using target from IDF_TARGET environment variable: $TARGET" +else + echo "Error: No target specified. Use:" + echo " $0 # Command line argument" + echo " IDF_TARGET= # Environment variable" + echo "" + echo "Supported targets: esp32, esp32s3" + exit 1 +fi + +# Set parameters based on target +case "$TARGET" in + "esp32") + CHIP="esp32" + FLASH_MODE="qio" + FLASH_FREQ="80m" + FLASH_SIZE="4MB" + APP_OFFSET="0x10000" + WWW_OFFSET="0x300000" + ;; + "esp32s3") + CHIP="esp32s3" + FLASH_MODE="qio" + FLASH_FREQ="80m" + FLASH_SIZE="16MB" + APP_OFFSET="0x10000" + WWW_OFFSET="0xEE0000" + ;; + *) + echo "Error: Unsupported target $TARGET" + exit 1 + ;; +esac + +echo "Building merged firmware for $TARGET..." +echo " Flash mode: $FLASH_MODE" +echo " Flash freq: $FLASH_FREQ" +echo " Flash size: $FLASH_SIZE" + +esptool.py --chip "$CHIP" merge_bin \ -o ../build/merged-firmware.bin \ - --flash_mode dio \ - --flash_freq 80m \ - --flash_size 4MB \ + --flash_mode "$FLASH_MODE" \ + --flash_freq "$FLASH_FREQ" \ + --flash_size "$FLASH_SIZE" \ 0x1000 ../build/bootloader/bootloader.bin \ 0x8000 ../build/partition_table/partition-table.bin \ - 0x20000 ../build/suntransit.bin \ - 0x300000 ../build/www.bin \ + "$APP_OFFSET" ../build/suntransit.bin \ + "$WWW_OFFSET" ../build/www.bin diff --git a/sdkconfig.defaults b/sdkconfig.defaults index ed80247..29d9564 100644 --- a/sdkconfig.defaults +++ b/sdkconfig.defaults @@ -4,8 +4,6 @@ CONFIG_BOOTLOADER_LOG_LEVEL_WARN=y CONFIG_BOOTLOADER_SKIP_VALIDATE_ON_POWER_ON=y CONFIG_ESPTOOLPY_FLASHMODE_QIO=y -CONFIG_ESPTOOLPY_FLASHFREQ_80M=y -CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y CONFIG_PARTITION_TABLE_CUSTOM=y CONFIG_COMPILER_OPTIMIZATION_PERF=y CONFIG_ESP_TLS_INSECURE=y diff --git a/sdkconfig.defaults.esp32 b/sdkconfig.defaults.esp32 new file mode 100644 index 0000000..c4715c8 --- /dev/null +++ b/sdkconfig.defaults.esp32 @@ -0,0 +1,3 @@ +CONFIG_ESPTOOLPY_FLASHFREQ_80M=y +CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_esp32.csv" diff --git a/sdkconfig.defaults.esp32s3 b/sdkconfig.defaults.esp32s3 new file mode 100644 index 0000000..cca1cf3 --- /dev/null +++ b/sdkconfig.defaults.esp32s3 @@ -0,0 +1,8 @@ +CONFIG_IDF_TARGET="esp32s3" +CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_esp32s3.csv" +CONFIG_SPIRAM=y +CONFIG_SPIRAM_MODE_OCT=y +CONFIG_SPIRAM_XIP_FROM_PSRAM=y +CONFIG_SPIRAM_SPEED_80M=y +CONFIG_ESP32S3_DATA_CACHE_LINE_64B=y diff --git a/simulator/include/lvgl_sdl.h b/simulator/include/lvgl_sdl.h index 912b94c..f578bae 100644 --- a/simulator/include/lvgl_sdl.h +++ b/simulator/include/lvgl_sdl.h @@ -6,9 +6,7 @@ #include "lvgl.h" #include "ui.hpp" -#define SDL_HOR_RES 480 -#define SDL_VER_RES 320 -#define SDL_ZOOM 3 +#define SDL_ZOOM 2 namespace LVGL_SDL {