diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 0793b98..613afab 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -8,10 +8,10 @@ "settings": { "terminal.integrated.defaultProfile.linux": "bash", "idf.gitPath": "/usr/bin/git", - "idf.espIdfPath": "/opt/esp/idf", + "idf.espIdfPath": "/opt/esp/idf", "idf.toolsPath": "/opt/esp/tools", "idf.pythonBinPath": "/opt/esp/idf/venv/bin/python3", - "idf.useIDFKConfig": true + "idf.useIDFKConfig": true }, "extensions": [ "espressif.esp-idf-extension", @@ -19,5 +19,8 @@ ] } }, - "runArgs": ["--privileged"] + "runArgs": [ + "--privileged", + "--device=/dev/ttyACM0" + ] } \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index afa0ce2..46771b6 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,7 +4,7 @@ "idf.openOcdConfigs": [ "board/esp32s3-builtin.cfg" ], - "idf.port": "detect", + "idf.port": "/dev/ttyACM0", "idf.currentSetup": "/opt/esp/idf", "idf.customExtraVars": { "IDF_TARGET": "esp32s3" @@ -14,5 +14,6 @@ "--background-index", "--query-driver=**", "--compile-commands-dir=/Users/yulinling/work/work-hardware/HeavenlyHeroStar/build" - ] + ], + "idf.flashType": "UART" } diff --git a/README.md b/README.md index 8c855c5..5fdac34 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,66 @@ | Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-S2 | ESP32-S3 | ESP32-P4 | ESP32-H2 | | ----------------- | ----- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- | -------- | +# 外围硬件 + +| 硬件类别 | 组件/型号 | 关键参数/功能 | 备注 | +| :----------------- | :--------------- | :--------------------------------- | :------------------------------- | +| **核心处理器** | ESP32-S3R8 | Xtensa 32位LX7双核,**主频240MHz** | 乐鑫高性能芯片 | +| **存储** | 内置 SRAM | 512KB | 芯片内部 | +| | 内置 ROM | 384KB | 芯片内部 | +| | 叠封 PSRAM | **8MB** | 用于运行代码,性能优异 | +| | 外接 Flash | **16MB** (W25Q128) | 存储程序和数据 | +| **显示与触摸** | LCD 屏幕 | 1.9英寸,170×320分辨率,262K彩色 | 驱动IC为ST7789V2 | +| | 触摸控制芯片 | **CST816** (电容式) | **触控版特有**,通过I2C接口 | +| **无线通信** | Wi-Fi | 2.4GHz, 802.11 b/g/n | | +| | 蓝牙 | Bluetooth 5 (BLE) | | +| | 板载天线 | 贴片陶瓷天线 | | +| | 外部天线接口 | **IPEX-1 连接器** | **触控版特有**,需修改焊盘启用 | +| **传感器** | 六轴惯性测量单元 | **QMI8658** | 包含3轴加速度计和3轴陀螺仪 | +| **存储扩展** | Micro SD 卡槽 | 支持Micro SD卡 | 位于PCB背面 | +| **电源管理** | 电池接口 | MX1.25 连接器 | 支持3.7V锂电池**充放电** | +| | USB供电 | USB Type-C 接口 | 同时用于下载调试 | +| | 充电指示灯 | 红色LED | 充电时亮起,充满熄灭 | +| **用户交互与调试** | 复位按键 | RESET | 系统复位 | +| | 启动按键 | BOOT | 用于下载模式和引导 | +| **扩展接口** | Pico兼容排针 | 引出丰富GPIO | 兼容树莓派Pico生态,可连接扩展板 | + +# 外围接口 + +| 接口名称 | 接口类型 | 引脚/GPIO | 功能说明 | +| :------------- | :--- | :------------- | :------------------- | +| **LCD 显示屏** | SPI | IO9 | LCD\_RST(复位) | +| | | IO10 | LCD\_CLK(时钟) | +| | | IO11 | LCD\_DC(数据/命令) | +| | | IO12 | LCD\_CS(片选) | +| | | IO13 | LCD\_DIN(数据输入) | +| | | IO14 | LCD\_BL(背光控制,PWM) | +| **触摸屏** | I2C | IO47 | TP\_SDA(数据线) | +| | | IO48 | TP\_SCL(时钟线) | +| | GPIO | IO17 | TP\_RESET(复位) | +| | | IO21 | TP\_INT(中断) | +| **SD 卡** | SPI | IO5 | SD\_CS(片选) | +| | | IO39 | SD\_CLK(时钟) | +| | | IO40 | SD\_MISO(主入从出) | +| | | IO41 | SD\_MOSI(主出从入) | +| **IMU 传感器** | I2C | IO8 | IMU\_SDA(数据线) | +| (QMI8658A) | | IO7 | IMU\_SCL(时钟线) | +| | GPIO | IO6 | IMU\_INT1(中断1) | +| | | IO15 | IMU\_INT2(中断2) | +| **UART0 串口** | UART | IO43 | U0\_TX(发送) | +| | | IO44 | U0\_RX(接收) | +| **用户按键** | GPIO | IO0 | BOOT0(启动/下载模式) | +| | | IO4 | KEY\_IO(用户按键) | +| **用户 LED** | GPIO | IO16 | LED\_A(指示灯) | +| **电池检测** | ADC | IO3 | BAT\_ADC(电池电压采集) | +| **USB Type-C** | USB | VBUS/D+/D- | 供电 + 程序下载 + 串口通信 | +| **锂电池接口** | 电源 | J1 | 电池充电与供电(ETA6098) | +| **WiFi/蓝牙天线** | 射频 | J5 (U.FL-IPEX) | 外接天线座 | +| **TF 卡座** | SPI | TF1 | MicroSD 卡扩展存储 | +| **外部 Flash** | SPI | U5 (W25Q32) | 4MB 板载 Flash | +| **扩展排针 J3** | 混合 | IO0~IO14 | 20Pin 排针,引出主要 GPIO | +| **扩展排针 J4** | 混合 | IO14~IO48等 | 20Pin 排针,含 USB/3V3/地 | + # Wi-Fi Station Example (See the README.md file in the upper level 'examples' directory for more information about examples.) @@ -16,8 +76,8 @@ Open the project configuration menu (`idf.py menuconfig`). In the `Example Configuration` menu: * Set the Wi-Fi configuration. - * Set `WiFi SSID`. - * Set `WiFi Password`. + * Set `WiFi SSID`. + * Set `WiFi Password`. Optional: If you need, change the other options according to your requirements. @@ -29,6 +89,16 @@ Run `idf.py -p PORT flash monitor` to build, flash and monitor the project. (To exit the serial monitor, type ``Ctrl-]``.) +### Attach USB device in WSL + +If you are using Windows Subsystem for Linux (WSL) and need to forward the ESP board from Windows to WSL, you can attach the device with: + +```bash +usbipd attach --wsl --busid 3-1 --auto-attach +``` + +Replace `3-1` with the actual bus ID of your device from `usbipd list`. This allows the board to be detected by the ESP-IDF tools in WSL. + See the Getting Started Guide for all the steps to configure and use the ESP-IDF to build projects. * [ESP-IDF Getting Started Guide on ESP32](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/index.html) @@ -36,9 +106,11 @@ See the Getting Started Guide for all the steps to configure and use the ESP-IDF * [ESP-IDF Getting Started Guide on ESP32-C3](https://docs.espressif.com/projects/esp-idf/en/latest/esp32c3/get-started/index.html) ## Example Output + Note that the output, in particular the order of the output, may vary depending on the environment. Console output if station connects to AP successfully: + ``` I (589) wifi station: ESP_WIFI_MODE_STA I (599) wifi: wifi driver task: 3ffc08b4, prio:23, stack:3584, core=0 @@ -72,6 +144,7 @@ I (2089) wifi station: connected to ap SSID:myssid password:mypassword ``` Console output if the station failed to connect to AP: + ``` I (589) wifi station: ESP_WIFI_MODE_STA I (599) wifi: wifi driver task: 3ffc08b4, prio:23, stack:3584, core=0 diff --git a/dependencies.lock b/dependencies.lock index db91379..e9b52a7 100644 --- a/dependencies.lock +++ b/dependencies.lock @@ -1,8 +1,57 @@ dependencies: + atanisoft/esp_lcd_touch_xpt2046: + component_hash: 7e6381b67b6e487379118368b8e91624dc87036ef5734818de1db9eb35697998 + dependencies: + - name: espressif/esp_lcd_touch + registry_url: https://components.espressif.com + require: private + version: '>=1.0.4' + - name: idf + require: private + version: '>=4.4' + source: + registry_url: https://components.espressif.com/ + type: service + version: 1.0.6 + espressif/esp_lcd_touch: + component_hash: 3f85a7d95af876f1a6ecca8eb90a81614890d0f03a038390804e5a77e2caf862 + dependencies: + - name: idf + require: private + version: '>=4.4.2' + source: + registry_url: https://components.espressif.com + type: service + version: 1.2.1 + espressif/esp_lcd_touch_stmpe610: + component_hash: d8adce47eabe3f8caa23c5acf03cfefe78012628abd974673ccb9a577c3d738b + dependencies: + - name: espressif/esp_lcd_touch + registry_url: https://components.espressif.com + require: public + version: ^1.2.0 + - name: idf + require: private + version: '>=5.0' + source: + registry_url: https://components.espressif.com/ + type: service + version: 1.0.8 idf: source: type: idf version: 6.2.0 -manifest_hash: 0938fe5fc43e8ea0c6dda60b9f593e186303cb1b17412f4d696784db8099a7e9 + lvgl/lvgl: + component_hash: b702d642e03e95928046d5c6726558e6444e112420c77efa5fdb6650b0a13c5d + dependencies: [] + source: + registry_url: https://components.espressif.com/ + type: service + version: 9.3.0 +direct_dependencies: +- atanisoft/esp_lcd_touch_xpt2046 +- espressif/esp_lcd_touch_stmpe610 +- lvgl/lvgl +manifest_hash: 783844712ff012ac0ccef68126d4d5ff8016553ec5d5055c68eab3b7cae073cf target: esp32s3 version: 3.0.0 diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 2fe9758..294df87 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -1,3 +1,3 @@ -idf_component_register(SRCS "station_example_main.c" +idf_component_register(SRCS "main.c" "lvgl_demo_ui.c" PRIV_REQUIRES esp_wifi nvs_flash INCLUDE_DIRS ".") diff --git a/main/idf_component.yml b/main/idf_component.yml index 42ff274..0251d87 100644 --- a/main/idf_component.yml +++ b/main/idf_component.yml @@ -1,4 +1,10 @@ dependencies: + lvgl/lvgl: 9.3.0 + esp_lcd_touch_stmpe610: ^1.0.0 + atanisoft/esp_lcd_touch_xpt2046: 1.0.6 + # esp_lcd_touch_cst816: + # version: "^1.0.0" + # public: true espressif/esp_wifi_remote: version: ">=0.10,<2.0" rules: diff --git a/main/lvgl_demo_ui.c b/main/lvgl_demo_ui.c new file mode 100644 index 0000000..a47d76f --- /dev/null +++ b/main/lvgl_demo_ui.c @@ -0,0 +1,56 @@ +/* + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: CC0-1.0 + */ + +// This demo UI is adapted from LVGL official example: https://docs.lvgl.io/master/examples.html#loader-with-arc + +#include "lvgl.h" + +static lv_obj_t * btn; +static lv_display_rotation_t rotation = LV_DISP_ROTATION_0; + +static void btn_cb(lv_event_t * e) +{ + lv_display_t *disp = lv_event_get_user_data(e); + rotation++; + if (rotation > LV_DISP_ROTATION_270) { + rotation = LV_DISP_ROTATION_0; + } + lv_disp_set_rotation(disp, rotation); +} +static void set_angle(void * obj, int32_t v) +{ + lv_arc_set_value(obj, v); +} + +void example_lvgl_demo_ui(lv_display_t *disp) +{ + lv_obj_t *scr = lv_display_get_screen_active(disp); + + btn = lv_button_create(scr); + lv_obj_t * lbl = lv_label_create(btn); + lv_label_set_text_static(lbl, LV_SYMBOL_REFRESH" ROTATE"); + lv_obj_align(btn, LV_ALIGN_BOTTOM_LEFT, 30, -30); + /*Button event*/ + lv_obj_add_event_cb(btn, btn_cb, LV_EVENT_CLICKED, disp); + + /*Create an Arc*/ + lv_obj_t * arc = lv_arc_create(scr); + lv_arc_set_rotation(arc, 270); + lv_arc_set_bg_angles(arc, 0, 360); + lv_obj_remove_style(arc, NULL, LV_PART_KNOB); /*Be sure the knob is not displayed*/ + lv_obj_remove_flag(arc, LV_OBJ_FLAG_CLICKABLE); /*To not allow adjusting by click*/ + lv_obj_center(arc); + + lv_anim_t a; + lv_anim_init(&a); + lv_anim_set_var(&a, arc); + lv_anim_set_exec_cb(&a, set_angle); + lv_anim_set_duration(&a, 1000); + lv_anim_set_repeat_count(&a, LV_ANIM_REPEAT_INFINITE); /*Just for the demo*/ + lv_anim_set_repeat_delay(&a, 500); + lv_anim_set_values(&a, 0, 100); + lv_anim_start(&a); +} diff --git a/main/main.c b/main/main.c new file mode 100644 index 0000000..d875c4f --- /dev/null +++ b/main/main.c @@ -0,0 +1,490 @@ +/* WiFi station Example + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ +#include +#include +#include +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/event_groups.h" +#include "esp_timer.h" +#include "esp_lcd_panel_io.h" +#include "esp_lcd_panel_vendor.h" +#include "esp_lcd_panel_ops.h" +#include "esp_lcd_panel_st7789.h" +#include "driver/gpio.h" +#include "driver/spi_master.h" +#include "driver/i2c.h" +#include "esp_err.h" +#include "esp_log.h" +#include "lvgl.h" +#include "esp_system.h" +#include "esp_wifi.h" +#include "esp_event.h" +#include "esp_log.h" +#include "nvs_flash.h" + +#include "lwip/err.h" +#include "lwip/sys.h" + +/* The examples use WiFi configuration that you can set via project configuration menu + + If you'd rather not, just change the below entries to strings with + the config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid" +*/ +#define EXAMPLE_ESP_WIFI_SSID CONFIG_ESP_WIFI_SSID +#define EXAMPLE_ESP_WIFI_PASS CONFIG_ESP_WIFI_PASSWORD +#define EXAMPLE_ESP_MAXIMUM_RETRY CONFIG_ESP_MAXIMUM_RETRY + +#if CONFIG_ESP_STATION_EXAMPLE_WPA3_SAE_PWE_HUNT_AND_PECK +#define ESP_WIFI_SAE_MODE WPA3_SAE_PWE_HUNT_AND_PECK +#define EXAMPLE_H2E_IDENTIFIER "" +#elif CONFIG_ESP_STATION_EXAMPLE_WPA3_SAE_PWE_HASH_TO_ELEMENT +#define ESP_WIFI_SAE_MODE WPA3_SAE_PWE_HASH_TO_ELEMENT +#define EXAMPLE_H2E_IDENTIFIER CONFIG_ESP_WIFI_PW_ID +#elif CONFIG_ESP_STATION_EXAMPLE_WPA3_SAE_PWE_BOTH +#define ESP_WIFI_SAE_MODE WPA3_SAE_PWE_BOTH +#define EXAMPLE_H2E_IDENTIFIER CONFIG_ESP_WIFI_PW_ID +#endif +#if CONFIG_ESP_WIFI_AUTH_OPEN +#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_OPEN +#elif CONFIG_ESP_WIFI_AUTH_WEP +#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WEP +#elif CONFIG_ESP_WIFI_AUTH_WPA_PSK +#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA_PSK +#elif CONFIG_ESP_WIFI_AUTH_WPA2_PSK +#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA2_PSK +#elif CONFIG_ESP_WIFI_AUTH_WPA_WPA2_PSK +#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA_WPA2_PSK +#elif CONFIG_ESP_WIFI_AUTH_WPA3_PSK +#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA3_PSK +#elif CONFIG_ESP_WIFI_AUTH_WPA2_WPA3_PSK +#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA2_WPA3_PSK +#elif CONFIG_ESP_WIFI_AUTH_WAPI_PSK +#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WAPI_PSK +#endif + +#if CONFIG_EXAMPLE_LCD_TOUCH_CONTROLLER_STMPE610 +#include "esp_lcd_touch_stmpe610.h" +#elif CONFIG_EXAMPLE_LCD_TOUCH_CONTROLLER_XPT2046 +#include "esp_lcd_touch_xpt2046.h" +#endif + +// Using SPI2 in the example +#define LCD_HOST SPI2_HOST + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////// Please update the following configuration according to your LCD spec ////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#define EXAMPLE_LCD_PIXEL_CLOCK_HZ (20 * 1000 * 1000) +#define EXAMPLE_LCD_BK_LIGHT_ON_LEVEL 1 +#define EXAMPLE_LCD_BK_LIGHT_OFF_LEVEL !EXAMPLE_LCD_BK_LIGHT_ON_LEVEL + +// LCD SPI 管脚(根据实际开发板) +#define EXAMPLE_PIN_NUM_SCLK 10 +#define EXAMPLE_PIN_NUM_MOSI 13 +#define EXAMPLE_PIN_NUM_MISO -1 // LCD 不需要 MISO +#define EXAMPLE_PIN_NUM_LCD_DC 11 +#define EXAMPLE_PIN_NUM_LCD_RST 9 +#define EXAMPLE_PIN_NUM_LCD_CS 12 +#define EXAMPLE_PIN_NUM_BK_LIGHT 14 // 背光 PWM +#define EXAMPLE_PIN_NUM_TOUCH_CS 15 + +// 触摸屏 - 改为 I2C 接口 +#define EXAMPLE_PIN_NUM_TOUCH_SDA 47 +#define EXAMPLE_PIN_NUM_TOUCH_SCL 48 +#define EXAMPLE_PIN_NUM_TOUCH_RST 17 +#define EXAMPLE_PIN_NUM_TOUCH_INT 21 + +// 用户按键和 LED +#define EXAMPLE_PIN_NUM_KEY 4 +#define EXAMPLE_PIN_NUM_LED 16 + +#define TOUCH_I2C_MASTER_NUM I2C_NUM_0 +#define TOUCH_I2C_MASTER_FREQ_HZ 400000 + +// The pixel number in horizontal and vertical +#define EXAMPLE_LCD_H_RES 240 +#define EXAMPLE_LCD_V_RES 320 +// Bit number used to represent command and parameter +#define EXAMPLE_LCD_CMD_BITS 8 +#define EXAMPLE_LCD_PARAM_BITS 8 + +#define EXAMPLE_LVGL_DRAW_BUF_LINES 20 // number of display lines in each draw buffer +#define EXAMPLE_LVGL_TICK_PERIOD_MS 2 +#define EXAMPLE_LVGL_TASK_MAX_DELAY_MS 500 +#define EXAMPLE_LVGL_TASK_MIN_DELAY_MS 1000 / CONFIG_FREERTOS_HZ +#define EXAMPLE_LVGL_TASK_STACK_SIZE (4 * 1024) +#define EXAMPLE_LVGL_TASK_PRIORITY 2 + +// LVGL library is not thread-safe, this example will call LVGL APIs from different tasks, so use a mutex to protect it +static _lock_t lvgl_api_lock; + +/* FreeRTOS event group to signal when we are connected*/ +static EventGroupHandle_t s_wifi_event_group; + +/* The event group allows multiple bits for each event, but we only care about two events: + * - we are connected to the AP with an IP + * - we failed to connect after the maximum amount of retries */ +#define WIFI_CONNECTED_BIT BIT0 +#define WIFI_FAIL_BIT BIT1 + +static const char *TAG = "example"; +// static const char *TAG = "wifi station"; + +static int s_retry_num = 0; + +extern void example_lvgl_demo_ui(lv_disp_t *disp); + +static bool example_notify_lvgl_flush_ready(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 false; +} + +/* Rotate display and touch, when rotated screen in LVGL. Called when driver parameters are updated. */ +static void example_lvgl_port_update_callback(lv_display_t *disp) +{ + esp_lcd_panel_handle_t panel_handle = lv_display_get_user_data(disp); + lv_display_rotation_t rotation = lv_display_get_rotation(disp); + + switch (rotation) { + case LV_DISPLAY_ROTATION_0: + // Rotate LCD display + esp_lcd_panel_swap_xy(panel_handle, false); + esp_lcd_panel_mirror(panel_handle, true, false); + break; + case LV_DISPLAY_ROTATION_90: + // Rotate LCD display + esp_lcd_panel_swap_xy(panel_handle, true); + esp_lcd_panel_mirror(panel_handle, true, true); + break; + case LV_DISPLAY_ROTATION_180: + // Rotate LCD display + esp_lcd_panel_swap_xy(panel_handle, false); + esp_lcd_panel_mirror(panel_handle, false, true); + break; + case LV_DISPLAY_ROTATION_270: + // Rotate LCD display + esp_lcd_panel_swap_xy(panel_handle, true); + esp_lcd_panel_mirror(panel_handle, false, false); + break; + } +} + +static void example_lvgl_flush_cb(lv_display_t *disp, const lv_area_t *area, uint8_t *px_map) +{ + example_lvgl_port_update_callback(disp); + esp_lcd_panel_handle_t panel_handle = lv_display_get_user_data(disp); + int offsetx1 = area->x1; + int offsetx2 = area->x2; + int offsety1 = area->y1; + int offsety2 = area->y2; + // because SPI LCD is big-endian, we need to swap the RGB bytes order + lv_draw_sw_rgb565_swap(px_map, (offsetx2 + 1 - offsetx1) * (offsety2 + 1 - offsety1)); + // copy a buffer's content to a specific area of the display + esp_lcd_panel_draw_bitmap(panel_handle, offsetx1, offsety1, offsetx2 + 1, offsety2 + 1, px_map); +} + +#if CONFIG_EXAMPLE_LCD_TOUCH_ENABLED +static void example_lvgl_touch_cb(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; + + esp_lcd_touch_handle_t touch_pad = lv_indev_get_user_data(indev); + esp_lcd_touch_read_data(touch_pad); + /* Get coordinates */ + bool touchpad_pressed = esp_lcd_touch_get_coordinates(touch_pad, 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_PRESSED; + } else { + data->state = LV_INDEV_STATE_RELEASED; + } +} +#endif + +static void example_increase_lvgl_tick(void *arg) +{ + /* Tell LVGL how many milliseconds has elapsed */ + lv_tick_inc(EXAMPLE_LVGL_TICK_PERIOD_MS); +} + +static void example_lvgl_port_task(void *arg) +{ + ESP_LOGI(TAG, "Starting LVGL task"); + uint32_t time_till_next_ms = 0; + while (1) { + _lock_acquire(&lvgl_api_lock); + time_till_next_ms = lv_timer_handler(); + _lock_release(&lvgl_api_lock); + // in case of triggering a task watch dog time out + time_till_next_ms = MAX(time_till_next_ms, EXAMPLE_LVGL_TASK_MIN_DELAY_MS); + // in case of lvgl display not ready yet + time_till_next_ms = MIN(time_till_next_ms, EXAMPLE_LVGL_TASK_MAX_DELAY_MS); + usleep(1000 * time_till_next_ms); + } +} + +static void event_handler(void* arg, esp_event_base_t event_base, + int32_t event_id, void* event_data) +{ + if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) { + esp_wifi_connect(); + } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) { + if (s_retry_num < EXAMPLE_ESP_MAXIMUM_RETRY) { + esp_wifi_connect(); + s_retry_num++; + ESP_LOGI(TAG, "retry to connect to the AP"); + } else { + xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT); + } + ESP_LOGI(TAG,"connect to the AP fail"); + } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) { + ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data; + ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip)); + s_retry_num = 0; + xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT); + } +} + +void wifi_init_sta(void) +{ + s_wifi_event_group = xEventGroupCreate(); + + ESP_ERROR_CHECK(esp_netif_init()); + + ESP_ERROR_CHECK(esp_event_loop_create_default()); + esp_netif_create_default_wifi_sta(); + + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + ESP_ERROR_CHECK(esp_wifi_init(&cfg)); + + esp_event_handler_instance_t instance_any_id; + esp_event_handler_instance_t instance_got_ip; + ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, + ESP_EVENT_ANY_ID, + &event_handler, + NULL, + &instance_any_id)); + ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, + IP_EVENT_STA_GOT_IP, + &event_handler, + NULL, + &instance_got_ip)); + + wifi_config_t wifi_config = { + .sta = { + .ssid = EXAMPLE_ESP_WIFI_SSID, + .password = EXAMPLE_ESP_WIFI_PASS, + /* Authmode threshold resets to WPA2 as default if password matches WPA2 standards (password len => 8). + * If you want to connect the device to deprecated WEP/WPA networks, Please set the threshold value + * to WIFI_AUTH_WEP/WIFI_AUTH_WPA_PSK and set the password with length and format matching to + * WIFI_AUTH_WEP/WIFI_AUTH_WPA_PSK standards. + */ + .threshold.authmode = ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD, + .sae_pwe_h2e = ESP_WIFI_SAE_MODE, + .sae_h2e_identifier = EXAMPLE_H2E_IDENTIFIER, + }, + }; + ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) ); + ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config) ); + ESP_ERROR_CHECK(esp_wifi_start() ); + + ESP_LOGI(TAG, "wifi_init_sta finished."); + + /* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum + * number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */ + EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group, + WIFI_CONNECTED_BIT | WIFI_FAIL_BIT, + pdFALSE, + pdFALSE, + portMAX_DELAY); + + /* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually + * happened. */ + if (bits & WIFI_CONNECTED_BIT) { + ESP_LOGI(TAG, "connected to ap SSID:%s password:%s", + EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS); + } else if (bits & WIFI_FAIL_BIT) { + ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s", + EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS); + } else { + ESP_LOGE(TAG, "UNEXPECTED EVENT"); + } +} + +void app_main(void) +{ + //Initialize NVS + esp_err_t ret = nvs_flash_init(); + if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { + ESP_ERROR_CHECK(nvs_flash_erase()); + ret = nvs_flash_init(); + } + ESP_ERROR_CHECK(ret); + + if (CONFIG_LOG_MAXIMUM_LEVEL > CONFIG_LOG_DEFAULT_LEVEL) { + /* If you only want to open more logs in the wifi module, you need to make the max level greater than the default level, + * and call esp_log_level_set() before esp_wifi_init() to improve the log level of the wifi module. */ + esp_log_level_set("wifi", CONFIG_LOG_MAXIMUM_LEVEL); + } + + ESP_LOGI(TAG, "ESP_WIFI_MODE_STA"); + wifi_init_sta(); + + ESP_LOGI(TAG, "Turn off LCD backlight"); + gpio_config_t bk_gpio_config = { + .mode = GPIO_MODE_OUTPUT, + .pin_bit_mask = 1ULL << EXAMPLE_PIN_NUM_BK_LIGHT + }; + ESP_ERROR_CHECK(gpio_config(&bk_gpio_config)); + + ESP_LOGI(TAG, "Initialize SPI bus"); + spi_bus_config_t buscfg = { + .sclk_io_num = EXAMPLE_PIN_NUM_SCLK, + .mosi_io_num = EXAMPLE_PIN_NUM_MOSI, + .miso_io_num = EXAMPLE_PIN_NUM_MISO, + .quadwp_io_num = -1, + .quadhd_io_num = -1, + .max_transfer_sz = EXAMPLE_LCD_H_RES * 80 * sizeof(uint16_t), + }; + ESP_ERROR_CHECK(spi_bus_initialize(LCD_HOST, &buscfg, SPI_DMA_CH_AUTO)); + + ESP_LOGI(TAG, "Install panel IO"); + esp_lcd_panel_io_handle_t io_handle = NULL; + esp_lcd_panel_io_spi_config_t io_config = { + .dc_gpio_num = EXAMPLE_PIN_NUM_LCD_DC, + .cs_gpio_num = EXAMPLE_PIN_NUM_LCD_CS, + .pclk_hz = EXAMPLE_LCD_PIXEL_CLOCK_HZ, + .lcd_cmd_bits = EXAMPLE_LCD_CMD_BITS, + .lcd_param_bits = EXAMPLE_LCD_PARAM_BITS, + .spi_mode = 0, + .trans_queue_depth = 10, + }; + // Attach the LCD to the SPI bus + ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi(LCD_HOST, &io_config, &io_handle)); + + esp_lcd_panel_handle_t panel_handle = NULL; + esp_lcd_panel_dev_config_t panel_config = { + .reset_gpio_num = EXAMPLE_PIN_NUM_LCD_RST, + .rgb_ele_order = LCD_RGB_ELEMENT_ORDER_BGR, + .bits_per_pixel = 16, + }; + ESP_LOGI(TAG, "Install ST7789 panel driver"); + ESP_ERROR_CHECK(esp_lcd_new_panel_st7789(io_handle, &panel_config, &panel_handle)); + ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_handle)); + ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle)); + ESP_ERROR_CHECK(esp_lcd_panel_mirror(panel_handle, true, false)); + + // user can flush pre-defined pattern to the screen before we turn on the screen or backlight + ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_handle, true)); + + ESP_LOGI(TAG, "Turn on LCD backlight"); + gpio_set_level(EXAMPLE_PIN_NUM_BK_LIGHT, EXAMPLE_LCD_BK_LIGHT_ON_LEVEL); + + ESP_LOGI(TAG, "Initialize LVGL library"); + lv_init(); + + // create a lvgl display + lv_display_t *display = lv_display_create(EXAMPLE_LCD_H_RES, EXAMPLE_LCD_V_RES); + + // alloc draw buffers used by LVGL + // it's recommended to choose the size of the draw buffer(s) to be at least 1/10 screen sized + size_t draw_buffer_sz = EXAMPLE_LCD_H_RES * EXAMPLE_LVGL_DRAW_BUF_LINES * sizeof(lv_color16_t); + + void *buf1 = spi_bus_dma_memory_alloc(LCD_HOST, draw_buffer_sz, 0); + assert(buf1); + void *buf2 = spi_bus_dma_memory_alloc(LCD_HOST, draw_buffer_sz, 0); + assert(buf2); + // initialize LVGL draw buffers + lv_display_set_buffers(display, buf1, buf2, draw_buffer_sz, LV_DISPLAY_RENDER_MODE_PARTIAL); + // associate the mipi panel handle to the display + lv_display_set_user_data(display, panel_handle); + // set color depth + lv_display_set_color_format(display, LV_COLOR_FORMAT_RGB565); + // set the callback which can copy the rendered image to an area of the display + lv_display_set_flush_cb(display, example_lvgl_flush_cb); + + 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 = &example_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, EXAMPLE_LVGL_TICK_PERIOD_MS * 1000)); + + ESP_LOGI(TAG, "Register io panel event callback for LVGL flush ready notification"); + const esp_lcd_panel_io_callbacks_t cbs = { + .on_color_trans_done = example_notify_lvgl_flush_ready, + }; + /* Register done callback */ + ESP_ERROR_CHECK(esp_lcd_panel_io_register_event_callbacks(io_handle, &cbs, display)); + + #if CONFIG_EXAMPLE_LCD_TOUCH_ENABLED + // 仅在触摸启用时初始化 I2C + ESP_LOGI(TAG, "Initialize I2C for touch"); + i2c_config_t i2c_conf = { + .mode = I2C_MODE_MASTER, + .sda_io_num = EXAMPLE_PIN_NUM_TOUCH_SDA, + .scl_io_num = EXAMPLE_PIN_NUM_TOUCH_SCL, + .sda_pullup_en = GPIO_PULLUP_ENABLE, + .scl_pullup_en = GPIO_PULLUP_ENABLE, + .master.clk_speed = TOUCH_I2C_MASTER_FREQ_HZ, + }; + ESP_ERROR_CHECK(i2c_param_config(TOUCH_I2C_MASTER_NUM, &i2c_conf)); + ESP_ERROR_CHECK(i2c_driver_install(TOUCH_I2C_MASTER_NUM, I2C_MODE_MASTER, 0, 0, 0)); + + ESP_LOGI(TAG, "Initialize touch controller CST816"); + + esp_lcd_touch_handle_t tp = NULL; + esp_lcd_touch_config_t tp_cfg = { + .x_max = EXAMPLE_LCD_H_RES, + .y_max = EXAMPLE_LCD_V_RES, + .rst_gpio_num = EXAMPLE_PIN_NUM_TOUCH_RST, + .int_gpio_num = EXAMPLE_PIN_NUM_TOUCH_INT, + .flags = { + .swap_xy = 0, + .mirror_x = 0, + .mirror_y = 0, + }, + }; + + // CST816 使用 I2C 接口 + ESP_ERROR_CHECK(esp_lcd_touch_new_i2c_cst816( + TOUCH_I2C_MASTER_NUM, + &tp_cfg, + &tp + )); + + static lv_indev_t *indev; + indev = lv_indev_create(); + lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER); + lv_indev_set_display(indev, display); + lv_indev_set_user_data(indev, tp); + lv_indev_set_read_cb(indev, example_lvgl_touch_cb); + #endif + + ESP_LOGI(TAG, "Create LVGL task"); + xTaskCreate(example_lvgl_port_task, "LVGL", EXAMPLE_LVGL_TASK_STACK_SIZE, NULL, EXAMPLE_LVGL_TASK_PRIORITY, NULL); + + ESP_LOGI(TAG, "Display LVGL Meter Widget"); + // Lock the mutex due to the LVGL APIs are not thread-safe + _lock_acquire(&lvgl_api_lock); + example_lvgl_demo_ui(display); + _lock_release(&lvgl_api_lock); +} diff --git a/main/station_example_main.c b/main/station_example_main.c deleted file mode 100644 index d5ed5eb..0000000 --- a/main/station_example_main.c +++ /dev/null @@ -1,179 +0,0 @@ -/* WiFi station Example - - This example code is in the Public Domain (or CC0 licensed, at your option.) - - Unless required by applicable law or agreed to in writing, this - software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR - CONDITIONS OF ANY KIND, either express or implied. -*/ -#include -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "freertos/event_groups.h" -#include "esp_system.h" -#include "esp_wifi.h" -#include "esp_event.h" -#include "esp_log.h" -#include "nvs_flash.h" - -#include "lwip/err.h" -#include "lwip/sys.h" - -/* The examples use WiFi configuration that you can set via project configuration menu - - If you'd rather not, just change the below entries to strings with - the config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid" -*/ -#define EXAMPLE_ESP_WIFI_SSID CONFIG_ESP_WIFI_SSID -#define EXAMPLE_ESP_WIFI_PASS CONFIG_ESP_WIFI_PASSWORD -#define EXAMPLE_ESP_MAXIMUM_RETRY CONFIG_ESP_MAXIMUM_RETRY - -#if CONFIG_ESP_STATION_EXAMPLE_WPA3_SAE_PWE_HUNT_AND_PECK -#define ESP_WIFI_SAE_MODE WPA3_SAE_PWE_HUNT_AND_PECK -#define EXAMPLE_H2E_IDENTIFIER "" -#elif CONFIG_ESP_STATION_EXAMPLE_WPA3_SAE_PWE_HASH_TO_ELEMENT -#define ESP_WIFI_SAE_MODE WPA3_SAE_PWE_HASH_TO_ELEMENT -#define EXAMPLE_H2E_IDENTIFIER CONFIG_ESP_WIFI_PW_ID -#elif CONFIG_ESP_STATION_EXAMPLE_WPA3_SAE_PWE_BOTH -#define ESP_WIFI_SAE_MODE WPA3_SAE_PWE_BOTH -#define EXAMPLE_H2E_IDENTIFIER CONFIG_ESP_WIFI_PW_ID -#endif -#if CONFIG_ESP_WIFI_AUTH_OPEN -#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_OPEN -#elif CONFIG_ESP_WIFI_AUTH_WEP -#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WEP -#elif CONFIG_ESP_WIFI_AUTH_WPA_PSK -#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA_PSK -#elif CONFIG_ESP_WIFI_AUTH_WPA2_PSK -#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA2_PSK -#elif CONFIG_ESP_WIFI_AUTH_WPA_WPA2_PSK -#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA_WPA2_PSK -#elif CONFIG_ESP_WIFI_AUTH_WPA3_PSK -#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA3_PSK -#elif CONFIG_ESP_WIFI_AUTH_WPA2_WPA3_PSK -#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA2_WPA3_PSK -#elif CONFIG_ESP_WIFI_AUTH_WAPI_PSK -#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WAPI_PSK -#endif - -/* FreeRTOS event group to signal when we are connected*/ -static EventGroupHandle_t s_wifi_event_group; - -/* The event group allows multiple bits for each event, but we only care about two events: - * - we are connected to the AP with an IP - * - we failed to connect after the maximum amount of retries */ -#define WIFI_CONNECTED_BIT BIT0 -#define WIFI_FAIL_BIT BIT1 - -static const char *TAG = "wifi station"; - -static int s_retry_num = 0; - - -static void event_handler(void* arg, esp_event_base_t event_base, - int32_t event_id, void* event_data) -{ - if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) { - esp_wifi_connect(); - } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) { - if (s_retry_num < EXAMPLE_ESP_MAXIMUM_RETRY) { - esp_wifi_connect(); - s_retry_num++; - ESP_LOGI(TAG, "retry to connect to the AP"); - } else { - xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT); - } - ESP_LOGI(TAG,"connect to the AP fail"); - } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) { - ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data; - ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip)); - s_retry_num = 0; - xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT); - } -} - -void wifi_init_sta(void) -{ - s_wifi_event_group = xEventGroupCreate(); - - ESP_ERROR_CHECK(esp_netif_init()); - - ESP_ERROR_CHECK(esp_event_loop_create_default()); - esp_netif_create_default_wifi_sta(); - - wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); - ESP_ERROR_CHECK(esp_wifi_init(&cfg)); - - esp_event_handler_instance_t instance_any_id; - esp_event_handler_instance_t instance_got_ip; - ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, - ESP_EVENT_ANY_ID, - &event_handler, - NULL, - &instance_any_id)); - ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, - IP_EVENT_STA_GOT_IP, - &event_handler, - NULL, - &instance_got_ip)); - - wifi_config_t wifi_config = { - .sta = { - .ssid = EXAMPLE_ESP_WIFI_SSID, - .password = EXAMPLE_ESP_WIFI_PASS, - /* Authmode threshold resets to WPA2 as default if password matches WPA2 standards (password len => 8). - * If you want to connect the device to deprecated WEP/WPA networks, Please set the threshold value - * to WIFI_AUTH_WEP/WIFI_AUTH_WPA_PSK and set the password with length and format matching to - * WIFI_AUTH_WEP/WIFI_AUTH_WPA_PSK standards. - */ - .threshold.authmode = ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD, - .sae_pwe_h2e = ESP_WIFI_SAE_MODE, - .sae_h2e_identifier = EXAMPLE_H2E_IDENTIFIER, - }, - }; - ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) ); - ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config) ); - ESP_ERROR_CHECK(esp_wifi_start() ); - - ESP_LOGI(TAG, "wifi_init_sta finished."); - - /* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum - * number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */ - EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group, - WIFI_CONNECTED_BIT | WIFI_FAIL_BIT, - pdFALSE, - pdFALSE, - portMAX_DELAY); - - /* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually - * happened. */ - if (bits & WIFI_CONNECTED_BIT) { - ESP_LOGI(TAG, "connected to ap SSID:%s password:%s", - EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS); - } else if (bits & WIFI_FAIL_BIT) { - ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s", - EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS); - } else { - ESP_LOGE(TAG, "UNEXPECTED EVENT"); - } -} - -void app_main(void) -{ - //Initialize NVS - esp_err_t ret = nvs_flash_init(); - if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { - ESP_ERROR_CHECK(nvs_flash_erase()); - ret = nvs_flash_init(); - } - ESP_ERROR_CHECK(ret); - - if (CONFIG_LOG_MAXIMUM_LEVEL > CONFIG_LOG_DEFAULT_LEVEL) { - /* If you only want to open more logs in the wifi module, you need to make the max level greater than the default level, - * and call esp_log_level_set() before esp_wifi_init() to improve the log level of the wifi module. */ - esp_log_level_set("wifi", CONFIG_LOG_MAXIMUM_LEVEL); - } - - ESP_LOGI(TAG, "ESP_WIFI_MODE_STA"); - wifi_init_sta(); -}