feat: 集成 dzbj LVGL 显示模块 + 配网模式内存优化
阶段1: 将 dzbj 项目的 LVGL 8.3.11 LCD 显示集成到 AI小智 主项目, 开机显示 ScreenHome 界面,同时优化配网模式下的内存使用, 确保 WiFi+BLE+LVGL 三者共存运行。 ## 新增功能 ### dzbj 显示模块集成 - 新增 main/dzbj/ 目录,移植 LCD 驱动(ST77916 QSPI)、触摸驱动(CST816S)、 LVGL 初始化和 SquareLine Studio UI 界面 - I2C 总线共享:dzbj 触摸控制器复用主项目的 I2C_NUM_1 总线 - GPIO 冲突解决:LED(GPIO21)、Touch1(GPIO1)、Touch4(GPIO7) 改为 NC, 电池 ADC 从 GPIO6 改为 GPIO3 - 添加 LVGL、esp_lcd_st77916、esp_lcd_touch_cst816s 等组件依赖 - managed_components 纳入版本管理 ### 配网模式轻量化启动 - BoxAudioCodec: 新增 output_only 模式,仅创建 I2S TX 通道(省 ~13KB DMA) 跳过 ES7210 ADC 初始化(省 ~2-4KB) - AudioCodec: 新增 StartOutputOnly() 方法,仅启用扬声器输出 - Application: 配网模式跳过 Opus 编码器、输入重采样器、协议初始化、 天气位置检测等网络业务 - 板级构造函数: 配网模式跳过电池检测、IMU传感器、PowerSaveTimer ### WifiBoard 配网流程修复 - NeedsProvisioning() 静态方法: 读取 NVS force_ap 和 SSID 列表, 用于提前判断配网模式 - force_ap 竞态修复: 构造函数不再清零 force_ap,改在 StartNetwork() 清零, 确保 NeedsProvisioning() 能正确读到 force_ap=1 - Application 缓存 provisioning_mode_ 成员变量,避免重复读 NVS ### BLE 配网重启修复 - 配网成功后用 esp_timer 延迟重启替代 xTaskCreate, 避免内存紧张时任务创建失败导致设备不重启 - 注释掉 WiFi 连接成功后的 MAC 地址发送步骤 ### sdkconfig 内存优化 - BT_ALLOCATION_FROM_SPIRAM_FIRST=y (BLE 动态分配优先 PSRAM) - SPIRAM_MALLOC_RESERVE_INTERNAL=32768 - NVS_ALLOCATE_CACHE_IN_SPIRAM=y - WiFi 静态缓冲区数量优化 (RX=10, TX=8) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
d5fcb917b1
commit
c24a9bc162
4
.gitignore
vendored
4
.gitignore
vendored
@ -6,5 +6,9 @@
|
|||||||
# 忽略根目录下的uniapp_code文件夹(这是APP端的业务)
|
# 忽略根目录下的uniapp_code文件夹(这是APP端的业务)
|
||||||
/uniapp_code
|
/uniapp_code
|
||||||
|
|
||||||
|
|
||||||
# 忽略 macOS 系统文件
|
# 忽略 macOS 系统文件
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|
||||||
|
.cache
|
||||||
|
.claude
|
||||||
|
|||||||
394
06-AI对话和电子吧唧双模式适配说明.md
Normal file
394
06-AI对话和电子吧唧双模式适配说明.md
Normal file
@ -0,0 +1,394 @@
|
|||||||
|
# AI对话 + 电子吧唧 双模式适配可行性分析
|
||||||
|
|
||||||
|
> 分析日期:2026-02-27
|
||||||
|
> 硬件平台:movecall-moji-esp32s3 (ESP32-S3-N16R8)
|
||||||
|
> ESP-IDF版本:5.4.2
|
||||||
|
> LVGL版本:8.3.11 (dzbj项目)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 一、项目现状
|
||||||
|
|
||||||
|
### 1.1 主项目 (Baji_Rtc_Toy)
|
||||||
|
|
||||||
|
基于 AI小智 开源项目改造,当前功能:
|
||||||
|
- 火山引擎 RTC 语音对话(WiFi 连接)
|
||||||
|
- BLE 配网(Bluedroid,Service 0xABF0)
|
||||||
|
- 音频编解码(ES8311 + Opus)
|
||||||
|
- 唤醒词检测(esp-sr AFE)
|
||||||
|
- **无 LCD 显示**(`lcd_display.cc` 已注释,managed_components 中无 LVGL)
|
||||||
|
|
||||||
|
关键文件:
|
||||||
|
- `main/application.cc` — 应用主类,状态管理
|
||||||
|
- `main/boards/movecall-moji-esp32s3/` — 板级实现
|
||||||
|
- `main/boards/common/wifi_board.cc` — WiFi/BLE 网络管理
|
||||||
|
- `main/protocols/volc_rtc_protocol.cc` — 火山 RTC 协议
|
||||||
|
- `main/bluetooth_provisioning.cc` — BLE 配网
|
||||||
|
- `main/display/` — Display 抽象层(已预留 LCD 接口,未编译)
|
||||||
|
|
||||||
|
### 1.2 dzbj 子项目 (电子吧唧)
|
||||||
|
|
||||||
|
独立的 ESP32-S3 LVGL 项目,位于 `/dzbj/` 目录,当前功能:
|
||||||
|
- 360×360 ST77916 QSPI LCD + CST816S 触摸
|
||||||
|
- LVGL 8.3.11 三屏界面(ScreenHome/ScreenImg/ScreenSet)
|
||||||
|
- BLE GATT 图片传输服务(Service 0x0B00)
|
||||||
|
- GIF 播放、JPEG 解码、SPIFFS 图片管理
|
||||||
|
- 低功耗休眠/唤醒管理
|
||||||
|
- PWM 背光控制、手电筒功能
|
||||||
|
|
||||||
|
关键文件:
|
||||||
|
- `dzbj/main/lcd/lcd.c` — ST77916 QSPI + CST816S 驱动
|
||||||
|
- `dzbj/main/ui/` — SquareLine Studio 生成的 UI 代码
|
||||||
|
- `dzbj/main/pages/pages.c` — 图片处理 + PWM 亮度
|
||||||
|
- `dzbj/main/ble/ble.c` — BLE 图片传输 GATT Server
|
||||||
|
- `dzbj/main/sleep_mgr/sleep_mgr.c` — 低功耗管理
|
||||||
|
|
||||||
|
### 1.3 AI小智原生 LVGL 版本
|
||||||
|
|
||||||
|
**AI小智原生项目不使用 LVGL 9.2.2**。实际情况:
|
||||||
|
|
||||||
|
| 项目 | LVGL 版本 | 状态 |
|
||||||
|
|------|-----------|------|
|
||||||
|
| 主项目 (Baji_Rtc_Toy) | **无 LVGL** | `lcd_display.cc` 已注释,managed_components 中无 lvgl |
|
||||||
|
| dzbj 子项目 | **8.3.11** | 完整集成 LVGL + esp_lvgl_port 2.5.0 |
|
||||||
|
| AI小智 Display 框架 | **预留接口** | `Display` 基类已编译,方法为空操作(no-op) |
|
||||||
|
|
||||||
|
`main/CMakeLists.txt` 第11-12行明确注释了 LCD 支持:
|
||||||
|
```cmake
|
||||||
|
#"display/lcd_display.cc" # 移除LCD显示器支持
|
||||||
|
#"display/oled_display.cc" # 移除OLED显示器支持
|
||||||
|
```
|
||||||
|
|
||||||
|
AI小智框架的 `LcdDisplay` 类已预留 emoji 表情(21种)、聊天气泡(微信风格)、主题切换(深色/浅色) 功能,但当前未编译链接。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 二、双模式架构设计
|
||||||
|
|
||||||
|
### 2.1 架构概览
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────┐
|
||||||
|
│ LVGL 8.3.11 │
|
||||||
|
│ (常驻,两个模式共享) │
|
||||||
|
├────────────────────┬────────────────────────────┤
|
||||||
|
│ AI 聊天模式 │ 电子吧唧模式 │
|
||||||
|
│ │ │
|
||||||
|
│ WiFi + RTC 协议 │ BLE GATT Server │
|
||||||
|
│ emoji 表情显示 │ ScreenHome/Img/Set │
|
||||||
|
│ 聊天气泡文本 │ 图片浏览 + GIF │
|
||||||
|
│ 唤醒词检测 │ BLE 图片传输 │
|
||||||
|
│ 音频编解码 │ 手电筒/低功耗 │
|
||||||
|
├────────────────────┴────────────────────────────┤
|
||||||
|
│ 长按 BOOT 5秒 切换 │
|
||||||
|
│ AI→吧唧: 关WiFi+RTC → 启BLE → 切换UI │
|
||||||
|
│ 吧唧→AI: 关BLE → 启WiFi+RTC → 切换UI │
|
||||||
|
└─────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.2 模式定义
|
||||||
|
|
||||||
|
**AI 聊天模式**:
|
||||||
|
- 网络:WiFi 连接
|
||||||
|
- 协议:火山引擎 RTC 实时对话
|
||||||
|
- 音频:唤醒词检测 + Opus 编解码 + I2S 输出
|
||||||
|
- 显示:emoji 表情 + 聊天气泡文本 + 状态栏
|
||||||
|
- BLE:**关闭**
|
||||||
|
|
||||||
|
**电子吧唧模式**:
|
||||||
|
- 网络:**WiFi 关闭**
|
||||||
|
- BLE:GATT Server(图片传输 + 配网服务)
|
||||||
|
- 显示:ScreenHome(主界面)→ ScreenImg(图片浏览)→ ScreenSet(设置)
|
||||||
|
- 功能:GIF 播放、JPEG 解码、SPIFFS 图片管理、手电筒、低功耗
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 三、内存预算分析(核心瓶颈)
|
||||||
|
|
||||||
|
### 3.1 硬件规格
|
||||||
|
|
||||||
|
- **内部 SRAM**:~334KB DIRAM(可用)
|
||||||
|
- **PSRAM**:8MB OCT-SPI 80MHz
|
||||||
|
- **Flash**:16MB
|
||||||
|
|
||||||
|
### 3.2 常驻组件(两模式共享)
|
||||||
|
|
||||||
|
| 组件 | DIRAM 占用 | 说明 |
|
||||||
|
|------|-----------|------|
|
||||||
|
| LVGL 库 (.bss/.data) | ~34KB | 图形引擎核心 |
|
||||||
|
| FreeRTOS | ~22KB | 内核 + idle/timer 任务 |
|
||||||
|
| HAL + SPI Flash | ~30KB | 硬件抽象 + Flash 驱动 |
|
||||||
|
| Heap 管理器 | ~8KB | 内存分配器 |
|
||||||
|
| esp_system / esp_hw | ~18KB | 系统支持 |
|
||||||
|
| lwip 协议栈 | ~4KB | TCP/IP(即使 WiFi 关闭也常驻) |
|
||||||
|
| 主应用 (main) | ~5KB | Application 框架 |
|
||||||
|
| LVGL 任务栈 | 8KB | LVGL 刷新任务 |
|
||||||
|
| **常驻小计** | **~129KB** | |
|
||||||
|
|
||||||
|
### 3.3 AI 聊天模式额外占用
|
||||||
|
|
||||||
|
| 组件 | DIRAM 占用 | 说明 |
|
||||||
|
|------|-----------|------|
|
||||||
|
| WiFi 驱动 (net80211+pp) | ~13KB 静态 + ~40-50KB 动态 | TX/RX 缓冲区 |
|
||||||
|
| RTC 协议 | ~5-10KB | 火山引擎连接 |
|
||||||
|
| 音频处理 | ~10-15KB | Opus编解码 + 管道 |
|
||||||
|
| 唤醒词 (esp-sr) | ~15-20KB | AFE + 模型加载 |
|
||||||
|
| **AI模式小计** | **~83-108KB** | |
|
||||||
|
| **AI模式总计** | **~212-237KB** | 常驻 + AI |
|
||||||
|
| **AI模式剩余** | **~97-122KB** | 用于堆分配 |
|
||||||
|
|
||||||
|
### 3.4 电子吧唧模式额外占用
|
||||||
|
|
||||||
|
| 组件 | DIRAM 占用 | 说明 |
|
||||||
|
|------|-----------|------|
|
||||||
|
| BLE Bluedroid 静态 | ~13KB | libbt.a 静态数据 |
|
||||||
|
| BLE 控制器 | ~15KB | 动态分配(PSRAM优先后减少) |
|
||||||
|
| BLE 任务栈 | ~15KB | BTC(3KB) + BTU(4KB) + 控制器 |
|
||||||
|
| dzbj 业务任务 | ~18KB | GIF(4KB) + 按键(3KB) + 电池(4KB) + 睡眠(3KB) + BLE处理(8KB) |
|
||||||
|
| **吧唧模式小计** | **~61KB** | |
|
||||||
|
| **吧唧模式总计** | **~190KB** | 常驻 + 吧唧 |
|
||||||
|
| **吧唧模式剩余** | **~144KB** | 充裕 |
|
||||||
|
|
||||||
|
### 3.5 关键结论
|
||||||
|
|
||||||
|
| 场景 | 内存占用 | 剩余 | 可行性 |
|
||||||
|
|------|----------|------|--------|
|
||||||
|
| AI 聊天模式(单独) | ~212-237KB | ~97-122KB | **可行**(偏紧) |
|
||||||
|
| 电子吧唧模式(单独) | ~190KB | ~144KB | **可行**(充裕) |
|
||||||
|
| 两模式同时运行 | ~274-345KB | 不足 | **不可行** |
|
||||||
|
| 模式切换(互斥) | 单次一个模式 | 够用 | **可行,需验证** |
|
||||||
|
|
||||||
|
**验证数据**:之前测试中 WiFi + BLE 同时运行导致 `assert failed: vQueueDelete queue.c:2355`(FreeRTOS 信号量分配失败),确认内部 SRAM 不足以支撑两者同时运行。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 四、模式切换技术方案
|
||||||
|
|
||||||
|
### 4.1 AI → 电子吧唧 切换流程
|
||||||
|
|
||||||
|
```
|
||||||
|
用户长按 BOOT 5秒
|
||||||
|
│
|
||||||
|
├─ 1. 关闭 AI 资源
|
||||||
|
│ ├─ protocol_->CloseAudioChannel() // 关闭 RTC 音频通道
|
||||||
|
│ ├─ volc_rtc_stop() + volc_rtc_destroy() // 销毁 RTC 实例
|
||||||
|
│ ├─ StopAudioProcessor() // 停止音频处理器
|
||||||
|
│ ├─ 停止唤醒词检测
|
||||||
|
│ └─ esp_wifi_stop() + esp_wifi_deinit() // 完全释放 WiFi
|
||||||
|
│ → 释放 ~83-108KB 内部 SRAM
|
||||||
|
│
|
||||||
|
├─ 2. 启动吧唧资源
|
||||||
|
│ ├─ esp_bt_controller_init() // 初始化 BLE 控制器
|
||||||
|
│ ├─ esp_bluedroid_init() + enable() // 启动 Bluedroid
|
||||||
|
│ ├─ 注册 GATT Server(图片传输服务)
|
||||||
|
│ ├─ 启动 BLE 广播
|
||||||
|
│ └─ 启动 dzbj 业务任务(按键/电池/睡眠管理)
|
||||||
|
│
|
||||||
|
└─ 3. 切换界面
|
||||||
|
└─ lv_scr_load_anim(ui_ScreenHome, ...)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.2 电子吧唧 → AI 切换流程
|
||||||
|
|
||||||
|
```
|
||||||
|
用户长按 BOOT 5秒
|
||||||
|
│
|
||||||
|
├─ 1. 关闭吧唧资源
|
||||||
|
│ ├─ esp_ble_gap_stop_advertising() // 停止广播
|
||||||
|
│ ├─ esp_ble_gatts_app_unregister() // 注销 GATT
|
||||||
|
│ ├─ esp_bluedroid_disable() + deinit() // 关闭 Bluedroid
|
||||||
|
│ ├─ esp_bt_controller_disable() + deinit() // 关闭控制器
|
||||||
|
│ └─ 停止 dzbj 业务任务
|
||||||
|
│ → 释放 ~43-61KB 内部 SRAM
|
||||||
|
│
|
||||||
|
├─ 2. 启动 AI 资源
|
||||||
|
│ ├─ esp_wifi_init() + esp_wifi_start() // 初始化 WiFi
|
||||||
|
│ ├─ WifiStation::Start() // 连接 WiFi
|
||||||
|
│ ├─ WaitForConnected() // 等待连接
|
||||||
|
│ ├─ 创建 VolcRtcProtocol 实例
|
||||||
|
│ ├─ protocol_->Start() // 启动 RTC 连接
|
||||||
|
│ └─ 启动音频处理器 + 唤醒词检测
|
||||||
|
│
|
||||||
|
└─ 3. 切换界面
|
||||||
|
└─ lv_scr_load_anim(ai_chat_screen, ...)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.3 BOOT 按键检测逻辑
|
||||||
|
|
||||||
|
```
|
||||||
|
当前逻辑(movecall_moji_esp32s3.cc):
|
||||||
|
- 单击: Idle↔Listening 切换
|
||||||
|
- 长按 5s(仅配网模式): 生产测试
|
||||||
|
|
||||||
|
需要改为:
|
||||||
|
- 单击: 保持原逻辑(AI模式下 Idle↔Listening,吧唧模式下返回 ScreenHome)
|
||||||
|
- 长按 5s: 模式切换(AI ↔ 吧唧)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 五、实施方案
|
||||||
|
|
||||||
|
### 5.1 改动清单
|
||||||
|
|
||||||
|
#### 第一步:硬件层(改动小)
|
||||||
|
|
||||||
|
| 文件 | 改动内容 | 改动程度 |
|
||||||
|
|------|----------|----------|
|
||||||
|
| `movecall-moji-esp32s3/config.h` | 添加 LCD/Touch GPIO 定义 | 小 |
|
||||||
|
| `movecall_moji_esp32s3.cc` | 初始化 LCD 驱动(参考 dzbj lcd.c) | 中 |
|
||||||
|
|
||||||
|
**GPIO 冲突注意**:
|
||||||
|
- movecall-moji `BUILTIN_LED_GPIO = GPIO_NUM_21` 与 dzbj LCD D3 (GPIO 21) 冲突
|
||||||
|
- 需要重新映射 LED 引脚或调整 LCD 引脚
|
||||||
|
- dzbj 触摸用独立 I2C 引脚(GPIO 5/6),与音频 ES8311 (GPIO 17/18) 不冲突
|
||||||
|
|
||||||
|
#### 第二步:LVGL 集成(改动中等)
|
||||||
|
|
||||||
|
| 文件 | 改动内容 | 改动程度 |
|
||||||
|
|------|----------|----------|
|
||||||
|
| `main/idf_component.yml` | 添加 lvgl 8.3.11 + esp_lvgl_port 2.5.0 + esp_lcd_st77916 | 小 |
|
||||||
|
| `main/CMakeLists.txt` | 取消注释 lcd_display.cc,添加 dzbj 模块源文件 | 中 |
|
||||||
|
| `main/ui/` | 从 dzbj 复制 SquareLine 生成的 UI 代码 | 复制 |
|
||||||
|
| `main/pages/` | 从 dzbj 复制页面管理模块 | 复制+小改 |
|
||||||
|
| `main/sleep_mgr/` | 从 dzbj 复制低功耗管理模块 | 复制+小改 |
|
||||||
|
|
||||||
|
#### 第三步:AI 聊天 UI(新开发)
|
||||||
|
|
||||||
|
| 内容 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| 创建 AI 聊天屏幕 | 基于 LVGL 8.3.11,包含 emoji 显示区 + 聊天气泡容器 + 状态栏 |
|
||||||
|
| emoji 表情渲染 | 参考 `LcdDisplay::SetEmotion()` 实现,21种表情映射 |
|
||||||
|
| 聊天气泡 | 参考 `LcdDisplay::SetChatMessage()` 实现微信风格气泡 |
|
||||||
|
| 对接 Application | SetEmotion/SetChatMessage 调用新 UI |
|
||||||
|
|
||||||
|
**注意**:`main/display/lcd_display.h` 中使用了 `lv_draw_buf_t`(LVGL 9.x 类型),需要适配为 8.3.11 的 `lv_disp_draw_buf_t`。
|
||||||
|
|
||||||
|
#### 第四步:模式切换管理(核心改动)
|
||||||
|
|
||||||
|
| 文件 | 改动内容 | 改动程度 |
|
||||||
|
|------|----------|----------|
|
||||||
|
| 新增 `mode_manager.h/cc` | 双模式状态机 + WiFi/BLE init/deinit | 新建 |
|
||||||
|
| `movecall_moji_esp32s3.cc` | BOOT 长按 5s 检测 | 中 |
|
||||||
|
| `application.cc` | 添加模式切换回调 | 中 |
|
||||||
|
|
||||||
|
### 5.2 不需要大改动的模块
|
||||||
|
|
||||||
|
| 模块 | 改动程度 | 说明 |
|
||||||
|
|------|----------|------|
|
||||||
|
| dzbj UI 代码 (ui_ScreenHome/Img/Set) | **几乎不改** | 直接复制使用 |
|
||||||
|
| dzbj pages.c (GIF/JPEG/PWM) | **小改** | 适配新的 GPIO 定义 |
|
||||||
|
| dzbj sleep_mgr | **小改** | 与 AI小智的 PowerSaveTimer 整合 |
|
||||||
|
| dzbj ble.c (图片传输) | **不改** | 电子吧唧模式下直接使用 |
|
||||||
|
| bluetooth_provisioning.cc | **不改** | 配网逻辑保持不变 |
|
||||||
|
| VolcRtcProtocol | **不改** | AI模式下原样使用 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 六、风险评估
|
||||||
|
|
||||||
|
### 6.1 高风险
|
||||||
|
|
||||||
|
| 风险 | 影响 | 缓解方案 |
|
||||||
|
|------|------|----------|
|
||||||
|
| **WiFi deinit 内存泄漏** | 每次切换泄漏几KB,多次切换后崩溃 | 实测 `esp_wifi_deinit()` 后用 `heap_caps_get_free_size()` 验证回收量 |
|
||||||
|
| **BLE deinit 内存泄漏** | Bluedroid 完全释放困难 | 考虑使用 NimBLE 替代 Bluedroid(更轻量,deinit 更可靠) |
|
||||||
|
| **内部 SRAM 碎片化** | 反复 init/deinit 导致碎片,大块分配失败 | 用 `heap_caps_get_largest_free_block()` 监控最大连续块 |
|
||||||
|
|
||||||
|
### 6.2 中等风险
|
||||||
|
|
||||||
|
| 风险 | 影响 | 缓解方案 |
|
||||||
|
|------|------|----------|
|
||||||
|
| **GPIO 引脚冲突** | LCD 引脚与现有外设冲突 (GPIO 21) | 仔细对照两个项目的 GPIO 分配表,重新映射 |
|
||||||
|
| **LVGL API 版本差异** | `lcd_display.h` 用了 `lv_draw_buf_t` (9.x) | 适配为 8.3.11 的 `lv_disp_draw_buf_t` |
|
||||||
|
| **Flash 空间** | 新增 LVGL(323KB) + emoji字体 + UI资源 | 当前 app 分区 5MB,固件 ~3.5MB,剩余 ~1.5MB 充足 |
|
||||||
|
|
||||||
|
### 6.3 低风险
|
||||||
|
|
||||||
|
| 风险 | 影响 | 缓解方案 |
|
||||||
|
|------|------|----------|
|
||||||
|
| I2C 总线共享 | 音频 ES8311 (GPIO 17/18) vs 触摸 CST816S | dzbj 触摸用独立 I2C 引脚(GPIO 5/6),不冲突 |
|
||||||
|
| PSRAM 带宽 | LVGL DMA + 音频 + WiFi 并行 | AI模式无 GIF 播放,PSRAM 带宽充足 |
|
||||||
|
| LVGL 界面切换 | 两套 UI 共存 | LVGL 对象可存放 PSRAM,界面切换无需重启 LVGL |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 七、NimBLE vs Bluedroid 选型建议
|
||||||
|
|
||||||
|
当前 dzbj 和配网都使用 Bluedroid,但在双模式切换场景下 NimBLE 更优:
|
||||||
|
|
||||||
|
| 对比项 | Bluedroid | NimBLE |
|
||||||
|
|--------|-----------|--------|
|
||||||
|
| Flash 占用 | ~277KB (libbt+libbtdm) | ~120KB |
|
||||||
|
| 内部 SRAM | ~35-45KB 动态 | ~15-20KB 动态 |
|
||||||
|
| deinit 可靠性 | 一般(可能有泄漏) | 较好 |
|
||||||
|
| Classic BT | 支持 | 不支持(仅 BLE) |
|
||||||
|
| GATT Server | 支持 | 支持 |
|
||||||
|
| 迁移工作量 | — | 中等(API 不同,逻辑相同) |
|
||||||
|
|
||||||
|
**建议**:如果不需要经典蓝牙,优先考虑迁移到 NimBLE。节省 ~150KB Flash + ~20KB 内部 SRAM,并且 deinit 更可靠。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 八、分区表设计
|
||||||
|
|
||||||
|
当前分区表(已移除 storage):
|
||||||
|
|
||||||
|
```csv
|
||||||
|
# Name, Type, SubType, Offset, Size, Flags
|
||||||
|
nvs, data, nvs, 0x9000, 0x4000,
|
||||||
|
otadata, data, ota, 0xd000, 0x2000,
|
||||||
|
phy_init, data, phy, 0xf000, 0x1000,
|
||||||
|
model, data, spiffs, 0x10000, 0x300000,
|
||||||
|
ota_0, app, ota_0, 0x310000, 5M,
|
||||||
|
ota_1, app, ota_1, 0x820000, 5M,
|
||||||
|
```
|
||||||
|
|
||||||
|
**建议**:如果需要 SPIFFS 存储图片(dzbj 的图片浏览功能),需要重新添加 storage 分区,或复用 model 分区的一部分空间。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 九、推荐实施路线
|
||||||
|
|
||||||
|
```
|
||||||
|
阶段 1: 点亮屏幕(基础验证) 预计改动量: 小
|
||||||
|
├─ 确认 LCD GPIO 映射(解决 GPIO 21 冲突)
|
||||||
|
├─ 在 main/idf_component.yml 添加 LVGL 8.3.11 依赖
|
||||||
|
├─ 在 movecall-moji 板上初始化 LCD + LVGL
|
||||||
|
├─ 显示 dzbj ScreenHome 界面
|
||||||
|
└─ 验证 LVGL + WiFi 内存占用(确认不冲突)
|
||||||
|
|
||||||
|
阶段 2: 电子吧唧模式完整复制 预计改动量: 中
|
||||||
|
├─ 复制 dzbj 的 UI/pages/ble/sleep_mgr 模块到主项目
|
||||||
|
├─ 关闭 WiFi 后启动 BLE + ScreenHome
|
||||||
|
├─ 验证 BLE 图片传输功能
|
||||||
|
└─ 验证低功耗管理
|
||||||
|
|
||||||
|
阶段 3: AI 聊天 UI 开发 预计改动量: 中
|
||||||
|
├─ 基于 LVGL 8.3.11 创建聊天屏幕(emoji + 气泡)
|
||||||
|
├─ 对接 Application 的 SetEmotion/SetChatMessage
|
||||||
|
├─ 关闭 BLE 后启动 WiFi + RTC
|
||||||
|
└─ 验证语音对话 + 屏幕显示联动
|
||||||
|
|
||||||
|
阶段 4: 模式切换集成 预计改动量: 中
|
||||||
|
├─ 实现 BOOT 长按 5s 检测
|
||||||
|
├─ 实现 WiFi ↔ BLE 完整 init/deinit 切换
|
||||||
|
├─ 界面切换 + 资源释放验证
|
||||||
|
└─ 长时间稳定性测试(反复切换 100+ 次)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 十、结论
|
||||||
|
|
||||||
|
| 问题 | 结论 |
|
||||||
|
|------|------|
|
||||||
|
| AI小智用 LVGL 9.2.2? | **不是**,当前项目无 LVGL,框架预留了 LCD 接口 |
|
||||||
|
| 显示 emoji 需要 LVGL? | **是**,emoji 字体渲染和聊天气泡都依赖 LVGL |
|
||||||
|
| 保持 LVGL 8.3.11? | **可行**,dzbj 代码直接复用 |
|
||||||
|
| 双模式切换可行? | **可行**,但需验证 WiFi/BLE deinit 的内存回收 |
|
||||||
|
| 内存够用? | **单模式够用**(AI剩余~100KB,吧唧剩余~144KB),同时运行不够 |
|
||||||
|
| dzbj 代码大改? | **不需要**,UI/pages/ble 模块几乎原样复制 |
|
||||||
|
| 最大技术风险? | **WiFi/BLE 反复 init/deinit 的内存泄漏和碎片化** |
|
||||||
|
|
||||||
|
**总体评估**:双模式互斥切换方案在技术上可行,资源预算满足单模式运行。最大不确定性在于 WiFi/BLE 的完整 deinit 是否能可靠回收内存,需要实际编码验证。建议从阶段1(点亮屏幕)开始逐步推进。
|
||||||
@ -22,7 +22,7 @@ dependencies:
|
|||||||
78/esp-opus-encoder:
|
78/esp-opus-encoder:
|
||||||
dependencies: []
|
dependencies: []
|
||||||
source:
|
source:
|
||||||
path: /Users/rdzleo/Desktop/Kapi_Rtc_toy/components/78__esp-opus-encoder
|
path: /Users/rdzleo/Desktop/Baji_Rtc_Toy/components/78__esp-opus-encoder
|
||||||
type: local
|
type: local
|
||||||
version: 2.3.3
|
version: 2.3.3
|
||||||
78/esp-wifi-connect:
|
78/esp-wifi-connect:
|
||||||
@ -107,6 +107,58 @@ dependencies:
|
|||||||
registry_url: https://components.espressif.com/
|
registry_url: https://components.espressif.com/
|
||||||
type: service
|
type: service
|
||||||
version: 1.3.6
|
version: 1.3.6
|
||||||
|
espressif/esp_lcd_st77916:
|
||||||
|
component_hash: 5fa0f8b1274576d4484e2b8d9358e2a5d09c721511bef0dce6a55b4206b5f0e9
|
||||||
|
dependencies:
|
||||||
|
- name: espressif/cmake_utilities
|
||||||
|
registry_url: https://components.espressif.com
|
||||||
|
require: private
|
||||||
|
version: 0.*
|
||||||
|
- name: idf
|
||||||
|
require: private
|
||||||
|
version: '>5.0.4,!=5.1.1'
|
||||||
|
source:
|
||||||
|
registry_url: https://components.espressif.com/
|
||||||
|
type: service
|
||||||
|
version: 1.0.1
|
||||||
|
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_cst816s:
|
||||||
|
component_hash: 51dfa9cee38d8a20f4b625d7f89120dff08c8557e613e09dfb31f53d48648235
|
||||||
|
dependencies:
|
||||||
|
- name: espressif/esp_lcd_touch
|
||||||
|
registry_url: https://components.espressif.com
|
||||||
|
require: public
|
||||||
|
version: ^1.0.4
|
||||||
|
- name: idf
|
||||||
|
require: private
|
||||||
|
version: '>=4.4.2'
|
||||||
|
source:
|
||||||
|
registry_url: https://components.espressif.com/
|
||||||
|
type: service
|
||||||
|
version: 1.1.0
|
||||||
|
espressif/esp_lvgl_port:
|
||||||
|
component_hash: bb938deffba7d80b2ce582a796c053681b0439e0a7033666688e0f1f5b921125
|
||||||
|
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.5.0
|
||||||
espressif/knob:
|
espressif/knob:
|
||||||
component_hash: a389d980693ad195b2160de22a72f3391694230188ab16b8f3c7ec4410a7c417
|
component_hash: a389d980693ad195b2160de22a72f3391694230188ab16b8f3c7ec4410a7c417
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -135,6 +187,13 @@ dependencies:
|
|||||||
source:
|
source:
|
||||||
type: idf
|
type: idf
|
||||||
version: 5.4.2
|
version: 5.4.2
|
||||||
|
lvgl/lvgl:
|
||||||
|
component_hash: 948bff879a345149b83065535bbc4a026ce9f47498a22881e432a264b9098015
|
||||||
|
dependencies: []
|
||||||
|
source:
|
||||||
|
registry_url: https://components.espressif.com/
|
||||||
|
type: service
|
||||||
|
version: 8.3.11
|
||||||
direct_dependencies:
|
direct_dependencies:
|
||||||
- 78/esp-ml307
|
- 78/esp-ml307
|
||||||
- 78/esp-opus
|
- 78/esp-opus
|
||||||
@ -143,9 +202,14 @@ direct_dependencies:
|
|||||||
- espressif/button
|
- espressif/button
|
||||||
- espressif/esp-sr
|
- espressif/esp-sr
|
||||||
- espressif/esp_codec_dev
|
- espressif/esp_codec_dev
|
||||||
|
- espressif/esp_lcd_st77916
|
||||||
|
- espressif/esp_lcd_touch
|
||||||
|
- espressif/esp_lcd_touch_cst816s
|
||||||
|
- espressif/esp_lvgl_port
|
||||||
- espressif/knob
|
- espressif/knob
|
||||||
- espressif/led_strip
|
- espressif/led_strip
|
||||||
- idf
|
- idf
|
||||||
manifest_hash: 217c85e43cd481cc56ce0b16a30be29d4ec85147267643b49c7f33df4750201f
|
- lvgl/lvgl
|
||||||
|
manifest_hash: f912ad61bf8c653f10e6eb6988299d0c0083fc812504487ba14571084326b35a
|
||||||
target: esp32s3
|
target: esp32s3
|
||||||
version: 2.0.0
|
version: 2.0.0
|
||||||
|
|||||||
@ -22,9 +22,32 @@ set(SOURCES "audio_codecs/audio_codec.cc"
|
|||||||
#"ble_service.cc" # BLE JSON 通讯服务(暂不使用,保留代码)
|
#"ble_service.cc" # BLE JSON 通讯服务(暂不使用,保留代码)
|
||||||
"weather_api.cc"
|
"weather_api.cc"
|
||||||
"main.cc"
|
"main.cc"
|
||||||
|
# dzbj 电子吧唧显示模块
|
||||||
|
"dzbj/lcd.c"
|
||||||
|
"dzbj/pages_pwm.c"
|
||||||
|
"dzbj/dzbj_init.c"
|
||||||
|
# SquareLine Studio UI 文件
|
||||||
|
"ui/ui.c"
|
||||||
|
"ui/ui_helpers.c"
|
||||||
|
"ui/screens/ui_ScreenHome.c"
|
||||||
|
"ui/screens/ui_ScreenImg.c"
|
||||||
|
"ui/screens/ui_ScreenSet.c"
|
||||||
|
"ui/components/ui_comp_hook.c"
|
||||||
|
# dzbj stub 实现(Phase 1 空实现)
|
||||||
|
"pages/pages_stub.c"
|
||||||
|
# UI 图片资源
|
||||||
|
"ui/images/ui_img_s1_png.c"
|
||||||
|
"ui/images/ui_img_s6_png.c"
|
||||||
|
"ui/images/ui_img_s8_png.c"
|
||||||
|
"ui/images/ui_img_s9_png.c"
|
||||||
|
"ui/images/ui_img_s10_png.c"
|
||||||
|
"ui/images/ui_img_s11_png.c"
|
||||||
|
"ui/images/ui_img_s12_png.c"
|
||||||
|
"ui/images/ui_img_s13_png.c"
|
||||||
|
"ui/images/ui_img_s14_png.c"
|
||||||
)
|
)
|
||||||
|
|
||||||
set(INCLUDE_DIRS "." "display" "audio_codecs" "protocols" "audio_processing" "audio")
|
set(INCLUDE_DIRS "." "display" "audio_codecs" "protocols" "audio_processing" "audio" "dzbj" "ui")
|
||||||
|
|
||||||
# 添加 IOT 相关文件
|
# 添加 IOT 相关文件
|
||||||
file(GLOB IOT_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/iot/things/*.cc)
|
file(GLOB IOT_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/iot/things/*.cc)
|
||||||
@ -201,7 +224,7 @@ endif()
|
|||||||
idf_component_register(SRCS ${SOURCES}
|
idf_component_register(SRCS ${SOURCES}
|
||||||
EMBED_FILES ${LANG_SOUNDS} ${COMMON_SOUNDS}
|
EMBED_FILES ${LANG_SOUNDS} ${COMMON_SOUNDS}
|
||||||
INCLUDE_DIRS ${INCLUDE_DIRS}
|
INCLUDE_DIRS ${INCLUDE_DIRS}
|
||||||
REQUIRES esp_wifi esp_netif esp_event nvs_flash bt spi_flash app_update efuse volc_engine_rtc_lite common zlib
|
REQUIRES esp_wifi esp_netif esp_event nvs_flash bt spi_flash app_update efuse volc_engine_rtc_lite common zlib esp_lcd driver
|
||||||
WHOLE_ARCHIVE
|
WHOLE_ARCHIVE
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@ -547,25 +547,36 @@ void Application::Start() {
|
|||||||
|
|
||||||
/* Setup the audio codec */
|
/* Setup the audio codec */
|
||||||
auto codec = board.GetAudioCodec();
|
auto codec = board.GetAudioCodec();
|
||||||
opus_decoder_ = std::make_unique<OpusDecoderWrapper>(codec->output_sample_rate(), 1, OPUS_FRAME_DURATION_MS);
|
provisioning_mode_ = WifiBoard::NeedsProvisioning();
|
||||||
opus_encoder_ = std::make_unique<OpusEncoderWrapper>(16000, 1, OPUS_FRAME_DURATION_MS);
|
|
||||||
if (realtime_chat_enabled_) {
|
|
||||||
ESP_LOGI(TAG, "实时聊天已启用,将opus编码器复杂度设置为0");// 实时聊天已启用,将opus编码器复杂度设置为0
|
|
||||||
opus_encoder_->SetComplexity(0);
|
|
||||||
} else if (board.GetBoardType() == "ml307") {
|
|
||||||
ESP_LOGI(TAG, "检测到ML307板卡,将opus编码器复杂度设置为5");// 检测到ML307板卡,将opus编码器复杂度设置为5
|
|
||||||
opus_encoder_->SetComplexity(5);
|
|
||||||
} else {
|
|
||||||
ESP_LOGI(TAG, "检测到WiFi板卡,将opus编码器复杂度设置为3");// 检测到WiFi板卡,将opus编码器复杂度设置为3
|
|
||||||
opus_encoder_->SetComplexity(3);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (codec->input_sample_rate() != 16000) {
|
// Opus 解码器始终需要(播放提示音)
|
||||||
input_resampler_.Configure(codec->input_sample_rate(), 16000);
|
opus_decoder_ = std::make_unique<OpusDecoderWrapper>(codec->output_sample_rate(), 1, OPUS_FRAME_DURATION_MS);
|
||||||
reference_resampler_.Configure(codec->input_sample_rate(), 16000);
|
|
||||||
|
if (provisioning_mode_) {
|
||||||
|
// 配网模式:跳过编码器、输入重采样器,仅启用扬声器输出
|
||||||
|
ESP_LOGI(TAG, "配网模式:跳过 Opus 编码器、输入重采样器、麦克风输入");
|
||||||
|
codec->StartOutputOnly();
|
||||||
|
} else {
|
||||||
|
// 正常模式:完整初始化
|
||||||
|
opus_encoder_ = std::make_unique<OpusEncoderWrapper>(16000, 1, OPUS_FRAME_DURATION_MS);
|
||||||
|
if (realtime_chat_enabled_) {
|
||||||
|
ESP_LOGI(TAG, "实时聊天已启用,将opus编码器复杂度设置为0");
|
||||||
|
opus_encoder_->SetComplexity(0);
|
||||||
|
} else if (board.GetBoardType() == "ml307") {
|
||||||
|
ESP_LOGI(TAG, "检测到ML307板卡,将opus编码器复杂度设置为5");
|
||||||
|
opus_encoder_->SetComplexity(5);
|
||||||
|
} else {
|
||||||
|
ESP_LOGI(TAG, "检测到WiFi板卡,将opus编码器复杂度设置为3");
|
||||||
|
opus_encoder_->SetComplexity(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (codec->input_sample_rate() != 16000) {
|
||||||
|
input_resampler_.Configure(codec->input_sample_rate(), 16000);
|
||||||
|
reference_resampler_.Configure(codec->input_sample_rate(), 16000);
|
||||||
|
}
|
||||||
|
uplink_resampler_.Configure(16000, 8000);
|
||||||
|
codec->Start();
|
||||||
}
|
}
|
||||||
uplink_resampler_.Configure(16000, 8000);
|
|
||||||
codec->Start();
|
|
||||||
{
|
{
|
||||||
int battery_level = 0;
|
int battery_level = 0;
|
||||||
bool charging = false;
|
bool charging = false;
|
||||||
@ -622,6 +633,14 @@ void Application::Start() {
|
|||||||
/* Wait for the network to be ready */
|
/* Wait for the network to be ready */
|
||||||
board.StartNetwork();
|
board.StartNetwork();
|
||||||
|
|
||||||
|
// 配网模式:跳过协议初始化、天气检测、唤醒词检测等网络相关业务
|
||||||
|
if (provisioning_mode_) {
|
||||||
|
ESP_LOGI(TAG, "配网模式:跳过协议初始化、位置检测等网络业务");
|
||||||
|
SetDeviceState(kDeviceStateIdle);
|
||||||
|
esp_timer_start_periodic(clock_timer_handle_, 1000000);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize the protocol
|
// Initialize the protocol
|
||||||
display->SetStatus(Lang::Strings::LOADING_PROTOCOL);
|
display->SetStatus(Lang::Strings::LOADING_PROTOCOL);
|
||||||
#if CONFIG_CONNECTION_TYPE_VOLC_RTC
|
#if CONFIG_CONNECTION_TYPE_VOLC_RTC
|
||||||
@ -2285,11 +2304,14 @@ void Application::SetDeviceState(DeviceState state) {
|
|||||||
wake_word_detect_.Start();
|
wake_word_detect_.Start();
|
||||||
#endif
|
#endif
|
||||||
// 设备开机后首次进入idle状态时,自动检测NVS中的位置并调用API后设置当前位置
|
// 设备开机后首次进入idle状态时,自动检测NVS中的位置并调用API后设置当前位置
|
||||||
|
// 配网模式下跳过(无 WiFi 连接,HTTP 请求必然失败)
|
||||||
if (!first_idle_location_checked_) {
|
if (!first_idle_location_checked_) {
|
||||||
first_idle_location_checked_ = true;// 首次查询城市天气
|
first_idle_location_checked_ = true;
|
||||||
Schedule([]() {
|
if (!provisioning_mode_) {
|
||||||
AutoDetectAndSetLocation();// 自动检测并设置当前位置
|
Schedule([]() {
|
||||||
});
|
AutoDetectAndSetLocation();
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case kDeviceStateConnecting:
|
case kDeviceStateConnecting:
|
||||||
|
|||||||
@ -150,6 +150,7 @@ private:
|
|||||||
bool voice_detected_ = false;
|
bool voice_detected_ = false;
|
||||||
bool audio_paused_ = false; // 音频暂停状态标志
|
bool audio_paused_ = false; // 音频暂停状态标志
|
||||||
float current_speaker_volume_ = 0.0f; // 当前扬声器音量,用于语音打断判断
|
float current_speaker_volume_ = 0.0f; // 当前扬声器音量,用于语音打断判断
|
||||||
|
bool provisioning_mode_ = false; // 配网模式标志(缓存,避免重复读NVS)
|
||||||
bool first_idle_location_checked_ = false;// 是否首次查询城市天气
|
bool first_idle_location_checked_ = false;// 是否首次查询城市天气
|
||||||
bool send_pcm_uplink_ = true; // 是否发送PCM音频数据到服务器,由SDK内部转码为G711A
|
bool send_pcm_uplink_ = true; // 是否发送PCM音频数据到服务器,由SDK内部转码为G711A
|
||||||
bool send_g711a_uplink_ = false;// 是否直接发送G711A音频数据到服务器
|
bool send_g711a_uplink_ = false;// 是否直接发送G711A音频数据到服务器
|
||||||
|
|||||||
@ -42,6 +42,22 @@ void AudioCodec::Start() {
|
|||||||
ESP_LOGI(TAG, "Audio codec started");
|
ESP_LOGI(TAG, "Audio codec started");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AudioCodec::StartOutputOnly() {
|
||||||
|
Settings settings("audio", false);
|
||||||
|
output_volume_ = settings.GetInt("output_volume", output_volume_);
|
||||||
|
if (output_volume_ <= 0) {
|
||||||
|
ESP_LOGW(TAG, "Output volume value (%d) is too small, setting to default (10)", output_volume_);
|
||||||
|
output_volume_ = 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 仅启用 TX 通道(扬声器输出),跳过 RX 通道(麦克风输入)
|
||||||
|
ESP_ERROR_CHECK(i2s_channel_enable(tx_handle_));
|
||||||
|
// 跳过: i2s_channel_enable(rx_handle_) — 配网模式不需要麦克风
|
||||||
|
// 跳过: EnableInput(true) — 不打开 ES7210 麦克风
|
||||||
|
EnableOutput(true);
|
||||||
|
ESP_LOGI(TAG, "Audio codec started (output only, provisioning mode)");
|
||||||
|
}
|
||||||
|
|
||||||
void AudioCodec::SetOutputVolume(int volume) {
|
void AudioCodec::SetOutputVolume(int volume) {
|
||||||
output_volume_ = volume;
|
output_volume_ = volume;
|
||||||
ESP_LOGI(TAG, "Set output volume to %d", output_volume_);
|
ESP_LOGI(TAG, "Set output volume to %d", output_volume_);
|
||||||
|
|||||||
@ -16,7 +16,7 @@ public:
|
|||||||
AudioCodec();
|
AudioCodec();
|
||||||
virtual ~AudioCodec();
|
virtual ~AudioCodec();
|
||||||
|
|
||||||
static constexpr int kDefaultOutputVolume = 40; // 默认输出音量 系统默认音量设置为100(最大音量),原来为70 产测固件使用
|
static constexpr int kDefaultOutputVolume = 80; // 默认输出音量 系统默认音量设置为100(最大音量),原来为70 产测固件使用
|
||||||
inline static int default_output_volume() { return kDefaultOutputVolume; }
|
inline static int default_output_volume() { return kDefaultOutputVolume; }
|
||||||
|
|
||||||
virtual void SetOutputVolume(int volume);
|
virtual void SetOutputVolume(int volume);
|
||||||
@ -25,6 +25,7 @@ public:
|
|||||||
virtual void EnableOutput(bool enable);
|
virtual void EnableOutput(bool enable);
|
||||||
|
|
||||||
void Start();
|
void Start();
|
||||||
|
void StartOutputOnly(); // 配网模式:仅启用输出通道(跳过麦克风输入)
|
||||||
void OutputData(std::vector<int16_t>& data);
|
void OutputData(std::vector<int16_t>& data);
|
||||||
bool InputData(std::vector<int16_t>& data);
|
bool InputData(std::vector<int16_t>& data);
|
||||||
|
|
||||||
|
|||||||
@ -8,25 +8,32 @@ static const char TAG[] = "BoxAudioCodec";
|
|||||||
|
|
||||||
BoxAudioCodec::BoxAudioCodec(void* i2c_master_handle, int input_sample_rate, int output_sample_rate,
|
BoxAudioCodec::BoxAudioCodec(void* i2c_master_handle, int input_sample_rate, int output_sample_rate,
|
||||||
gpio_num_t mclk, gpio_num_t bclk, gpio_num_t ws, gpio_num_t dout, gpio_num_t din,
|
gpio_num_t mclk, gpio_num_t bclk, gpio_num_t ws, gpio_num_t dout, gpio_num_t din,
|
||||||
gpio_num_t pa_pin, uint8_t es8311_addr, uint8_t es7210_addr, bool input_reference) {
|
gpio_num_t pa_pin, uint8_t es8311_addr, uint8_t es7210_addr, bool input_reference,
|
||||||
duplex_ = true; // 是否双工
|
bool output_only) {
|
||||||
input_reference_ = input_reference; // 是否使用参考输入,实现回声消除
|
output_only_ = output_only;
|
||||||
input_channels_ = input_reference_ ? 2 : 1; // 输入通道数
|
duplex_ = !output_only; // 配网模式不需要双工
|
||||||
|
input_reference_ = input_reference;
|
||||||
|
input_channels_ = input_reference_ ? 2 : 1;
|
||||||
input_sample_rate_ = input_sample_rate;
|
input_sample_rate_ = input_sample_rate;
|
||||||
output_sample_rate_ = output_sample_rate;
|
output_sample_rate_ = output_sample_rate;
|
||||||
|
|
||||||
CreateDuplexChannels(mclk, bclk, ws, dout, din);
|
if (output_only_) {
|
||||||
|
// 配网模式:仅创建 TX 通道,省 ~11.5KB RX DMA 内存
|
||||||
|
CreateTxOnlyChannel(mclk, bclk, ws, dout);
|
||||||
|
} else {
|
||||||
|
CreateDuplexChannels(mclk, bclk, ws, dout, din);
|
||||||
|
}
|
||||||
|
|
||||||
// Do initialize of related interface: data_if, ctrl_if and gpio_if
|
// 初始化 I2S 数据接口
|
||||||
audio_codec_i2s_cfg_t i2s_cfg = {
|
audio_codec_i2s_cfg_t i2s_cfg = {
|
||||||
.port = I2S_NUM_0,
|
.port = I2S_NUM_0,
|
||||||
.rx_handle = rx_handle_,
|
.rx_handle = rx_handle_, // 配网模式下为 nullptr
|
||||||
.tx_handle = tx_handle_,
|
.tx_handle = tx_handle_,
|
||||||
};
|
};
|
||||||
data_if_ = audio_codec_new_i2s_data(&i2s_cfg);
|
data_if_ = audio_codec_new_i2s_data(&i2s_cfg);
|
||||||
assert(data_if_ != NULL);
|
assert(data_if_ != NULL);
|
||||||
|
|
||||||
// Output
|
// Output(ES8311 DAC)
|
||||||
audio_codec_i2c_cfg_t i2c_cfg = {
|
audio_codec_i2c_cfg_t i2c_cfg = {
|
||||||
.port = (i2c_port_t)1,
|
.port = (i2c_port_t)1,
|
||||||
.addr = es8311_addr,
|
.addr = es8311_addr,
|
||||||
@ -57,33 +64,38 @@ BoxAudioCodec::BoxAudioCodec(void* i2c_master_handle, int input_sample_rate, int
|
|||||||
output_dev_ = esp_codec_dev_new(&dev_cfg);
|
output_dev_ = esp_codec_dev_new(&dev_cfg);
|
||||||
assert(output_dev_ != NULL);
|
assert(output_dev_ != NULL);
|
||||||
|
|
||||||
// Input
|
// Input(ES7210 ADC)— 配网模式跳过,省 ~2-4KB
|
||||||
i2c_cfg.addr = es7210_addr;
|
if (!output_only_) {
|
||||||
in_ctrl_if_ = audio_codec_new_i2c_ctrl(&i2c_cfg);
|
i2c_cfg.addr = es7210_addr;
|
||||||
assert(in_ctrl_if_ != NULL);
|
in_ctrl_if_ = audio_codec_new_i2c_ctrl(&i2c_cfg);
|
||||||
|
assert(in_ctrl_if_ != NULL);
|
||||||
|
|
||||||
es7210_codec_cfg_t es7210_cfg = {};
|
es7210_codec_cfg_t es7210_cfg = {};
|
||||||
es7210_cfg.ctrl_if = in_ctrl_if_;
|
es7210_cfg.ctrl_if = in_ctrl_if_;
|
||||||
es7210_cfg.mic_selected = ES7120_SEL_MIC1 | ES7120_SEL_MIC2;
|
es7210_cfg.mic_selected = ES7120_SEL_MIC1 | ES7120_SEL_MIC2;
|
||||||
in_codec_if_ = es7210_codec_new(&es7210_cfg);
|
in_codec_if_ = es7210_codec_new(&es7210_cfg);
|
||||||
assert(in_codec_if_ != NULL);
|
assert(in_codec_if_ != NULL);
|
||||||
|
|
||||||
dev_cfg.dev_type = ESP_CODEC_DEV_TYPE_IN;
|
dev_cfg.dev_type = ESP_CODEC_DEV_TYPE_IN;
|
||||||
dev_cfg.codec_if = in_codec_if_;
|
dev_cfg.codec_if = in_codec_if_;
|
||||||
input_dev_ = esp_codec_dev_new(&dev_cfg);
|
input_dev_ = esp_codec_dev_new(&dev_cfg);
|
||||||
assert(input_dev_ != NULL);
|
assert(input_dev_ != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
ESP_LOGI(TAG, "BoxAudioDevice initialized");
|
ESP_LOGI(TAG, "BoxAudioDevice initialized (%s)", output_only_ ? "output only" : "duplex");
|
||||||
}
|
}
|
||||||
|
|
||||||
BoxAudioCodec::~BoxAudioCodec() {
|
BoxAudioCodec::~BoxAudioCodec() {
|
||||||
ESP_ERROR_CHECK(esp_codec_dev_close(output_dev_));
|
ESP_ERROR_CHECK(esp_codec_dev_close(output_dev_));
|
||||||
esp_codec_dev_delete(output_dev_);
|
esp_codec_dev_delete(output_dev_);
|
||||||
ESP_ERROR_CHECK(esp_codec_dev_close(input_dev_));
|
|
||||||
esp_codec_dev_delete(input_dev_);
|
|
||||||
|
|
||||||
audio_codec_delete_codec_if(in_codec_if_);
|
if (input_dev_) {
|
||||||
audio_codec_delete_ctrl_if(in_ctrl_if_);
|
ESP_ERROR_CHECK(esp_codec_dev_close(input_dev_));
|
||||||
|
esp_codec_dev_delete(input_dev_);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in_codec_if_) audio_codec_delete_codec_if(in_codec_if_);
|
||||||
|
if (in_ctrl_if_) audio_codec_delete_ctrl_if(in_ctrl_if_);
|
||||||
audio_codec_delete_codec_if(out_codec_if_);
|
audio_codec_delete_codec_if(out_codec_if_);
|
||||||
audio_codec_delete_ctrl_if(out_ctrl_if_);
|
audio_codec_delete_ctrl_if(out_ctrl_if_);
|
||||||
audio_codec_delete_gpio_if(gpio_if_);
|
audio_codec_delete_gpio_if(gpio_if_);
|
||||||
@ -178,6 +190,56 @@ void BoxAudioCodec::CreateDuplexChannels(gpio_num_t mclk, gpio_num_t bclk, gpio_
|
|||||||
ESP_LOGI(TAG, "Duplex channels created");
|
ESP_LOGI(TAG, "Duplex channels created");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BoxAudioCodec::CreateTxOnlyChannel(gpio_num_t mclk, gpio_num_t bclk, gpio_num_t ws, gpio_num_t dout) {
|
||||||
|
i2s_chan_config_t chan_cfg = {
|
||||||
|
.id = I2S_NUM_0,
|
||||||
|
.role = I2S_ROLE_MASTER,
|
||||||
|
.dma_desc_num = 6,
|
||||||
|
.dma_frame_num = 240,
|
||||||
|
.auto_clear_after_cb = true,
|
||||||
|
.auto_clear_before_cb = false,
|
||||||
|
.intr_priority = 0,
|
||||||
|
};
|
||||||
|
// 仅创建 TX 通道,rx_handle_ 保持 nullptr,省 ~11.5KB RX DMA 内存
|
||||||
|
ESP_ERROR_CHECK(i2s_new_channel(&chan_cfg, &tx_handle_, NULL));
|
||||||
|
|
||||||
|
i2s_std_config_t std_cfg = {
|
||||||
|
.clk_cfg = {
|
||||||
|
.sample_rate_hz = (uint32_t)output_sample_rate_,
|
||||||
|
.clk_src = I2S_CLK_SRC_DEFAULT,
|
||||||
|
.ext_clk_freq_hz = 0,
|
||||||
|
.mclk_multiple = I2S_MCLK_MULTIPLE_256
|
||||||
|
},
|
||||||
|
.slot_cfg = {
|
||||||
|
.data_bit_width = I2S_DATA_BIT_WIDTH_16BIT,
|
||||||
|
.slot_bit_width = I2S_SLOT_BIT_WIDTH_AUTO,
|
||||||
|
.slot_mode = I2S_SLOT_MODE_STEREO,
|
||||||
|
.slot_mask = I2S_STD_SLOT_BOTH,
|
||||||
|
.ws_width = I2S_DATA_BIT_WIDTH_16BIT,
|
||||||
|
.ws_pol = false,
|
||||||
|
.bit_shift = true,
|
||||||
|
.left_align = true,
|
||||||
|
.big_endian = false,
|
||||||
|
.bit_order_lsb = false
|
||||||
|
},
|
||||||
|
.gpio_cfg = {
|
||||||
|
.mclk = mclk,
|
||||||
|
.bclk = bclk,
|
||||||
|
.ws = ws,
|
||||||
|
.dout = dout,
|
||||||
|
.din = I2S_GPIO_UNUSED,
|
||||||
|
.invert_flags = {
|
||||||
|
.mclk_inv = false,
|
||||||
|
.bclk_inv = false,
|
||||||
|
.ws_inv = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ESP_ERROR_CHECK(i2s_channel_init_std_mode(tx_handle_, &std_cfg));
|
||||||
|
ESP_LOGI(TAG, "TX-only channel created (provisioning mode)");
|
||||||
|
}
|
||||||
|
|
||||||
void BoxAudioCodec::SetOutputVolume(int volume) {
|
void BoxAudioCodec::SetOutputVolume(int volume) {
|
||||||
ESP_ERROR_CHECK(esp_codec_dev_set_out_vol(output_dev_, volume));
|
ESP_ERROR_CHECK(esp_codec_dev_set_out_vol(output_dev_, volume));
|
||||||
AudioCodec::SetOutputVolume(volume);
|
AudioCodec::SetOutputVolume(volume);
|
||||||
|
|||||||
@ -17,8 +17,10 @@ private:
|
|||||||
|
|
||||||
esp_codec_dev_handle_t output_dev_ = nullptr;
|
esp_codec_dev_handle_t output_dev_ = nullptr;
|
||||||
esp_codec_dev_handle_t input_dev_ = nullptr;
|
esp_codec_dev_handle_t input_dev_ = nullptr;
|
||||||
|
bool output_only_ = false; // 配网模式:仅输出,跳过 RX DMA 和 ES7210
|
||||||
|
|
||||||
void CreateDuplexChannels(gpio_num_t mclk, gpio_num_t bclk, gpio_num_t ws, gpio_num_t dout, gpio_num_t din);
|
void CreateDuplexChannels(gpio_num_t mclk, gpio_num_t bclk, gpio_num_t ws, gpio_num_t dout, gpio_num_t din);
|
||||||
|
void CreateTxOnlyChannel(gpio_num_t mclk, gpio_num_t bclk, gpio_num_t ws, gpio_num_t dout);
|
||||||
|
|
||||||
virtual int Read(int16_t* dest, int samples) override;
|
virtual int Read(int16_t* dest, int samples) override;
|
||||||
virtual int Write(const int16_t* data, int samples) override;
|
virtual int Write(const int16_t* data, int samples) override;
|
||||||
@ -26,7 +28,8 @@ private:
|
|||||||
public:
|
public:
|
||||||
BoxAudioCodec(void* i2c_master_handle, int input_sample_rate, int output_sample_rate,
|
BoxAudioCodec(void* i2c_master_handle, int input_sample_rate, int output_sample_rate,
|
||||||
gpio_num_t mclk, gpio_num_t bclk, gpio_num_t ws, gpio_num_t dout, gpio_num_t din,
|
gpio_num_t mclk, gpio_num_t bclk, gpio_num_t ws, gpio_num_t dout, gpio_num_t din,
|
||||||
gpio_num_t pa_pin, uint8_t es8311_addr, uint8_t es7210_addr, bool input_reference);
|
gpio_num_t pa_pin, uint8_t es8311_addr, uint8_t es7210_addr, bool input_reference,
|
||||||
|
bool output_only = false);
|
||||||
virtual ~BoxAudioCodec();
|
virtual ~BoxAudioCodec();
|
||||||
|
|
||||||
virtual void SetOutputVolume(int volume) override;
|
virtual void SetOutputVolume(int volume) override;
|
||||||
|
|||||||
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
#include "bluetooth_provisioning.h"
|
#include "bluetooth_provisioning.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
|
#include "esp_timer.h"
|
||||||
#include "esp_bt.h"
|
#include "esp_bt.h"
|
||||||
#include "esp_bt_main.h"
|
#include "esp_bt_main.h"
|
||||||
#include "esp_bt_device.h"
|
#include "esp_bt_device.h"
|
||||||
@ -1340,23 +1341,12 @@ void BluetoothProvisioning::IPEventHandler(void* arg, esp_event_base_t event_bas
|
|||||||
xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
|
xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 发送MAC地址
|
// 跳过MAC地址发送,仅通过 ReportWiFiStatus 发送连接状态
|
||||||
ESP_LOGI(TAG, "🔍 [DEBUG] 检查客户端连接状态: client_connected_=%s",
|
// // 发送MAC地址
|
||||||
self->client_connected_ ? "true" : "false");
|
// if (self && self->client_connected_) {
|
||||||
if (self && self->client_connected_) {
|
// bool mac_sent = self->SendMacAddressReliably();
|
||||||
ESP_LOGI(TAG, "🔍 [DEBUG] 使用专用函数发送设备MAC地址...");
|
// ESP_LOGI(TAG, "MAC地址发送结果: %s", mac_sent ? "成功" : "失败");
|
||||||
bool mac_sent = self->SendMacAddressReliably();
|
// }
|
||||||
if (mac_sent) {
|
|
||||||
ESP_LOGI(TAG, "✅ 设备MAC地址发送成功");
|
|
||||||
} else {
|
|
||||||
ESP_LOGW(TAG, "⚠️ 设备MAC地址发送失败");
|
|
||||||
}
|
|
||||||
|
|
||||||
ESP_LOGI(TAG, "🔍 [DEBUG] 已跳过WiFi连接报告发送,仅发送设备MAC地址");
|
|
||||||
} else {
|
|
||||||
ESP_LOGW(TAG, "🔍 [DEBUG] 无法发送: client_connected_=%s",
|
|
||||||
self->client_connected_ ? "true" : "false");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 启用WiFi配置自动保存到NVS存储
|
// 启用WiFi配置自动保存到NVS存储
|
||||||
ESP_LOGI(TAG, "💾 启用WiFi配置自动保存到NVS存储...");
|
ESP_LOGI(TAG, "💾 启用WiFi配置自动保存到NVS存储...");
|
||||||
@ -1403,11 +1393,22 @@ void BluetoothProvisioning::IPEventHandler(void* arg, esp_event_base_t event_bas
|
|||||||
self->GetStateString().c_str(),
|
self->GetStateString().c_str(),
|
||||||
self->client_connected_ ? "true" : "false");
|
self->client_connected_ ? "true" : "false");
|
||||||
|
|
||||||
// 延迟2000ms后强制重启设备
|
// 用 esp_timer 延迟重启,避免在事件回调中直接调用 esp_restart()
|
||||||
|
// 不使用 xTaskCreate,配网模式下内存紧张可能导致任务创建失败
|
||||||
ESP_LOGI(TAG, "⏰ 延迟2000ms后重启设备以确保配置生效...");
|
ESP_LOGI(TAG, "⏰ 延迟2000ms后重启设备以确保配置生效...");
|
||||||
vTaskDelay(pdMS_TO_TICKS(2000));
|
esp_timer_handle_t restart_timer;
|
||||||
ESP_LOGI(TAG, "🔄 强制重启设备...");
|
esp_timer_create_args_t timer_args = {};
|
||||||
esp_restart();
|
timer_args.callback = [](void*) {
|
||||||
|
ESP_LOGI("BLE_PROV", "🔄 强制重启设备...");
|
||||||
|
esp_restart();
|
||||||
|
};
|
||||||
|
timer_args.name = "prov_restart";
|
||||||
|
if (esp_timer_create(&timer_args, &restart_timer) == ESP_OK) {
|
||||||
|
esp_timer_start_once(restart_timer, 2000 * 1000); // 2秒,单位微秒
|
||||||
|
} else {
|
||||||
|
ESP_LOGE(TAG, "定时器创建失败,直接重启");
|
||||||
|
esp_restart();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -44,13 +44,13 @@ static const char *TAG = "WifiBoard"; ///< 日志标签,用于标识WiFi板
|
|||||||
*/
|
*/
|
||||||
WifiBoard::WifiBoard() {
|
WifiBoard::WifiBoard() {
|
||||||
// 读取NVS存储中的强制AP模式标志
|
// 读取NVS存储中的强制AP模式标志
|
||||||
|
// 注意:这里只读取不清零,清零在 StartNetwork() 中进行
|
||||||
|
// 确保后续 NeedsProvisioning() 静态方法能正确读到 force_ap=1
|
||||||
Settings settings("wifi", true);
|
Settings settings("wifi", true);
|
||||||
wifi_config_mode_ = settings.GetInt("force_ap") == 1;
|
wifi_config_mode_ = settings.GetInt("force_ap") == 1;
|
||||||
|
|
||||||
// 如果检测到强制AP模式,重置为0并记录日志
|
|
||||||
if (wifi_config_mode_) {
|
if (wifi_config_mode_) {
|
||||||
ESP_LOGI(TAG, "force_ap is set to 1, reset to 0");
|
ESP_LOGI(TAG, "force_ap is set to 1, will clear in StartNetwork()");
|
||||||
settings.SetInt("force_ap", 0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,6 +62,18 @@ std::string WifiBoard::GetBoardType() {
|
|||||||
return "wifi";
|
return "wifi";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool WifiBoard::NeedsProvisioning() {
|
||||||
|
// 检查 force_ap 标志
|
||||||
|
Settings settings("wifi", true);
|
||||||
|
if (settings.GetInt("force_ap") == 1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// 检查是否有保存的 WiFi 凭据
|
||||||
|
auto& ssid_manager = SsidManager::GetInstance();
|
||||||
|
auto ssid_list = ssid_manager.GetSsidList();
|
||||||
|
return ssid_list.empty();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 进入WiFi配置模式
|
* @brief 进入WiFi配置模式
|
||||||
*
|
*
|
||||||
@ -139,6 +151,14 @@ void WifiBoard::EnterWifiConfigMode() {
|
|||||||
* 否则尝试连接已保存的WiFi网络。
|
* 否则尝试连接已保存的WiFi网络。
|
||||||
*/
|
*/
|
||||||
void WifiBoard::StartNetwork() {
|
void WifiBoard::StartNetwork() {
|
||||||
|
// 在所有 NeedsProvisioning() 调用完成后,清除 force_ap 标志
|
||||||
|
// 防止设备在配网过程中崩溃后无限循环进入配网模式
|
||||||
|
if (wifi_config_mode_) {
|
||||||
|
Settings settings("wifi", true);
|
||||||
|
settings.SetInt("force_ap", 0);
|
||||||
|
ESP_LOGI(TAG, "force_ap cleared to 0");
|
||||||
|
}
|
||||||
|
|
||||||
// 用户可以在启动时按BOOT按钮进入WiFi配置模式
|
// 用户可以在启动时按BOOT按钮进入WiFi配置模式
|
||||||
// 开机按BOOT进入配网模式
|
// 开机按BOOT进入配网模式
|
||||||
if (wifi_config_mode_) {
|
if (wifi_config_mode_) {
|
||||||
|
|||||||
@ -139,6 +139,13 @@ public:
|
|||||||
* @return false BLE配网未激活
|
* @return false BLE配网未激活
|
||||||
*/
|
*/
|
||||||
bool IsBleProvisioningActive() const { return ble_provisioning_active_; }
|
bool IsBleProvisioningActive() const { return ble_provisioning_active_; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 早期检测是否需要配网(读NVS,无需WiFi/BLE已初始化)
|
||||||
|
* @return true 需要配网(无WiFi凭据或force_ap=1)
|
||||||
|
* 用于在板级构造函数和Application::Start()中提前跳过不必要的外设初始化
|
||||||
|
*/
|
||||||
|
static bool NeedsProvisioning();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // WIFI_BOARD_H
|
#endif // WIFI_BOARD_H
|
||||||
|
|||||||
@ -26,7 +26,7 @@
|
|||||||
#define AUDIO_INPUT_REFERENCE 0
|
#define AUDIO_INPUT_REFERENCE 0
|
||||||
|
|
||||||
// 系统指示灯与启动按钮
|
// 系统指示灯与启动按钮
|
||||||
#define BUILTIN_LED_GPIO GPIO_NUM_21 // 板载LED (GPIO 21) *******
|
#define BUILTIN_LED_GPIO GPIO_NUM_NC // 已被 LCD D3 占用(GPIO21)
|
||||||
#define BOOT_BUTTON_GPIO GPIO_NUM_0 // BOOT按钮 BOOT GPIO0
|
#define BOOT_BUTTON_GPIO GPIO_NUM_0 // BOOT按钮 BOOT GPIO0
|
||||||
|
|
||||||
// 按键GPIO定义
|
// 按键GPIO定义
|
||||||
@ -34,16 +34,20 @@
|
|||||||
#define KEY2_GPIO GPIO_NUM_NC // KEY2 - 本项目不启用该 按键
|
#define KEY2_GPIO GPIO_NUM_NC // KEY2 - 本项目不启用该 按键
|
||||||
#define KEY4_GPIO GPIO_NUM_4 // KEY4 - 播放故事(发送文本消息) Stoey GPIO04
|
#define KEY4_GPIO GPIO_NUM_4 // KEY4 - 播放故事(发送文本消息) Stoey GPIO04
|
||||||
|
|
||||||
// ADC电量检测引脚
|
// ADC电量检测引脚(GPIO6 已被触摸 RST 占用,改为 GPIO3)
|
||||||
#define BATTERY_ADC_GPIO GPIO_NUM_6 // 电池电压检测引脚(GPIO6) BAT_MEAS_ADC GPIO6
|
#define BATTERY_ADC_GPIO GPIO_NUM_3 // 电池电压检测引脚(GPIO3)
|
||||||
#define BATTERY_ADC_CHANNEL ADC_CHANNEL_5 // GPIO6对应ADC1_CHANNEL_5 ADC_CHN ADC1_CHN_5
|
#define BATTERY_ADC_CHANNEL ADC_CHANNEL_2 // GPIO3 对应 ADC1_CHANNEL_2
|
||||||
#define BATTERY_ADC_UNIT ADC_UNIT_1 // 使用ADC单元1
|
#define BATTERY_ADC_UNIT ADC_UNIT_1 // 使用ADC单元1
|
||||||
|
|
||||||
// 六路触摸按键定义
|
// 电容触摸板按钮开关(0=禁用,1=启用)
|
||||||
#define TOUCH1_GPIO GPIO_NUM_1 // Touch1 GPIO01
|
// 本项目不使用触摸按钮功能,禁用以节约资源(touch_pad驱动、ISR、FreeRTOS任务、队列)
|
||||||
|
#define ENABLE_TOUCH_PAD_BUTTONS 0
|
||||||
|
|
||||||
|
// 六路触摸按键定义(Touch1/Touch4 已被 LCD 占用)
|
||||||
|
#define TOUCH1_GPIO GPIO_NUM_NC // 已被 LCD 背光 EN 占用(GPIO1)
|
||||||
#define TOUCH2_GPIO GPIO_NUM_2 // Touch2 GPIO02
|
#define TOUCH2_GPIO GPIO_NUM_2 // Touch2 GPIO02
|
||||||
#define TOUCH3_GPIO GPIO_NUM_15 // Touch3 GPIO15
|
#define TOUCH3_GPIO GPIO_NUM_15 // Touch3 GPIO15
|
||||||
#define TOUCH4_GPIO GPIO_NUM_7 // Touch4 GPIO07
|
#define TOUCH4_GPIO GPIO_NUM_NC // 已被 LCD RST 占用(GPIO7)
|
||||||
#define TOUCH5_GPIO GPIO_NUM_NC // Touch5 (未连接)
|
#define TOUCH5_GPIO GPIO_NUM_NC // Touch5 (未连接)
|
||||||
#define TOUCH6_GPIO GPIO_NUM_NC // Touch6 (未连接)
|
#define TOUCH6_GPIO GPIO_NUM_NC // Touch6 (未连接)
|
||||||
|
|
||||||
|
|||||||
@ -14,6 +14,7 @@
|
|||||||
#include "imu_sensor_thing.h" // 引入IMU传感器IoT设备头文件
|
#include "imu_sensor_thing.h" // 引入IMU传感器IoT设备头文件
|
||||||
#include "system_info.h" // 引入系统信息头文件
|
#include "system_info.h" // 引入系统信息头文件
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
|
#include "dzbj/dzbj_init.h" // dzbj 显示模块初始化
|
||||||
#include <cmath> // 添加数学函数头文件
|
#include <cmath> // 添加数学函数头文件
|
||||||
|
|
||||||
#include <wifi_station.h>
|
#include <wifi_station.h>
|
||||||
@ -36,6 +37,7 @@
|
|||||||
#define TAG "Airhub1"
|
#define TAG "Airhub1"
|
||||||
#define Pro_TAG "Airhub"
|
#define Pro_TAG "Airhub"
|
||||||
|
|
||||||
|
#if ENABLE_TOUCH_PAD_BUTTONS
|
||||||
#include <driver/touch_pad.h>
|
#include <driver/touch_pad.h>
|
||||||
#include <driver/touch_sensor.h>
|
#include <driver/touch_sensor.h>
|
||||||
|
|
||||||
@ -61,9 +63,11 @@ typedef struct {
|
|||||||
|
|
||||||
// 前向声明TouchEventTask函数
|
// 前向声明TouchEventTask函数
|
||||||
static void TouchEventTask(void* arg);
|
static void TouchEventTask(void* arg);
|
||||||
|
#endif // ENABLE_TOUCH_PAD_BUTTONS
|
||||||
|
|
||||||
class MovecallMojiESP32S3 : public WifiBoard {
|
class MovecallMojiESP32S3 : public WifiBoard {
|
||||||
private:
|
private:
|
||||||
|
#if ENABLE_TOUCH_PAD_BUTTONS
|
||||||
// 触摸状态相关
|
// 触摸状态相关
|
||||||
touch_state_t touch_states_[4]; // 每个触摸点的状态
|
touch_state_t touch_states_[4]; // 每个触摸点的状态
|
||||||
uint32_t touch_last_time_[4]; // 每个触摸点的最后操作时间
|
uint32_t touch_last_time_[4]; // 每个触摸点的最后操作时间
|
||||||
@ -79,10 +83,13 @@ private:
|
|||||||
int active_touch_pad_ = -1; // 当前活跃的触摸点编号
|
int active_touch_pad_ = -1; // 当前活跃的触摸点编号
|
||||||
uint32_t touch_task_start_time_ = 0; // 触摸任务开始时间
|
uint32_t touch_task_start_time_ = 0; // 触摸任务开始时间
|
||||||
const uint32_t TOUCH_TASK_TIMEOUT_MS = 10000; // 任务超时时间(10秒)
|
const uint32_t TOUCH_TASK_TIMEOUT_MS = 10000; // 任务超时时间(10秒)
|
||||||
|
#endif // ENABLE_TOUCH_PAD_BUTTONS
|
||||||
|
|
||||||
PowerSaveTimer* power_save_timer_;
|
PowerSaveTimer* power_save_timer_;
|
||||||
static MovecallMojiESP32S3* instance_;
|
static MovecallMojiESP32S3* instance_;
|
||||||
|
#if ENABLE_TOUCH_PAD_BUTTONS
|
||||||
static void IRAM_ATTR TouchPadISR(void* arg);
|
static void IRAM_ATTR TouchPadISR(void* arg);
|
||||||
|
#endif
|
||||||
i2c_master_bus_handle_t codec_i2c_bus_;
|
i2c_master_bus_handle_t codec_i2c_bus_;
|
||||||
|
|
||||||
// QMI8658A姿态传感器相关
|
// QMI8658A姿态传感器相关
|
||||||
@ -116,17 +123,20 @@ private:
|
|||||||
Button story_button_{KEY4_GPIO};
|
Button story_button_{KEY4_GPIO};
|
||||||
|
|
||||||
bool production_test_mode_ = false;// 是否开启生产测试模式
|
bool production_test_mode_ = false;// 是否开启生产测试模式
|
||||||
|
#if ENABLE_TOUCH_PAD_BUTTONS
|
||||||
static const int TOUCH_QUEUE_SIZE = 5;// 触摸事件队列大小
|
static const int TOUCH_QUEUE_SIZE = 5;// 触摸事件队列大小
|
||||||
|
|
||||||
// 生产测试模式触摸检测标志位
|
// 生产测试模式触摸检测标志位
|
||||||
bool touch_detected_flag_ = false; // 触摸检测标志位
|
bool touch_detected_flag_ = false; // 触摸检测标志位
|
||||||
int touched_pad_index_ = -1; // 被触摸的触摸板索引
|
int touched_pad_index_ = -1; // 被触摸的触摸板索引
|
||||||
|
#endif
|
||||||
|
|
||||||
void EnterProductionTestMode();// 进入生产测试模式函数
|
void EnterProductionTestMode();// 进入生产测试模式函数
|
||||||
|
|
||||||
void ReportDeviceStatus(int battery_level);// 上报设备状态到服务器
|
void ReportDeviceStatus(int battery_level);// 上报设备状态到服务器
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
#if ENABLE_TOUCH_PAD_BUTTONS
|
||||||
// 将静态队列句柄移到public以便静态函数访问
|
// 将静态队列句柄移到public以便静态函数访问
|
||||||
static QueueHandle_t touch_event_queue_;
|
static QueueHandle_t touch_event_queue_;
|
||||||
|
|
||||||
@ -138,6 +148,7 @@ public:
|
|||||||
void LockTouchTask(int touch_pad_num);
|
void LockTouchTask(int touch_pad_num);
|
||||||
// 解锁触摸任务,允许处理新的触摸
|
// 解锁触摸任务,允许处理新的触摸
|
||||||
void UnlockTouchTask();
|
void UnlockTouchTask();
|
||||||
|
#endif // ENABLE_TOUCH_PAD_BUTTONS
|
||||||
|
|
||||||
// 获取电池电量百分比
|
// 获取电池电量百分比
|
||||||
bool GetBatteryLevel(int &level, bool& charging, bool& discharging) override {
|
bool GetBatteryLevel(int &level, bool& charging, bool& discharging) override {
|
||||||
@ -171,10 +182,9 @@ public:
|
|||||||
status_report_ticks_(0),
|
status_report_ticks_(0),
|
||||||
status_report_enabled_(false),
|
status_report_enabled_(false),
|
||||||
rtc_online_(false),
|
rtc_online_(false),
|
||||||
production_test_mode_(false),
|
production_test_mode_(false)
|
||||||
touch_detected_flag_(false),
|
|
||||||
touched_pad_index_(-1)
|
|
||||||
{
|
{
|
||||||
|
#if ENABLE_TOUCH_PAD_BUTTONS
|
||||||
// 初始化触摸状态
|
// 初始化触摸状态
|
||||||
for (int i = 0; i < 4; ++i) {
|
for (int i = 0; i < 4; ++i) {
|
||||||
touch_states_[i] = TOUCH_STATE_IDLE;
|
touch_states_[i] = TOUCH_STATE_IDLE;
|
||||||
@ -187,6 +197,9 @@ public:
|
|||||||
touch_task_locked_ = false;
|
touch_task_locked_ = false;
|
||||||
active_touch_pad_ = -1;
|
active_touch_pad_ = -1;
|
||||||
touch_task_start_time_ = 0;
|
touch_task_start_time_ = 0;
|
||||||
|
touch_detected_flag_ = false;
|
||||||
|
touched_pad_index_ = -1;
|
||||||
|
#endif
|
||||||
|
|
||||||
// 使用240MHz作为CPU最大频率,10秒进入睡眠,-1表示不自动关机
|
// 使用240MHz作为CPU最大频率,10秒进入睡眠,-1表示不自动关机
|
||||||
power_save_timer_ = new PowerSaveTimer(240, 10, -1);
|
power_save_timer_ = new PowerSaveTimer(240, 10, -1);
|
||||||
@ -221,25 +234,34 @@ public:
|
|||||||
// 初始化I2C总线(必须在IMU传感器初始化之前)
|
// 初始化I2C总线(必须在IMU传感器初始化之前)
|
||||||
InitializeCodecI2c();
|
InitializeCodecI2c();
|
||||||
|
|
||||||
|
// 初始化 dzbj 显示模块(LCD + Touch + LVGL + UI)
|
||||||
|
dzbj_display_init(codec_i2c_bus_);
|
||||||
|
|
||||||
// 初始化IoT功能,启用语音音量控制
|
// 初始化IoT功能,启用语音音量控制
|
||||||
InitializeIot();
|
InitializeIot();
|
||||||
|
|
||||||
// 初始化电量检测
|
// 配网模式下跳过非必要外设,节省内部 DRAM 给 WiFi+BLE 使用
|
||||||
InitializeBatteryMonitor();
|
bool provisioning_mode = WifiBoard::NeedsProvisioning();
|
||||||
|
if (provisioning_mode) {
|
||||||
|
ESP_LOGI(TAG, "配网模式:跳过电池检测、IMU传感器、低功耗管理");
|
||||||
|
battery_level_ = 100; // 设置默认电量
|
||||||
|
} else {
|
||||||
|
// 初始化电量检测
|
||||||
|
InitializeBatteryMonitor();
|
||||||
|
|
||||||
// 初始化IMU传感器
|
// 初始化IMU传感器
|
||||||
InitializeImuSensor();
|
InitializeImuSensor();
|
||||||
|
|
||||||
// 启用PowerSaveTimer,启用完整的低功耗管理
|
// 启用PowerSaveTimer,启用完整的低功耗管理
|
||||||
power_save_timer_->SetEnabled(true);
|
power_save_timer_->SetEnabled(true);
|
||||||
ESP_LOGI(TAG, "🔋 PowerSaveTimer已启用,20秒无活动将进入低功耗模式");
|
ESP_LOGI(TAG, "🔋 PowerSaveTimer已启用,20秒无活动将进入低功耗模式");
|
||||||
|
}
|
||||||
|
|
||||||
|
#if ENABLE_TOUCH_PAD_BUTTONS
|
||||||
// 延迟调用触摸板初始化,避免在构造函数中就调用
|
// 延迟调用触摸板初始化,避免在构造函数中就调用
|
||||||
ESP_LOGI(TAG, "在构造函数完成后调用触摸初始化");
|
ESP_LOGI(TAG, "在构造函数完成后调用触摸初始化");
|
||||||
// 使用task来延迟初始化触摸功能
|
|
||||||
xTaskCreate([](void* arg) {
|
xTaskCreate([](void* arg) {
|
||||||
MovecallMojiESP32S3* board = static_cast<MovecallMojiESP32S3*>(arg);
|
MovecallMojiESP32S3* board = static_cast<MovecallMojiESP32S3*>(arg);
|
||||||
// 延迟一段时间,确保其他组件初始化完成
|
|
||||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||||
ESP_LOGI(TAG, "开始延迟初始化触摸板...");
|
ESP_LOGI(TAG, "开始延迟初始化触摸板...");
|
||||||
if (board) {
|
if (board) {
|
||||||
@ -247,157 +269,99 @@ public:
|
|||||||
}
|
}
|
||||||
vTaskDelete(NULL);
|
vTaskDelete(NULL);
|
||||||
}, "touch_init", 4096, this, 5, NULL);
|
}, "touch_init", 4096, this, 5, NULL);
|
||||||
|
#else
|
||||||
|
ESP_LOGI(TAG, "电容触摸板按钮已禁用 (ENABLE_TOUCH_PAD_BUTTONS=0)");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_TOUCH_PAD_BUTTONS
|
||||||
// 发送触摸消息
|
// 发送触摸消息
|
||||||
void SendTouchMessage(int touch_pad_num) {
|
void SendTouchMessage(int touch_pad_num) {
|
||||||
const char* message = nullptr;
|
const char* message = nullptr;
|
||||||
power_save_timer_->WakeUp();
|
power_save_timer_->WakeUp();
|
||||||
|
|
||||||
// 获取当前应用状态
|
|
||||||
auto& app = Application::GetInstance();
|
auto& app = Application::GetInstance();
|
||||||
auto current_state = app.GetDeviceState();
|
auto current_state = app.GetDeviceState();
|
||||||
|
|
||||||
// 仅在 Dialog 对话状态且内部 listening 开启时有效
|
|
||||||
if (!(current_state == kDeviceStateDialog && app.IsDialogUploadEnabled())) {
|
if (!(current_state == kDeviceStateDialog && app.IsDialogUploadEnabled())) {
|
||||||
ESP_LOGI(TAG, "触摸事件无效:仅在Dialog+listening内部状态下有效");
|
ESP_LOGI(TAG, "触摸事件无效:仅在Dialog+listening内部状态下有效");
|
||||||
if (touch_task_locked_ && active_touch_pad_ == touch_pad_num) {
|
if (touch_task_locked_ && active_touch_pad_ == touch_pad_num) {
|
||||||
xTaskCreate([](void* arg) {
|
xTaskCreate([](void* arg) {
|
||||||
MovecallMojiESP32S3* board = static_cast<MovecallMojiESP32S3*>(arg);
|
static_cast<MovecallMojiESP32S3*>(arg)->UnlockTouchTask();
|
||||||
if (board) {
|
|
||||||
board->UnlockTouchTask();
|
|
||||||
}
|
|
||||||
vTaskDelete(NULL);
|
vTaskDelete(NULL);
|
||||||
}, "unlock_invalid_state", 4096, this, 5, NULL);
|
}, "unlock", 4096, this, 5, NULL);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 根据流程图中的情况处理触摸事件:
|
|
||||||
// 1. 如果当前是Speaking状态,触摸事件不生效
|
|
||||||
if (current_state == kDeviceStateSpeaking) {
|
if (current_state == kDeviceStateSpeaking) {
|
||||||
ESP_LOGI(TAG, "当前处于Speaking状态,触摸事件被忽略");
|
|
||||||
// 由于任务未能执行,立即解锁触摸任务
|
|
||||||
if (touch_task_locked_ && active_touch_pad_ == touch_pad_num) {
|
if (touch_task_locked_ && active_touch_pad_ == touch_pad_num) {
|
||||||
ESP_LOGI(TAG, "触摸任务无法执行,创建任务来解锁");
|
|
||||||
// 创建任务来解锁,避免直接调用可能导致栈溢出的操作
|
|
||||||
xTaskCreate([](void* arg) {
|
xTaskCreate([](void* arg) {
|
||||||
MovecallMojiESP32S3* board = static_cast<MovecallMojiESP32S3*>(arg);
|
static_cast<MovecallMojiESP32S3*>(arg)->UnlockTouchTask();
|
||||||
if (board) {
|
|
||||||
board->UnlockTouchTask();
|
|
||||||
}
|
|
||||||
vTaskDelete(NULL);
|
vTaskDelete(NULL);
|
||||||
}, "unlock_failed", 4096, this, 5, NULL);
|
}, "unlock", 4096, this, 5, NULL);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 如果当前是Listening状态且已检测到语音输入,触摸事件不生效
|
|
||||||
if (current_state == kDeviceStateListening && app.IsVoiceDetected()) {
|
if (current_state == kDeviceStateListening && app.IsVoiceDetected()) {
|
||||||
ESP_LOGI(TAG, "当前处于Listening状态且已检测到语音输入,触摸事件被忽略");
|
|
||||||
// 由于任务未能执行,立即解锁触摸任务
|
|
||||||
if (touch_task_locked_ && active_touch_pad_ == touch_pad_num) {
|
if (touch_task_locked_ && active_touch_pad_ == touch_pad_num) {
|
||||||
ESP_LOGI(TAG, "触摸任务无法执行,创建任务来解锁");
|
|
||||||
// 创建任务来解锁,避免直接调用可能导致栈溢出的操作
|
|
||||||
xTaskCreate([](void* arg) {
|
xTaskCreate([](void* arg) {
|
||||||
MovecallMojiESP32S3* board = static_cast<MovecallMojiESP32S3*>(arg);
|
static_cast<MovecallMojiESP32S3*>(arg)->UnlockTouchTask();
|
||||||
if (board) {
|
|
||||||
board->UnlockTouchTask();
|
|
||||||
}
|
|
||||||
vTaskDelete(NULL);
|
vTaskDelete(NULL);
|
||||||
}, "unlock_failed", 4096, this, 5, NULL);
|
}, "unlock", 4096, this, 5, NULL);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 根据触摸点选择消息
|
|
||||||
switch (touch_pad_num) {
|
switch (touch_pad_num) {
|
||||||
case 0: message = "有人在摸摸你的脑袋"; break;
|
case 0: message = "有人在摸摸你的肚子"; break;
|
||||||
case 1: message = "有人在摸摸你的肚子"; break;
|
case 1: message = "有人在摸摸你的下巴"; break;
|
||||||
case 2: message = "有人在摸摸你的下巴"; break;
|
|
||||||
case 3: message = "有人在摸摸你的后背"; break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 发送消息
|
|
||||||
if (message != nullptr) {
|
if (message != nullptr) {
|
||||||
ESP_LOGI(TAG, "发送触摸消息: \"%s\"", message);
|
ESP_LOGI(TAG, "发送触摸消息: \"%s\"", message);
|
||||||
|
|
||||||
// 仅在 Dialog+内部listening 下发送;其他状态在前面已返回
|
|
||||||
|
|
||||||
// SendTextMessage内部会自动检查协议是否初始化
|
|
||||||
app.SendTextMessage(message);
|
app.SendTextMessage(message);
|
||||||
ESP_LOGI(TAG, "消息已发送");
|
|
||||||
|
|
||||||
// 消息已发送,开始监听语音回复
|
|
||||||
// 任务将在收到回复或超时后结束
|
|
||||||
// 通过TaskStateMonitor监听设备状态变化
|
|
||||||
|
|
||||||
// 创建一个任务来监控设备状态变化
|
|
||||||
if (touch_task_locked_ && active_touch_pad_ == touch_pad_num) {
|
if (touch_task_locked_ && active_touch_pad_ == touch_pad_num) {
|
||||||
ESP_LOGI(TAG, "创建任务状态监控");
|
|
||||||
|
|
||||||
xTaskCreate([](void* arg) {
|
xTaskCreate([](void* arg) {
|
||||||
MovecallMojiESP32S3* board = static_cast<MovecallMojiESP32S3*>(arg);
|
MovecallMojiESP32S3* board = static_cast<MovecallMojiESP32S3*>(arg);
|
||||||
auto& app = Application::GetInstance();
|
auto& app = Application::GetInstance();
|
||||||
uint32_t start_time = esp_timer_get_time() / 1000;
|
uint32_t start_time = esp_timer_get_time() / 1000;
|
||||||
|
|
||||||
// 等待设备状态变为Speaking或超时
|
|
||||||
// 如果超时或设备重新回到Idle状态,则解锁触摸任务
|
|
||||||
while (true) {
|
while (true) {
|
||||||
auto state = app.GetDeviceState();
|
auto state = app.GetDeviceState();
|
||||||
uint32_t current_time = esp_timer_get_time() / 1000;
|
uint32_t elapsed = esp_timer_get_time() / 1000 - start_time;
|
||||||
uint32_t elapsed = current_time - start_time;
|
|
||||||
|
|
||||||
// 如果设备开始说话,等待它说完
|
|
||||||
if (state == kDeviceStateSpeaking) {
|
if (state == kDeviceStateSpeaking) {
|
||||||
ESP_LOGI(TAG, "检测到设备进入Speaking状态,等待说话完成");
|
|
||||||
// 等待设备回到Idle状态
|
|
||||||
while (app.GetDeviceState() == kDeviceStateSpeaking) {
|
while (app.GetDeviceState() == kDeviceStateSpeaking) {
|
||||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||||
|
if (esp_timer_get_time() / 1000 - start_time > 30000) break;
|
||||||
// 检查超时
|
|
||||||
uint32_t now = esp_timer_get_time() / 1000;
|
|
||||||
if (now - start_time > 30000) { // 30秒超时
|
|
||||||
ESP_LOGW(TAG, "等待说话完成超时");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ESP_LOGI(TAG, "设备说话已完成,解锁触摸任务");
|
|
||||||
board->UnlockTouchTask();
|
board->UnlockTouchTask();
|
||||||
break;
|
break;
|
||||||
}
|
} else if (state == kDeviceStateIdle && elapsed > 1000) {
|
||||||
// 如果设备回到Idle状态,可能是消息被忽略
|
board->UnlockTouchTask();
|
||||||
else if (state == kDeviceStateIdle && elapsed > 1000) {
|
break;
|
||||||
ESP_LOGW(TAG, "设备回到Idle状态,消息可能被忽略");
|
} else if (elapsed > 10000) {
|
||||||
board->UnlockTouchTask();
|
board->UnlockTouchTask();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// 如果等待太久,自动解锁
|
|
||||||
else if (elapsed > 10000) { // 10秒超时
|
|
||||||
ESP_LOGW(TAG, "等待回复超时,解锁触摸任务");
|
|
||||||
board->UnlockTouchTask();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
vTaskDelay(200 / portTICK_PERIOD_MS);
|
vTaskDelay(200 / portTICK_PERIOD_MS);
|
||||||
}
|
}
|
||||||
vTaskDelete(NULL);
|
vTaskDelete(NULL);
|
||||||
}, "task_monitor", 8192, this, 5, NULL);
|
}, "task_monitor", 8192, this, 5, NULL);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 无效的触摸点或消息,自动解锁
|
|
||||||
if (touch_task_locked_ && active_touch_pad_ == touch_pad_num) {
|
if (touch_task_locked_ && active_touch_pad_ == touch_pad_num) {
|
||||||
// 创建任务来解锁
|
|
||||||
xTaskCreate([](void* arg) {
|
xTaskCreate([](void* arg) {
|
||||||
MovecallMojiESP32S3* board = static_cast<MovecallMojiESP32S3*>(arg);
|
static_cast<MovecallMojiESP32S3*>(arg)->UnlockTouchTask();
|
||||||
if (board) {
|
|
||||||
board->UnlockTouchTask();
|
|
||||||
}
|
|
||||||
vTaskDelete(NULL);
|
vTaskDelete(NULL);
|
||||||
}, "unlock_invalid", 4096, this, 5, NULL);
|
}, "unlock", 4096, this, 5, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif // ENABLE_TOUCH_PAD_BUTTONS
|
||||||
|
|
||||||
// 析构函数
|
// 析构函数
|
||||||
~MovecallMojiESP32S3() {
|
~MovecallMojiESP32S3() {
|
||||||
@ -512,6 +476,7 @@ public:
|
|||||||
last_click_time = current_time;
|
last_click_time = current_time;
|
||||||
ESP_LOGI(TAG, "BOOT button clicked");
|
ESP_LOGI(TAG, "BOOT button clicked");
|
||||||
|
|
||||||
|
#if ENABLE_TOUCH_PAD_BUTTONS
|
||||||
// 创建一个单独的任务来处理触摸解锁,避免在按钮回调中执行复杂操作
|
// 创建一个单独的任务来处理触摸解锁,避免在按钮回调中执行复杂操作
|
||||||
xTaskCreate([](void* arg) {
|
xTaskCreate([](void* arg) {
|
||||||
MovecallMojiESP32S3* board = static_cast<MovecallMojiESP32S3*>(arg);
|
MovecallMojiESP32S3* board = static_cast<MovecallMojiESP32S3*>(arg);
|
||||||
@ -520,6 +485,7 @@ public:
|
|||||||
}
|
}
|
||||||
vTaskDelete(NULL);
|
vTaskDelete(NULL);
|
||||||
}, "boot_unlock", 4096, this, 5, NULL);
|
}, "boot_unlock", 4096, this, 5, NULL);
|
||||||
|
#endif
|
||||||
|
|
||||||
// 获取当前应用实例和状态
|
// 获取当前应用实例和状态
|
||||||
auto &app = Application::GetInstance();
|
auto &app = Application::GetInstance();
|
||||||
@ -1367,15 +1333,16 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if ENABLE_TOUCH_PAD_BUTTONS
|
||||||
// 设置触摸阈值
|
// 设置触摸阈值
|
||||||
void CalibrateTouchThresholds() {
|
void CalibrateTouchThresholds() {
|
||||||
touch_pad_t touch_pads[4] = {TOUCH_PAD_NUM1, TOUCH_PAD_NUM2, TOUCH_PAD_NUM3, TOUCH_PAD_NUM7};
|
touch_pad_t touch_pads[2] = {TOUCH_PAD_NUM2, TOUCH_PAD_NUM3}; // Touch1(GPIO1)/Touch4(GPIO7) 被 LCD 占用
|
||||||
|
|
||||||
// 使用固定阈值5000
|
// 使用固定阈值5000
|
||||||
uint32_t default_threshold = 5000; // 设置为5000,降低灵敏度减少误触发
|
uint32_t default_threshold = 5000; // 设置为5000,降低灵敏度减少误触发
|
||||||
|
|
||||||
// 为每个触摸板设置阈值
|
// 为每个触摸板设置阈值
|
||||||
for (int i = 0; i < 4; ++i) {
|
for (int i = 0; i < 2; ++i) {
|
||||||
// 先读取原始值作为参考
|
// 先读取原始值作为参考
|
||||||
uint32_t touch_value = 0;
|
uint32_t touch_value = 0;
|
||||||
esp_err_t ret = touch_pad_read_raw_data(touch_pads[i], &touch_value);
|
esp_err_t ret = touch_pad_read_raw_data(touch_pads[i], &touch_value);
|
||||||
@ -1448,9 +1415,9 @@ public:
|
|||||||
|
|
||||||
// 配置触摸传感器
|
// 配置触摸传感器
|
||||||
ESP_LOGI(TAG, "配置触摸传感器...");
|
ESP_LOGI(TAG, "配置触摸传感器...");
|
||||||
touch_pad_t touch_pads[4] = {TOUCH_PAD_NUM1, TOUCH_PAD_NUM2, TOUCH_PAD_NUM3, TOUCH_PAD_NUM7};
|
touch_pad_t touch_pads[2] = {TOUCH_PAD_NUM2, TOUCH_PAD_NUM3}; // Touch1(GPIO1)/Touch4(GPIO7) 被 LCD 占用
|
||||||
|
|
||||||
for (int i = 0; i < 4; ++i) {
|
for (int i = 0; i < 2; ++i) {
|
||||||
touch_pad_config(touch_pads[i]);
|
touch_pad_config(touch_pads[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1486,6 +1453,7 @@ public:
|
|||||||
touch_pad_fsm_start();
|
touch_pad_fsm_start();
|
||||||
ESP_LOGI(TAG, "触摸板初始化完成");
|
ESP_LOGI(TAG, "触摸板初始化完成");
|
||||||
}
|
}
|
||||||
|
#endif // ENABLE_TOUCH_PAD_BUTTONS
|
||||||
|
|
||||||
AudioCodec* GetAudioCodec() {
|
AudioCodec* GetAudioCodec() {
|
||||||
// 使用延迟初始化模式,确保I2C总线和编解码器按正确顺序初始化
|
// 使用延迟初始化模式,确保I2C总线和编解码器按正确顺序初始化
|
||||||
@ -1495,7 +1463,10 @@ public:
|
|||||||
if (audio_codec == nullptr && !init_attempted) {
|
if (audio_codec == nullptr && !init_attempted) {
|
||||||
init_attempted = true; // 标记为已尝试初始化
|
init_attempted = true; // 标记为已尝试初始化
|
||||||
|
|
||||||
ESP_LOGI(TAG, "Initializing audio codec...");
|
// 配网模式:仅创建 TX 通道,跳过 RX DMA(~11.5KB)和 ES7210(~2-4KB)
|
||||||
|
bool output_only = WifiBoard::NeedsProvisioning();
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "Initializing audio codec (%s)...", output_only ? "output only" : "duplex");
|
||||||
// 确保I2C总线已初始化
|
// 确保I2C总线已初始化
|
||||||
if (codec_i2c_bus_ == nullptr) {
|
if (codec_i2c_bus_ == nullptr) {
|
||||||
ESP_LOGI(TAG, "Initializing I2C bus for audio codec...");
|
ESP_LOGI(TAG, "Initializing I2C bus for audio codec...");
|
||||||
@ -1504,7 +1475,9 @@ public:
|
|||||||
|
|
||||||
if (codec_i2c_bus_ != nullptr) {
|
if (codec_i2c_bus_ != nullptr) {
|
||||||
try {
|
try {
|
||||||
ESP_LOGI(TAG, "Creating BoxAudioCodec (ES8311+ES7210, %s reference) ...", AUDIO_INPUT_REFERENCE ? "with" : "without");
|
ESP_LOGI(TAG, "Creating BoxAudioCodec (ES8311%s, %s reference) ...",
|
||||||
|
output_only ? "" : "+ES7210",
|
||||||
|
AUDIO_INPUT_REFERENCE ? "with" : "without");
|
||||||
audio_codec = new BoxAudioCodec(
|
audio_codec = new BoxAudioCodec(
|
||||||
codec_i2c_bus_,
|
codec_i2c_bus_,
|
||||||
AUDIO_INPUT_SAMPLE_RATE,
|
AUDIO_INPUT_SAMPLE_RATE,
|
||||||
@ -1517,7 +1490,8 @@ public:
|
|||||||
AUDIO_CODEC_PA_PIN,
|
AUDIO_CODEC_PA_PIN,
|
||||||
AUDIO_CODEC_ES8311_ADDR,
|
AUDIO_CODEC_ES8311_ADDR,
|
||||||
AUDIO_CODEC_ES7210_ADDR,
|
AUDIO_CODEC_ES7210_ADDR,
|
||||||
AUDIO_INPUT_REFERENCE
|
AUDIO_INPUT_REFERENCE,
|
||||||
|
output_only
|
||||||
);
|
);
|
||||||
ESP_LOGI(TAG, "Audio codec initialized successfully");
|
ESP_LOGI(TAG, "Audio codec initialized successfully");
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
@ -1534,8 +1508,9 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual Led* GetLed() override {
|
virtual Led* GetLed() override {
|
||||||
static SingleLed led_strip(BUILTIN_LED_GPIO);// 初始化单灯条对象
|
// BUILTIN_LED_GPIO 为 NC(GPIO21 已被 LCD D3 占用)
|
||||||
return &led_strip;
|
static NoLed no_led;
|
||||||
|
return &no_led;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Display* GetDisplay() override {
|
virtual Display* GetDisplay() override {
|
||||||
@ -1637,6 +1612,7 @@ void MovecallMojiESP32S3::ReportDeviceStatus(int battery_level) {
|
|||||||
|
|
||||||
// 初始化静态成员变量
|
// 初始化静态成员变量
|
||||||
MovecallMojiESP32S3* MovecallMojiESP32S3::instance_ = nullptr;
|
MovecallMojiESP32S3* MovecallMojiESP32S3::instance_ = nullptr;
|
||||||
|
#if ENABLE_TOUCH_PAD_BUTTONS
|
||||||
QueueHandle_t MovecallMojiESP32S3::touch_event_queue_ = nullptr;
|
QueueHandle_t MovecallMojiESP32S3::touch_event_queue_ = nullptr;
|
||||||
|
|
||||||
// 处理触摸事件的任务
|
// 处理触摸事件的任务
|
||||||
@ -1674,7 +1650,7 @@ static void TouchEventTask(void* arg) {
|
|||||||
// 收到实际触摸事件(应该都是按下事件)
|
// 收到实际触摸事件(应该都是按下事件)
|
||||||
uint32_t current_time = esp_timer_get_time() / 1000; // 当前时间(毫秒)
|
uint32_t current_time = esp_timer_get_time() / 1000; // 当前时间(毫秒)
|
||||||
|
|
||||||
if (touch_event.pad_num >= 0 && touch_event.pad_num < 4) {
|
if (touch_event.pad_num >= 0 && touch_event.pad_num < 2) {
|
||||||
int pad = touch_event.pad_num;
|
int pad = touch_event.pad_num;
|
||||||
|
|
||||||
// 记录详细的调试信息
|
// 记录详细的调试信息
|
||||||
@ -1704,7 +1680,7 @@ static void TouchEventTask(void* arg) {
|
|||||||
uint32_t current_time = esp_timer_get_time() / 1000; // 毫秒
|
uint32_t current_time = esp_timer_get_time() / 1000; // 毫秒
|
||||||
|
|
||||||
// 检查每个触摸点
|
// 检查每个触摸点
|
||||||
for (int i = 0; i < 4; ++i) {
|
for (int i = 0; i < 2; ++i) {
|
||||||
if (is_touch_active[i]) {
|
if (is_touch_active[i]) {
|
||||||
// 如果触摸点处于激活状态并超过释放延迟
|
// 如果触摸点处于激活状态并超过释放延迟
|
||||||
if (current_time - touch_start_time[i] >= RELEASE_DELAY_MS) {
|
if (current_time - touch_start_time[i] >= RELEASE_DELAY_MS) {
|
||||||
@ -1717,8 +1693,8 @@ static void TouchEventTask(void* arg) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 检查触摸状态 (使用touch_pad_read_raw_data直接读取触摸值)
|
// 检查触摸状态 (使用touch_pad_read_raw_data直接读取触摸值)
|
||||||
touch_pad_t touch_pads[4] = {TOUCH_PAD_NUM1, TOUCH_PAD_NUM2, TOUCH_PAD_NUM3, TOUCH_PAD_NUM7};
|
touch_pad_t touch_pads[2] = {TOUCH_PAD_NUM2, TOUCH_PAD_NUM3}; // Touch1(GPIO1)/Touch4(GPIO7) 被 LCD 占用
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 2; i++) {
|
||||||
if (is_touch_active[i]) {
|
if (is_touch_active[i]) {
|
||||||
// 尝试读取当前触摸值,如果大于阈值,则触摸已释放
|
// 尝试读取当前触摸值,如果大于阈值,则触摸已释放
|
||||||
uint32_t touch_value = 0;
|
uint32_t touch_value = 0;
|
||||||
@ -1741,9 +1717,9 @@ void IRAM_ATTR MovecallMojiESP32S3::TouchPadISR(void* arg) {
|
|||||||
touch_pad_clear_status();
|
touch_pad_clear_status();
|
||||||
|
|
||||||
// 处理触摸事件
|
// 处理触摸事件
|
||||||
touch_pad_t touch_pads[4] = {TOUCH_PAD_NUM1, TOUCH_PAD_NUM2, TOUCH_PAD_NUM3, TOUCH_PAD_NUM7};
|
touch_pad_t touch_pads[2] = {TOUCH_PAD_NUM2, TOUCH_PAD_NUM3}; // Touch1(GPIO1)/Touch4(GPIO7) 被 LCD 占用
|
||||||
|
|
||||||
for (int i = 0; i < 4; ++i) {
|
for (int i = 0; i < 2; ++i) {
|
||||||
// 检查按下事件
|
// 检查按下事件
|
||||||
if (pad_intr & (1 << touch_pads[i])) {
|
if (pad_intr & (1 << touch_pads[i])) {
|
||||||
// 生产测试模式:独立处理,不影响正常业务逻辑
|
// 生产测试模式:独立处理,不影响正常业务逻辑
|
||||||
@ -2008,6 +1984,7 @@ void MovecallMojiESP32S3::ResetAllTouchStates() {
|
|||||||
// 清除触摸中断状态
|
// 清除触摸中断状态
|
||||||
touch_pad_clear_status();
|
touch_pad_clear_status();
|
||||||
}
|
}
|
||||||
|
#endif // ENABLE_TOUCH_PAD_BUTTONS
|
||||||
|
|
||||||
// 进入生产测试模式- 新增代码
|
// 进入生产测试模式- 新增代码
|
||||||
// ==============================================================================
|
// ==============================================================================
|
||||||
|
|||||||
41
main/dzbj/dzbj_gpio.h
Normal file
41
main/dzbj/dzbj_gpio.h
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#ifndef _DZBJ_GPIO_H_
|
||||||
|
#define _DZBJ_GPIO_H_
|
||||||
|
|
||||||
|
// dzbj LCD/Touch GPIO 定义(从 dzbj 项目移植)
|
||||||
|
// 注意:I2C_MASTER_NUM 改为 I2C_NUM_1,与主项目共享总线
|
||||||
|
|
||||||
|
// 触摸功能开关(0=禁用,1=启用)
|
||||||
|
// 本项目不使用触摸屏功能,禁用以节约资源(I2C 触摸控制器初始化、GPIO、LVGL 输入驱动、内存)
|
||||||
|
#define DZBJ_ENABLE_TOUCH 1
|
||||||
|
|
||||||
|
#include "esp_lvgl_port.h"
|
||||||
|
|
||||||
|
#define PIN_NUM_SCL 18 // I2C SCL
|
||||||
|
#define PIN_NUM_SDA 17 // I2C SDA
|
||||||
|
#define I2C_MASTER_FREQ_HZ 100000
|
||||||
|
#define I2C_MASTER_NUM I2C_NUM_1 // 改为 I2C_NUM_1,与主项目音频编解码器共享
|
||||||
|
|
||||||
|
// LCD QSPI 引脚
|
||||||
|
#define PIN_LCD_EN 1 // 背光使能(PWM)
|
||||||
|
#define PIN_LCD_D0 11 // 数据0
|
||||||
|
#define PIN_LCD_D1 13 // 数据1
|
||||||
|
#define PIN_LCD_D2 14 // 数据2
|
||||||
|
#define PIN_LCD_D3 21 // 数据3
|
||||||
|
#define PIN_LCD_CLK 12 // 时钟
|
||||||
|
#define PIN_LCD_CS 47 // 片选
|
||||||
|
#define PIN_LCD_RST 7 // 复位
|
||||||
|
|
||||||
|
#define LCD_HIGH 360
|
||||||
|
#define LCD_WID 360
|
||||||
|
|
||||||
|
// 触摸引脚
|
||||||
|
#define PIN_TP_RST 6 // 触摸复位
|
||||||
|
#define PIN_TP_INT 5 // 触摸中断
|
||||||
|
|
||||||
|
#define LCD_TAG "LCD"
|
||||||
|
#define SPI_LCD_HOST SPI2_HOST
|
||||||
|
|
||||||
|
#define PIN_MOTOR_EN -1 // 电机使能(未使用)
|
||||||
|
#define PIN_BAT_ADC 3 // 电池ADC检测引脚
|
||||||
|
|
||||||
|
#endif // _DZBJ_GPIO_H_
|
||||||
44
main/dzbj/dzbj_init.c
Normal file
44
main/dzbj/dzbj_init.c
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
#include "dzbj_init.h"
|
||||||
|
#include "dzbj_gpio.h"
|
||||||
|
#include "lcd.h"
|
||||||
|
#include "pages_pwm.h"
|
||||||
|
#include "ui/ui.h"
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
|
||||||
|
#define TAG "DZBJ"
|
||||||
|
|
||||||
|
void dzbj_display_init(i2c_master_bus_handle_t i2c_bus) {
|
||||||
|
ESP_LOGI(TAG, "开始初始化 dzbj 显示模块...");
|
||||||
|
|
||||||
|
// 1. LCD 硬件初始化(QSPI ST77916)
|
||||||
|
lcd_init();
|
||||||
|
ESP_LOGI(TAG, "LCD 硬件初始化完成");
|
||||||
|
|
||||||
|
#if DZBJ_ENABLE_TOUCH
|
||||||
|
// 2. 传入 I2C 总线句柄(与音频编解码器共享)
|
||||||
|
lcd_set_i2c_bus(i2c_bus);
|
||||||
|
|
||||||
|
// 3. 触摸控制器初始化(CST816S)
|
||||||
|
touch_init();
|
||||||
|
#else
|
||||||
|
(void)i2c_bus;
|
||||||
|
ESP_LOGI(TAG, "屏幕触摸已禁用 (DZBJ_ENABLE_TOUCH=0)");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// 4. LVGL 初始化(显示)
|
||||||
|
lvgl_lcd_init();
|
||||||
|
ESP_LOGI(TAG, "LVGL 初始化完成");
|
||||||
|
|
||||||
|
// 5. SquareLine UI 初始化
|
||||||
|
ui_init();
|
||||||
|
ESP_LOGI(TAG, "UI 初始化完成");
|
||||||
|
|
||||||
|
// 6. 等待首帧渲染完成
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(100));
|
||||||
|
|
||||||
|
// 7. 点亮背光
|
||||||
|
pwm_init();
|
||||||
|
ESP_LOGI(TAG, "背光已点亮,dzbj 显示模块初始化完成");
|
||||||
|
}
|
||||||
18
main/dzbj/dzbj_init.h
Normal file
18
main/dzbj/dzbj_init.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#ifndef _DZBJ_INIT_H_
|
||||||
|
#define _DZBJ_INIT_H_
|
||||||
|
|
||||||
|
#include <driver/i2c_master.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// dzbj 显示模块初始化入口
|
||||||
|
// i2c_bus: 主项目的 I2C 总线句柄(与音频编解码器共享)
|
||||||
|
void dzbj_display_init(i2c_master_bus_handle_t i2c_bus);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // _DZBJ_INIT_H_
|
||||||
403
main/dzbj/lcd.c
Normal file
403
main/dzbj/lcd.c
Normal file
@ -0,0 +1,403 @@
|
|||||||
|
#include "dzbj_gpio.h"
|
||||||
|
#include "esp_lvgl_port.h"
|
||||||
|
#include "esp_lcd_st77916.h"
|
||||||
|
#include "esp_err.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "lcd.h"
|
||||||
|
#if DZBJ_ENABLE_TOUCH
|
||||||
|
#include "esp_lcd_touch_cst816s.h"
|
||||||
|
#endif
|
||||||
|
#include <string.h>
|
||||||
|
#include "esp_heap_caps.h"
|
||||||
|
|
||||||
|
// ST77916 初始化命令(从 dzbj 项目已验证的驱动版本提取)
|
||||||
|
// 主项目 managed_component 新版默认命令与本硬件面板不匹配,需手动注入
|
||||||
|
static const st77916_lcd_init_cmd_t lcd_init_cmds[] = {
|
||||||
|
{0xF0, (uint8_t[]){0x28}, 1, 0},
|
||||||
|
{0xF2, (uint8_t[]){0x28}, 1, 0},
|
||||||
|
{0x73, (uint8_t[]){0xF0}, 1, 0},
|
||||||
|
{0x7C, (uint8_t[]){0xD1}, 1, 0},
|
||||||
|
{0x83, (uint8_t[]){0xE0}, 1, 0},
|
||||||
|
{0x84, (uint8_t[]){0x61}, 1, 0},
|
||||||
|
{0xF2, (uint8_t[]){0x82}, 1, 0},
|
||||||
|
{0xF0, (uint8_t[]){0x00}, 1, 0},
|
||||||
|
{0xF0, (uint8_t[]){0x01}, 1, 0},
|
||||||
|
{0xF1, (uint8_t[]){0x01}, 1, 0},
|
||||||
|
{0xB0, (uint8_t[]){0x5E}, 1, 0},
|
||||||
|
{0xB1, (uint8_t[]){0x55}, 1, 0},
|
||||||
|
{0xB2, (uint8_t[]){0x24}, 1, 0},
|
||||||
|
{0xB3, (uint8_t[]){0x01}, 1, 0},
|
||||||
|
{0xB4, (uint8_t[]){0x87}, 1, 0},
|
||||||
|
{0xB5, (uint8_t[]){0x44}, 1, 0},
|
||||||
|
{0xB6, (uint8_t[]){0x8B}, 1, 0},
|
||||||
|
{0xB7, (uint8_t[]){0x40}, 1, 0},
|
||||||
|
{0xB8, (uint8_t[]){0x86}, 1, 0},
|
||||||
|
{0xB9, (uint8_t[]){0x15}, 1, 0},
|
||||||
|
{0xBA, (uint8_t[]){0x00}, 1, 0},
|
||||||
|
{0xBB, (uint8_t[]){0x08}, 1, 0},
|
||||||
|
{0xBC, (uint8_t[]){0x08}, 1, 0},
|
||||||
|
{0xBD, (uint8_t[]){0x00}, 1, 0},
|
||||||
|
{0xBE, (uint8_t[]){0x00}, 1, 0},
|
||||||
|
{0xBF, (uint8_t[]){0x07}, 1, 0},
|
||||||
|
{0xC0, (uint8_t[]){0x80}, 1, 0},
|
||||||
|
{0xC1, (uint8_t[]){0x10}, 1, 0},
|
||||||
|
{0xC2, (uint8_t[]){0x37}, 1, 0},
|
||||||
|
{0xC3, (uint8_t[]){0x80}, 1, 0},
|
||||||
|
{0xC4, (uint8_t[]){0x10}, 1, 0},
|
||||||
|
{0xC5, (uint8_t[]){0x37}, 1, 0},
|
||||||
|
{0xC6, (uint8_t[]){0xA9}, 1, 0},
|
||||||
|
{0xC7, (uint8_t[]){0x41}, 1, 0},
|
||||||
|
{0xC8, (uint8_t[]){0x01}, 1, 0},
|
||||||
|
{0xC9, (uint8_t[]){0xA9}, 1, 0},
|
||||||
|
{0xCA, (uint8_t[]){0x41}, 1, 0},
|
||||||
|
{0xCB, (uint8_t[]){0x01}, 1, 0},
|
||||||
|
{0xCC, (uint8_t[]){0x7F}, 1, 0},
|
||||||
|
{0xCD, (uint8_t[]){0x7F}, 1, 0},
|
||||||
|
{0xCE, (uint8_t[]){0xFF}, 1, 0},
|
||||||
|
{0xD0, (uint8_t[]){0x91}, 1, 0},
|
||||||
|
{0xD1, (uint8_t[]){0x68}, 1, 0},
|
||||||
|
{0xD2, (uint8_t[]){0x68}, 1, 0},
|
||||||
|
{0xF5, (uint8_t[]){0x00, 0xA5}, 2, 0},
|
||||||
|
{0xDD, (uint8_t[]){0x40}, 1, 0},
|
||||||
|
{0xDE, (uint8_t[]){0x40}, 1, 0},
|
||||||
|
{0xF1, (uint8_t[]){0x10}, 1, 0},
|
||||||
|
{0xF0, (uint8_t[]){0x00}, 1, 0},
|
||||||
|
{0xF0, (uint8_t[]){0x02}, 1, 0},
|
||||||
|
{0xE0, (uint8_t[]){0xF0, 0x10, 0x18, 0x0D, 0x0C, 0x38, 0x3E, 0x44, 0x51, 0x39, 0x15, 0x15, 0x30, 0x34}, 14, 0},
|
||||||
|
{0xE1, (uint8_t[]){0xF0, 0x0F, 0x17, 0x0D, 0x0B, 0x07, 0x3E, 0x33, 0x51, 0x39, 0x15, 0x15, 0x30, 0x34}, 14, 0},
|
||||||
|
{0xF0, (uint8_t[]){0x10}, 1, 0},
|
||||||
|
{0xF3, (uint8_t[]){0x10}, 1, 0},
|
||||||
|
{0xE0, (uint8_t[]){0x08}, 1, 0},
|
||||||
|
{0xE1, (uint8_t[]){0x00}, 1, 0},
|
||||||
|
{0xE2, (uint8_t[]){0x00}, 1, 0},
|
||||||
|
{0xE3, (uint8_t[]){0x00}, 1, 0},
|
||||||
|
{0xE4, (uint8_t[]){0xE0}, 1, 0},
|
||||||
|
{0xE5, (uint8_t[]){0x06}, 1, 0},
|
||||||
|
{0xE6, (uint8_t[]){0x21}, 1, 0},
|
||||||
|
{0xE7, (uint8_t[]){0x03}, 1, 0},
|
||||||
|
{0xE8, (uint8_t[]){0x05}, 1, 0},
|
||||||
|
{0xE9, (uint8_t[]){0x02}, 1, 0},
|
||||||
|
{0xEA, (uint8_t[]){0xE9}, 1, 0},
|
||||||
|
{0xEB, (uint8_t[]){0x00}, 1, 0},
|
||||||
|
{0xEC, (uint8_t[]){0x00}, 1, 0},
|
||||||
|
{0xED, (uint8_t[]){0x14}, 1, 0},
|
||||||
|
{0xEE, (uint8_t[]){0xFF}, 1, 0},
|
||||||
|
{0xEF, (uint8_t[]){0x00}, 1, 0},
|
||||||
|
{0xF8, (uint8_t[]){0xFF}, 1, 0},
|
||||||
|
{0xF9, (uint8_t[]){0x00}, 1, 0},
|
||||||
|
{0xFA, (uint8_t[]){0x00}, 1, 0},
|
||||||
|
{0xFB, (uint8_t[]){0x30}, 1, 0},
|
||||||
|
{0xFC, (uint8_t[]){0x00}, 1, 0},
|
||||||
|
{0xFD, (uint8_t[]){0x00}, 1, 0},
|
||||||
|
{0xFE, (uint8_t[]){0x00}, 1, 0},
|
||||||
|
{0xFF, (uint8_t[]){0x00}, 1, 0},
|
||||||
|
{0x60, (uint8_t[]){0x40}, 1, 0},
|
||||||
|
{0x61, (uint8_t[]){0x05}, 1, 0},
|
||||||
|
{0x62, (uint8_t[]){0x00}, 1, 0},
|
||||||
|
{0x63, (uint8_t[]){0x42}, 1, 0},
|
||||||
|
{0x64, (uint8_t[]){0xDA}, 1, 0},
|
||||||
|
{0x65, (uint8_t[]){0x00}, 1, 0},
|
||||||
|
{0x66, (uint8_t[]){0x00}, 1, 0},
|
||||||
|
{0x67, (uint8_t[]){0x00}, 1, 0},
|
||||||
|
{0x68, (uint8_t[]){0x00}, 1, 0},
|
||||||
|
{0x69, (uint8_t[]){0x00}, 1, 0},
|
||||||
|
{0x6A, (uint8_t[]){0x00}, 1, 0},
|
||||||
|
{0x6B, (uint8_t[]){0x00}, 1, 0},
|
||||||
|
{0x70, (uint8_t[]){0x40}, 1, 0},
|
||||||
|
{0x71, (uint8_t[]){0x04}, 1, 0},
|
||||||
|
{0x72, (uint8_t[]){0x00}, 1, 0},
|
||||||
|
{0x73, (uint8_t[]){0x42}, 1, 0},
|
||||||
|
{0x74, (uint8_t[]){0xD9}, 1, 0},
|
||||||
|
{0x75, (uint8_t[]){0x00}, 1, 0},
|
||||||
|
{0x76, (uint8_t[]){0x00}, 1, 0},
|
||||||
|
{0x77, (uint8_t[]){0x00}, 1, 0},
|
||||||
|
{0x78, (uint8_t[]){0x00}, 1, 0},
|
||||||
|
{0x79, (uint8_t[]){0x00}, 1, 0},
|
||||||
|
{0x7A, (uint8_t[]){0x00}, 1, 0},
|
||||||
|
{0x7B, (uint8_t[]){0x00}, 1, 0},
|
||||||
|
{0x80, (uint8_t[]){0x48}, 1, 0},
|
||||||
|
{0x81, (uint8_t[]){0x00}, 1, 0},
|
||||||
|
{0x82, (uint8_t[]){0x07}, 1, 0},
|
||||||
|
{0x83, (uint8_t[]){0x02}, 1, 0},
|
||||||
|
{0x84, (uint8_t[]){0xD7}, 1, 0},
|
||||||
|
{0x85, (uint8_t[]){0x04}, 1, 0},
|
||||||
|
{0x86, (uint8_t[]){0x00}, 1, 0},
|
||||||
|
{0x87, (uint8_t[]){0x00}, 1, 0},
|
||||||
|
{0x88, (uint8_t[]){0x48}, 1, 0},
|
||||||
|
{0x89, (uint8_t[]){0x00}, 1, 0},
|
||||||
|
{0x8A, (uint8_t[]){0x09}, 1, 0},
|
||||||
|
{0x8B, (uint8_t[]){0x02}, 1, 0},
|
||||||
|
{0x8C, (uint8_t[]){0xD9}, 1, 0},
|
||||||
|
{0x8D, (uint8_t[]){0x04}, 1, 0},
|
||||||
|
{0x8E, (uint8_t[]){0x00}, 1, 0},
|
||||||
|
{0x8F, (uint8_t[]){0x00}, 1, 0},
|
||||||
|
{0x90, (uint8_t[]){0x48}, 1, 0},
|
||||||
|
{0x91, (uint8_t[]){0x00}, 1, 0},
|
||||||
|
{0x92, (uint8_t[]){0x0B}, 1, 0},
|
||||||
|
{0x93, (uint8_t[]){0x02}, 1, 0},
|
||||||
|
{0x94, (uint8_t[]){0xDB}, 1, 0},
|
||||||
|
{0x95, (uint8_t[]){0x04}, 1, 0},
|
||||||
|
{0x96, (uint8_t[]){0x00}, 1, 0},
|
||||||
|
{0x97, (uint8_t[]){0x00}, 1, 0},
|
||||||
|
{0x98, (uint8_t[]){0x48}, 1, 0},
|
||||||
|
{0x99, (uint8_t[]){0x00}, 1, 0},
|
||||||
|
{0x9A, (uint8_t[]){0x0D}, 1, 0},
|
||||||
|
{0x9B, (uint8_t[]){0x02}, 1, 0},
|
||||||
|
{0x9C, (uint8_t[]){0xDD}, 1, 0},
|
||||||
|
{0x9D, (uint8_t[]){0x04}, 1, 0},
|
||||||
|
{0x9E, (uint8_t[]){0x00}, 1, 0},
|
||||||
|
{0x9F, (uint8_t[]){0x00}, 1, 0},
|
||||||
|
{0xA0, (uint8_t[]){0x48}, 1, 0},
|
||||||
|
{0xA1, (uint8_t[]){0x00}, 1, 0},
|
||||||
|
{0xA2, (uint8_t[]){0x06}, 1, 0},
|
||||||
|
{0xA3, (uint8_t[]){0x02}, 1, 0},
|
||||||
|
{0xA4, (uint8_t[]){0xD6}, 1, 0},
|
||||||
|
{0xA5, (uint8_t[]){0x04}, 1, 0},
|
||||||
|
{0xA6, (uint8_t[]){0x00}, 1, 0},
|
||||||
|
{0xA7, (uint8_t[]){0x00}, 1, 0},
|
||||||
|
{0xA8, (uint8_t[]){0x48}, 1, 0},
|
||||||
|
{0xA9, (uint8_t[]){0x00}, 1, 0},
|
||||||
|
{0xAA, (uint8_t[]){0x08}, 1, 0},
|
||||||
|
{0xAB, (uint8_t[]){0x02}, 1, 0},
|
||||||
|
{0xAC, (uint8_t[]){0xD8}, 1, 0},
|
||||||
|
{0xAD, (uint8_t[]){0x04}, 1, 0},
|
||||||
|
{0xAE, (uint8_t[]){0x00}, 1, 0},
|
||||||
|
{0xAF, (uint8_t[]){0x00}, 1, 0},
|
||||||
|
{0xB0, (uint8_t[]){0x48}, 1, 0},
|
||||||
|
{0xB1, (uint8_t[]){0x00}, 1, 0},
|
||||||
|
{0xB2, (uint8_t[]){0x0A}, 1, 0},
|
||||||
|
{0xB3, (uint8_t[]){0x02}, 1, 0},
|
||||||
|
{0xB4, (uint8_t[]){0xDA}, 1, 0},
|
||||||
|
{0xB5, (uint8_t[]){0x04}, 1, 0},
|
||||||
|
{0xB6, (uint8_t[]){0x00}, 1, 0},
|
||||||
|
{0xB7, (uint8_t[]){0x00}, 1, 0},
|
||||||
|
{0xB8, (uint8_t[]){0x48}, 1, 0},
|
||||||
|
{0xB9, (uint8_t[]){0x00}, 1, 0},
|
||||||
|
{0xBA, (uint8_t[]){0x0C}, 1, 0},
|
||||||
|
{0xBB, (uint8_t[]){0x02}, 1, 0},
|
||||||
|
{0xBC, (uint8_t[]){0xDC}, 1, 0},
|
||||||
|
{0xBD, (uint8_t[]){0x04}, 1, 0},
|
||||||
|
{0xBE, (uint8_t[]){0x00}, 1, 0},
|
||||||
|
{0xBF, (uint8_t[]){0x00}, 1, 0},
|
||||||
|
{0xC0, (uint8_t[]){0x10}, 1, 0},
|
||||||
|
{0xC1, (uint8_t[]){0x47}, 1, 0},
|
||||||
|
{0xC2, (uint8_t[]){0x56}, 1, 0},
|
||||||
|
{0xC3, (uint8_t[]){0x65}, 1, 0},
|
||||||
|
{0xC4, (uint8_t[]){0x74}, 1, 0},
|
||||||
|
{0xC5, (uint8_t[]){0x88}, 1, 0},
|
||||||
|
{0xC6, (uint8_t[]){0x99}, 1, 0},
|
||||||
|
{0xC7, (uint8_t[]){0x01}, 1, 0},
|
||||||
|
{0xC8, (uint8_t[]){0xBB}, 1, 0},
|
||||||
|
{0xC9, (uint8_t[]){0xAA}, 1, 0},
|
||||||
|
{0xD0, (uint8_t[]){0x10}, 1, 0},
|
||||||
|
{0xD1, (uint8_t[]){0x47}, 1, 0},
|
||||||
|
{0xD2, (uint8_t[]){0x56}, 1, 0},
|
||||||
|
{0xD3, (uint8_t[]){0x65}, 1, 0},
|
||||||
|
{0xD4, (uint8_t[]){0x74}, 1, 0},
|
||||||
|
{0xD5, (uint8_t[]){0x88}, 1, 0},
|
||||||
|
{0xD6, (uint8_t[]){0x99}, 1, 0},
|
||||||
|
{0xD7, (uint8_t[]){0x01}, 1, 0},
|
||||||
|
{0xD8, (uint8_t[]){0xBB}, 1, 0},
|
||||||
|
{0xD9, (uint8_t[]){0xAA}, 1, 0},
|
||||||
|
{0xF3, (uint8_t[]){0x01}, 1, 0},
|
||||||
|
{0xF0, (uint8_t[]){0x00}, 1, 0},
|
||||||
|
{0x3A, (uint8_t[]){0x55}, 1, 0},
|
||||||
|
{0x21, (uint8_t[]){0x00}, 1, 0},
|
||||||
|
{0x11, (uint8_t[]){0x00}, 1, 120},
|
||||||
|
{0x29, (uint8_t[]){0x00}, 1, 0},
|
||||||
|
};
|
||||||
|
|
||||||
|
static lv_disp_t * disp_handle = NULL;
|
||||||
|
static esp_lcd_panel_handle_t panel_handle = NULL;
|
||||||
|
static esp_lcd_panel_io_handle_t io_handle = NULL;
|
||||||
|
#if DZBJ_ENABLE_TOUCH
|
||||||
|
static esp_lcd_touch_handle_t touch_handle = NULL;
|
||||||
|
static esp_lcd_panel_io_handle_t tp_io_handle = NULL;
|
||||||
|
// 外部传入的 I2C 总线句柄(与主项目共享)
|
||||||
|
static i2c_master_bus_handle_t ext_i2c_bus = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void lcd_set_i2c_bus(i2c_master_bus_handle_t bus) {
|
||||||
|
#if DZBJ_ENABLE_TOUCH
|
||||||
|
ext_i2c_bus = bus;
|
||||||
|
#else
|
||||||
|
(void)bus;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void lcd_init(){
|
||||||
|
const spi_bus_config_t buscfg = ST77916_PANEL_BUS_QSPI_CONFIG(PIN_LCD_CLK,
|
||||||
|
PIN_LCD_D0,
|
||||||
|
PIN_LCD_D1,
|
||||||
|
PIN_LCD_D2,
|
||||||
|
PIN_LCD_D3,
|
||||||
|
LCD_HIGH * 80 * sizeof(uint16_t));
|
||||||
|
spi_bus_initialize(SPI_LCD_HOST, &buscfg, SPI_DMA_CH_AUTO);
|
||||||
|
|
||||||
|
// QSPI 80MHz
|
||||||
|
esp_lcd_panel_io_spi_config_t io_config = ST77916_PANEL_IO_QSPI_CONFIG(PIN_LCD_CS, NULL, NULL);
|
||||||
|
io_config.pclk_hz = 80 * 1000 * 1000;
|
||||||
|
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)SPI_LCD_HOST, &io_config, &io_handle));
|
||||||
|
const st77916_vendor_config_t vendor_config = {
|
||||||
|
.init_cmds = lcd_init_cmds,
|
||||||
|
.init_cmds_size = sizeof(lcd_init_cmds) / sizeof(st77916_lcd_init_cmd_t),
|
||||||
|
.flags = {
|
||||||
|
.use_qspi_interface = 1,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const esp_lcd_panel_dev_config_t panel_config = {
|
||||||
|
.reset_gpio_num = PIN_LCD_RST,
|
||||||
|
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,
|
||||||
|
.bits_per_pixel = 16,
|
||||||
|
.vendor_config = &vendor_config,
|
||||||
|
};
|
||||||
|
ESP_ERROR_CHECK(esp_lcd_new_panel_st77916(io_handle, &panel_config, &panel_handle));
|
||||||
|
esp_lcd_panel_reset(panel_handle);
|
||||||
|
esp_lcd_panel_init(panel_handle);
|
||||||
|
|
||||||
|
// 清空LCD GRAM,避免显示上次关机时的残留画面
|
||||||
|
size_t clear_buffer_size = LCD_WID * 40;
|
||||||
|
uint16_t *clear_buffer = heap_caps_malloc(clear_buffer_size * sizeof(uint16_t), MALLOC_CAP_DMA);
|
||||||
|
if (clear_buffer) {
|
||||||
|
memset(clear_buffer, 0, clear_buffer_size * sizeof(uint16_t));
|
||||||
|
for (int y = 0; y < LCD_HIGH; y += 40) {
|
||||||
|
int lines = (y + 40 > LCD_HIGH) ? (LCD_HIGH - y) : 40;
|
||||||
|
esp_lcd_panel_draw_bitmap(panel_handle, 0, y, LCD_WID, y + lines, clear_buffer);
|
||||||
|
}
|
||||||
|
heap_caps_free(clear_buffer);
|
||||||
|
ESP_LOGI(LCD_TAG, "LCD GRAM cleared (black filled)");
|
||||||
|
} else {
|
||||||
|
ESP_LOGE(LCD_TAG, "Failed to allocate clear buffer");
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_lcd_panel_disp_on_off(panel_handle, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if DZBJ_ENABLE_TOUCH
|
||||||
|
// 初始化触摸控制器(使用外部传入的 I2C 总线)
|
||||||
|
void touch_init(){
|
||||||
|
const esp_lcd_touch_config_t tp_cfg = {
|
||||||
|
.x_max = LCD_WID,
|
||||||
|
.y_max = LCD_HIGH,
|
||||||
|
.rst_gpio_num = PIN_TP_RST,
|
||||||
|
.int_gpio_num = PIN_TP_INT,
|
||||||
|
.levels = {
|
||||||
|
.reset = 0,
|
||||||
|
.interrupt = 0,
|
||||||
|
},
|
||||||
|
.flags = {
|
||||||
|
.swap_xy = false,
|
||||||
|
.mirror_x = false,
|
||||||
|
.mirror_y = false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const esp_lcd_panel_io_i2c_config_t tp_io_config = ESP_LCD_TOUCH_IO_I2C_CST816S_CONFIG();
|
||||||
|
|
||||||
|
// 使用外部传入的 I2C 总线句柄(与音频编解码器共享 I2C_NUM_1)
|
||||||
|
i2c_master_bus_handle_t i2c_bus = ext_i2c_bus;
|
||||||
|
if (i2c_bus == NULL) {
|
||||||
|
ESP_LOGE(LCD_TAG, "I2C bus not set, call lcd_set_i2c_bus() first");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 直接传入 i2c_master_bus_handle_t,_Generic 宏分派到 V2(新驱动)
|
||||||
|
// 不要强转为 esp_lcd_i2c_bus_handle_t(uint32_t),否则会触发 V1 legacy 驱动冲突
|
||||||
|
esp_err_t err = esp_lcd_new_panel_io_i2c(i2c_bus, &tp_io_config, &tp_io_handle);
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
ESP_LOGE(LCD_TAG, "Failed to create I2C IO for touch: %s", esp_err_to_name(err));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
err = esp_lcd_touch_new_i2c_cst816s(tp_io_handle, &tp_cfg, &touch_handle);
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
ESP_LOGE(LCD_TAG, "Failed to create touch handle: %s", esp_err_to_name(err));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ESP_LOGI(LCD_TAG, "Touch controller initialized successfully");
|
||||||
|
}
|
||||||
|
#endif // DZBJ_ENABLE_TOUCH
|
||||||
|
|
||||||
|
// 初始化LVGL显示
|
||||||
|
void lvgl_lcd_init(){
|
||||||
|
const lvgl_port_cfg_t lvgl_cfg = {
|
||||||
|
.task_priority = 4,
|
||||||
|
.task_stack = 8192,
|
||||||
|
.task_affinity = -1,
|
||||||
|
.task_max_sleep_ms = 500,
|
||||||
|
.timer_period_ms = 5
|
||||||
|
};
|
||||||
|
lvgl_port_init(&lvgl_cfg);
|
||||||
|
|
||||||
|
// 使用内部 DMA 内存,20 行单缓冲(360×20×2 = 14400 字节)
|
||||||
|
// PSRAM 缓冲区与 SPI DMA 不兼容(spi transmit queue 失败)
|
||||||
|
// 单缓冲 + 小行数,节省内部 SRAM 给 WiFi/BLE
|
||||||
|
#define LVGL_DRAW_BUF_LINES 20
|
||||||
|
size_t buffer_size = LCD_WID * LVGL_DRAW_BUF_LINES;
|
||||||
|
|
||||||
|
ESP_LOGI(LCD_TAG, "LVGL buffer: %d bytes (W:%d, Lines:%d, DMA, single)",
|
||||||
|
buffer_size * sizeof(uint16_t), LCD_WID, LVGL_DRAW_BUF_LINES);
|
||||||
|
|
||||||
|
const lvgl_port_display_cfg_t disp_cfg = {
|
||||||
|
.io_handle = io_handle,
|
||||||
|
.panel_handle = panel_handle,
|
||||||
|
.buffer_size = buffer_size,
|
||||||
|
.double_buffer = false,
|
||||||
|
.hres = LCD_WID,
|
||||||
|
.vres = LCD_HIGH,
|
||||||
|
.monochrome = false,
|
||||||
|
.rotation = {
|
||||||
|
.swap_xy = false,
|
||||||
|
.mirror_x = false,
|
||||||
|
.mirror_y = false,
|
||||||
|
},
|
||||||
|
.flags = {
|
||||||
|
.buff_dma = true,
|
||||||
|
.buff_spiram = false,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
disp_handle = lvgl_port_add_disp(&disp_cfg);
|
||||||
|
|
||||||
|
#if DZBJ_ENABLE_TOUCH
|
||||||
|
if (touch_handle != NULL) {
|
||||||
|
lvgl_port_touch_cfg_t touch_cgf = {
|
||||||
|
.disp = disp_handle,
|
||||||
|
.handle = touch_handle,
|
||||||
|
};
|
||||||
|
lvgl_port_add_touch(&touch_cgf);
|
||||||
|
ESP_LOGI(LCD_TAG, "Touch controller added to LVGL");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if DZBJ_ENABLE_TOUCH
|
||||||
|
void get_touch(uint16_t* touchx, uint16_t* touchy){
|
||||||
|
if (touch_handle == NULL) {
|
||||||
|
*touchx = 0;
|
||||||
|
*touchy = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
*touchx = touch_handle->data.coords[0].x;
|
||||||
|
*touchy = touch_handle->data.coords[0].y;
|
||||||
|
}
|
||||||
|
#endif // DZBJ_ENABLE_TOUCH
|
||||||
|
|
||||||
|
// 清空LCD GRAM为黑色(用于低功耗熄屏前,避免残影)
|
||||||
|
void lcd_clear_screen_black(void) {
|
||||||
|
if (panel_handle == NULL) {
|
||||||
|
ESP_LOGE(LCD_TAG, "Panel handle is NULL, cannot clear screen");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t clear_buffer_size = LCD_WID * 40;
|
||||||
|
uint16_t *clear_buffer = heap_caps_malloc(clear_buffer_size * sizeof(uint16_t), MALLOC_CAP_DMA);
|
||||||
|
if (clear_buffer) {
|
||||||
|
memset(clear_buffer, 0, clear_buffer_size * sizeof(uint16_t));
|
||||||
|
for (int y = 0; y < LCD_HIGH; y += 40) {
|
||||||
|
int lines = (y + 40 > LCD_HIGH) ? (LCD_HIGH - y) : 40;
|
||||||
|
esp_lcd_panel_draw_bitmap(panel_handle, 0, y, LCD_WID, y + lines, clear_buffer);
|
||||||
|
}
|
||||||
|
heap_caps_free(clear_buffer);
|
||||||
|
ESP_LOGI(LCD_TAG, "LCD GRAM cleared to black (for low power mode)");
|
||||||
|
} else {
|
||||||
|
ESP_LOGE(LCD_TAG, "Failed to allocate clear buffer");
|
||||||
|
}
|
||||||
|
}
|
||||||
21
main/dzbj/lcd.h
Normal file
21
main/dzbj/lcd.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#ifndef _DZBJ_LCD_H_
|
||||||
|
#define _DZBJ_LCD_H_
|
||||||
|
|
||||||
|
#include "dzbj_gpio.h"
|
||||||
|
#include "esp_lvgl_port.h"
|
||||||
|
#include "esp_lcd_st77916.h"
|
||||||
|
#include <driver/i2c_master.h>
|
||||||
|
|
||||||
|
void lcd_init(void);
|
||||||
|
void lvgl_lcd_init(void);
|
||||||
|
void lcd_clear_screen_black(void);
|
||||||
|
|
||||||
|
// I2C 总线共享:传入主项目的 I2C 总线句柄,供触摸控制器使用
|
||||||
|
void lcd_set_i2c_bus(i2c_master_bus_handle_t bus);
|
||||||
|
|
||||||
|
#if DZBJ_ENABLE_TOUCH
|
||||||
|
void touch_init(void);
|
||||||
|
void get_touch(uint16_t* touchx, uint16_t* touchy);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // _DZBJ_LCD_H_
|
||||||
53
main/dzbj/pages_pwm.c
Normal file
53
main/dzbj/pages_pwm.c
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
#include "pages_pwm.h"
|
||||||
|
#include "dzbj_gpio.h"
|
||||||
|
#include "driver/ledc.h"
|
||||||
|
|
||||||
|
// 当前亮度值(用于休眠恢复)
|
||||||
|
static uint8_t current_brightness = 50;
|
||||||
|
|
||||||
|
// 获取当前亮度值
|
||||||
|
uint8_t pwm_get_brightness(void) {
|
||||||
|
return current_brightness;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置屏幕亮度,percent范围0-100
|
||||||
|
// 0=完全关闭背光,10~100为正常亮度范围
|
||||||
|
// 显示10%~100%映射到实际亮度20%~100%,背光低电平有效需反转占空比
|
||||||
|
void pwm_set_brightness(uint8_t percent) {
|
||||||
|
if (percent == 0) {
|
||||||
|
// 完全关闭背光(低电平有效,占空比100%=全高=关闭)
|
||||||
|
ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, 8191);
|
||||||
|
ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (percent < 10) percent = 10;
|
||||||
|
if (percent > 100) percent = 100;
|
||||||
|
current_brightness = percent;
|
||||||
|
uint32_t actual = 20 + (uint32_t)(percent - 10) * 80 / 90;
|
||||||
|
uint32_t duty = 8191 - (8191 * actual) / 100;
|
||||||
|
ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, duty);
|
||||||
|
ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化PWM背光
|
||||||
|
void pwm_init(void) {
|
||||||
|
ledc_timer_config_t ledc_timer = {
|
||||||
|
.speed_mode = LEDC_LOW_SPEED_MODE,
|
||||||
|
.timer_num = LEDC_TIMER_0,
|
||||||
|
.duty_resolution = LEDC_TIMER_13_BIT,
|
||||||
|
.freq_hz = 5000,
|
||||||
|
.clk_cfg = LEDC_AUTO_CLK
|
||||||
|
};
|
||||||
|
ledc_timer_config(&ledc_timer);
|
||||||
|
ledc_channel_config_t ledc_channel = {
|
||||||
|
.speed_mode = LEDC_LOW_SPEED_MODE,
|
||||||
|
.channel = LEDC_CHANNEL_0,
|
||||||
|
.timer_sel = LEDC_TIMER_0,
|
||||||
|
.intr_type = LEDC_INTR_DISABLE,
|
||||||
|
.gpio_num = PIN_LCD_EN,
|
||||||
|
.duty = 0,
|
||||||
|
.hpoint = 0
|
||||||
|
};
|
||||||
|
ledc_channel_config(&ledc_channel);
|
||||||
|
pwm_set_brightness(50); // 初始亮度50%
|
||||||
|
}
|
||||||
19
main/dzbj/pages_pwm.h
Normal file
19
main/dzbj/pages_pwm.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#ifndef _DZBJ_PAGES_PWM_H_
|
||||||
|
#define _DZBJ_PAGES_PWM_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// PWM 背光控制(从 dzbj pages.c 提取)
|
||||||
|
void pwm_init(void);
|
||||||
|
void pwm_set_brightness(uint8_t percent);
|
||||||
|
uint8_t pwm_get_brightness(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // _DZBJ_PAGES_PWM_H_
|
||||||
@ -8,6 +8,13 @@ dependencies:
|
|||||||
espressif/esp-sr: "^2.0.3"
|
espressif/esp-sr: "^2.0.3"
|
||||||
espressif/button: "^3.3.1"
|
espressif/button: "^3.3.1"
|
||||||
espressif/knob: "^1.0.0"
|
espressif/knob: "^1.0.0"
|
||||||
|
## LVGL 显示相关依赖(dzbj 电子吧唧模块)
|
||||||
|
esp_lvgl_port: "2.5.0"
|
||||||
|
lvgl/lvgl:
|
||||||
|
version: "8.3.11"
|
||||||
|
esp_lcd_st77916: "1.0.1"
|
||||||
|
esp_lcd_touch: "1.1.2"
|
||||||
|
esp_lcd_touch_cst816s: "1.1.0"
|
||||||
## Required IDF version
|
## Required IDF version
|
||||||
idf:
|
idf:
|
||||||
version: ">=5.3"
|
version: ">=5.3"
|
||||||
|
|||||||
22
main/pages/include/pages.h
Normal file
22
main/pages/include/pages.h
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#ifndef _PAGES_STUB_H_
|
||||||
|
#define _PAGES_STUB_H_
|
||||||
|
|
||||||
|
// Stub 头文件:dzbj ui_ScreenImg.c 引用,Phase 1 仅提供声明
|
||||||
|
// 实际实现将在后续阶段添加
|
||||||
|
|
||||||
|
#include "esp_err.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "lvgl.h"
|
||||||
|
|
||||||
|
void pwm_init(void);
|
||||||
|
void pwm_set_brightness(uint8_t percent);
|
||||||
|
uint8_t pwm_get_brightness(void);
|
||||||
|
|
||||||
|
const char* get_current_image(void);
|
||||||
|
bool delete_current_image(void);
|
||||||
|
void init_spiffs_image_list(void);
|
||||||
|
void free_spiffs_image_list(void);
|
||||||
|
bool set_image_index_by_name(const char *name);
|
||||||
|
|
||||||
|
#endif // _PAGES_STUB_H_
|
||||||
15
main/pages/pages_stub.c
Normal file
15
main/pages/pages_stub.c
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// Stub 实现:dzbj UI 文件引用的函数,Phase 1 仅提供空实现
|
||||||
|
// 实际实现将在后续阶段添加
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
const char* get_current_image(void) { return NULL; }
|
||||||
|
bool delete_current_image(void) { return false; }
|
||||||
|
void init_spiffs_image_list(void) {}
|
||||||
|
void free_spiffs_image_list(void) {}
|
||||||
|
bool set_image_index_by_name(const char *name) { (void)name; return false; }
|
||||||
|
const char* get_next_image(void) { return NULL; }
|
||||||
|
const char* get_prev_image(void) { return NULL; }
|
||||||
|
void update_ui_ImgBle(const char *img_name) { (void)img_name; }
|
||||||
13
main/sleep_mgr/include/sleep_mgr.h
Normal file
13
main/sleep_mgr/include/sleep_mgr.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#ifndef _SLEEP_MGR_STUB_H_
|
||||||
|
#define _SLEEP_MGR_STUB_H_
|
||||||
|
|
||||||
|
// Stub 头文件:dzbj ui_ScreenSet.c 引用,Phase 1 仅提供声明
|
||||||
|
// 实际实现将在后续阶段添加
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
static inline void sleep_mgr_set_enabled(bool enabled) {
|
||||||
|
(void)enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // _SLEEP_MGR_STUB_H_
|
||||||
@ -0,0 +1 @@
|
|||||||
|
5fa0f8b1274576d4484e2b8d9358e2a5d09c721511bef0dce6a55b4206b5f0e9
|
||||||
26
managed_components/espressif__esp_lcd_st77916/CHANGELOG.md
Normal file
26
managed_components/espressif__esp_lcd_st77916/CHANGELOG.md
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
# ChangeLog
|
||||||
|
|
||||||
|
## v1.0.1 - 2025-01-13
|
||||||
|
|
||||||
|
### bugfix:
|
||||||
|
|
||||||
|
* Fix issues of QSPI interface
|
||||||
|
|
||||||
|
## v1.0.0 - 2024-08-12
|
||||||
|
|
||||||
|
### Enhancements:
|
||||||
|
|
||||||
|
* Component version maintenance, code improvement, and documentation enhancement
|
||||||
|
|
||||||
|
## v0.0.1 - 2023-12-01
|
||||||
|
|
||||||
|
### Enhancements:
|
||||||
|
|
||||||
|
* Implement the driver for the ST77916 LCD controller
|
||||||
|
* Support SPI and QSPI interface
|
||||||
|
|
||||||
|
## v0.0.2 - 2023-12-15
|
||||||
|
|
||||||
|
### Enhancements:
|
||||||
|
|
||||||
|
* Fix issues of QSPI interface
|
||||||
@ -0,0 +1 @@
|
|||||||
|
{"version": "1.0", "algorithm": "sha256", "created_at": "2025-05-21T16:22:44.538744+00:00", "files": [{"path": "CMakeLists.txt", "size": 189, "hash": "d9e6afb7ee86418f0e7b00bc2130d0004cb2a19ffb33f33dd73fa2e95c307d25"}, {"path": "CHANGELOG.md", "size": 412, "hash": "3a0ee035cb4e3784eaba660eca2e713deeff7d145531fb0f7ffd8ce6e8938682"}, {"path": "idf_component.yml", "size": 459, "hash": "18cc04f5fc379b6279678983b0ea054e335f1636292ff856c9aa896b4b4037e0"}, {"path": "README.md", "size": 6085, "hash": "ff1ea508952e6d3ce099dad268a15d6c6ad25cc62de6d9e1776551b22d59b07a"}, {"path": "esp_lcd_st77916.c", "size": 21442, "hash": "a9124ac8a582d32fee40f60e6e5be747253ace5bc458d0e21972a84a416570ff"}, {"path": "license.txt", "size": 11358, "hash": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30"}, {"path": "include/esp_lcd_st77916.h", "size": 4954, "hash": "21f444cdc25ed1ceec379fe91fb5fd09d31ef179a946c9a7bd6f67d2e3599bfa"}, {"path": "test_apps/CMakeLists.txt", "size": 317, "hash": "cae0178540c6a4a24b56f590eb1f6bf4a85707bd521d9908b3abfc4aed8364b0"}, {"path": "test_apps/pytest_esp_lcd_st77916.py", "size": 300, "hash": "6513b1e4ab20df1aca721edef3485c23da4c0bc34920537ede6c1203ddd4f16a"}, {"path": "test_apps/sdkconfig.defaults", "size": 257, "hash": "b3f9660085595b907f7411e205468220c2dfb867de4de5d7fb3cbb406651dcab"}, {"path": "test_apps/main/CMakeLists.txt", "size": 54, "hash": "263db0b3aae2eae64e526904e06d12a8a5afc3ffe424bcb5992ac015c523c2b2"}, {"path": "test_apps/main/idf_component.yml", "size": 159, "hash": "fb0f2c2300bb6f5f80412b27393d83281fc13ed1a6fa8577e6b9f0f8af0d39f7"}, {"path": "test_apps/main/test_esp_lcd_st77916.c", "size": 7408, "hash": "220671da6d27e35fdf2e864ce0d26648e7974b32cff9afdd8f4c6715d24f9086"}]}
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
idf_component_register(SRCS "esp_lcd_st77916.c" INCLUDE_DIRS "include" PRIV_REQUIRES "driver" REQUIRES "esp_lcd")
|
||||||
|
|
||||||
|
include(package_manager)
|
||||||
|
cu_pkg_define_version(${CMAKE_CURRENT_LIST_DIR})
|
||||||
122
managed_components/espressif__esp_lcd_st77916/README.md
Normal file
122
managed_components/espressif__esp_lcd_st77916/README.md
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
# ESP LCD ST77916
|
||||||
|
|
||||||
|
[](https://components.espressif.com/components/espressif/esp_lcd_st77916)
|
||||||
|
|
||||||
|
Implementation of the ST77916 LCD controller with [esp_lcd](https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/api-reference/peripherals/lcd.html) component.
|
||||||
|
|
||||||
|
| LCD controller | Communication interface | Component name | Link to datasheet |
|
||||||
|
| :------------: | :---------------------: | :------------: | :---------------------------------------------------------------------------: |
|
||||||
|
| ST77916 | SPI/QSPI | esp_lcd_st77916 | [PDF](https://dl.espressif.com/AE/esp-iot-solution/ST77916_SPEC_V1.0.pdf) |
|
||||||
|
|
||||||
|
For more information on LCD, please refer to the [LCD documentation](https://docs.espressif.com/projects/esp-iot-solution/en/latest/display/lcd/index.html).
|
||||||
|
|
||||||
|
## Add to project
|
||||||
|
|
||||||
|
Packages from this repository are uploaded to [Espressif's component service](https://components.espressif.com/).
|
||||||
|
You can add them to your project via `idf.py add-dependancy`, e.g.
|
||||||
|
```
|
||||||
|
idf.py add-dependency "espressif/esp_lcd_st77916"
|
||||||
|
```
|
||||||
|
|
||||||
|
Alternatively, you can create `idf_component.yml`. More is in [Espressif's documentation](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/tools/idf-component-manager.html).
|
||||||
|
|
||||||
|
## Initialization Code
|
||||||
|
|
||||||
|
### SPI Interface
|
||||||
|
|
||||||
|
```c
|
||||||
|
ESP_LOGI(TAG, "Initialize SPI bus");
|
||||||
|
const spi_bus_config_t buscfg = ST77916_PANEL_BUS_SPI_CONFIG(EXAMPLE_PIN_NUM_LCD_PCLK, EXAMPLE_PIN_NUM_LCD_DATA0, EXAMPLE_LCD_H_RES * 80 * sizeof(uint16_t));
|
||||||
|
ESP_ERROR_CHECK(spi_bus_initialize(EXAMPLE_LCD_HOST, &buscfg, SPI_DMA_CH_AUTO));
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "Install panel IO");
|
||||||
|
esp_lcd_panel_io_handle_t io_handle = NULL;
|
||||||
|
const esp_lcd_panel_io_spi_config_t io_config = ST77916_PANEL_IO_SPI_CONFIG(EXAMPLE_PIN_NUM_LCD_CS, EXAMPLE_PIN_NUM_LCD_DC,
|
||||||
|
callback, &callback_data);
|
||||||
|
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)EXAMPLE_LCD_HOST, &io_config, &io_handle));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uncomment these line if use custom initialization commands.
|
||||||
|
* The array should be declared as static const and positioned outside the function.
|
||||||
|
*/
|
||||||
|
// static const st77916_lcd_init_cmd_t lcd_init_cmds[] = {
|
||||||
|
// // {cmd, { data }, data_size, delay_ms}
|
||||||
|
// {0xF0, (uint8_t []){0x08}, 1, 0},
|
||||||
|
// {0xF2, (uint8_t []){0x08}, 1, 0},
|
||||||
|
// {0x9B, (uint8_t []){0x51}, 1, 0},
|
||||||
|
// {0x86, (uint8_t []){0x53}, 1, 0},
|
||||||
|
// ...
|
||||||
|
// };
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "Install ST77916 panel driver");
|
||||||
|
esp_lcd_panel_handle_t panel_handle = NULL;
|
||||||
|
const st77916_vendor_config_t vendor_config = {
|
||||||
|
// .init_cmds = lcd_init_cmds, // Uncomment these line if use custom initialization commands
|
||||||
|
// .init_cmds_size = sizeof(lcd_init_cmds) / sizeof(st77916_lcd_init_cmd_t),
|
||||||
|
.flags = {
|
||||||
|
.use_qspi_interface = 0,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const esp_lcd_panel_dev_config_t panel_config = {
|
||||||
|
.reset_gpio_num = EXAMPLE_PIN_NUM_LCD_RST,
|
||||||
|
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB, // Implemented by LCD command `36h`
|
||||||
|
.bits_per_pixel = EXAMPLE_LCD_BIT_PER_PIXEL, // Implemented by LCD command `3Ah` (16/18)
|
||||||
|
.vendor_config = &vendor_config,
|
||||||
|
};
|
||||||
|
ESP_ERROR_CHECK(esp_lcd_new_panel_st77916(io_handle, &panel_config, &panel_handle));
|
||||||
|
esp_lcd_panel_reset(panel_handle);
|
||||||
|
esp_lcd_panel_init(panel_handle);
|
||||||
|
esp_lcd_panel_disp_on_off(panel_handle, true);
|
||||||
|
```
|
||||||
|
|
||||||
|
### QSPI Interface
|
||||||
|
|
||||||
|
```c
|
||||||
|
ESP_LOGI(TAG, "Initialize QSPI bus");
|
||||||
|
const spi_bus_config_t buscfg = ST77916_PANEL_BUS_QSPI_CONFIG(EXAMPLE_PIN_NUM_LCD_PCLK,
|
||||||
|
EXAMPLE_PIN_NUM_LCD_DATA0,
|
||||||
|
EXAMPLE_PIN_NUM_LCD_DATA1,
|
||||||
|
EXAMPLE_PIN_NUM_LCD_DATA2,
|
||||||
|
EXAMPLE_PIN_NUM_LCD_DATA3,
|
||||||
|
EXAMPLE_LCD_H_RES * 80 * sizeof(uint16_t));
|
||||||
|
ESP_ERROR_CHECK(spi_bus_initialize(EXAMPLE_LCD_HOST, &buscfg, SPI_DMA_CH_AUTO));
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "Install panel IO");
|
||||||
|
esp_lcd_panel_io_handle_t io_handle = NULL;
|
||||||
|
const esp_lcd_panel_io_spi_config_t io_config = ST77916_PANEL_IO_QSPI_CONFIG(EXAMPLE_PIN_NUM_LCD_CS, callback, &callback_data);
|
||||||
|
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)EXAMPLE_LCD_HOST, &io_config, &io_handle));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uncomment these line if use custom initialization commands.
|
||||||
|
* The array should be declared as static const and positioned outside the function.
|
||||||
|
*/
|
||||||
|
// static const st77916_lcd_init_cmd_t lcd_init_cmds[] = {
|
||||||
|
// // {cmd, { data }, data_size, delay_ms}
|
||||||
|
// {0xF0, (uint8_t []){0x08}, 1, 0},
|
||||||
|
// {0xF2, (uint8_t []){0x08}, 1, 0},
|
||||||
|
// {0x9B, (uint8_t []){0x51}, 1, 0},
|
||||||
|
// {0x86, (uint8_t []){0x53}, 1, 0},
|
||||||
|
// ...
|
||||||
|
// };
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "Install ST77916 panel driver");
|
||||||
|
esp_lcd_panel_handle_t panel_handle = NULL;
|
||||||
|
const st77916_vendor_config_t vendor_config = {
|
||||||
|
// .init_cmds = lcd_init_cmds, // Uncomment these line if use custom initialization commands
|
||||||
|
// .init_cmds_size = sizeof(lcd_init_cmds) / sizeof(st77916_lcd_init_cmd_t),
|
||||||
|
.flags = {
|
||||||
|
.use_qspi_interface = 1,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const esp_lcd_panel_dev_config_t panel_config = {
|
||||||
|
.reset_gpio_num = EXAMPLE_PIN_NUM_LCD_RST,
|
||||||
|
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB, // Implemented by LCD command `36h`
|
||||||
|
.bits_per_pixel = EXAMPLE_LCD_BIT_PER_PIXEL, // Implemented by LCD command `3Ah` (16/18)
|
||||||
|
.vendor_config = &vendor_config,
|
||||||
|
};
|
||||||
|
ESP_ERROR_CHECK(esp_lcd_new_panel_st77916(io_handle, &panel_config, &panel_handle));
|
||||||
|
|
||||||
|
esp_lcd_panel_reset(panel_handle);
|
||||||
|
esp_lcd_panel_init(panel_handle);
|
||||||
|
esp_lcd_panel_disp_on_off(panel_handle, true);
|
||||||
|
```
|
||||||
575
managed_components/espressif__esp_lcd_st77916/esp_lcd_st77916.c
Normal file
575
managed_components/espressif__esp_lcd_st77916/esp_lcd_st77916.c
Normal file
@ -0,0 +1,575 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
|
#include "driver/gpio.h"
|
||||||
|
#include "esp_check.h"
|
||||||
|
#include "esp_lcd_panel_interface.h"
|
||||||
|
#include "esp_lcd_panel_io.h"
|
||||||
|
#include "esp_lcd_panel_vendor.h"
|
||||||
|
#include "esp_lcd_panel_ops.h"
|
||||||
|
#include "esp_lcd_panel_commands.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
|
||||||
|
#include "esp_lcd_st77916.h"
|
||||||
|
|
||||||
|
#define LCD_OPCODE_WRITE_CMD (0x02ULL)
|
||||||
|
#define LCD_OPCODE_READ_CMD (0x0BULL)
|
||||||
|
#define LCD_OPCODE_WRITE_COLOR (0x32ULL)
|
||||||
|
|
||||||
|
#define ST77916_CMD_SET (0xF0)
|
||||||
|
#define ST77916_PARAM_SET (0x00)
|
||||||
|
|
||||||
|
static const char *TAG = "st77916";
|
||||||
|
|
||||||
|
static esp_err_t panel_st77916_del(esp_lcd_panel_t *panel);
|
||||||
|
static esp_err_t panel_st77916_reset(esp_lcd_panel_t *panel);
|
||||||
|
static esp_err_t panel_st77916_init(esp_lcd_panel_t *panel);
|
||||||
|
static esp_err_t panel_st77916_draw_bitmap(esp_lcd_panel_t *panel, int x_start, int y_start, int x_end, int y_end, const void *color_data);
|
||||||
|
static esp_err_t panel_st77916_invert_color(esp_lcd_panel_t *panel, bool invert_color_data);
|
||||||
|
static esp_err_t panel_st77916_mirror(esp_lcd_panel_t *panel, bool mirror_x, bool mirror_y);
|
||||||
|
static esp_err_t panel_st77916_swap_xy(esp_lcd_panel_t *panel, bool swap_axes);
|
||||||
|
static esp_err_t panel_st77916_set_gap(esp_lcd_panel_t *panel, int x_gap, int y_gap);
|
||||||
|
static esp_err_t panel_st77916_disp_on_off(esp_lcd_panel_t *panel, bool off);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
esp_lcd_panel_t base;
|
||||||
|
esp_lcd_panel_io_handle_t io;
|
||||||
|
int reset_gpio_num;
|
||||||
|
int x_gap;
|
||||||
|
int y_gap;
|
||||||
|
uint8_t fb_bits_per_pixel;
|
||||||
|
uint8_t madctl_val; // save current value of LCD_CMD_MADCTL register
|
||||||
|
uint8_t colmod_val; // save surrent value of LCD_CMD_COLMOD register
|
||||||
|
const st77916_lcd_init_cmd_t *init_cmds;
|
||||||
|
uint16_t init_cmds_size;
|
||||||
|
struct {
|
||||||
|
unsigned int use_qspi_interface: 1;
|
||||||
|
unsigned int reset_level: 1;
|
||||||
|
} flags;
|
||||||
|
} st77916_panel_t;
|
||||||
|
|
||||||
|
esp_err_t esp_lcd_new_panel_st77916(const esp_lcd_panel_io_handle_t io, const esp_lcd_panel_dev_config_t *panel_dev_config, esp_lcd_panel_handle_t *ret_panel)
|
||||||
|
{
|
||||||
|
ESP_RETURN_ON_FALSE(io && panel_dev_config && ret_panel, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||||
|
|
||||||
|
esp_err_t ret = ESP_OK;
|
||||||
|
st77916_panel_t *st77916 = NULL;
|
||||||
|
st77916 = calloc(1, sizeof(st77916_panel_t));
|
||||||
|
ESP_GOTO_ON_FALSE(st77916, ESP_ERR_NO_MEM, err, TAG, "no mem for st77916 panel");
|
||||||
|
|
||||||
|
if (panel_dev_config->reset_gpio_num >= 0) {
|
||||||
|
gpio_config_t io_conf = {
|
||||||
|
.mode = GPIO_MODE_OUTPUT,
|
||||||
|
.pin_bit_mask = 1ULL << panel_dev_config->reset_gpio_num,
|
||||||
|
};
|
||||||
|
ESP_GOTO_ON_ERROR(gpio_config(&io_conf), err, TAG, "configure GPIO for RST line failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (panel_dev_config->rgb_ele_order) {
|
||||||
|
case LCD_RGB_ELEMENT_ORDER_RGB:
|
||||||
|
st77916->madctl_val = 0;
|
||||||
|
break;
|
||||||
|
case LCD_RGB_ELEMENT_ORDER_BGR:
|
||||||
|
st77916->madctl_val |= LCD_CMD_BGR_BIT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ESP_GOTO_ON_FALSE(false, ESP_ERR_NOT_SUPPORTED, err, TAG, "unsupported color element order");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (panel_dev_config->bits_per_pixel) {
|
||||||
|
case 16: // RGB565
|
||||||
|
st77916->colmod_val = 0x55;
|
||||||
|
st77916->fb_bits_per_pixel = 16;
|
||||||
|
break;
|
||||||
|
case 18: // RGB666
|
||||||
|
st77916->colmod_val = 0x66;
|
||||||
|
// each color component (R/G/B) should occupy the 6 high bits of a byte, which means 3 full bytes are required for a pixel
|
||||||
|
st77916->fb_bits_per_pixel = 24;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ESP_GOTO_ON_FALSE(false, ESP_ERR_NOT_SUPPORTED, err, TAG, "unsupported pixel width");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
st77916->io = io;
|
||||||
|
st77916->reset_gpio_num = panel_dev_config->reset_gpio_num;
|
||||||
|
st77916->flags.reset_level = panel_dev_config->flags.reset_active_high;
|
||||||
|
st77916_vendor_config_t *vendor_config = (st77916_vendor_config_t *)panel_dev_config->vendor_config;
|
||||||
|
if (vendor_config) {
|
||||||
|
st77916->init_cmds = vendor_config->init_cmds;
|
||||||
|
st77916->init_cmds_size = vendor_config->init_cmds_size;
|
||||||
|
st77916->flags.use_qspi_interface = vendor_config->flags.use_qspi_interface;
|
||||||
|
}
|
||||||
|
st77916->base.del = panel_st77916_del;
|
||||||
|
st77916->base.reset = panel_st77916_reset;
|
||||||
|
st77916->base.init = panel_st77916_init;
|
||||||
|
st77916->base.draw_bitmap = panel_st77916_draw_bitmap;
|
||||||
|
st77916->base.invert_color = panel_st77916_invert_color;
|
||||||
|
st77916->base.set_gap = panel_st77916_set_gap;
|
||||||
|
st77916->base.mirror = panel_st77916_mirror;
|
||||||
|
st77916->base.swap_xy = panel_st77916_swap_xy;
|
||||||
|
st77916->base.disp_on_off = panel_st77916_disp_on_off;
|
||||||
|
*ret_panel = &(st77916->base);
|
||||||
|
ESP_LOGD(TAG, "new st77916 panel @%p", st77916);
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "LCD panel create success, version: %d.%d.%d", ESP_LCD_ST77916_VER_MAJOR, ESP_LCD_ST77916_VER_MINOR,
|
||||||
|
ESP_LCD_ST77916_VER_PATCH);
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
|
||||||
|
err:
|
||||||
|
if (st77916) {
|
||||||
|
if (panel_dev_config->reset_gpio_num >= 0) {
|
||||||
|
gpio_reset_pin(panel_dev_config->reset_gpio_num);
|
||||||
|
}
|
||||||
|
free(st77916);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t tx_param(st77916_panel_t *st77916, esp_lcd_panel_io_handle_t io, int lcd_cmd, const void *param, size_t param_size)
|
||||||
|
{
|
||||||
|
if (st77916->flags.use_qspi_interface) {
|
||||||
|
lcd_cmd &= 0xff;
|
||||||
|
lcd_cmd <<= 8;
|
||||||
|
lcd_cmd |= LCD_OPCODE_WRITE_CMD << 24;
|
||||||
|
}
|
||||||
|
return esp_lcd_panel_io_tx_param(io, lcd_cmd, param, param_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t tx_color(st77916_panel_t *st77916, esp_lcd_panel_io_handle_t io, int lcd_cmd, const void *param, size_t param_size)
|
||||||
|
{
|
||||||
|
if (st77916->flags.use_qspi_interface) {
|
||||||
|
lcd_cmd &= 0xff;
|
||||||
|
lcd_cmd <<= 8;
|
||||||
|
lcd_cmd |= LCD_OPCODE_WRITE_COLOR << 24;
|
||||||
|
}
|
||||||
|
return esp_lcd_panel_io_tx_color(io, lcd_cmd, param, param_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t panel_st77916_del(esp_lcd_panel_t *panel)
|
||||||
|
{
|
||||||
|
st77916_panel_t *st77916 = __containerof(panel, st77916_panel_t, base);
|
||||||
|
|
||||||
|
if (st77916->reset_gpio_num >= 0) {
|
||||||
|
gpio_reset_pin(st77916->reset_gpio_num);
|
||||||
|
}
|
||||||
|
ESP_LOGD(TAG, "del st77916 panel @%p", st77916);
|
||||||
|
free(st77916);
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t panel_st77916_reset(esp_lcd_panel_t *panel)
|
||||||
|
{
|
||||||
|
st77916_panel_t *st77916 = __containerof(panel, st77916_panel_t, base);
|
||||||
|
esp_lcd_panel_io_handle_t io = st77916->io;
|
||||||
|
|
||||||
|
// Perform hardware reset
|
||||||
|
if (st77916->reset_gpio_num >= 0) {
|
||||||
|
gpio_set_level(st77916->reset_gpio_num, st77916->flags.reset_level);
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(10));
|
||||||
|
gpio_set_level(st77916->reset_gpio_num, !st77916->flags.reset_level);
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(120));
|
||||||
|
} else { // Perform software reset
|
||||||
|
ESP_RETURN_ON_ERROR(tx_param(st77916, io, LCD_CMD_SWRESET, NULL, 0), TAG, "send command failed");
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(120));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const st77916_lcd_init_cmd_t vendor_specific_init_default[] = {
|
||||||
|
{0xF0, (uint8_t []){0x08}, 1, 0},
|
||||||
|
{0xF2, (uint8_t []){0x08}, 1, 0},
|
||||||
|
{0x9B, (uint8_t []){0x51}, 1, 0},
|
||||||
|
{0x86, (uint8_t []){0x53}, 1, 0},
|
||||||
|
{0xF2, (uint8_t []){0x80}, 1, 0},
|
||||||
|
{0xF0, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0xF0, (uint8_t []){0x01}, 1, 0},
|
||||||
|
{0xF1, (uint8_t []){0x01}, 1, 0},
|
||||||
|
{0xB0, (uint8_t []){0x54}, 1, 0},
|
||||||
|
{0xB1, (uint8_t []){0x3F}, 1, 0},
|
||||||
|
{0xB2, (uint8_t []){0x2A}, 1, 0},
|
||||||
|
{0xB4, (uint8_t []){0x46}, 1, 0},
|
||||||
|
{0xB5, (uint8_t []){0x34}, 1, 0},
|
||||||
|
{0xB6, (uint8_t []){0xD5}, 1, 0},
|
||||||
|
{0xB7, (uint8_t []){0x30}, 1, 0},
|
||||||
|
{0xB8, (uint8_t []){0x04}, 1, 0},
|
||||||
|
{0xBA, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0xBB, (uint8_t []){0x08}, 1, 0},
|
||||||
|
{0xBC, (uint8_t []){0x08}, 1, 0},
|
||||||
|
{0xBD, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0xC0, (uint8_t []){0x80}, 1, 0},
|
||||||
|
{0xC1, (uint8_t []){0x10}, 1, 0},
|
||||||
|
{0xC2, (uint8_t []){0x37}, 1, 0},
|
||||||
|
{0xC3, (uint8_t []){0x80}, 1, 0},
|
||||||
|
{0xC4, (uint8_t []){0x10}, 1, 0},
|
||||||
|
{0xC5, (uint8_t []){0x37}, 1, 0},
|
||||||
|
{0xC6, (uint8_t []){0xA9}, 1, 0},
|
||||||
|
{0xC7, (uint8_t []){0x41}, 1, 0},
|
||||||
|
{0xC8, (uint8_t []){0x51}, 1, 0},
|
||||||
|
{0xC9, (uint8_t []){0xA9}, 1, 0},
|
||||||
|
{0xCA, (uint8_t []){0x41}, 1, 0},
|
||||||
|
{0xCB, (uint8_t []){0x51}, 1, 0},
|
||||||
|
{0xD0, (uint8_t []){0x91}, 1, 0},
|
||||||
|
{0xD1, (uint8_t []){0x68}, 1, 0},
|
||||||
|
{0xD2, (uint8_t []){0x69}, 1, 0},
|
||||||
|
{0xF5, (uint8_t []){0x00, 0xA5}, 2, 0},
|
||||||
|
{0xDD, (uint8_t []){0x35}, 1, 0},
|
||||||
|
{0xDE, (uint8_t []){0x35}, 1, 0},
|
||||||
|
{0xF1, (uint8_t []){0x10}, 1, 0},
|
||||||
|
{0xF0, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0xF0, (uint8_t []){0x02}, 1, 0},
|
||||||
|
{0xE0, (uint8_t []){0x70, 0x09, 0x12, 0x0C, 0x0B, 0x27, 0x38, 0x54, 0x4E, 0x19, 0x15, 0x15, 0x2C, 0x2F}, 14, 0},
|
||||||
|
{0xE1, (uint8_t []){0x70, 0x08, 0x11, 0x0C, 0x0B, 0x27, 0x38, 0x43, 0x4C, 0x18, 0x14, 0x14, 0x2B, 0x2D}, 14, 0},
|
||||||
|
{0xF0, (uint8_t []){0x10}, 1, 0},
|
||||||
|
{0xF3, (uint8_t []){0x10}, 1, 0},
|
||||||
|
{0xE0, (uint8_t []){0x0A}, 1, 0},
|
||||||
|
{0xE1, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0xE2, (uint8_t []){0x0B}, 1, 0},
|
||||||
|
{0xE3, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0xE4, (uint8_t []){0xE0}, 1, 0},
|
||||||
|
{0xE5, (uint8_t []){0x06}, 1, 0},
|
||||||
|
{0xE6, (uint8_t []){0x21}, 1, 0},
|
||||||
|
{0xE7, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0xE8, (uint8_t []){0x05}, 1, 0},
|
||||||
|
{0xE9, (uint8_t []){0x82}, 1, 0},
|
||||||
|
{0xEA, (uint8_t []){0xDF}, 1, 0},
|
||||||
|
{0xEB, (uint8_t []){0x89}, 1, 0},
|
||||||
|
{0xEC, (uint8_t []){0x20}, 1, 0},
|
||||||
|
{0xED, (uint8_t []){0x14}, 1, 0},
|
||||||
|
{0xEE, (uint8_t []){0xFF}, 1, 0},
|
||||||
|
{0xEF, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0xF8, (uint8_t []){0xFF}, 1, 0},
|
||||||
|
{0xF9, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0xFA, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0xFB, (uint8_t []){0x30}, 1, 0},
|
||||||
|
{0xFC, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0xFD, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0xFE, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0xFF, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0x60, (uint8_t []){0x42}, 1, 0},
|
||||||
|
{0x61, (uint8_t []){0xE0}, 1, 0},
|
||||||
|
{0x62, (uint8_t []){0x40}, 1, 0},
|
||||||
|
{0x63, (uint8_t []){0x40}, 1, 0},
|
||||||
|
{0x64, (uint8_t []){0x02}, 1, 0},
|
||||||
|
{0x65, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0x66, (uint8_t []){0x40}, 1, 0},
|
||||||
|
{0x67, (uint8_t []){0x03}, 1, 0},
|
||||||
|
{0x68, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0x69, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0x6A, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0x6B, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0x70, (uint8_t []){0x42}, 1, 0},
|
||||||
|
{0x71, (uint8_t []){0xE0}, 1, 0},
|
||||||
|
{0x72, (uint8_t []){0x40}, 1, 0},
|
||||||
|
{0x73, (uint8_t []){0x40}, 1, 0},
|
||||||
|
{0x74, (uint8_t []){0x02}, 1, 0},
|
||||||
|
{0x75, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0x76, (uint8_t []){0x40}, 1, 0},
|
||||||
|
{0x77, (uint8_t []){0x03}, 1, 0},
|
||||||
|
{0x78, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0x79, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0x7A, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0x7B, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0x80, (uint8_t []){0x38}, 1, 0},
|
||||||
|
{0x81, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0x82, (uint8_t []){0x04}, 1, 0},
|
||||||
|
{0x83, (uint8_t []){0x02}, 1, 0},
|
||||||
|
{0x84, (uint8_t []){0xDC}, 1, 0},
|
||||||
|
{0x85, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0x86, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0x87, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0x88, (uint8_t []){0x38}, 1, 0},
|
||||||
|
{0x89, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0x8A, (uint8_t []){0x06}, 1, 0},
|
||||||
|
{0x8B, (uint8_t []){0x02}, 1, 0},
|
||||||
|
{0x8C, (uint8_t []){0xDE}, 1, 0},
|
||||||
|
{0x8D, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0x8E, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0x8F, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0x90, (uint8_t []){0x38}, 1, 0},
|
||||||
|
{0x91, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0x92, (uint8_t []){0x08}, 1, 0},
|
||||||
|
{0x93, (uint8_t []){0x02}, 1, 0},
|
||||||
|
{0x94, (uint8_t []){0xE0}, 1, 0},
|
||||||
|
{0x95, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0x96, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0x97, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0x98, (uint8_t []){0x38}, 1, 0},
|
||||||
|
{0x99, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0x9A, (uint8_t []){0x0A}, 1, 0},
|
||||||
|
{0x9B, (uint8_t []){0x02}, 1, 0},
|
||||||
|
{0x9C, (uint8_t []){0xE2}, 1, 0},
|
||||||
|
{0x9D, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0x9E, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0x9F, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0xA0, (uint8_t []){0x38}, 1, 0},
|
||||||
|
{0xA1, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0xA2, (uint8_t []){0x03}, 1, 0},
|
||||||
|
{0xA3, (uint8_t []){0x02}, 1, 0},
|
||||||
|
{0xA4, (uint8_t []){0xDB}, 1, 0},
|
||||||
|
{0xA5, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0xA6, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0xA7, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0xA8, (uint8_t []){0x38}, 1, 0},
|
||||||
|
{0xA9, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0xAA, (uint8_t []){0x05}, 1, 0},
|
||||||
|
{0xAB, (uint8_t []){0x02}, 1, 0},
|
||||||
|
{0xAC, (uint8_t []){0xDD}, 1, 0},
|
||||||
|
{0xAD, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0xAE, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0xAF, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0xB0, (uint8_t []){0x38}, 1, 0},
|
||||||
|
{0xB1, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0xB2, (uint8_t []){0x07}, 1, 0},
|
||||||
|
{0xB3, (uint8_t []){0x02}, 1, 0},
|
||||||
|
{0xB4, (uint8_t []){0xDF}, 1, 0},
|
||||||
|
{0xB5, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0xB6, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0xB7, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0xB8, (uint8_t []){0x38}, 1, 0},
|
||||||
|
{0xB9, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0xBA, (uint8_t []){0x09}, 1, 0},
|
||||||
|
{0xBB, (uint8_t []){0x02}, 1, 0},
|
||||||
|
{0xBC, (uint8_t []){0xE1}, 1, 0},
|
||||||
|
{0xBD, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0xBE, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0xBF, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0xC0, (uint8_t []){0x22}, 1, 0},
|
||||||
|
{0xC1, (uint8_t []){0xAA}, 1, 0},
|
||||||
|
{0xC2, (uint8_t []){0x65}, 1, 0},
|
||||||
|
{0xC3, (uint8_t []){0x74}, 1, 0},
|
||||||
|
{0xC4, (uint8_t []){0x47}, 1, 0},
|
||||||
|
{0xC5, (uint8_t []){0x56}, 1, 0},
|
||||||
|
{0xC6, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0xC7, (uint8_t []){0x88}, 1, 0},
|
||||||
|
{0xC8, (uint8_t []){0x99}, 1, 0},
|
||||||
|
{0xC9, (uint8_t []){0x33}, 1, 0},
|
||||||
|
{0xD0, (uint8_t []){0x11}, 1, 0},
|
||||||
|
{0xD1, (uint8_t []){0xAA}, 1, 0},
|
||||||
|
{0xD2, (uint8_t []){0x65}, 1, 0},
|
||||||
|
{0xD3, (uint8_t []){0x74}, 1, 0},
|
||||||
|
{0xD4, (uint8_t []){0x47}, 1, 0},
|
||||||
|
{0xD5, (uint8_t []){0x56}, 1, 0},
|
||||||
|
{0xD6, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0xD7, (uint8_t []){0x88}, 1, 0},
|
||||||
|
{0xD8, (uint8_t []){0x99}, 1, 0},
|
||||||
|
{0xD9, (uint8_t []){0x33}, 1, 0},
|
||||||
|
{0xF3, (uint8_t []){0x01}, 1, 0},
|
||||||
|
{0xF0, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0xF0, (uint8_t []){0x01}, 1, 0},
|
||||||
|
{0xF1, (uint8_t []){0x01}, 1, 0},
|
||||||
|
{0xA0, (uint8_t []){0x0B}, 1, 0},
|
||||||
|
{0xA3, (uint8_t []){0x2A}, 1, 0},
|
||||||
|
{0xA5, (uint8_t []){0xC3}, 1, 1},
|
||||||
|
{0xA3, (uint8_t []){0x2B}, 1, 0},
|
||||||
|
{0xA5, (uint8_t []){0xC3}, 1, 1},
|
||||||
|
{0xA3, (uint8_t []){0x2C}, 1, 0},
|
||||||
|
{0xA5, (uint8_t []){0xC3}, 1, 1},
|
||||||
|
{0xA3, (uint8_t []){0x2D}, 1, 0},
|
||||||
|
{0xA5, (uint8_t []){0xC3}, 1, 1},
|
||||||
|
{0xA3, (uint8_t []){0x2E}, 1, 0},
|
||||||
|
{0xA5, (uint8_t []){0xC3}, 1, 1},
|
||||||
|
{0xA3, (uint8_t []){0x2F}, 1, 0},
|
||||||
|
{0xA5, (uint8_t []){0xC3}, 1, 1},
|
||||||
|
{0xA3, (uint8_t []){0x30}, 1, 0},
|
||||||
|
{0xA5, (uint8_t []){0xC3}, 1, 1},
|
||||||
|
{0xA3, (uint8_t []){0x31}, 1, 0},
|
||||||
|
{0xA5, (uint8_t []){0xC3}, 1, 1},
|
||||||
|
{0xA3, (uint8_t []){0x32}, 1, 0},
|
||||||
|
{0xA5, (uint8_t []){0xC3}, 1, 1},
|
||||||
|
{0xA3, (uint8_t []){0x33}, 1, 0},
|
||||||
|
{0xA5, (uint8_t []){0xC3}, 1, 1},
|
||||||
|
{0xA0, (uint8_t []){0x09}, 1, 0},
|
||||||
|
{0xF1, (uint8_t []){0x10}, 1, 0},
|
||||||
|
{0xF0, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0x2A, (uint8_t []){0x00, 0x00, 0x01, 0x67}, 4, 0},
|
||||||
|
{0x2B, (uint8_t []){0x01, 0x68, 0x01, 0x68}, 4, 0},
|
||||||
|
{0x4D, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0x4E, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0x4F, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0x4C, (uint8_t []){0x01}, 1, 10},
|
||||||
|
{0x4C, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0x2A, (uint8_t []){0x00, 0x00, 0x01, 0x67}, 4, 0},
|
||||||
|
{0x2B, (uint8_t []){0x00, 0x00, 0x01, 0x67}, 4, 0},
|
||||||
|
{0x21, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0x11, (uint8_t []){0x00}, 1, 120},
|
||||||
|
};
|
||||||
|
|
||||||
|
static esp_err_t panel_st77916_init(esp_lcd_panel_t *panel)
|
||||||
|
{
|
||||||
|
st77916_panel_t *st77916 = __containerof(panel, st77916_panel_t, base);
|
||||||
|
esp_lcd_panel_io_handle_t io = st77916->io;
|
||||||
|
const st77916_lcd_init_cmd_t *init_cmds = NULL;
|
||||||
|
uint16_t init_cmds_size = 0;
|
||||||
|
bool is_user_set = true;
|
||||||
|
bool is_cmd_overwritten = false;
|
||||||
|
|
||||||
|
ESP_RETURN_ON_ERROR(tx_param(st77916, io, LCD_CMD_MADCTL, (uint8_t[]) {
|
||||||
|
st77916->madctl_val,
|
||||||
|
}, 1), TAG, "send command failed");
|
||||||
|
ESP_RETURN_ON_ERROR(tx_param(st77916, io, LCD_CMD_COLMOD, (uint8_t[]) {
|
||||||
|
st77916->colmod_val,
|
||||||
|
}, 1), TAG, "send command failed");
|
||||||
|
|
||||||
|
// vendor specific initialization, it can be different between manufacturers
|
||||||
|
// should consult the LCD supplier for initialization sequence code
|
||||||
|
if (st77916->init_cmds) {
|
||||||
|
init_cmds = st77916->init_cmds;
|
||||||
|
init_cmds_size = st77916->init_cmds_size;
|
||||||
|
} else {
|
||||||
|
init_cmds = vendor_specific_init_default;
|
||||||
|
init_cmds_size = sizeof(vendor_specific_init_default) / sizeof(st77916_lcd_init_cmd_t);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < init_cmds_size; i++) {
|
||||||
|
// Check if the command has been used or conflicts with the internal
|
||||||
|
if (is_user_set && (init_cmds[i].data_bytes > 0)) {
|
||||||
|
switch (init_cmds[i].cmd) {
|
||||||
|
case LCD_CMD_MADCTL:
|
||||||
|
is_cmd_overwritten = true;
|
||||||
|
st77916->madctl_val = ((uint8_t *)init_cmds[i].data)[0];
|
||||||
|
break;
|
||||||
|
case LCD_CMD_COLMOD:
|
||||||
|
is_cmd_overwritten = true;
|
||||||
|
st77916->colmod_val = ((uint8_t *)init_cmds[i].data)[0];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
is_cmd_overwritten = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_cmd_overwritten) {
|
||||||
|
is_cmd_overwritten = false;
|
||||||
|
ESP_LOGW(TAG, "The %02Xh command has been used and will be overwritten by external initialization sequence", init_cmds[i].cmd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send command
|
||||||
|
ESP_RETURN_ON_ERROR(tx_param(st77916, io, init_cmds[i].cmd, init_cmds[i].data, init_cmds[i].data_bytes), TAG, "send command failed");
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(init_cmds[i].delay_ms));
|
||||||
|
|
||||||
|
// Check if the current cmd is the "command set" cmd
|
||||||
|
if ((init_cmds[i].cmd == ST77916_CMD_SET)) {
|
||||||
|
is_user_set = ((uint8_t *)init_cmds[i].data)[0] == ST77916_PARAM_SET ? true : false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ESP_LOGD(TAG, "send init commands success");
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t panel_st77916_draw_bitmap(esp_lcd_panel_t *panel, int x_start, int y_start, int x_end, int y_end, const void *color_data)
|
||||||
|
{
|
||||||
|
st77916_panel_t *st77916 = __containerof(panel, st77916_panel_t, base);
|
||||||
|
assert((x_start < x_end) && (y_start < y_end) && "start position must be smaller than end position");
|
||||||
|
esp_lcd_panel_io_handle_t io = st77916->io;
|
||||||
|
|
||||||
|
x_start += st77916->x_gap;
|
||||||
|
x_end += st77916->x_gap;
|
||||||
|
y_start += st77916->y_gap;
|
||||||
|
y_end += st77916->y_gap;
|
||||||
|
|
||||||
|
// define an area of frame memory where MCU can access
|
||||||
|
ESP_RETURN_ON_ERROR(tx_param(st77916, io, LCD_CMD_CASET, (uint8_t[]) {
|
||||||
|
(x_start >> 8) & 0xFF,
|
||||||
|
x_start & 0xFF,
|
||||||
|
((x_end - 1) >> 8) & 0xFF,
|
||||||
|
(x_end - 1) & 0xFF,
|
||||||
|
}, 4), TAG, "send command failed");
|
||||||
|
ESP_RETURN_ON_ERROR(tx_param(st77916, io, LCD_CMD_RASET, (uint8_t[]) {
|
||||||
|
(y_start >> 8) & 0xFF,
|
||||||
|
y_start & 0xFF,
|
||||||
|
((y_end - 1) >> 8) & 0xFF,
|
||||||
|
(y_end - 1) & 0xFF,
|
||||||
|
}, 4), TAG, "send command failed");
|
||||||
|
// transfer frame buffer
|
||||||
|
size_t len = (x_end - x_start) * (y_end - y_start) * st77916->fb_bits_per_pixel / 8;
|
||||||
|
tx_color(st77916, io, LCD_CMD_RAMWR, color_data, len);
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t panel_st77916_invert_color(esp_lcd_panel_t *panel, bool invert_color_data)
|
||||||
|
{
|
||||||
|
st77916_panel_t *st77916 = __containerof(panel, st77916_panel_t, base);
|
||||||
|
esp_lcd_panel_io_handle_t io = st77916->io;
|
||||||
|
int command = 0;
|
||||||
|
if (invert_color_data) {
|
||||||
|
command = LCD_CMD_INVON;
|
||||||
|
} else {
|
||||||
|
command = LCD_CMD_INVOFF;
|
||||||
|
}
|
||||||
|
ESP_RETURN_ON_ERROR(tx_param(st77916, io, command, NULL, 0), TAG, "send command failed");
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t panel_st77916_mirror(esp_lcd_panel_t *panel, bool mirror_x, bool mirror_y)
|
||||||
|
{
|
||||||
|
st77916_panel_t *st77916 = __containerof(panel, st77916_panel_t, base);
|
||||||
|
esp_lcd_panel_io_handle_t io = st77916->io;
|
||||||
|
esp_err_t ret = ESP_OK;
|
||||||
|
|
||||||
|
if (mirror_x) {
|
||||||
|
st77916->madctl_val |= BIT(6);
|
||||||
|
} else {
|
||||||
|
st77916->madctl_val &= ~BIT(6);
|
||||||
|
}
|
||||||
|
if (mirror_y) {
|
||||||
|
st77916->madctl_val |= BIT(7);
|
||||||
|
} else {
|
||||||
|
st77916->madctl_val &= ~BIT(7);
|
||||||
|
}
|
||||||
|
ESP_RETURN_ON_ERROR(tx_param(st77916, io, LCD_CMD_MADCTL, (uint8_t[]) {
|
||||||
|
st77916->madctl_val
|
||||||
|
}, 1), TAG, "send command failed");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t panel_st77916_swap_xy(esp_lcd_panel_t *panel, bool swap_axes)
|
||||||
|
{
|
||||||
|
st77916_panel_t *st77916 = __containerof(panel, st77916_panel_t, base);
|
||||||
|
esp_lcd_panel_io_handle_t io = st77916->io;
|
||||||
|
if (swap_axes) {
|
||||||
|
st77916->madctl_val |= LCD_CMD_MV_BIT;
|
||||||
|
} else {
|
||||||
|
st77916->madctl_val &= ~LCD_CMD_MV_BIT;
|
||||||
|
}
|
||||||
|
ESP_RETURN_ON_ERROR(tx_param(st77916, io, LCD_CMD_MADCTL, (uint8_t[]) {
|
||||||
|
st77916->madctl_val
|
||||||
|
}, 1), TAG, "send command failed");
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t panel_st77916_set_gap(esp_lcd_panel_t *panel, int x_gap, int y_gap)
|
||||||
|
{
|
||||||
|
st77916_panel_t *st77916 = __containerof(panel, st77916_panel_t, base);
|
||||||
|
st77916->x_gap = x_gap;
|
||||||
|
st77916->y_gap = y_gap;
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t panel_st77916_disp_on_off(esp_lcd_panel_t *panel, bool on_off)
|
||||||
|
{
|
||||||
|
st77916_panel_t *st77916 = __containerof(panel, st77916_panel_t, base);
|
||||||
|
esp_lcd_panel_io_handle_t io = st77916->io;
|
||||||
|
int command = 0;
|
||||||
|
|
||||||
|
if (on_off) {
|
||||||
|
command = LCD_CMD_DISPON;
|
||||||
|
} else {
|
||||||
|
command = LCD_CMD_DISPOFF;
|
||||||
|
}
|
||||||
|
ESP_RETURN_ON_ERROR(tx_param(st77916, io, command, NULL, 0), TAG, "send command failed");
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
dependencies:
|
||||||
|
cmake_utilities: 0.*
|
||||||
|
idf: '>5.0.4,!=5.1.1'
|
||||||
|
description: ESP LCD ST77916(SPI & QSPI)
|
||||||
|
issues: https://github.com/espressif/esp-iot-solution/issues
|
||||||
|
repository: git://github.com/espressif/esp-iot-solution.git
|
||||||
|
repository_info:
|
||||||
|
commit_sha: 6a112f4ddfeaf30ec360567ea9260a39e195c385
|
||||||
|
path: components/display/lcd/esp_lcd_st77916
|
||||||
|
url: https://github.com/espressif/esp-iot-solution/tree/master/components/display/lcd/esp_lcd_st77916
|
||||||
|
version: 1.0.1
|
||||||
@ -0,0 +1,114 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "esp_lcd_panel_vendor.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief LCD panel initialization commands.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
int cmd; /*<! The specific LCD command */
|
||||||
|
const void *data; /*<! Buffer that holds the command specific data */
|
||||||
|
size_t data_bytes; /*<! Size of `data` in memory, in bytes */
|
||||||
|
unsigned int delay_ms; /*<! Delay in milliseconds after this command */
|
||||||
|
} st77916_lcd_init_cmd_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief LCD panel vendor configuration.
|
||||||
|
*
|
||||||
|
* @note This structure can be used to select interface type and override default initialization commands.
|
||||||
|
* @note This structure needs to be passed to the `vendor_config` field in `esp_lcd_panel_dev_config_t`.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
const st77916_lcd_init_cmd_t *init_cmds; /*!< Pointer to initialization commands array.
|
||||||
|
* The array should be declared as `static const` and positioned outside the function.
|
||||||
|
* Please refer to `vendor_specific_init_default` in source file
|
||||||
|
*/
|
||||||
|
uint16_t init_cmds_size; /*<! Number of commands in above array */
|
||||||
|
struct {
|
||||||
|
unsigned int use_qspi_interface: 1; /*<! Set to 1 if use QSPI interface, default is SPI interface */
|
||||||
|
} flags;
|
||||||
|
} st77916_vendor_config_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create LCD panel for model ST77916
|
||||||
|
*
|
||||||
|
* @param[in] io LCD panel IO handle
|
||||||
|
* @param[in] panel_dev_config General panel device configuration (Use `vendor_config` to select QSPI interface or override default initialization commands)
|
||||||
|
* @param[out] ret_panel Returned LCD panel handle
|
||||||
|
* @return
|
||||||
|
* - ESP_OK: Success
|
||||||
|
* - Otherwise: Fail
|
||||||
|
*/
|
||||||
|
esp_err_t esp_lcd_new_panel_st77916(const esp_lcd_panel_io_handle_t io, const esp_lcd_panel_dev_config_t *panel_dev_config, esp_lcd_panel_handle_t *ret_panel);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief LCD panel bus configuration structure
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#define ST77916_PANEL_BUS_SPI_CONFIG(sclk, mosi, max_trans_sz) \
|
||||||
|
{ \
|
||||||
|
.sclk_io_num = sclk, \
|
||||||
|
.mosi_io_num = mosi, \
|
||||||
|
.miso_io_num = -1, \
|
||||||
|
.quadhd_io_num = -1, \
|
||||||
|
.quadwp_io_num = -1, \
|
||||||
|
.max_transfer_sz = max_trans_sz, \
|
||||||
|
}
|
||||||
|
#define ST77916_PANEL_BUS_QSPI_CONFIG(sclk, d0, d1, d2, d3, max_trans_sz)\
|
||||||
|
{ \
|
||||||
|
.sclk_io_num = sclk, \
|
||||||
|
.data0_io_num = d0, \
|
||||||
|
.data1_io_num = d1, \
|
||||||
|
.data2_io_num = d2, \
|
||||||
|
.data3_io_num = d3, \
|
||||||
|
.max_transfer_sz = max_trans_sz, \
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief LCD panel IO configuration structure
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#define ST77916_PANEL_IO_SPI_CONFIG(cs, dc, cb, cb_ctx) \
|
||||||
|
{ \
|
||||||
|
.cs_gpio_num = cs, \
|
||||||
|
.dc_gpio_num = dc, \
|
||||||
|
.spi_mode = 0, \
|
||||||
|
.pclk_hz = 40 * 1000 * 1000, \
|
||||||
|
.trans_queue_depth = 10, \
|
||||||
|
.on_color_trans_done = cb, \
|
||||||
|
.user_ctx = cb_ctx, \
|
||||||
|
.lcd_cmd_bits = 8, \
|
||||||
|
.lcd_param_bits = 8, \
|
||||||
|
}
|
||||||
|
#define ST77916_PANEL_IO_QSPI_CONFIG(cs, cb, cb_ctx) \
|
||||||
|
{ \
|
||||||
|
.cs_gpio_num = cs, \
|
||||||
|
.dc_gpio_num = -1, \
|
||||||
|
.spi_mode = 0, \
|
||||||
|
.pclk_hz = 40 * 1000 * 1000, \
|
||||||
|
.trans_queue_depth = 10, \
|
||||||
|
.on_color_trans_done = cb, \
|
||||||
|
.user_ctx = cb_ctx, \
|
||||||
|
.lcd_cmd_bits = 32, \
|
||||||
|
.lcd_param_bits = 8, \
|
||||||
|
.flags = { \
|
||||||
|
.quad_mode = true, \
|
||||||
|
}, \
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
202
managed_components/espressif__esp_lcd_st77916/license.txt
Normal file
202
managed_components/espressif__esp_lcd_st77916/license.txt
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
# The following lines of boilerplate have to be in your project's CMakeLists
|
||||||
|
# in this exact order for cmake to work correctly
|
||||||
|
cmake_minimum_required(VERSION 3.5)
|
||||||
|
set(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components")
|
||||||
|
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||||
|
project(test_esp_lcd_st77916)
|
||||||
@ -0,0 +1 @@
|
|||||||
|
idf_component_register(SRCS "test_esp_lcd_st77916.c")
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
## IDF Component Manager Manifest File
|
||||||
|
dependencies:
|
||||||
|
idf: ">5.0.4,!=5.1.1"
|
||||||
|
esp_lcd_st77916:
|
||||||
|
version: "*"
|
||||||
|
override_path: "../../../esp_lcd_st77916"
|
||||||
@ -0,0 +1,187 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
|
#include "freertos/semphr.h"
|
||||||
|
#include "driver/spi_master.h"
|
||||||
|
#include "driver/gpio.h"
|
||||||
|
#include "esp_heap_caps.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "esp_lcd_panel_io.h"
|
||||||
|
#include "esp_lcd_panel_ops.h"
|
||||||
|
#include "unity.h"
|
||||||
|
#include "unity_test_runner.h"
|
||||||
|
|
||||||
|
#include "esp_lcd_st77916.h"
|
||||||
|
|
||||||
|
#define TEST_LCD_HOST SPI2_HOST
|
||||||
|
#define TEST_LCD_H_RES (360)
|
||||||
|
#define TEST_LCD_V_RES (360)
|
||||||
|
#define TEST_LCD_BIT_PER_PIXEL (16)
|
||||||
|
|
||||||
|
#define TEST_PIN_NUM_LCD_CS (GPIO_NUM_9)
|
||||||
|
#define TEST_PIN_NUM_LCD_PCLK (GPIO_NUM_10)
|
||||||
|
#define TEST_PIN_NUM_LCD_DATA0 (GPIO_NUM_11)
|
||||||
|
#define TEST_PIN_NUM_LCD_DATA1 (GPIO_NUM_12)
|
||||||
|
#define TEST_PIN_NUM_LCD_DATA2 (GPIO_NUM_13)
|
||||||
|
#define TEST_PIN_NUM_LCD_DATA3 (GPIO_NUM_14)
|
||||||
|
#define TEST_PIN_NUM_LCD_RST (GPIO_NUM_17)
|
||||||
|
#define TEST_PIN_NUM_LCD_DC (GPIO_NUM_8)
|
||||||
|
|
||||||
|
#define TEST_DELAY_TIME_MS (3000)
|
||||||
|
|
||||||
|
static char *TAG = "st77916_test";
|
||||||
|
static SemaphoreHandle_t refresh_finish = NULL;
|
||||||
|
|
||||||
|
IRAM_ATTR static bool test_notify_refresh_ready(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_io_event_data_t *edata, void *user_ctx)
|
||||||
|
{
|
||||||
|
BaseType_t need_yield = pdFALSE;
|
||||||
|
|
||||||
|
xSemaphoreGiveFromISR(refresh_finish, &need_yield);
|
||||||
|
return (need_yield == pdTRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_draw_bitmap(esp_lcd_panel_handle_t panel_handle)
|
||||||
|
{
|
||||||
|
refresh_finish = xSemaphoreCreateBinary();
|
||||||
|
TEST_ASSERT_NOT_NULL(refresh_finish);
|
||||||
|
|
||||||
|
uint16_t row_line = ((TEST_LCD_V_RES / TEST_LCD_BIT_PER_PIXEL) << 1) >> 1;
|
||||||
|
uint8_t byte_per_pixel = TEST_LCD_BIT_PER_PIXEL / 8;
|
||||||
|
uint8_t *color = (uint8_t *)heap_caps_calloc(1, row_line * TEST_LCD_H_RES * byte_per_pixel, MALLOC_CAP_DMA);
|
||||||
|
TEST_ASSERT_NOT_NULL(color);
|
||||||
|
|
||||||
|
for (int j = 0; j < TEST_LCD_BIT_PER_PIXEL; j++) {
|
||||||
|
for (int i = 0; i < row_line * TEST_LCD_H_RES; i++) {
|
||||||
|
for (int k = 0; k < byte_per_pixel; k++) {
|
||||||
|
color[i * byte_per_pixel + k] = (SPI_SWAP_DATA_TX(BIT(j), TEST_LCD_BIT_PER_PIXEL) >> (k * 8)) & 0xff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TEST_ESP_OK(esp_lcd_panel_draw_bitmap(panel_handle, 0, j * row_line, TEST_LCD_H_RES, (j + 1) * row_line, color));
|
||||||
|
xSemaphoreTake(refresh_finish, portMAX_DELAY);
|
||||||
|
}
|
||||||
|
free(color);
|
||||||
|
vSemaphoreDelete(refresh_finish);
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(TEST_DELAY_TIME_MS));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("test st77916 to draw color bar with SPI interface", "[st77916][spi]")
|
||||||
|
{
|
||||||
|
ESP_LOGI(TAG, "Initialize SPI bus");
|
||||||
|
const spi_bus_config_t buscfg = ST77916_PANEL_BUS_SPI_CONFIG(TEST_PIN_NUM_LCD_PCLK, TEST_PIN_NUM_LCD_DATA0, TEST_LCD_H_RES * 80 * TEST_LCD_BIT_PER_PIXEL / 8);
|
||||||
|
TEST_ESP_OK(spi_bus_initialize(TEST_LCD_HOST, &buscfg, SPI_DMA_CH_AUTO));
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "Install panel IO");
|
||||||
|
esp_lcd_panel_io_handle_t io_handle = NULL;
|
||||||
|
const esp_lcd_panel_io_spi_config_t io_config = ST77916_PANEL_IO_SPI_CONFIG(TEST_PIN_NUM_LCD_CS, TEST_PIN_NUM_LCD_DC,
|
||||||
|
test_notify_refresh_ready, NULL);
|
||||||
|
// Attach the LCD to the SPI bus
|
||||||
|
TEST_ESP_OK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)TEST_LCD_HOST, &io_config, &io_handle));
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "Install LCD driver of st77916");
|
||||||
|
esp_lcd_panel_handle_t panel_handle = NULL;
|
||||||
|
const esp_lcd_panel_dev_config_t panel_config = {
|
||||||
|
.reset_gpio_num = TEST_PIN_NUM_LCD_RST,
|
||||||
|
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,
|
||||||
|
.bits_per_pixel = TEST_LCD_BIT_PER_PIXEL,
|
||||||
|
};
|
||||||
|
TEST_ESP_OK(esp_lcd_new_panel_st77916(io_handle, &panel_config, &panel_handle));
|
||||||
|
esp_lcd_panel_reset(panel_handle);
|
||||||
|
esp_lcd_panel_init(panel_handle);
|
||||||
|
esp_lcd_panel_disp_on_off(panel_handle, true);
|
||||||
|
|
||||||
|
test_draw_bitmap(panel_handle);
|
||||||
|
|
||||||
|
TEST_ESP_OK(esp_lcd_panel_del(panel_handle));
|
||||||
|
TEST_ESP_OK(esp_lcd_panel_io_del(io_handle));
|
||||||
|
TEST_ESP_OK(spi_bus_free(TEST_LCD_HOST));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("test st77916 to draw color bar with QSPI interface", "[st77916][qspi]")
|
||||||
|
{
|
||||||
|
ESP_LOGI(TAG, "Initialize SPI bus");
|
||||||
|
const spi_bus_config_t buscfg = ST77916_PANEL_BUS_QSPI_CONFIG(TEST_PIN_NUM_LCD_PCLK, TEST_PIN_NUM_LCD_DATA0,
|
||||||
|
TEST_PIN_NUM_LCD_DATA1, TEST_PIN_NUM_LCD_DATA2,
|
||||||
|
TEST_PIN_NUM_LCD_DATA3, TEST_LCD_H_RES * 80 * TEST_LCD_BIT_PER_PIXEL / 8);
|
||||||
|
TEST_ESP_OK(spi_bus_initialize(TEST_LCD_HOST, &buscfg, SPI_DMA_CH_AUTO));
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "Install panel IO");
|
||||||
|
esp_lcd_panel_io_handle_t io_handle = NULL;
|
||||||
|
const esp_lcd_panel_io_spi_config_t io_config = ST77916_PANEL_IO_QSPI_CONFIG(TEST_PIN_NUM_LCD_CS, test_notify_refresh_ready, NULL);
|
||||||
|
// Attach the LCD to the SPI bus
|
||||||
|
TEST_ESP_OK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)TEST_LCD_HOST, &io_config, &io_handle));
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "Install LCD driver of st77916");
|
||||||
|
esp_lcd_panel_handle_t panel_handle = NULL;
|
||||||
|
const st77916_vendor_config_t vendor_config = {
|
||||||
|
.flags = {
|
||||||
|
.use_qspi_interface = 1,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const esp_lcd_panel_dev_config_t panel_config = {
|
||||||
|
.reset_gpio_num = TEST_PIN_NUM_LCD_RST,
|
||||||
|
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,
|
||||||
|
.bits_per_pixel = TEST_LCD_BIT_PER_PIXEL,
|
||||||
|
.vendor_config = (void *) &vendor_config,
|
||||||
|
};
|
||||||
|
TEST_ESP_OK(esp_lcd_new_panel_st77916(io_handle, &panel_config, &panel_handle));
|
||||||
|
esp_lcd_panel_reset(panel_handle);
|
||||||
|
esp_lcd_panel_init(panel_handle);
|
||||||
|
esp_lcd_panel_disp_on_off(panel_handle, true);
|
||||||
|
|
||||||
|
test_draw_bitmap(panel_handle);
|
||||||
|
|
||||||
|
TEST_ESP_OK(esp_lcd_panel_del(panel_handle));
|
||||||
|
TEST_ESP_OK(esp_lcd_panel_io_del(io_handle));
|
||||||
|
TEST_ESP_OK(spi_bus_free(TEST_LCD_HOST));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Some resources are lazy allocated in the LCD driver, the threadhold is left for that case
|
||||||
|
#define TEST_MEMORY_LEAK_THRESHOLD (-300)
|
||||||
|
|
||||||
|
static size_t before_free_8bit;
|
||||||
|
static size_t before_free_32bit;
|
||||||
|
|
||||||
|
static void check_leak(size_t before_free, size_t after_free, const char *type)
|
||||||
|
{
|
||||||
|
ssize_t delta = after_free - before_free;
|
||||||
|
printf("MALLOC_CAP_%s: Before %u bytes free, After %u bytes free (delta %d)\n", type, before_free, after_free, delta);
|
||||||
|
TEST_ASSERT_MESSAGE(delta >= TEST_MEMORY_LEAK_THRESHOLD, "memory leak");
|
||||||
|
}
|
||||||
|
|
||||||
|
void setUp(void)
|
||||||
|
{
|
||||||
|
before_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
|
||||||
|
before_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tearDown(void)
|
||||||
|
{
|
||||||
|
size_t after_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
|
||||||
|
size_t after_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
|
||||||
|
check_leak(before_free_8bit, after_free_8bit, "8BIT");
|
||||||
|
check_leak(before_free_32bit, after_free_32bit, "32BIT");
|
||||||
|
}
|
||||||
|
|
||||||
|
void app_main(void)
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* __ _____ _____ _____ ___ _ __
|
||||||
|
* / _\/__ \___ |___ / _ \/ |/ /_
|
||||||
|
* \ \ / /\/ / / / / (_) | | '_ \
|
||||||
|
* _\ \ / / / / / / \__, | | (_) |
|
||||||
|
* \__/ \/ /_/ /_/ /_/|_|\___/
|
||||||
|
*/
|
||||||
|
printf(" __ _____ _____ _____ ___ _ __\r\n");
|
||||||
|
printf(" / _\\/__ \\___ |___ / _ \\/ |/ /\r\n");
|
||||||
|
printf(" \\ \\ / /\\/ / / / / (_) | | '_ \r\n");
|
||||||
|
printf(" _\\ \\ / / / / / / \\__, | | (_) |\r\n");
|
||||||
|
printf(" \\__/ \\/ /_/ /_/ /_/|_|\\___/\r\n");
|
||||||
|
unity_run_menu();
|
||||||
|
}
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
# SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
import pytest
|
||||||
|
from pytest_embedded import Dut
|
||||||
|
|
||||||
|
@pytest.mark.target('esp32s3')
|
||||||
|
@pytest.mark.env('esp32_s3_lcd_ev_board')
|
||||||
|
def test_usb_stream(dut: Dut)-> None:
|
||||||
|
dut.run_all_single_board_cases()
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
# For IDF 5.0
|
||||||
|
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y
|
||||||
|
CONFIG_FREERTOS_HZ=1000
|
||||||
|
CONFIG_ESP_TASK_WDT_EN=n
|
||||||
|
CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=4096
|
||||||
|
|
||||||
|
# For IDF4.4
|
||||||
|
CONFIG_ESP32S2_DEFAULT_CPU_FREQ_240=y
|
||||||
|
CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240=y
|
||||||
|
CONFIG_ESP_TASK_WDT=n
|
||||||
@ -0,0 +1 @@
|
|||||||
|
779b4ba2464a3ae85681e4b860caa5fdc35801458c23f3039ee761bae7f442a4
|
||||||
@ -0,0 +1 @@
|
|||||||
|
{"version": "1.0", "algorithm": "sha256", "created_at": "2025-05-21T16:14:04.437587+00:00", "files": [{"path": "CMakeLists.txt", "size": 98, "hash": "8225b56a99e64e8b5dc0e497fa69b340dd559e7ded38a8520c18445d6b387d08"}, {"path": "idf_component.yml", "size": 393, "hash": "d797d5623ae38e5a7c87cb971eee470c78efd62165524d103348c27224406a9d"}, {"path": "Kconfig", "size": 285, "hash": "a26e92b112c7b917e7e7b1382ef70e21db404c3d5dddbcd2dadcfe07db7e2bb6"}, {"path": "README.md", "size": 483, "hash": "534ea088bd448300662562b5874029bbad5895afe2db8e65cf9e4f81d5a09228"}, {"path": "esp_lcd_touch.c", "size": 7197, "hash": "804eeea836e75a8a9c815fb53932a7d3c8811f2b167c3707f55bd400d376328b"}, {"path": "license.txt", "size": 11358, "hash": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30"}, {"path": "include/esp_lcd_touch.h", "size": 11507, "hash": "3769c5e0bb60a05475ec182607ca4edb02add622d38dd6ae75592ac0d8477cb1"}]}
|
||||||
@ -0,0 +1 @@
|
|||||||
|
idf_component_register(SRCS "esp_lcd_touch.c" INCLUDE_DIRS "include" REQUIRES "driver" "esp_lcd")
|
||||||
13
managed_components/espressif__esp_lcd_touch/Kconfig
Normal file
13
managed_components/espressif__esp_lcd_touch/Kconfig
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
menu "ESP LCD TOUCH"
|
||||||
|
|
||||||
|
config ESP_LCD_TOUCH_MAX_POINTS
|
||||||
|
int "Maximum count of the touch points"
|
||||||
|
range 1 10
|
||||||
|
default 5
|
||||||
|
|
||||||
|
config ESP_LCD_TOUCH_MAX_BUTTONS
|
||||||
|
int "Maximum count of the touch buttons supported"
|
||||||
|
range 0 10
|
||||||
|
default 1
|
||||||
|
|
||||||
|
endmenu
|
||||||
16
managed_components/espressif__esp_lcd_touch/README.md
Normal file
16
managed_components/espressif__esp_lcd_touch/README.md
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# ESP LCD Touch Component
|
||||||
|
|
||||||
|
[](https://components.espressif.com/components/espressif/esp_lcd_touch)
|
||||||
|
|
||||||
|
This componnent is main esp_lcd_touch component which defines main functions and types for easy adding specific touch controller component.
|
||||||
|
|
||||||
|
## Supported features
|
||||||
|
|
||||||
|
- [x] Read XY
|
||||||
|
- [x] Swap XY
|
||||||
|
- [x] Mirror X
|
||||||
|
- [x] Mirror Y
|
||||||
|
- [x] Interrupt callback
|
||||||
|
- [x] Sleep mode
|
||||||
|
- [ ] Calibration
|
||||||
|
|
||||||
266
managed_components/espressif__esp_lcd_touch/esp_lcd_touch.c
Normal file
266
managed_components/espressif__esp_lcd_touch/esp_lcd_touch.c
Normal file
@ -0,0 +1,266 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
|
#include "driver/gpio.h"
|
||||||
|
#include "esp_system.h"
|
||||||
|
#include "esp_err.h"
|
||||||
|
#include "esp_check.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "esp_lcd_touch.h"
|
||||||
|
|
||||||
|
static const char *TAG = "TP";
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Function definitions
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Local variables
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Public API functions
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
esp_err_t esp_lcd_touch_enter_sleep(esp_lcd_touch_handle_t tp)
|
||||||
|
{
|
||||||
|
assert(tp != NULL);
|
||||||
|
if (tp->enter_sleep == NULL) {
|
||||||
|
ESP_LOGE(TAG, "Sleep mode not supported!");
|
||||||
|
return ESP_FAIL;
|
||||||
|
} else {
|
||||||
|
return tp->enter_sleep(tp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_lcd_touch_exit_sleep(esp_lcd_touch_handle_t tp)
|
||||||
|
{
|
||||||
|
assert(tp != NULL);
|
||||||
|
if (tp->exit_sleep == NULL) {
|
||||||
|
ESP_LOGE(TAG, "Sleep mode not supported!");
|
||||||
|
return ESP_FAIL;
|
||||||
|
} else {
|
||||||
|
return tp->exit_sleep(tp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_lcd_touch_read_data(esp_lcd_touch_handle_t tp)
|
||||||
|
{
|
||||||
|
assert(tp != NULL);
|
||||||
|
assert(tp->read_data != NULL);
|
||||||
|
|
||||||
|
return tp->read_data(tp);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool esp_lcd_touch_get_coordinates(esp_lcd_touch_handle_t tp, uint16_t *x, uint16_t *y, uint16_t *strength, uint8_t *point_num, uint8_t max_point_num)
|
||||||
|
{
|
||||||
|
bool touched = false;
|
||||||
|
|
||||||
|
assert(tp != NULL);
|
||||||
|
assert(x != NULL);
|
||||||
|
assert(y != NULL);
|
||||||
|
assert(tp->get_xy != NULL);
|
||||||
|
|
||||||
|
touched = tp->get_xy(tp, x, y, strength, point_num, max_point_num);
|
||||||
|
if (!touched) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Process coordinates by user */
|
||||||
|
if (tp->config.process_coordinates != NULL) {
|
||||||
|
tp->config.process_coordinates(tp, x, y, strength, point_num, max_point_num);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Software coordinates adjustment needed */
|
||||||
|
bool sw_adj_needed = ((tp->config.flags.mirror_x && (tp->set_mirror_x == NULL)) ||
|
||||||
|
(tp->config.flags.mirror_y && (tp->set_mirror_y == NULL)) ||
|
||||||
|
(tp->config.flags.swap_xy && (tp->set_swap_xy == NULL)));
|
||||||
|
|
||||||
|
/* Adjust all coordinates */
|
||||||
|
for (int i = 0; (sw_adj_needed && i < *point_num); i++) {
|
||||||
|
|
||||||
|
/* Mirror X coordinates (if not supported by HW) */
|
||||||
|
if (tp->config.flags.mirror_x && tp->set_mirror_x == NULL) {
|
||||||
|
x[i] = tp->config.x_max - x[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mirror Y coordinates (if not supported by HW) */
|
||||||
|
if (tp->config.flags.mirror_y && tp->set_mirror_y == NULL) {
|
||||||
|
y[i] = tp->config.y_max - y[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Swap X and Y coordinates (if not supported by HW) */
|
||||||
|
if (tp->config.flags.swap_xy && tp->set_swap_xy == NULL) {
|
||||||
|
uint16_t tmp = x[i];
|
||||||
|
x[i] = y[i];
|
||||||
|
y[i] = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return touched;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if (CONFIG_ESP_LCD_TOUCH_MAX_BUTTONS > 0)
|
||||||
|
esp_err_t esp_lcd_touch_get_button_state(esp_lcd_touch_handle_t tp, uint8_t n, uint8_t *state)
|
||||||
|
{
|
||||||
|
assert(tp != NULL);
|
||||||
|
assert(state != NULL);
|
||||||
|
|
||||||
|
*state = 0;
|
||||||
|
|
||||||
|
if (tp->get_button_state) {
|
||||||
|
return tp->get_button_state(tp, n, state);
|
||||||
|
} else {
|
||||||
|
return ESP_ERR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
esp_err_t esp_lcd_touch_set_swap_xy(esp_lcd_touch_handle_t tp, bool swap)
|
||||||
|
{
|
||||||
|
assert(tp != NULL);
|
||||||
|
|
||||||
|
tp->config.flags.swap_xy = swap;
|
||||||
|
|
||||||
|
/* Is swap supported by HW? */
|
||||||
|
if (tp->set_swap_xy) {
|
||||||
|
return tp->set_swap_xy(tp, swap);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_lcd_touch_get_swap_xy(esp_lcd_touch_handle_t tp, bool *swap)
|
||||||
|
{
|
||||||
|
assert(tp != NULL);
|
||||||
|
assert(swap != NULL);
|
||||||
|
|
||||||
|
/* Is swap supported by HW? */
|
||||||
|
if (tp->get_swap_xy) {
|
||||||
|
return tp->get_swap_xy(tp, swap);
|
||||||
|
} else {
|
||||||
|
*swap = tp->config.flags.swap_xy;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_lcd_touch_set_mirror_x(esp_lcd_touch_handle_t tp, bool mirror)
|
||||||
|
{
|
||||||
|
assert(tp != NULL);
|
||||||
|
|
||||||
|
tp->config.flags.mirror_x = mirror;
|
||||||
|
|
||||||
|
/* Is mirror supported by HW? */
|
||||||
|
if (tp->set_mirror_x) {
|
||||||
|
return tp->set_mirror_x(tp, mirror);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_lcd_touch_get_mirror_x(esp_lcd_touch_handle_t tp, bool *mirror)
|
||||||
|
{
|
||||||
|
assert(tp != NULL);
|
||||||
|
assert(mirror != NULL);
|
||||||
|
|
||||||
|
/* Is swap supported by HW? */
|
||||||
|
if (tp->get_mirror_x) {
|
||||||
|
return tp->get_mirror_x(tp, mirror);
|
||||||
|
} else {
|
||||||
|
*mirror = tp->config.flags.mirror_x;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_lcd_touch_set_mirror_y(esp_lcd_touch_handle_t tp, bool mirror)
|
||||||
|
{
|
||||||
|
assert(tp != NULL);
|
||||||
|
|
||||||
|
tp->config.flags.mirror_y = mirror;
|
||||||
|
|
||||||
|
/* Is mirror supported by HW? */
|
||||||
|
if (tp->set_mirror_y) {
|
||||||
|
return tp->set_mirror_y(tp, mirror);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_lcd_touch_get_mirror_y(esp_lcd_touch_handle_t tp, bool *mirror)
|
||||||
|
{
|
||||||
|
assert(tp != NULL);
|
||||||
|
assert(mirror != NULL);
|
||||||
|
|
||||||
|
/* Is swap supported by HW? */
|
||||||
|
if (tp->get_mirror_y) {
|
||||||
|
return tp->get_mirror_y(tp, mirror);
|
||||||
|
} else {
|
||||||
|
*mirror = tp->config.flags.mirror_y;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_lcd_touch_del(esp_lcd_touch_handle_t tp)
|
||||||
|
{
|
||||||
|
assert(tp != NULL);
|
||||||
|
|
||||||
|
if (tp->del != NULL) {
|
||||||
|
return tp->del(tp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_lcd_touch_register_interrupt_callback(esp_lcd_touch_handle_t tp, esp_lcd_touch_interrupt_callback_t callback)
|
||||||
|
{
|
||||||
|
esp_err_t ret = ESP_OK;
|
||||||
|
assert(tp != NULL);
|
||||||
|
|
||||||
|
/* Interrupt pin is not selected */
|
||||||
|
if (tp->config.int_gpio_num == GPIO_NUM_NC) {
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
tp->config.interrupt_callback = callback;
|
||||||
|
|
||||||
|
if (callback != NULL) {
|
||||||
|
ret = gpio_install_isr_service(0);
|
||||||
|
/* ISR service can be installed from user before, then it returns invalid state */
|
||||||
|
if (ret != ESP_OK && ret != ESP_ERR_INVALID_STATE) {
|
||||||
|
ESP_LOGE(TAG, "GPIO ISR install failed");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
/* Add GPIO ISR handler */
|
||||||
|
ret = gpio_intr_enable(tp->config.int_gpio_num);
|
||||||
|
ESP_RETURN_ON_ERROR(ret, TAG, "GPIO ISR install failed");
|
||||||
|
ret = gpio_isr_handler_add(tp->config.int_gpio_num, (gpio_isr_t)tp->config.interrupt_callback, tp);
|
||||||
|
ESP_RETURN_ON_ERROR(ret, TAG, "GPIO ISR install failed");
|
||||||
|
} else {
|
||||||
|
/* Remove GPIO ISR handler */
|
||||||
|
ret = gpio_isr_handler_remove(tp->config.int_gpio_num);
|
||||||
|
ESP_RETURN_ON_ERROR(ret, TAG, "GPIO ISR remove handler failed");
|
||||||
|
ret = gpio_intr_disable(tp->config.int_gpio_num);
|
||||||
|
ESP_RETURN_ON_ERROR(ret, TAG, "GPIO ISR disable failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_lcd_touch_register_interrupt_callback_with_data(esp_lcd_touch_handle_t tp, esp_lcd_touch_interrupt_callback_t callback, void *user_data)
|
||||||
|
{
|
||||||
|
assert(tp != NULL);
|
||||||
|
|
||||||
|
tp->config.user_data = user_data;
|
||||||
|
return esp_lcd_touch_register_interrupt_callback(tp, callback);
|
||||||
|
}
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
dependencies:
|
||||||
|
idf:
|
||||||
|
version: '>=4.4.2'
|
||||||
|
description: ESP LCD Touch - main component for using touch screen controllers
|
||||||
|
repository: git://github.com/espressif/esp-bsp.git
|
||||||
|
repository_info:
|
||||||
|
commit_sha: 54e9ba5f17d0f007f5a4073240b5f6c20e099f91
|
||||||
|
path: components/lcd_touch/esp_lcd_touch
|
||||||
|
url: https://github.com/espressif/esp-bsp/tree/master/components/lcd_touch/esp_lcd_touch
|
||||||
|
version: 1.1.2
|
||||||
@ -0,0 +1,429 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* @brief ESP LCD touch
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "sdkconfig.h"
|
||||||
|
#include "esp_err.h"
|
||||||
|
#include "driver/gpio.h"
|
||||||
|
#include "esp_lcd_panel_io.h"
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/semphr.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Touch controller type
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
typedef struct esp_lcd_touch_s esp_lcd_touch_t;
|
||||||
|
typedef esp_lcd_touch_t *esp_lcd_touch_handle_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Touch controller interrupt callback type
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
typedef void (*esp_lcd_touch_interrupt_callback_t)(esp_lcd_touch_handle_t tp);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Touch Configuration Type
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
uint16_t x_max; /*!< X coordinates max (for mirroring) */
|
||||||
|
uint16_t y_max; /*!< Y coordinates max (for mirroring) */
|
||||||
|
|
||||||
|
gpio_num_t rst_gpio_num; /*!< GPIO number of reset pin */
|
||||||
|
gpio_num_t int_gpio_num; /*!< GPIO number of interrupt pin */
|
||||||
|
|
||||||
|
struct {
|
||||||
|
unsigned int reset: 1; /*!< Level of reset pin in reset */
|
||||||
|
unsigned int interrupt: 1;/*!< Active Level of interrupt pin */
|
||||||
|
} levels;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
unsigned int swap_xy: 1; /*!< Swap X and Y after read coordinates */
|
||||||
|
unsigned int mirror_x: 1; /*!< Mirror X after read coordinates */
|
||||||
|
unsigned int mirror_y: 1; /*!< Mirror Y after read coordinates */
|
||||||
|
} flags;
|
||||||
|
|
||||||
|
/*!< User callback called after get coordinates from touch controller for apply user adjusting */
|
||||||
|
void (*process_coordinates)(esp_lcd_touch_handle_t tp, uint16_t *x, uint16_t *y, uint16_t *strength, uint8_t *point_num, uint8_t max_point_num);
|
||||||
|
/*!< User callback called after the touch interrupt occurred */
|
||||||
|
esp_lcd_touch_interrupt_callback_t interrupt_callback;
|
||||||
|
/*!< User data passed to callback */
|
||||||
|
void *user_data;
|
||||||
|
/*!< User data passed to driver */
|
||||||
|
void *driver_data;
|
||||||
|
} esp_lcd_touch_config_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t points; /*!< Count of touch points saved */
|
||||||
|
|
||||||
|
struct {
|
||||||
|
uint16_t x; /*!< X coordinate */
|
||||||
|
uint16_t y; /*!< Y coordinate */
|
||||||
|
uint16_t strength; /*!< Strength */
|
||||||
|
} coords[CONFIG_ESP_LCD_TOUCH_MAX_POINTS];
|
||||||
|
|
||||||
|
#if (CONFIG_ESP_LCD_TOUCH_MAX_BUTTONS > 0)
|
||||||
|
uint8_t buttons; /*!< Count of buttons states saved */
|
||||||
|
|
||||||
|
struct {
|
||||||
|
uint8_t status; /*!< Status of button */
|
||||||
|
} button[CONFIG_ESP_LCD_TOUCH_MAX_BUTTONS];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
portMUX_TYPE lock; /*!< Lock for read/write */
|
||||||
|
} esp_lcd_touch_data_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Declare of Touch Type
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
struct esp_lcd_touch_s {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief set touch controller into sleep mode
|
||||||
|
*
|
||||||
|
* @note This function is usually blocking.
|
||||||
|
*
|
||||||
|
* @param tp: Touch handler
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - ESP_OK on success, otherwise returns ESP_ERR_xxx
|
||||||
|
*/
|
||||||
|
esp_err_t (*enter_sleep)(esp_lcd_touch_handle_t tp);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief set touch controller into normal mode
|
||||||
|
*
|
||||||
|
* @note This function is usually blocking.
|
||||||
|
*
|
||||||
|
* @param tp: Touch handler
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - ESP_OK on success, otherwise returns ESP_ERR_xxx
|
||||||
|
*/
|
||||||
|
esp_err_t (*exit_sleep)(esp_lcd_touch_handle_t tp);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read data from touch controller (mandatory)
|
||||||
|
*
|
||||||
|
* @note This function is usually blocking.
|
||||||
|
*
|
||||||
|
* @param tp: Touch handler
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - ESP_OK on success, otherwise returns ESP_ERR_xxx
|
||||||
|
*/
|
||||||
|
esp_err_t (*read_data)(esp_lcd_touch_handle_t tp);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get coordinates from touch controller (mandatory)
|
||||||
|
*
|
||||||
|
* @param tp: Touch handler
|
||||||
|
* @param x: Array of X coordinates
|
||||||
|
* @param y: Array of Y coordinates
|
||||||
|
* @param strength: Array of strengths
|
||||||
|
* @param point_num: Count of points touched (equals with count of items in x and y array)
|
||||||
|
* @param max_point_num: Maximum count of touched points to return (equals with max size of x and y array)
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - Returns true, when touched and coordinates readed. Otherwise returns false.
|
||||||
|
*/
|
||||||
|
bool (*get_xy)(esp_lcd_touch_handle_t tp, uint16_t *x, uint16_t *y, uint16_t *strength, uint8_t *point_num, uint8_t max_point_num);
|
||||||
|
|
||||||
|
|
||||||
|
#if (CONFIG_ESP_LCD_TOUCH_MAX_BUTTONS > 0)
|
||||||
|
/**
|
||||||
|
* @brief Get button state (optional)
|
||||||
|
*
|
||||||
|
* @param tp: Touch handler
|
||||||
|
* @param n: Button index
|
||||||
|
* @param state: Button state
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - Returns true, when touched and coordinates readed. Otherwise returns false.
|
||||||
|
*/
|
||||||
|
esp_err_t (*get_button_state)(esp_lcd_touch_handle_t tp, uint8_t n, uint8_t *state);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Swap X and Y after read coordinates (optional)
|
||||||
|
* If set, then not used SW swapping.
|
||||||
|
*
|
||||||
|
* @param tp: Touch handler
|
||||||
|
* @param swap: Set swap value
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - ESP_OK on success, otherwise returns ESP_ERR_xxx
|
||||||
|
*/
|
||||||
|
esp_err_t (*set_swap_xy)(esp_lcd_touch_handle_t tp, bool swap);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Are X and Y coordinates swapped (optional)
|
||||||
|
*
|
||||||
|
* @param tp: Touch handler
|
||||||
|
* @param swap: Get swap value
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - ESP_OK on success, otherwise returns ESP_ERR_xxx
|
||||||
|
*/
|
||||||
|
esp_err_t (*get_swap_xy)(esp_lcd_touch_handle_t tp, bool *swap);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Mirror X after read coordinates
|
||||||
|
* If set, then not used SW mirroring.
|
||||||
|
*
|
||||||
|
* @param tp: Touch handler
|
||||||
|
* @param mirror: Set X mirror value
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - ESP_OK on success, otherwise returns ESP_ERR_xxx
|
||||||
|
*/
|
||||||
|
esp_err_t (*set_mirror_x)(esp_lcd_touch_handle_t tp, bool mirror);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Is mirrored X (optional)
|
||||||
|
*
|
||||||
|
* @param tp: Touch handler
|
||||||
|
* @param mirror: Get X mirror value
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - ESP_OK on success, otherwise returns ESP_ERR_xxx
|
||||||
|
*/
|
||||||
|
esp_err_t (*get_mirror_x)(esp_lcd_touch_handle_t tp, bool *mirror);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Mirror Y after read coordinates
|
||||||
|
* If set, then not used SW mirroring.
|
||||||
|
*
|
||||||
|
* @param tp: Touch handler
|
||||||
|
* @param mirror: Set Y mirror value
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - ESP_OK on success, otherwise returns ESP_ERR_xxx
|
||||||
|
*/
|
||||||
|
esp_err_t (*set_mirror_y)(esp_lcd_touch_handle_t tp, bool mirror);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Is mirrored Y (optional)
|
||||||
|
*
|
||||||
|
* @param tp: Touch handler
|
||||||
|
* @param mirror: Get Y mirror value
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - ESP_OK on success, otherwise returns ESP_ERR_xxx
|
||||||
|
*/
|
||||||
|
esp_err_t (*get_mirror_y)(esp_lcd_touch_handle_t tp, bool *mirror);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Delete Touch
|
||||||
|
*
|
||||||
|
* @param tp: Touch handler
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - ESP_OK on success, otherwise returns ESP_ERR_xxx
|
||||||
|
*/
|
||||||
|
esp_err_t (*del)(esp_lcd_touch_handle_t tp);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Configuration structure
|
||||||
|
*/
|
||||||
|
esp_lcd_touch_config_t config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Communication interface
|
||||||
|
*/
|
||||||
|
esp_lcd_panel_io_handle_t io;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Data structure
|
||||||
|
*/
|
||||||
|
esp_lcd_touch_data_t data;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read data from touch controller
|
||||||
|
*
|
||||||
|
* @note This function is usually blocking.
|
||||||
|
*
|
||||||
|
* @param tp: Touch handler
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - ESP_OK on success
|
||||||
|
* - ESP_ERR_INVALID_ARG parameter error
|
||||||
|
* - ESP_FAIL sending command error, slave hasn't ACK the transfer
|
||||||
|
* - ESP_ERR_INVALID_STATE I2C driver not installed or not in master mode
|
||||||
|
* - ESP_ERR_TIMEOUT operation timeout because the bus is busy
|
||||||
|
*/
|
||||||
|
esp_err_t esp_lcd_touch_read_data(esp_lcd_touch_handle_t tp);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read coordinates from touch controller
|
||||||
|
*
|
||||||
|
* @param tp: Touch handler
|
||||||
|
* @param x: Array of X coordinates
|
||||||
|
* @param y: Array of Y coordinates
|
||||||
|
* @param strength: Array of the strengths (can be NULL)
|
||||||
|
* @param point_num: Count of points touched (equals with count of items in x and y array)
|
||||||
|
* @param max_point_num: Maximum count of touched points to return (equals with max size of x and y array)
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - Returns true, when touched and coordinates readed. Otherwise returns false.
|
||||||
|
*/
|
||||||
|
bool esp_lcd_touch_get_coordinates(esp_lcd_touch_handle_t tp, uint16_t *x, uint16_t *y, uint16_t *strength, uint8_t *point_num, uint8_t max_point_num);
|
||||||
|
|
||||||
|
|
||||||
|
#if (CONFIG_ESP_LCD_TOUCH_MAX_BUTTONS > 0)
|
||||||
|
/**
|
||||||
|
* @brief Get button state
|
||||||
|
*
|
||||||
|
* @param tp: Touch handler
|
||||||
|
* @param n: Button index
|
||||||
|
* @param state: Button state
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - ESP_OK on success
|
||||||
|
* - ESP_ERR_NOT_SUPPORTED if this function is not supported by controller
|
||||||
|
* - ESP_ERR_INVALID_ARG if bad button index
|
||||||
|
*/
|
||||||
|
esp_err_t esp_lcd_touch_get_button_state(esp_lcd_touch_handle_t tp, uint8_t n, uint8_t *state);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Swap X and Y after read coordinates
|
||||||
|
*
|
||||||
|
* @param tp: Touch handler
|
||||||
|
* @param swap: Set swap value
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - ESP_OK on success
|
||||||
|
*/
|
||||||
|
esp_err_t esp_lcd_touch_set_swap_xy(esp_lcd_touch_handle_t tp, bool swap);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Are X and Y coordinates swapped
|
||||||
|
*
|
||||||
|
* @param tp: Touch handler
|
||||||
|
* @param swap: Get swap value
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - ESP_OK on success
|
||||||
|
*/
|
||||||
|
esp_err_t esp_lcd_touch_get_swap_xy(esp_lcd_touch_handle_t tp, bool *swap);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Mirror X after read coordinates
|
||||||
|
*
|
||||||
|
* @param tp: Touch handler
|
||||||
|
* @param mirror: Set X mirror value
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - ESP_OK on success
|
||||||
|
*/
|
||||||
|
esp_err_t esp_lcd_touch_set_mirror_x(esp_lcd_touch_handle_t tp, bool mirror);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Is mirrored X
|
||||||
|
*
|
||||||
|
* @param tp: Touch handler
|
||||||
|
* @param mirror: Get X mirror value
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - ESP_OK on success
|
||||||
|
*/
|
||||||
|
esp_err_t esp_lcd_touch_get_mirror_x(esp_lcd_touch_handle_t tp, bool *mirror);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Mirror Y after read coordinates
|
||||||
|
*
|
||||||
|
* @param tp: Touch handler
|
||||||
|
* @param mirror: Set Y mirror value
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - ESP_OK on success
|
||||||
|
*/
|
||||||
|
esp_err_t esp_lcd_touch_set_mirror_y(esp_lcd_touch_handle_t tp, bool mirror);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Is mirrored Y
|
||||||
|
*
|
||||||
|
* @param tp: Touch handler
|
||||||
|
* @param mirror: Get Y mirror value
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - ESP_OK on success
|
||||||
|
*/
|
||||||
|
esp_err_t esp_lcd_touch_get_mirror_y(esp_lcd_touch_handle_t tp, bool *mirror);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Delete touch (free all allocated memory and restart HW)
|
||||||
|
*
|
||||||
|
* @param tp: Touch handler
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - ESP_OK on success
|
||||||
|
*/
|
||||||
|
esp_err_t esp_lcd_touch_del(esp_lcd_touch_handle_t tp);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Register user callback called after the touch interrupt occurred
|
||||||
|
*
|
||||||
|
* @param tp: Touch handler
|
||||||
|
* @param callback: Interrupt callback
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - ESP_OK on success
|
||||||
|
*/
|
||||||
|
esp_err_t esp_lcd_touch_register_interrupt_callback(esp_lcd_touch_handle_t tp, esp_lcd_touch_interrupt_callback_t callback);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Register user callback called after the touch interrupt occurred with user data
|
||||||
|
*
|
||||||
|
* @param tp: Touch handler
|
||||||
|
* @param callback: Interrupt callback
|
||||||
|
* @param user_data: User data passed to callback
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - ESP_OK on success
|
||||||
|
*/
|
||||||
|
esp_err_t esp_lcd_touch_register_interrupt_callback_with_data(esp_lcd_touch_handle_t tp, esp_lcd_touch_interrupt_callback_t callback, void *user_data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enter sleep mode
|
||||||
|
*
|
||||||
|
* @param tp: Touch handler
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - ESP_OK on success
|
||||||
|
* - ESP_ERR_INVALID_ARG if parameter is invalid
|
||||||
|
*/
|
||||||
|
esp_err_t esp_lcd_touch_enter_sleep(esp_lcd_touch_handle_t tp);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Exit sleep mode
|
||||||
|
*
|
||||||
|
* @param tp: Touch handler
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - ESP_OK on success
|
||||||
|
* - ESP_ERR_INVALID_ARG if parameter is invalid
|
||||||
|
*/
|
||||||
|
esp_err_t esp_lcd_touch_exit_sleep(esp_lcd_touch_handle_t tp);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
202
managed_components/espressif__esp_lcd_touch/license.txt
Normal file
202
managed_components/espressif__esp_lcd_touch/license.txt
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
@ -0,0 +1 @@
|
|||||||
|
51dfa9cee38d8a20f4b625d7f89120dff08c8557e613e09dfb31f53d48648235
|
||||||
@ -0,0 +1 @@
|
|||||||
|
{"version": "1.0", "algorithm": "sha256", "created_at": "2025-07-15T10:57:47.123029+00:00", "files": [{"path": "CMakeLists.txt", "size": 97, "hash": "d4040e28d59a678c38fb13f6ff29881cb38f9d2fac05fd4b8aed03217a5c7c8c"}, {"path": "Kconfig", "size": 264, "hash": "761b9f2ac330cba6f0c20e468fccf9b9102ad6850662ae1ca275a96e8618614f"}, {"path": "README.md", "size": 3649, "hash": "5148d990b8ae99f98c658f11c78ce45895d4ff15ea36215a54fd82f4bab124f9"}, {"path": "esp_lcd_touch_cst816s.c", "size": 6287, "hash": "01b3594c722b1fe6f05d254b081d6a4e8014d56b0f0e06c58d298d4fa882ce0c"}, {"path": "idf_component.yml", "size": 310, "hash": "db2bba3e94b118082f0dbcef98a8d29acef18a93d24c4a414661679ab5e0c431"}, {"path": "license.txt", "size": 11358, "hash": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30"}, {"path": "include/esp_lcd_touch_cst816s.h", "size": 2783, "hash": "04963086236fcd655e8181a98cfa30a9aabf1b5ae6ad6917c7b91f8dcf819857"}, {"path": "test_apps/CMakeLists.txt", "size": 323, "hash": "b9ab8ef50938023920a2c970fa71ca85db6a15f7929007f7f10a84402ceee2b8"}, {"path": "test_apps/sdkconfig.defaults", "size": 49, "hash": "dccb276c3ef85f8f4d6c32edf7c8b582cf2d416f42950b778d7af95a9808e7d4"}, {"path": "test_apps/main/CMakeLists.txt", "size": 60, "hash": "f593b1ac477df2a76bb8c338660adcbd45e1f0f7e0bd8ddc135a566e39d1f62d"}, {"path": "test_apps/main/idf_component.yml", "size": 162, "hash": "ef2ce20977812a320b63bf45f407c4d8b24a679f92adb85fd4db574ef115995b"}, {"path": "test_apps/main/test_esp_lcd_touch_cst816s.c", "size": 2080, "hash": "040124f0040988334ae7d40709c3747304e1538d3f8a8e48cbf45cc8121d2be1"}]}
|
||||||
@ -0,0 +1 @@
|
|||||||
|
idf_component_register(SRCS "esp_lcd_touch_cst816s.c" INCLUDE_DIRS "include" REQUIRES "esp_lcd")
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
menu "ESP LCD TOUCH - CST816S"
|
||||||
|
|
||||||
|
config ESP_LCD_TOUCH_CST816S_DISABLE_READ_ID
|
||||||
|
bool "Disable reading ID during initialization"
|
||||||
|
default n
|
||||||
|
help
|
||||||
|
For some CST816 series chips, reading ID may cause initialization failure.
|
||||||
|
|
||||||
|
endmenu
|
||||||
@ -0,0 +1,94 @@
|
|||||||
|
# ESP LCD Touch CST816S Controller
|
||||||
|
|
||||||
|
[](https://components.espressif.com/components/espressif/esp_lcd_touch_cst816s)
|
||||||
|
|
||||||
|
Implementation of the CST816S touch controller with esp_lcd_touch component.
|
||||||
|
|
||||||
|
| Touch controller | Communication interface | Component name | Link to datasheet |
|
||||||
|
| :--------------: | :---------------------: | :-------------------: | :------------------------------------------------------------------------: |
|
||||||
|
| CST816S | I2C | esp_lcd_touch_cst816s | [datasheet](https://www.buydisplay.com/download/ic/DS-CST816S_DS_V1.3.pdf) |
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
> * There are two things about the driver are noteworthy (from [document](https://doc.riot-os.org/group__drivers__cst816s.html)):
|
||||||
|
> * It only responds to I2C commands after an event, such as a touch detection. Do not expect it to respond on init. Instead after a touch event, it will assert the IRQ and respond to I2C reads for a short time.
|
||||||
|
> * While it should be able to detect multiple finger events, this version of the chip always returns only a single finger event and a gesture. Reading the display data multiple times during a single event will return the last sampled finger position.
|
||||||
|
> * For some chips, reading ID may cause initialization failure. Disable reading ID by setting `CONFIG_ESP_LCD_TOUCH_CST816S_DISABLE_READ_ID` to `y` in `menuconfig`.
|
||||||
|
|
||||||
|
## Add to project
|
||||||
|
|
||||||
|
Packages from this repository are uploaded to [Espressif's component service](https://components.espressif.com/).
|
||||||
|
You can add them to your project via `idf.py add-dependancy`, e.g.
|
||||||
|
```
|
||||||
|
idf.py add-dependency esp_lcd_touch_cst816s==1.0.0
|
||||||
|
```
|
||||||
|
|
||||||
|
Alternatively, you can create `idf_component.yml`. More is in [Espressif's documentation](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/tools/idf-component-manager.html).
|
||||||
|
|
||||||
|
## Example use
|
||||||
|
|
||||||
|
Define a mutex for the touch and create it before initialize the touch:
|
||||||
|
|
||||||
|
```
|
||||||
|
static SemaphoreHandle_t touch_mux;
|
||||||
|
|
||||||
|
touch_mux = xSemaphoreCreateBinary();
|
||||||
|
```
|
||||||
|
|
||||||
|
Define a callback function used by ISR:
|
||||||
|
|
||||||
|
```
|
||||||
|
static void touch_callback(esp_lcd_touch_handle_t tp)
|
||||||
|
{
|
||||||
|
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||||
|
xSemaphoreGiveFromISR(touch_mux, &xHigherPriorityTaskWoken);
|
||||||
|
|
||||||
|
if (xHigherPriorityTaskWoken) {
|
||||||
|
portYIELD_FROM_ISR();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Initialization of the touch component.
|
||||||
|
|
||||||
|
```
|
||||||
|
esp_lcd_panel_io_i2c_config_t io_config = ESP_LCD_TOUCH_IO_I2C_CST816S_CONFIG();
|
||||||
|
|
||||||
|
esp_lcd_touch_config_t tp_cfg = {
|
||||||
|
.x_max = CONFIG_LCD_HRES,
|
||||||
|
.y_max = CONFIG_LCD_VRES,
|
||||||
|
.rst_gpio_num = CONFIG_LCD_TOUCH_RST,
|
||||||
|
.int_gpio_num = CONFIG_LCD_TOUCH_INT,
|
||||||
|
.levels = {
|
||||||
|
.reset = 0,
|
||||||
|
.interrupt = 0,
|
||||||
|
},
|
||||||
|
.flags = {
|
||||||
|
.swap_xy = 0,
|
||||||
|
.mirror_x = 0,
|
||||||
|
.mirror_y = 0,
|
||||||
|
},
|
||||||
|
.interrupt_callback = touch_callback,
|
||||||
|
};
|
||||||
|
|
||||||
|
esp_lcd_touch_handle_t tp;
|
||||||
|
esp_lcd_touch_new_i2c_cst816s(io_handle, &tp_cfg, &tp);
|
||||||
|
```
|
||||||
|
|
||||||
|
Read data from the touch controller and store it in RAM memory. It should be called regularly in poll.
|
||||||
|
|
||||||
|
```
|
||||||
|
if (xSemaphoreTake(touch_mux, 0) == pdTRUE) {
|
||||||
|
esp_lcd_touch_read_data(tp); // read only when ISR was triggled
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Get one X and Y coordinates with strength of touch.
|
||||||
|
|
||||||
|
```
|
||||||
|
uint16_t touch_x[1];
|
||||||
|
uint16_t touch_y[1];
|
||||||
|
uint16_t touch_strength[1];
|
||||||
|
uint8_t touch_cnt = 0;
|
||||||
|
|
||||||
|
bool touchpad_pressed = esp_lcd_touch_get_coordinates(tp, touch_x, touch_y, touch_strength, &touch_cnt, 1);
|
||||||
|
```
|
||||||
@ -0,0 +1,192 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
|
#include "driver/gpio.h"
|
||||||
|
#include "esp_system.h"
|
||||||
|
#include "esp_err.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "esp_check.h"
|
||||||
|
#include "esp_lcd_panel_io.h"
|
||||||
|
#include "esp_lcd_touch.h"
|
||||||
|
|
||||||
|
#define POINT_NUM_MAX (1)
|
||||||
|
|
||||||
|
#define DATA_START_REG (0x02)
|
||||||
|
#define CHIP_ID_REG (0xA7)
|
||||||
|
|
||||||
|
static const char *TAG = "CST816S";
|
||||||
|
|
||||||
|
static esp_err_t read_data(esp_lcd_touch_handle_t tp);
|
||||||
|
static bool get_xy(esp_lcd_touch_handle_t tp, uint16_t *x, uint16_t *y, uint16_t *strength, uint8_t *point_num, uint8_t max_point_num);
|
||||||
|
static esp_err_t del(esp_lcd_touch_handle_t tp);
|
||||||
|
|
||||||
|
static esp_err_t i2c_read_bytes(esp_lcd_touch_handle_t tp, uint16_t reg, uint8_t *data, uint8_t len);
|
||||||
|
|
||||||
|
static esp_err_t reset(esp_lcd_touch_handle_t tp);
|
||||||
|
static esp_err_t read_id(esp_lcd_touch_handle_t tp);
|
||||||
|
|
||||||
|
esp_err_t esp_lcd_touch_new_i2c_cst816s(const esp_lcd_panel_io_handle_t io, const esp_lcd_touch_config_t *config, esp_lcd_touch_handle_t *tp)
|
||||||
|
{
|
||||||
|
ESP_RETURN_ON_FALSE(io, ESP_ERR_INVALID_ARG, TAG, "Invalid io");
|
||||||
|
ESP_RETURN_ON_FALSE(config, ESP_ERR_INVALID_ARG, TAG, "Invalid config");
|
||||||
|
ESP_RETURN_ON_FALSE(tp, ESP_ERR_INVALID_ARG, TAG, "Invalid touch handle");
|
||||||
|
|
||||||
|
/* Prepare main structure */
|
||||||
|
esp_err_t ret = ESP_OK;
|
||||||
|
esp_lcd_touch_handle_t cst816s = calloc(1, sizeof(esp_lcd_touch_t));
|
||||||
|
ESP_GOTO_ON_FALSE(cst816s, ESP_ERR_NO_MEM, err, TAG, "Touch handle malloc failed");
|
||||||
|
|
||||||
|
/* Communication interface */
|
||||||
|
cst816s->io = io;
|
||||||
|
/* Only supported callbacks are set */
|
||||||
|
cst816s->read_data = read_data;
|
||||||
|
cst816s->get_xy = get_xy;
|
||||||
|
cst816s->del = del;
|
||||||
|
/* Mutex */
|
||||||
|
cst816s->data.lock.owner = portMUX_FREE_VAL;
|
||||||
|
/* Save config */
|
||||||
|
memcpy(&cst816s->config, config, sizeof(esp_lcd_touch_config_t));
|
||||||
|
|
||||||
|
/* Prepare pin for touch interrupt */
|
||||||
|
if (cst816s->config.int_gpio_num != GPIO_NUM_NC) {
|
||||||
|
const gpio_config_t int_gpio_config = {
|
||||||
|
.mode = GPIO_MODE_INPUT,
|
||||||
|
.intr_type = (cst816s->config.levels.interrupt ? GPIO_INTR_POSEDGE : GPIO_INTR_NEGEDGE),
|
||||||
|
.pin_bit_mask = BIT64(cst816s->config.int_gpio_num)
|
||||||
|
};
|
||||||
|
ESP_GOTO_ON_ERROR(gpio_config(&int_gpio_config), err, TAG, "GPIO intr config failed");
|
||||||
|
|
||||||
|
/* Register interrupt callback */
|
||||||
|
if (cst816s->config.interrupt_callback) {
|
||||||
|
esp_lcd_touch_register_interrupt_callback(cst816s, cst816s->config.interrupt_callback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Prepare pin for touch controller reset */
|
||||||
|
if (cst816s->config.rst_gpio_num != GPIO_NUM_NC) {
|
||||||
|
const gpio_config_t rst_gpio_config = {
|
||||||
|
.mode = GPIO_MODE_OUTPUT,
|
||||||
|
.pin_bit_mask = BIT64(cst816s->config.rst_gpio_num)
|
||||||
|
};
|
||||||
|
ESP_GOTO_ON_ERROR(gpio_config(&rst_gpio_config), err, TAG, "GPIO reset config failed");
|
||||||
|
}
|
||||||
|
/* Reset controller */
|
||||||
|
ESP_GOTO_ON_ERROR(reset(cst816s), err, TAG, "Reset failed");
|
||||||
|
/* Read product id */
|
||||||
|
#ifdef CONFIG_ESP_LCD_TOUCH_CST816S_DISABLE_READ_ID
|
||||||
|
ESP_LOGI(TAG, "Read ID disabled");
|
||||||
|
#else
|
||||||
|
ESP_GOTO_ON_ERROR(read_id(cst816s), err, TAG, "Read ID failed");
|
||||||
|
#endif
|
||||||
|
*tp = cst816s;
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
err:
|
||||||
|
if (cst816s) {
|
||||||
|
del(cst816s);
|
||||||
|
}
|
||||||
|
ESP_LOGE(TAG, "Initialization failed!");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t read_data(esp_lcd_touch_handle_t tp)
|
||||||
|
{
|
||||||
|
typedef struct {
|
||||||
|
uint8_t num;
|
||||||
|
uint8_t x_h : 4;
|
||||||
|
uint8_t : 4;
|
||||||
|
uint8_t x_l;
|
||||||
|
uint8_t y_h : 4;
|
||||||
|
uint8_t : 4;
|
||||||
|
uint8_t y_l;
|
||||||
|
} data_t;
|
||||||
|
|
||||||
|
data_t point;
|
||||||
|
ESP_RETURN_ON_ERROR(i2c_read_bytes(tp, DATA_START_REG, (uint8_t *)&point, sizeof(data_t)), TAG, "I2C read failed");
|
||||||
|
|
||||||
|
portENTER_CRITICAL(&tp->data.lock);
|
||||||
|
point.num = (point.num > POINT_NUM_MAX ? POINT_NUM_MAX : point.num);
|
||||||
|
tp->data.points = point.num;
|
||||||
|
/* Fill all coordinates */
|
||||||
|
for (int i = 0; i < point.num; i++) {
|
||||||
|
tp->data.coords[i].x = point.x_h << 8 | point.x_l;
|
||||||
|
tp->data.coords[i].y = point.y_h << 8 | point.y_l;
|
||||||
|
}
|
||||||
|
portEXIT_CRITICAL(&tp->data.lock);
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool get_xy(esp_lcd_touch_handle_t tp, uint16_t *x, uint16_t *y, uint16_t *strength, uint8_t *point_num, uint8_t max_point_num)
|
||||||
|
{
|
||||||
|
portENTER_CRITICAL(&tp->data.lock);
|
||||||
|
/* Count of points */
|
||||||
|
*point_num = (tp->data.points > max_point_num ? max_point_num : tp->data.points);
|
||||||
|
for (size_t i = 0; i < *point_num; i++) {
|
||||||
|
x[i] = tp->data.coords[i].x;
|
||||||
|
y[i] = tp->data.coords[i].y;
|
||||||
|
|
||||||
|
if (strength) {
|
||||||
|
strength[i] = tp->data.coords[i].strength;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Invalidate */
|
||||||
|
tp->data.points = 0;
|
||||||
|
portEXIT_CRITICAL(&tp->data.lock);
|
||||||
|
|
||||||
|
return (*point_num > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t del(esp_lcd_touch_handle_t tp)
|
||||||
|
{
|
||||||
|
/* Reset GPIO pin settings */
|
||||||
|
if (tp->config.int_gpio_num != GPIO_NUM_NC) {
|
||||||
|
gpio_reset_pin(tp->config.int_gpio_num);
|
||||||
|
if (tp->config.interrupt_callback) {
|
||||||
|
gpio_isr_handler_remove(tp->config.int_gpio_num);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (tp->config.rst_gpio_num != GPIO_NUM_NC) {
|
||||||
|
gpio_reset_pin(tp->config.rst_gpio_num);
|
||||||
|
}
|
||||||
|
/* Release memory */
|
||||||
|
free(tp);
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t reset(esp_lcd_touch_handle_t tp)
|
||||||
|
{
|
||||||
|
if (tp->config.rst_gpio_num != GPIO_NUM_NC) {
|
||||||
|
ESP_RETURN_ON_ERROR(gpio_set_level(tp->config.rst_gpio_num, tp->config.levels.reset), TAG, "GPIO set level failed");
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(200));
|
||||||
|
ESP_RETURN_ON_ERROR(gpio_set_level(tp->config.rst_gpio_num, !tp->config.levels.reset), TAG, "GPIO set level failed");
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(200));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef CONFIG_ESP_LCD_TOUCH_CST816S_DISABLE_READ_ID
|
||||||
|
static esp_err_t read_id(esp_lcd_touch_handle_t tp)
|
||||||
|
{
|
||||||
|
uint8_t id;
|
||||||
|
ESP_RETURN_ON_ERROR(i2c_read_bytes(tp, CHIP_ID_REG, &id, 1), TAG, "I2C read failed");
|
||||||
|
ESP_LOGI(TAG, "IC id: %d", id);
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static esp_err_t i2c_read_bytes(esp_lcd_touch_handle_t tp, uint16_t reg, uint8_t *data, uint8_t len)
|
||||||
|
{
|
||||||
|
ESP_RETURN_ON_FALSE(data, ESP_ERR_INVALID_ARG, TAG, "Invalid data");
|
||||||
|
|
||||||
|
return esp_lcd_panel_io_rx_param(tp->io, reg, data, len);
|
||||||
|
}
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
dependencies:
|
||||||
|
esp_lcd_touch:
|
||||||
|
public: true
|
||||||
|
version: ^1.0.4
|
||||||
|
idf: '>=4.4.2'
|
||||||
|
description: ESP LCD Touch CST816S - touch controller CST816S
|
||||||
|
repository: git://github.com/espressif/esp-bsp.git
|
||||||
|
url: https://github.com/espressif/esp-bsp/tree/master/components/lcd_touch/esp_lcd_touch_cst816s
|
||||||
|
version: 1.1.0
|
||||||
@ -0,0 +1,81 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* @brief ESP LCD touch: CST816S
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esp_idf_version.h"
|
||||||
|
#include "esp_lcd_touch.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create a new CST816S touch driver
|
||||||
|
*
|
||||||
|
* @note The I2C communication should be initialized before use this function.
|
||||||
|
*
|
||||||
|
* @param io LCD panel IO handle, it should be created by `esp_lcd_new_panel_io_i2c()`
|
||||||
|
* @param config Touch panel configuration
|
||||||
|
* @param tp Touch panel handle
|
||||||
|
* @return
|
||||||
|
* - ESP_OK: on success
|
||||||
|
*/
|
||||||
|
esp_err_t esp_lcd_touch_new_i2c_cst816s(const esp_lcd_panel_io_handle_t io, const esp_lcd_touch_config_t *config, esp_lcd_touch_handle_t *tp);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief I2C address of the CST816S controller
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#define ESP_LCD_TOUCH_IO_I2C_CST816S_ADDRESS (0x15)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Touch IO configuration structure
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 2, 0)
|
||||||
|
#define ESP_LCD_TOUCH_IO_I2C_CST816S_CONFIG() \
|
||||||
|
{ \
|
||||||
|
.dev_addr = ESP_LCD_TOUCH_IO_I2C_CST816S_ADDRESS, \
|
||||||
|
.on_color_trans_done = 0, \
|
||||||
|
.user_ctx = 0, \
|
||||||
|
.control_phase_bytes = 1, \
|
||||||
|
.dc_bit_offset = 0, \
|
||||||
|
.lcd_cmd_bits = 8, \
|
||||||
|
.lcd_param_bits = 0, \
|
||||||
|
.flags = \
|
||||||
|
{ \
|
||||||
|
.dc_low_on_data = 0, \
|
||||||
|
.disable_control_phase = 1, \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define ESP_LCD_TOUCH_IO_I2C_CST816S_CONFIG() \
|
||||||
|
{ \
|
||||||
|
.dev_addr = ESP_LCD_TOUCH_IO_I2C_CST816S_ADDRESS, \
|
||||||
|
.on_color_trans_done = 0, \
|
||||||
|
.user_ctx = 0, \
|
||||||
|
.control_phase_bytes = 1, \
|
||||||
|
.dc_bit_offset = 0, \
|
||||||
|
.lcd_cmd_bits = 8, \
|
||||||
|
.lcd_param_bits = 0, \
|
||||||
|
.flags = \
|
||||||
|
{ \
|
||||||
|
.dc_low_on_data = 0, \
|
||||||
|
.disable_control_phase = 1, \
|
||||||
|
}, \
|
||||||
|
.scl_speed_hz = 100000 \
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
202
managed_components/espressif__esp_lcd_touch_cst816s/license.txt
Normal file
202
managed_components/espressif__esp_lcd_touch_cst816s/license.txt
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
# The following lines of boilerplate have to be in your project's CMakeLists
|
||||||
|
# in this exact order for cmake to work correctly
|
||||||
|
cmake_minimum_required(VERSION 3.5)
|
||||||
|
set(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components")
|
||||||
|
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||||
|
project(test_esp_lcd_touch_cst816s)
|
||||||
@ -0,0 +1 @@
|
|||||||
|
idf_component_register(SRCS "test_esp_lcd_touch_cst816s.c")
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
## IDF Component Manager Manifest File
|
||||||
|
dependencies:
|
||||||
|
idf: ">=4.4"
|
||||||
|
esp_lcd_touch_cst816s:
|
||||||
|
version: "*"
|
||||||
|
override_path: "../../../esp_lcd_touch_cst816s"
|
||||||
@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: CC0-1.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include "driver/i2c.h"
|
||||||
|
#include "driver/gpio.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "unity.h"
|
||||||
|
#include "unity_test_runner.h"
|
||||||
|
|
||||||
|
#include "esp_lcd_touch_cst816s.h"
|
||||||
|
|
||||||
|
#define TEST_TOUCH_I2C_NUM (0)
|
||||||
|
#define TEST_TOUCH_I2C_CLK_HZ (400000)
|
||||||
|
|
||||||
|
#define TEST_LCD_H_RES (240)
|
||||||
|
#define TEST_LCD_V_RES (240)
|
||||||
|
|
||||||
|
/* LCD touch pins */
|
||||||
|
#define TEST_TOUCH_I2C_SCL (GPIO_NUM_18)
|
||||||
|
#define TEST_TOUCH_I2C_SDA (GPIO_NUM_8)
|
||||||
|
#define TEST_TOUCH_GPIO_INT (GPIO_NUM_3)
|
||||||
|
|
||||||
|
TEST_CASE("test cst816s to initialize touch", "[cst816s][i2c]")
|
||||||
|
{
|
||||||
|
/* Initilize I2C */
|
||||||
|
const i2c_config_t i2c_conf = {
|
||||||
|
.mode = I2C_MODE_MASTER,
|
||||||
|
.sda_io_num = TEST_TOUCH_I2C_SDA,
|
||||||
|
.sda_pullup_en = GPIO_PULLUP_DISABLE,
|
||||||
|
.scl_io_num = TEST_TOUCH_I2C_SCL,
|
||||||
|
.scl_pullup_en = GPIO_PULLUP_DISABLE,
|
||||||
|
.master.clk_speed = TEST_TOUCH_I2C_CLK_HZ
|
||||||
|
};
|
||||||
|
TEST_ESP_OK(i2c_param_config(TEST_TOUCH_I2C_NUM, &i2c_conf));
|
||||||
|
TEST_ESP_OK(i2c_driver_install(TEST_TOUCH_I2C_NUM, i2c_conf.mode, 0, 0, 0));
|
||||||
|
|
||||||
|
/* Initialize touch HW */
|
||||||
|
const esp_lcd_touch_config_t tp_cfg = {
|
||||||
|
.x_max = TEST_LCD_H_RES,
|
||||||
|
.y_max = TEST_LCD_V_RES,
|
||||||
|
.rst_gpio_num = GPIO_NUM_NC, // Shared with LCD reset
|
||||||
|
.int_gpio_num = TEST_TOUCH_GPIO_INT,
|
||||||
|
.levels = {
|
||||||
|
.reset = 0,
|
||||||
|
.interrupt = 0,
|
||||||
|
},
|
||||||
|
.flags = {
|
||||||
|
.swap_xy = 0,
|
||||||
|
.mirror_x = 1,
|
||||||
|
.mirror_y = 0,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
esp_lcd_touch_handle_t touch_handle;
|
||||||
|
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_CST816S_CONFIG();
|
||||||
|
TEST_ESP_OK(esp_lcd_new_panel_io_i2c((esp_lcd_i2c_bus_handle_t)TEST_TOUCH_I2C_NUM, &tp_io_config, &tp_io_handle));
|
||||||
|
TEST_ESP_OK(esp_lcd_touch_new_i2c_cst816s(tp_io_handle, &tp_cfg, &touch_handle));
|
||||||
|
}
|
||||||
|
|
||||||
|
void app_main(void)
|
||||||
|
{
|
||||||
|
printf("CST816S Test\r\n");
|
||||||
|
unity_run_menu();
|
||||||
|
}
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
CONFIG_FREERTOS_HZ=1000
|
||||||
|
CONFIG_ESP_TASK_WDT_EN=n
|
||||||
@ -0,0 +1 @@
|
|||||||
|
bb938deffba7d80b2ce582a796c053681b0439e0a7033666688e0f1f5b921125
|
||||||
137
managed_components/espressif__esp_lvgl_port/CHANGELOG.md
Normal file
137
managed_components/espressif__esp_lvgl_port/CHANGELOG.md
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
## 2.5.0
|
||||||
|
|
||||||
|
### Features (Functional change for button v4 users)
|
||||||
|
- Updated LVGL port for using IoT button component v4 (LVGL port not anymore creating button, need to be created in app and included handle to LVGL port)
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
- Fixed buffer size by selected color format
|
||||||
|
- Fixed memory leak in LVGL8 in display removing https://github.com/espressif/esp-bsp/issues/462
|
||||||
|
- Fixed draw buffer alignment
|
||||||
|
|
||||||
|
## 2.4.4
|
||||||
|
|
||||||
|
### Features
|
||||||
|
- Changed queue to event group in main LVGL task for speed up https://github.com/espressif/esp-bsp/issues/492
|
||||||
|
- Reworked handling encoder (knob) https://github.com/espressif/esp-bsp/pull/450
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
- Fixed a crash when esp_lvgl_port was initialized from high priority task https://github.com/espressif/esp-bsp/issues/455
|
||||||
|
- Allow to swap bytes when used SW rotation https://github.com/espressif/esp-bsp/issues/497
|
||||||
|
|
||||||
|
## 2.4.3
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
- Fixed a display context pointer bug
|
||||||
|
- Fixed I2C example for using with LVGL9
|
||||||
|
|
||||||
|
### Features
|
||||||
|
- Support for LV_COLOR_FORMAT_I1 for monochromatic screen
|
||||||
|
|
||||||
|
## 2.4.2
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
- Fixed SW rotation in LVGL9.2
|
||||||
|
- Fixed freeing right buffers when error
|
||||||
|
|
||||||
|
## 2.4.1
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
- Fixed the issue of the DPI callback function not being initialized.
|
||||||
|
|
||||||
|
## 2.4.0
|
||||||
|
|
||||||
|
### Features
|
||||||
|
- Added support for direct mode and full refresh mode in the MIPI-DSI interface.
|
||||||
|
- Optimized avoid-tear feature and LVGL task.
|
||||||
|
|
||||||
|
## 2.3.3
|
||||||
|
|
||||||
|
### Features
|
||||||
|
- Updated RGB screen flush handling in LVGL9.
|
||||||
|
|
||||||
|
## 2.3.2
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
- Fixed rotation type compatibility with LVGL8.
|
||||||
|
|
||||||
|
## 2.3.1
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
- Fixed LVGL version resolution if LVGL is not a managed component
|
||||||
|
- Fixed link error with LVGL v9.2
|
||||||
|
- Fixed event error with LVGL v9.2
|
||||||
|
|
||||||
|
## 2.3.0
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
- Fixed LVGL port for using with LVGL9 OS FreeRTOS enabled
|
||||||
|
- Fixed bad handled touch due to synchronization timer task
|
||||||
|
|
||||||
|
### Features
|
||||||
|
- Added support for SW rotation in LVGL9
|
||||||
|
|
||||||
|
## 2.2.2
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
- Fixed missing callback in IDF4.4.3 and lower for LVGL port
|
||||||
|
|
||||||
|
## 2.2.1
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
- Added missing includes
|
||||||
|
- Fixed watchdog error in some cases in LVGL9
|
||||||
|
|
||||||
|
## 2.2.0
|
||||||
|
|
||||||
|
### Features
|
||||||
|
- Added RGB display support
|
||||||
|
- Added support for direct mode and full refresh mode
|
||||||
|
|
||||||
|
### Breaking changes
|
||||||
|
- Removed MIPI-DSI from display configuration structure - use `lvgl_port_add_disp_dsi` instead
|
||||||
|
|
||||||
|
## 2.1.0
|
||||||
|
|
||||||
|
### Features
|
||||||
|
- Added LVGL sleep feature: The esp_lvgl_port handling can sleep if the display and touch are inactive (only with LVGL9)
|
||||||
|
- Added support for different display color modes (only with LVGL9)
|
||||||
|
- Added script for generating C array images during build (depends on LVGL version)
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
- Applied initial display rotation from configuration https://github.com/espressif/esp-bsp/pull/278
|
||||||
|
- Added blocking wait for LVGL task stop during esp_lvgl_port de-initialization https://github.com/espressif/esp-bsp/issues/277
|
||||||
|
- Added missing esp_idf_version.h include
|
||||||
|
|
||||||
|
## 2.0.0
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
- Divided into files per feature
|
||||||
|
- Added support for LVGL9
|
||||||
|
- Added support for MIPI-DSI display
|
||||||
|
|
||||||
|
## 1.4.0
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
- Added support for USB HID mouse/keyboard as an input device
|
||||||
|
|
||||||
|
## 1.3.0
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
- Added low power interface
|
||||||
|
|
||||||
|
## 1.2.0
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
- Added support for encoder (knob) as an input device
|
||||||
|
|
||||||
|
## 1.1.0
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
- Added support for navigation buttons as an input device
|
||||||
File diff suppressed because one or more lines are too long
124
managed_components/espressif__esp_lvgl_port/CMakeLists.txt
Normal file
124
managed_components/espressif__esp_lvgl_port/CMakeLists.txt
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
include($ENV{IDF_PATH}/tools/cmake/version.cmake) # $ENV{IDF_VERSION} was added after v4.3...
|
||||||
|
|
||||||
|
if("${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}" VERSION_LESS "4.4")
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# This component uses a CMake workaround, so we can compile esp_lvgl_port for both LVGL8.x and LVGL9.x
|
||||||
|
# At the time of idf_component_register() we don't know which LVGL version is used, so we only register an INTERFACE component (with no sources)
|
||||||
|
# Later, when we know the LVGL version, we create another CMake library called 'lvgl_port_lib' and link it to the 'esp_lvgl_port' INTERFACE component
|
||||||
|
idf_component_register(
|
||||||
|
INCLUDE_DIRS "include"
|
||||||
|
PRIV_INCLUDE_DIRS "priv_include"
|
||||||
|
REQUIRES "esp_lcd")
|
||||||
|
|
||||||
|
# Get LVGL version
|
||||||
|
idf_build_get_property(build_components BUILD_COMPONENTS)
|
||||||
|
if(lvgl IN_LIST build_components)
|
||||||
|
set(lvgl_name lvgl) # Local component
|
||||||
|
set(lvgl_ver $ENV{LVGL_VERSION}) # Get the version from env variable (set from LVGL v9.2)
|
||||||
|
else()
|
||||||
|
set(lvgl_name lvgl__lvgl) # Managed component
|
||||||
|
idf_component_get_property(lvgl_ver ${lvgl_name} COMPONENT_VERSION) # Get the version from esp-idf build system
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if("${lvgl_ver}" STREQUAL "")
|
||||||
|
message("Could not determine LVGL version, assuming v9.x")
|
||||||
|
set(lvgl_ver "9.0.0")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Select folder by LVGL version
|
||||||
|
message(STATUS "LVGL version: ${lvgl_ver}")
|
||||||
|
if(lvgl_ver VERSION_LESS "9.0.0")
|
||||||
|
message(VERBOSE "Compiling esp_lvgl_port for LVGL8")
|
||||||
|
set(PORT_FOLDER "lvgl8")
|
||||||
|
else()
|
||||||
|
message(VERBOSE "Compiling esp_lvgl_port for LVGL9")
|
||||||
|
set(PORT_FOLDER "lvgl9")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Add LVGL port extensions
|
||||||
|
set(PORT_PATH "src/${PORT_FOLDER}")
|
||||||
|
set(ADD_SRCS "")
|
||||||
|
set(ADD_LIBS "")
|
||||||
|
|
||||||
|
idf_build_get_property(build_components BUILD_COMPONENTS)
|
||||||
|
if("espressif__button" IN_LIST build_components)
|
||||||
|
list(APPEND ADD_SRCS "${PORT_PATH}/esp_lvgl_port_button.c")
|
||||||
|
list(APPEND ADD_LIBS idf::espressif__button)
|
||||||
|
endif()
|
||||||
|
if("button" IN_LIST build_components)
|
||||||
|
list(APPEND ADD_SRCS "${PORT_PATH}/esp_lvgl_port_button.c")
|
||||||
|
list(APPEND ADD_LIBS idf::button)
|
||||||
|
endif()
|
||||||
|
if("espressif__esp_lcd_touch" IN_LIST build_components)
|
||||||
|
list(APPEND ADD_SRCS "${PORT_PATH}/esp_lvgl_port_touch.c")
|
||||||
|
list(APPEND ADD_LIBS idf::espressif__esp_lcd_touch)
|
||||||
|
endif()
|
||||||
|
if("esp_lcd_touch" IN_LIST build_components)
|
||||||
|
list(APPEND ADD_SRCS "${PORT_PATH}/esp_lvgl_port_touch.c")
|
||||||
|
list(APPEND ADD_LIBS idf::esp_lcd_touch)
|
||||||
|
endif()
|
||||||
|
if("espressif__knob" IN_LIST build_components)
|
||||||
|
list(APPEND ADD_SRCS "${PORT_PATH}/esp_lvgl_port_knob.c")
|
||||||
|
list(APPEND ADD_LIBS idf::espressif__knob)
|
||||||
|
endif()
|
||||||
|
if("knob" IN_LIST build_components)
|
||||||
|
list(APPEND ADD_SRCS "${PORT_PATH}/esp_lvgl_port_knob.c")
|
||||||
|
list(APPEND ADD_LIBS idf::knob)
|
||||||
|
endif()
|
||||||
|
if("espressif__usb_host_hid" IN_LIST build_components)
|
||||||
|
list(APPEND ADD_SRCS "${PORT_PATH}/esp_lvgl_port_usbhid.c" "images/${PORT_FOLDER}/img_cursor.c")
|
||||||
|
list(APPEND ADD_LIBS idf::espressif__usb_host_hid)
|
||||||
|
endif()
|
||||||
|
if("usb_host_hid" IN_LIST build_components)
|
||||||
|
list(APPEND ADD_SRCS "${PORT_PATH}/esp_lvgl_port_usbhid.c" "images/${PORT_FOLDER}/img_cursor.c")
|
||||||
|
list(APPEND ADD_LIBS idf::usb_host_hid)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Include SIMD assembly source code for rendering, only for (9.1.0 <= LVG_version < 9.2.0) and only for esp32 and esp32s3
|
||||||
|
if((lvgl_ver VERSION_GREATER_EQUAL "9.1.0") AND (lvgl_ver VERSION_LESS "9.2.0"))
|
||||||
|
if(CONFIG_IDF_TARGET_ESP32 OR CONFIG_IDF_TARGET_ESP32S3)
|
||||||
|
message(VERBOSE "Compiling SIMD")
|
||||||
|
if(CONFIG_IDF_TARGET_ESP32S3)
|
||||||
|
file(GLOB_RECURSE ASM_SRCS ${PORT_PATH}/simd/*_esp32s3.S) # Select only esp32s3 related files
|
||||||
|
else()
|
||||||
|
file(GLOB_RECURSE ASM_SRCS ${PORT_PATH}/simd/*_esp32.S) # Select only esp32 related files
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Explicitly add all assembly macro files
|
||||||
|
file(GLOB_RECURSE ASM_MACROS ${PORT_PATH}/simd/lv_macro_*.S)
|
||||||
|
list(APPEND ADD_SRCS ${ASM_MACROS})
|
||||||
|
list(APPEND ADD_SRCS ${ASM_SRCS})
|
||||||
|
|
||||||
|
# Include component libraries, so lvgl component would see lvgl_port includes
|
||||||
|
idf_component_get_property(lvgl_lib ${lvgl_name} COMPONENT_LIB)
|
||||||
|
target_include_directories(${lvgl_lib} PRIVATE "include")
|
||||||
|
|
||||||
|
# Force link .S files
|
||||||
|
set_property(TARGET ${COMPONENT_LIB} APPEND PROPERTY INTERFACE_LINK_LIBRARIES "-u lv_color_blend_to_argb8888_esp")
|
||||||
|
set_property(TARGET ${COMPONENT_LIB} APPEND PROPERTY INTERFACE_LINK_LIBRARIES "-u lv_color_blend_to_rgb565_esp")
|
||||||
|
set_property(TARGET ${COMPONENT_LIB} APPEND PROPERTY INTERFACE_LINK_LIBRARIES "-u lv_color_blend_to_rgb888_esp")
|
||||||
|
set_property(TARGET ${COMPONENT_LIB} APPEND PROPERTY INTERFACE_LINK_LIBRARIES "-u lv_rgb565_blend_normal_to_rgb565_esp")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Here we create the real lvgl_port_lib
|
||||||
|
add_library(lvgl_port_lib STATIC
|
||||||
|
${PORT_PATH}/esp_lvgl_port.c
|
||||||
|
${PORT_PATH}/esp_lvgl_port_disp.c
|
||||||
|
${ADD_SRCS}
|
||||||
|
)
|
||||||
|
target_include_directories(lvgl_port_lib PUBLIC "include")
|
||||||
|
target_include_directories(lvgl_port_lib PRIVATE "priv_include")
|
||||||
|
target_link_libraries(lvgl_port_lib PUBLIC
|
||||||
|
idf::esp_lcd
|
||||||
|
idf::${lvgl_name}
|
||||||
|
)
|
||||||
|
target_link_libraries(lvgl_port_lib PRIVATE
|
||||||
|
idf::esp_timer
|
||||||
|
${ADD_LIBS}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Finally, link the lvgl_port_lib its esp-idf interface library
|
||||||
|
target_link_libraries(${COMPONENT_LIB} INTERFACE lvgl_port_lib)
|
||||||
366
managed_components/espressif__esp_lvgl_port/README.md
Normal file
366
managed_components/espressif__esp_lvgl_port/README.md
Normal file
@ -0,0 +1,366 @@
|
|||||||
|
# LVGL ESP Portation
|
||||||
|
|
||||||
|
[](https://components.espressif.com/components/espressif/esp_lvgl_port)
|
||||||
|

|
||||||
|
|
||||||
|
This component helps with using LVGL with Espressif's LCD and touch drivers. It can be used with any project with LCD display.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
* Initialization of the LVGL
|
||||||
|
* Create task and timer
|
||||||
|
* Handle rotating
|
||||||
|
* Power saving
|
||||||
|
* Add/remove display (using [`esp_lcd`](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/lcd.html))
|
||||||
|
* Add/remove touch input (using [`esp_lcd_touch`](https://github.com/espressif/esp-bsp/tree/master/components/lcd_touch))
|
||||||
|
* Add/remove navigation buttons input (using [`button`](https://github.com/espressif/esp-iot-solution/tree/master/components/button))
|
||||||
|
* Add/remove encoder input (using [`knob`](https://github.com/espressif/esp-iot-solution/tree/master/components/knob))
|
||||||
|
* Add/remove USB HID mouse/keyboard input (using [`usb_host_hid`](https://components.espressif.com/components/espressif/usb_host_hid))
|
||||||
|
|
||||||
|
## LVGL Version
|
||||||
|
|
||||||
|
This component supports **LVGL8** and **LVGL9**. By default, it selects the latest LVGL version. If you want to use a specific version (e.g. latest LVGL8), you can easily define this requirement in `idf_component.yml` in your project like this:
|
||||||
|
|
||||||
|
```
|
||||||
|
lvgl/lvgl:
|
||||||
|
version: "^8"
|
||||||
|
public: true
|
||||||
|
```
|
||||||
|
|
||||||
|
### LVGL Version Compatibility
|
||||||
|
|
||||||
|
This component is fully compatible with LVGL version 9. All types and functions are used from LVGL9. Some LVGL9 types are not supported in LVGL8 and there are retyped in [`esp_lvgl_port_compatibility.h`](include/esp_lvgl_port_compatibility.h) header file. **Please, be aware, that some draw and object functions are not compatible between LVGL8 and LVGL9.**
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### Initialization
|
||||||
|
``` c
|
||||||
|
const lvgl_port_cfg_t lvgl_cfg = ESP_LVGL_PORT_INIT_CONFIG();
|
||||||
|
esp_err_t err = lvgl_port_init(&lvgl_cfg);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Add screen
|
||||||
|
|
||||||
|
Add an LCD screen to the LVGL. It can be called multiple times for adding multiple LCD screens.
|
||||||
|
|
||||||
|
``` c
|
||||||
|
static lv_disp_t * disp_handle;
|
||||||
|
|
||||||
|
/* LCD IO */
|
||||||
|
esp_lcd_panel_io_handle_t io_handle = NULL;
|
||||||
|
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t) 1, &io_config, &io_handle));
|
||||||
|
|
||||||
|
/* LCD driver initialization */
|
||||||
|
esp_lcd_panel_handle_t lcd_panel_handle;
|
||||||
|
ESP_ERROR_CHECK(esp_lcd_new_panel_st7789(io_handle, &panel_config, &lcd_panel_handle));
|
||||||
|
|
||||||
|
/* Add LCD screen */
|
||||||
|
const lvgl_port_display_cfg_t disp_cfg = {
|
||||||
|
.io_handle = io_handle,
|
||||||
|
.panel_handle = lcd_panel_handle,
|
||||||
|
.buffer_size = DISP_WIDTH*DISP_HEIGHT,
|
||||||
|
.double_buffer = true,
|
||||||
|
.hres = DISP_WIDTH,
|
||||||
|
.vres = DISP_HEIGHT,
|
||||||
|
.monochrome = false,
|
||||||
|
.mipi_dsi = false,
|
||||||
|
.color_format = LV_COLOR_FORMAT_RGB565,
|
||||||
|
.rotation = {
|
||||||
|
.swap_xy = false,
|
||||||
|
.mirror_x = false,
|
||||||
|
.mirror_y = false,
|
||||||
|
},
|
||||||
|
.flags = {
|
||||||
|
.buff_dma = true,
|
||||||
|
.swap_bytes = false,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
disp_handle = lvgl_port_add_disp(&disp_cfg);
|
||||||
|
|
||||||
|
/* ... the rest of the initialization ... */
|
||||||
|
|
||||||
|
/* If deinitializing LVGL port, remember to delete all displays: */
|
||||||
|
lvgl_port_remove_disp(disp_handle);
|
||||||
|
```
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
> 1. For adding RGB or MIPI-DSI screen, use functions `lvgl_port_add_disp_rgb` or `lvgl_port_add_disp_dsi`.
|
||||||
|
> 2. DMA buffer can be used only when you use color format `LV_COLOR_FORMAT_RGB565`.
|
||||||
|
|
||||||
|
### Add touch input
|
||||||
|
|
||||||
|
Add touch input to the LVGL. It can be called more times for adding more touch inputs.
|
||||||
|
``` c
|
||||||
|
/* Touch driver initialization */
|
||||||
|
...
|
||||||
|
esp_lcd_touch_handle_t tp;
|
||||||
|
esp_err_t err = esp_lcd_touch_new_i2c_gt911(io_handle, &tp_cfg, &tp);
|
||||||
|
|
||||||
|
/* Add touch input (for selected screen) */
|
||||||
|
const lvgl_port_touch_cfg_t touch_cfg = {
|
||||||
|
.disp = disp_handle,
|
||||||
|
.handle = tp,
|
||||||
|
};
|
||||||
|
lv_indev_t* touch_handle = lvgl_port_add_touch(&touch_cfg);
|
||||||
|
|
||||||
|
/* ... the rest of the initialization ... */
|
||||||
|
|
||||||
|
/* If deinitializing LVGL port, remember to delete all touches: */
|
||||||
|
lvgl_port_remove_touch(touch_handle);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Add buttons input
|
||||||
|
|
||||||
|
Add buttons input to the LVGL. It can be called more times for adding more buttons inputs for different displays. This feature is available only when the component `espressif/button` was added into the project.
|
||||||
|
``` c
|
||||||
|
/* Buttons configuration structure */
|
||||||
|
const button_gpio_config_t bsp_button_config[] = {
|
||||||
|
{
|
||||||
|
.gpio_num = GPIO_NUM_37,
|
||||||
|
.active_level = 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.gpio_num = GPIO_NUM_38,
|
||||||
|
.active_level = 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.gpio_num = GPIO_NUM_39,
|
||||||
|
.active_level = 0,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const button_config_t btn_cfg = {0};
|
||||||
|
button_handle_t prev_btn_handle = NULL;
|
||||||
|
button_handle_t next_btn_handle = NULL;
|
||||||
|
button_handle_t enter_btn_handle = NULL;
|
||||||
|
iot_button_new_gpio_device(&btn_cfg, &bsp_button_config[0], &prev_btn_handle);
|
||||||
|
iot_button_new_gpio_device(&btn_cfg, &bsp_button_config[1], &next_btn_handle);
|
||||||
|
iot_button_new_gpio_device(&btn_cfg, &bsp_button_config[2], &enter_btn_handle);
|
||||||
|
|
||||||
|
const lvgl_port_nav_btns_cfg_t btns = {
|
||||||
|
.disp = disp_handle,
|
||||||
|
.button_prev = prev_btn_handle,
|
||||||
|
.button_next = next_btn_handle,
|
||||||
|
.button_enter = enter_btn_handle
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Add buttons input (for selected screen) */
|
||||||
|
lv_indev_t* buttons_handle = lvgl_port_add_navigation_buttons(&btns);
|
||||||
|
|
||||||
|
/* ... the rest of the initialization ... */
|
||||||
|
|
||||||
|
/* If deinitializing LVGL port, remember to delete all buttons: */
|
||||||
|
lvgl_port_remove_navigation_buttons(buttons_handle);
|
||||||
|
```
|
||||||
|
> [!NOTE]
|
||||||
|
> When you use navigation buttons for control LVGL objects, these objects must be added to LVGL groups. See [LVGL documentation](https://docs.lvgl.io/master/overview/indev.html?highlight=lv_indev_get_act#keypad-and-encoder) for more info.
|
||||||
|
|
||||||
|
### Add encoder input
|
||||||
|
|
||||||
|
Add encoder input to the LVGL. It can be called more times for adding more encoder inputs for different displays. This feature is available only when the component `espressif/knob` was added into the project.
|
||||||
|
``` c
|
||||||
|
|
||||||
|
static const button_gpio_config_t encoder_btn_config = {
|
||||||
|
.gpio_num = GPIO_BTN_PRESS,
|
||||||
|
.active_level = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
const knob_config_t encoder_a_b_config = {
|
||||||
|
.default_direction = 0,
|
||||||
|
.gpio_encoder_a = GPIO_ENCODER_A,
|
||||||
|
.gpio_encoder_b = GPIO_ENCODER_B,
|
||||||
|
};
|
||||||
|
|
||||||
|
const button_config_t btn_cfg = {0};
|
||||||
|
button_handle_t encoder_btn_handle = NULL;
|
||||||
|
BSP_ERROR_CHECK_RETURN_NULL(iot_button_new_gpio_device(&btn_cfg, &encoder_btn_config, &encoder_btn_handle));
|
||||||
|
|
||||||
|
/* Encoder configuration structure */
|
||||||
|
const lvgl_port_encoder_cfg_t encoder = {
|
||||||
|
.disp = disp_handle,
|
||||||
|
.encoder_a_b = &encoder_a_b_config,
|
||||||
|
.encoder_enter = encoder_btn_handle
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Add encoder input (for selected screen) */
|
||||||
|
lv_indev_t* encoder_handle = lvgl_port_add_encoder(&encoder);
|
||||||
|
|
||||||
|
/* ... the rest of the initialization ... */
|
||||||
|
|
||||||
|
/* If deinitializing LVGL port, remember to delete all encoders: */
|
||||||
|
lvgl_port_remove_encoder(encoder_handle);
|
||||||
|
```
|
||||||
|
> [!NOTE]
|
||||||
|
> When you use encoder for control LVGL objects, these objects must be added to LVGL groups. See [LVGL documentation](https://docs.lvgl.io/master/overview/indev.html?highlight=lv_indev_get_act#keypad-and-encoder) for more info.
|
||||||
|
|
||||||
|
### Add USB HID keyboard and mouse input
|
||||||
|
|
||||||
|
Add mouse and keyboard input to the LVGL. This feature is available only when the component [usb_host_hid](https://components.espressif.com/components/espressif/usb_host_hid) was added into the project.
|
||||||
|
|
||||||
|
``` c
|
||||||
|
/* USB initialization */
|
||||||
|
usb_host_config_t host_config = {
|
||||||
|
.skip_phy_setup = false,
|
||||||
|
.intr_flags = ESP_INTR_FLAG_LEVEL1,
|
||||||
|
};
|
||||||
|
ESP_ERROR_CHECK(usb_host_install(&host_config));
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
/* Add mouse input device */
|
||||||
|
const lvgl_port_hid_mouse_cfg_t mouse_cfg = {
|
||||||
|
.disp = display,
|
||||||
|
.sensitivity = 1, /* Sensitivity of the mouse moving */
|
||||||
|
};
|
||||||
|
lvgl_port_add_usb_hid_mouse_input(&mouse_cfg);
|
||||||
|
|
||||||
|
/* Add keyboard input device */
|
||||||
|
const lvgl_port_hid_keyboard_cfg_t kb_cfg = {
|
||||||
|
.disp = display,
|
||||||
|
};
|
||||||
|
kb_indev = lvgl_port_add_usb_hid_keyboard_input(&kb_cfg);
|
||||||
|
```
|
||||||
|
|
||||||
|
Keyboard special behavior (when objects are in group):
|
||||||
|
- **TAB**: Select next object
|
||||||
|
- **SHIFT** + **TAB**: Select previous object
|
||||||
|
- **ENTER**: Control object (e.g. click to button)
|
||||||
|
- **ARROWS** or **HOME** or **END**: Move in text area
|
||||||
|
- **DEL** or **Backspace**: Remove character in textarea
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
> When you use keyboard for control LVGL objects, these objects must be added to LVGL groups. See [LVGL documentation](https://docs.lvgl.io/master/overview/indev.html?highlight=lv_indev_get_act#keypad-and-encoder) for more info.
|
||||||
|
|
||||||
|
### LVGL API usage
|
||||||
|
|
||||||
|
Every LVGL calls must be protected with these lock/unlock commands:
|
||||||
|
``` c
|
||||||
|
/* Wait for the other task done the screen operation */
|
||||||
|
lvgl_port_lock(0);
|
||||||
|
...
|
||||||
|
lv_obj_t * screen = lv_disp_get_scr_act(disp_handle);
|
||||||
|
lv_obj_t * obj = lv_label_create(screen);
|
||||||
|
...
|
||||||
|
/* Screen operation done -> release for the other task */
|
||||||
|
lvgl_port_unlock();
|
||||||
|
```
|
||||||
|
|
||||||
|
### Rotating screen
|
||||||
|
|
||||||
|
LVGL port supports rotation of the display. You can select whether you'd like software rotation or hardware rotation.
|
||||||
|
Software rotation requires no additional logic in your `flush_cb` callback.
|
||||||
|
|
||||||
|
Rotation mode can be selected in the `lvgl_port_display_cfg_t` structure.
|
||||||
|
``` c
|
||||||
|
const lvgl_port_display_cfg_t disp_cfg = {
|
||||||
|
...
|
||||||
|
.flags = {
|
||||||
|
...
|
||||||
|
.sw_rotate = true / false, // true: software; false: hardware
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Display rotation can be changed at runtime.
|
||||||
|
|
||||||
|
``` c
|
||||||
|
lv_disp_set_rotation(disp_handle, LV_DISP_ROT_90);
|
||||||
|
```
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
> This feature consume more RAM.
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
> During the hardware rotating, the component call [`esp_lcd`](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/lcd.html) API. When using software rotation, you cannot use neither `direct_mode` nor `full_refresh` in the driver. See [LVGL documentation](https://docs.lvgl.io/8.3/porting/display.html?highlight=sw_rotate) for more info.
|
||||||
|
|
||||||
|
### Using PSRAM canvas
|
||||||
|
|
||||||
|
If the SRAM is insufficient, you can use the PSRAM as a canvas and use a small trans_buffer to carry it, this makes drawing more efficient.
|
||||||
|
``` c
|
||||||
|
const lvgl_port_display_cfg_t disp_cfg = {
|
||||||
|
...
|
||||||
|
.buffer_size = DISP_WIDTH * DISP_HEIGHT, // in PSRAM, not DMA-capable
|
||||||
|
.trans_size = size, // in SRAM, DMA-capable
|
||||||
|
.flags = {
|
||||||
|
.buff_spiram = true,
|
||||||
|
.buff_dma = false,
|
||||||
|
...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Generating images (C Array)
|
||||||
|
|
||||||
|
Images can be generated during build by adding these lines to end of the main CMakeLists.txt:
|
||||||
|
```
|
||||||
|
# Generate C array for each image
|
||||||
|
lvgl_port_create_c_image("images/logo.png" "images/" "ARGB8888" "NONE")
|
||||||
|
lvgl_port_create_c_image("images/image.png" "images/" "ARGB8888" "NONE")
|
||||||
|
# Add generated images to build
|
||||||
|
lvgl_port_add_images(${COMPONENT_LIB} "images/")
|
||||||
|
```
|
||||||
|
|
||||||
|
Usage of create C image function:
|
||||||
|
```
|
||||||
|
lvgl_port_create_c_image(input_image output_folder color_format compression)
|
||||||
|
```
|
||||||
|
|
||||||
|
Available color formats:
|
||||||
|
L8,I1,I2,I4,I8,A1,A2,A4,A8,ARGB8888,XRGB8888,RGB565,RGB565A8,RGB888,TRUECOLOR,TRUECOLOR_ALPHA,AUTO
|
||||||
|
|
||||||
|
Available compression:
|
||||||
|
NONE,RLE,LZ4
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
> Parameters `color_format` and `compression` are used only in LVGL 9.
|
||||||
|
|
||||||
|
## Power Saving
|
||||||
|
|
||||||
|
The LVGL port can be optimized for power saving mode. There are two main features.
|
||||||
|
|
||||||
|
### LVGL task sleep
|
||||||
|
|
||||||
|
For optimization power saving, the LVGL task should sleep, when it does nothing. Set `task_max_sleep_ms` to big value, the LVGL task will wait for events only.
|
||||||
|
|
||||||
|
The LVGL task can sleep till these situations:
|
||||||
|
* LVGL display invalidate
|
||||||
|
* LVGL animation in process
|
||||||
|
* Touch interrupt
|
||||||
|
* Button interrupt
|
||||||
|
* Knob interrupt
|
||||||
|
* USB mouse/keyboard interrupt
|
||||||
|
* Timeout (`task_max_sleep_ms` in configuration structure)
|
||||||
|
* User wake (by function `lvgl_port_task_wake`)
|
||||||
|
|
||||||
|
> [!WARNING]
|
||||||
|
> This feature is available from LVGL 9.
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
> Don't forget to set the interrupt pin in LCD touch when you set a big time for sleep in `task_max_sleep_ms`.
|
||||||
|
|
||||||
|
### Stopping the timer
|
||||||
|
|
||||||
|
Timers can still work during light-sleep mode. You can stop LVGL timer before use light-sleep by function:
|
||||||
|
|
||||||
|
```
|
||||||
|
lvgl_port_stop();
|
||||||
|
```
|
||||||
|
|
||||||
|
and resume LVGL timer after wake by function:
|
||||||
|
|
||||||
|
```
|
||||||
|
lvgl_port_resume();
|
||||||
|
```
|
||||||
|
|
||||||
|
## Performance
|
||||||
|
|
||||||
|
Key feature of every graphical application is performance. Recommended settings for improving LCD performance is described in a separate document [here](docs/performance.md).
|
||||||
|
|
||||||
|
### Performance monitor
|
||||||
|
|
||||||
|
For show performance monitor in LVGL9, please add these lines to sdkconfig.defaults and rebuild all.
|
||||||
|
|
||||||
|
```
|
||||||
|
CONFIG_LV_USE_OBSERVER=y
|
||||||
|
CONFIG_LV_USE_SYSMON=y
|
||||||
|
CONFIG_LV_USE_PERF_MONITOR=y
|
||||||
|
```
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
168
managed_components/espressif__esp_lvgl_port/docs/performance.md
Normal file
168
managed_components/espressif__esp_lvgl_port/docs/performance.md
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
# LCD & LVGL Performance
|
||||||
|
|
||||||
|
This document provides steps, how to set up your LCD and LVGL port for the best performance and comparison of different settings. All settings and measurements are valid for Espressif's chips. Examples in [ESP-BSP](https://github.com/espressif/esp-bsp) are ready to use with the best performance.
|
||||||
|
|
||||||
|
## Performance metrics
|
||||||
|
|
||||||
|
In this document we will use following metrics for performance evaluation:
|
||||||
|
|
||||||
|
1. Measure time needed for refreshing the whole screen.
|
||||||
|
2. Use LVGL's [lv_demo_benchmark()](https://github.com/lvgl/lvgl/tree/v8.3.6/demos/benchmark) -test suite- to measure Frames per second (weighted FPS).
|
||||||
|
3. Use LVGL's [lv_demo_music()](https://github.com/lvgl/lvgl/tree/v8.3.6/demos/music) -demo application- to measure Frames per second (average FPS).
|
||||||
|
|
||||||
|
## Settings on ESP32 chips which have impact on LCD and LVGL performance
|
||||||
|
|
||||||
|
Following options and settings have impact on LCD performance (FPS). Some options yield only small difference in FPS (e.g. ~1 FPS), and some of them are more significant. Usually it depends on complexity of the graphical application (number of widgets...), resources (CPU time, RAM available...) and size of screen (definition and color depth).
|
||||||
|
|
||||||
|
Another set of key parametes are hardware related (graphical IO, frame buffer location), which are not yet covered in this document.
|
||||||
|
|
||||||
|
### LVGL Buffer configuration
|
||||||
|
|
||||||
|
**This is by far the most significant setting.** Users are encouraged to focus on correct frame buffer configuration before moving ahead with other optimizations.
|
||||||
|
|
||||||
|
On the other hand, the frame buffer(s) will consume significant portion of your RAM. In the graph below, you can see different frame buffer settings and resulting FPS:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Main takeaways from the graph are:
|
||||||
|
|
||||||
|
* The size of **LVGL buffer** and **double buffering** feature has big impact on performance.
|
||||||
|
* Frame buffer size >25% of the screen does not bring relevant performance boost
|
||||||
|
* Frame buffer size <10% will have severe negative effect on performance
|
||||||
|
|
||||||
|
*Note:* The measurements are valid for frame buffer in internal SRAM. Placing the frame buffer into external PSRAM will yield worse results.
|
||||||
|
|
||||||
|
### Compiler optimization level
|
||||||
|
|
||||||
|
Recommended level is "Performance" for good results. The "Performance" setting causes the compiled code to be larger and faster.
|
||||||
|
|
||||||
|
* `CONFIG_COMPILER_OPTIMIZATION_PERF=y`
|
||||||
|
|
||||||
|
### CPU frequency
|
||||||
|
|
||||||
|
The CPU frequency has a big impact on LCD performance. The recommended value is maximum -> 240 MHz.
|
||||||
|
|
||||||
|
* `CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y`
|
||||||
|
|
||||||
|
### Flash frequency and mode
|
||||||
|
|
||||||
|
The flash clock frequency and mode (bus width) has a big impact on LCD performance. Your choices will be limited by your hardware flash configuration. The higher the frequency and bus width, the better.
|
||||||
|
|
||||||
|
* `CONFIG_ESPTOOLPY_FLASHFREQ_120M=y`
|
||||||
|
* `CONFIG_ESPTOOLPY_FLASHMODE_QIO=y` or `CONFIG_ESPTOOLPY_OCT_FLASH` on supported chips
|
||||||
|
|
||||||
|
More information about SPI Flash configuration can be found in [ESP-IDF Programming Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/api-guides/flash_psram_config.html).
|
||||||
|
|
||||||
|
### Fast LVGL memory
|
||||||
|
|
||||||
|
This option puts the most frequently used LVGL functions into IRAM for execution speed up.
|
||||||
|
|
||||||
|
* `CONFIG_LV_ATTRIBUTE_FAST_MEM_USE_IRAM=y`
|
||||||
|
|
||||||
|
### Affinity main task to second core
|
||||||
|
|
||||||
|
The main LVGL task can be processed on the second core of the CPU. It can increase performance. (It is available only on dual-core chips)
|
||||||
|
|
||||||
|
* `CONFIG_ESP_MAIN_TASK_AFFINITY_CPU1=y`
|
||||||
|
|
||||||
|
### Using esp-idf `memcpy` and `memset` instead LVGL's configuration
|
||||||
|
|
||||||
|
Native esp-idf implementation are a little (~1-3 FPS) faster (only for LVGL8).
|
||||||
|
|
||||||
|
* `CONFIG_LV_MEMCPY_MEMSET_STD=y`
|
||||||
|
|
||||||
|
### Default LVGL display refresh period
|
||||||
|
|
||||||
|
This setting can improve subjective performance during screen transitions (scrolling, etc.).
|
||||||
|
|
||||||
|
LVGL8
|
||||||
|
* `CONFIG_LV_DISP_DEF_REFR_PERIOD=10`
|
||||||
|
|
||||||
|
LVGL9
|
||||||
|
* `CONFIG_LV_DEF_REFR_PERIOD=10`
|
||||||
|
|
||||||
|
## Example FPS improvement vs graphical settings
|
||||||
|
|
||||||
|
The LVGL9 benchmark demo uses a different algorithm for measuring FPS. In this case, we used the same algorithm for measurement in LVGL8 for comparison.
|
||||||
|
|
||||||
|
### RGB LCD, PSRAM (octal) with GDMA - ESP32-S3-LCD-EV-BOARD
|
||||||
|
|
||||||
|
<img src="https://github.com/espressif/esp-bsp/blob/master/docu/pics/esp32-s3-lcd-ev-board_800x480.png?raw=true" align="right" width="300px" />
|
||||||
|
|
||||||
|
Default settings:
|
||||||
|
* BSP example `display_lvgl_demos`
|
||||||
|
* LCD: 4.3" 800x480
|
||||||
|
* Interface: RGB
|
||||||
|
* LVGL buffer size: 800 x 480
|
||||||
|
* LVGL buffer mode: Direct (avoid-tearing)
|
||||||
|
* LVGL double buffer: NO
|
||||||
|
* Optimization: Debug
|
||||||
|
* CPU frequency: 160 MHz
|
||||||
|
* Flash frequency: 80 MHz
|
||||||
|
* PSRAM frequency: 80 MHz
|
||||||
|
* Flash mode: DIO
|
||||||
|
* LVGL display refresh period: 30 ms
|
||||||
|
|
||||||
|
| Average FPS (LVGL8) | Average FPS (LVGL 9.2) | Changed settings |
|
||||||
|
| :---: | :---: | ---------------- |
|
||||||
|
| 12 | 9 | Default |
|
||||||
|
| 13 | 9 | + Optimization: Performance (`CONFIG_COMPILER_OPTIMIZATION_PERF=y`) |
|
||||||
|
| 14 | 11 | + CPU frequency: 240 MHz (`CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y`) |
|
||||||
|
| 14 | 11 | + Flash mode: QIO (`CONFIG_ESPTOOLPY_FLASHMODE_QIO=y`) |
|
||||||
|
| 15 | 11 | + LVGL fast memory enabled (`CONFIG_LV_ATTRIBUTE_FAST_MEM_USE_IRAM=y`) |
|
||||||
|
| 16 | 11 | + (`CONFIG_LV_DISP_DEF_REFR_PERIOD=10` / `CONFIG_LV_DEF_REFR_PERIOD=10`) |
|
||||||
|
|
||||||
|
### Parallel 8080 LCD (only for LVGL8)
|
||||||
|
|
||||||
|
<img src="https://github.com/espressif/esp-bsp/blob/master/docu/pics/7inch-Capacitive-Touch-LCD-C_l.jpg?raw=true" align="right" width="300px" />
|
||||||
|
|
||||||
|
Default settings:
|
||||||
|
* BSP example `display_lvgl_demos` with `ws_7inch` component
|
||||||
|
* LCD: 7" 800x480
|
||||||
|
* Intarface: 16bit parallel Intel 8080
|
||||||
|
* LCD IO clock: 20 MHz
|
||||||
|
* LVGL buffer size: 800 x 50
|
||||||
|
* LVGL double buffer: YES
|
||||||
|
* Optimization: Debug
|
||||||
|
* CPU frequency: 160 MHz
|
||||||
|
* Flash frequency: 80 MHz
|
||||||
|
* Flash mode: DIO
|
||||||
|
* LVGL display refresh period: 30 ms
|
||||||
|
|
||||||
|
#### Internal RAM with DMA
|
||||||
|
|
||||||
|
| Average FPS | Weighted FPS | Changed settings |
|
||||||
|
| :---: | :---: | ---------------- |
|
||||||
|
| 17 | 32 | Default |
|
||||||
|
| 18 | 36 | + Optimization: Performance (`CONFIG_COMPILER_OPTIMIZATION_PERF=y`) |
|
||||||
|
| 21 | 46 | + CPU frequency: 240 MHz (`CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y`) |
|
||||||
|
| 26 | 56 | + Flash frequency: 120 MHz, Flash mode: QIO (`CONFIG_ESPTOOLPY_FLASHFREQ_120M=y` + `CONFIG_ESPTOOLPY_FLASHMODE_QIO=y`) |
|
||||||
|
| 28 | **60** | + LVGL fast memory enabled (`CONFIG_LV_ATTRIBUTE_FAST_MEM_USE_IRAM=y`) |
|
||||||
|
| 41 | 55 | + (`CONFIG_LV_DISP_DEF_REFR_PERIOD=10`) |
|
||||||
|
|
||||||
|
#### PSRAM (QUAD) without DMA
|
||||||
|
|
||||||
|
Default changes:
|
||||||
|
* LCD IO clock: 2 MHz
|
||||||
|
* PSRAM frequency: 80 MHz
|
||||||
|
|
||||||
|
| Average FPS | Weighted FPS | Changed settings |
|
||||||
|
| :---: | :---: | ---------------- |
|
||||||
|
| 11 | 7 | Default |
|
||||||
|
| 11 | 7 | + Optimization: Performance (`CONFIG_COMPILER_OPTIMIZATION_PERF=y`) |
|
||||||
|
| 12 | 8 | + CPU frequency: 240 MHz (`CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y`) |
|
||||||
|
| 12 | 9 | + Flash frequency: 120 MHz, PSRAM frequency: 120 MHz, Flash mode: QIO (`CONFIG_ESPTOOLPY_FLASHFREQ_120M=y` + `CONFIG_SPIRAM_SPEED_120M=y` + `CONFIG_ESPTOOLPY_FLASHMODE_QIO=y`) |
|
||||||
|
| 12 | 9 | + LVGL fast memory enabled (`CONFIG_LV_ATTRIBUTE_FAST_MEM_USE_IRAM=y`) |
|
||||||
|
| 12 | 8 | + LVGL buffer size: 800 x 480 |
|
||||||
|
| 26 | 8 | + (`CONFIG_LV_DISP_DEF_REFR_PERIOD=10`) |
|
||||||
|
| 31 | 23 | + LCD clock: 10 MHz [^1] |
|
||||||
|
|
||||||
|
[^1]: This is not working in default and sometimes in fast changes on screen is not working properly.
|
||||||
|
|
||||||
|
## Conclusion
|
||||||
|
|
||||||
|
The graphical performance depends on a lot of things and settings, many of which affect the whole system (Compiler, Flash, CPU, PSRAM configuration...). The user should primarily focus on trade-off between frame-buffer(s) size and RAM consumption of the buffer, before optimizing the design further.
|
||||||
|
|
||||||
|
Other configuration options not covered in this document are:
|
||||||
|
* Hardware interfaces, color depth, screen definition (size), clocks, LCD controller and more.
|
||||||
|
* Complexity of the graphical application (number of LVGL objects and their styles).
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.16)
|
||||||
|
|
||||||
|
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||||
|
project(i2c_oled)
|
||||||
@ -0,0 +1,73 @@
|
|||||||
|
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
|
||||||
|
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- |
|
||||||
|
|
||||||
|
# I2C OLED example
|
||||||
|
|
||||||
|
[esp_lcd](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/lcd.html) supports I2C interfaced OLED LCD, whose color depth is usually 1bpp.
|
||||||
|
|
||||||
|
This example shows how to make use of the SSD1306 panel driver from `esp_lcd` component to facilitate the porting of LVGL library. In the end, example will display a scrolling text on the OLED screen.
|
||||||
|
|
||||||
|
## LVGL Version
|
||||||
|
|
||||||
|
This example is using the **LVGL8** version. For use it with LVGL9 version, please delete file [sdkconfig.defaults](sdkconfig.defaults) and change version to `"^9"` on this line in [idf_component.yml](main/idf_component.yml) file:
|
||||||
|
```
|
||||||
|
lvgl/lvgl: "^8"
|
||||||
|
```
|
||||||
|
|
||||||
|
NOTE: When you are changing LVGL versions, please remove these files and folders before new build:
|
||||||
|
- build/
|
||||||
|
- managed_components/
|
||||||
|
- dependencies.lock
|
||||||
|
- sdkconfig
|
||||||
|
|
||||||
|
## How to use the example
|
||||||
|
|
||||||
|
### Hardware Required
|
||||||
|
|
||||||
|
* An ESP development board
|
||||||
|
* An SSD1306 OLED LCD, with I2C interface
|
||||||
|
* An USB cable for power supply and programming
|
||||||
|
|
||||||
|
### Hardware Connection
|
||||||
|
|
||||||
|
The connection between ESP Board and the LCD is as follows:
|
||||||
|
|
||||||
|
```
|
||||||
|
ESP Board OLED LCD (I2C)
|
||||||
|
+------------------+ +-------------------+
|
||||||
|
| GND+--------------+GND |
|
||||||
|
| | | |
|
||||||
|
| 3V3+--------------+VCC |
|
||||||
|
| | | |
|
||||||
|
| SDA+--------------+SDA |
|
||||||
|
| | | |
|
||||||
|
| SCL+--------------+SCL |
|
||||||
|
+------------------+ +-------------------+
|
||||||
|
```
|
||||||
|
|
||||||
|
The GPIO number used by this example can be changed in [lvgl_example_main.c](main/i2c_oled_example_main.c). Please pay attention to the I2C hardware device address as well, you should refer to your module's spec and schematic to determine that address.
|
||||||
|
|
||||||
|
### Build and Flash
|
||||||
|
|
||||||
|
Run `idf.py -p PORT build flash monitor` to build, flash and monitor the project. A scrolling text will show up on the LCD as expected.
|
||||||
|
|
||||||
|
The first time you run `idf.py` for the example will cost extra time as the build system needs to address the component dependencies and downloads the missing components from registry into `managed_components` folder.
|
||||||
|
|
||||||
|
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||||
|
|
||||||
|
See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects.
|
||||||
|
|
||||||
|
### Example Output
|
||||||
|
|
||||||
|
```bash
|
||||||
|
...
|
||||||
|
I (0) cpu_start: Starting scheduler on APP CPU.
|
||||||
|
I (345) example: Initialize I2C bus
|
||||||
|
I (345) example: Install panel IO
|
||||||
|
I (345) example: Install SSD1306 panel driver
|
||||||
|
I (455) example: Initialize LVGL library
|
||||||
|
I (455) example: Register display driver to LVGL
|
||||||
|
I (455) example: Install LVGL tick timer
|
||||||
|
I (455) example: Display LVGL Scroll Text
|
||||||
|
...
|
||||||
|
```
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
idf_component_register(
|
||||||
|
SRCS "i2c_oled_example_main.c" "lvgl_demo_ui.c"
|
||||||
|
INCLUDE_DIRS "."
|
||||||
|
REQUIRES driver
|
||||||
|
)
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
menu "Example Configuration"
|
||||||
|
|
||||||
|
choice EXAMPLE_LCD_CONTROLLER
|
||||||
|
prompt "LCD controller model"
|
||||||
|
default EXAMPLE_LCD_CONTROLLER_SSD1306
|
||||||
|
help
|
||||||
|
Select LCD controller model
|
||||||
|
|
||||||
|
config EXAMPLE_LCD_CONTROLLER_SSD1306
|
||||||
|
bool "SSD1306"
|
||||||
|
|
||||||
|
config EXAMPLE_LCD_CONTROLLER_SH1107
|
||||||
|
bool "SH1107"
|
||||||
|
endchoice
|
||||||
|
|
||||||
|
if EXAMPLE_LCD_CONTROLLER_SSD1306
|
||||||
|
choice EXAMPLE_SSD1306_HEIGHT
|
||||||
|
prompt "SSD1306 Height in pixels"
|
||||||
|
default EXAMPLE_SSD1306_HEIGHT_64
|
||||||
|
help
|
||||||
|
Height of the display in pixels. a.k.a vertical resolution
|
||||||
|
|
||||||
|
config EXAMPLE_SSD1306_HEIGHT_64
|
||||||
|
bool "64"
|
||||||
|
config EXAMPLE_SSD1306_HEIGHT_32
|
||||||
|
bool "32"
|
||||||
|
endchoice
|
||||||
|
|
||||||
|
config EXAMPLE_SSD1306_HEIGHT
|
||||||
|
int
|
||||||
|
default 64 if EXAMPLE_SSD1306_HEIGHT_64
|
||||||
|
default 32 if EXAMPLE_SSD1306_HEIGHT_32
|
||||||
|
endif
|
||||||
|
|
||||||
|
endmenu
|
||||||
@ -0,0 +1,155 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: CC0-1.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
|
#include "esp_timer.h"
|
||||||
|
#include "esp_lcd_panel_io.h"
|
||||||
|
#include "esp_lcd_panel_ops.h"
|
||||||
|
#include "driver/i2c_master.h"
|
||||||
|
#include "esp_err.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "lvgl.h"
|
||||||
|
#include "esp_lvgl_port.h"
|
||||||
|
|
||||||
|
#if CONFIG_EXAMPLE_LCD_CONTROLLER_SH1107
|
||||||
|
#include "esp_lcd_sh1107.h"
|
||||||
|
#else
|
||||||
|
#include "esp_lcd_panel_vendor.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static const char *TAG = "example";
|
||||||
|
|
||||||
|
#define I2C_HOST 0
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//////////////////// Please update the following configuration according to your LCD spec //////////////////////////////
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#define EXAMPLE_LCD_PIXEL_CLOCK_HZ (400 * 1000)
|
||||||
|
#define EXAMPLE_PIN_NUM_SDA 18
|
||||||
|
#define EXAMPLE_PIN_NUM_SCL 23
|
||||||
|
#define EXAMPLE_PIN_NUM_RST -1
|
||||||
|
#define EXAMPLE_I2C_HW_ADDR 0x3C
|
||||||
|
|
||||||
|
// The pixel number in horizontal and vertical
|
||||||
|
#if CONFIG_EXAMPLE_LCD_CONTROLLER_SSD1306
|
||||||
|
#define EXAMPLE_LCD_H_RES 128
|
||||||
|
#define EXAMPLE_LCD_V_RES CONFIG_EXAMPLE_SSD1306_HEIGHT
|
||||||
|
#elif CONFIG_EXAMPLE_LCD_CONTROLLER_SH1107
|
||||||
|
#define EXAMPLE_LCD_H_RES 64
|
||||||
|
#define EXAMPLE_LCD_V_RES 128
|
||||||
|
#endif
|
||||||
|
// Bit number used to represent command and parameter
|
||||||
|
#define EXAMPLE_LCD_CMD_BITS 8
|
||||||
|
#define EXAMPLE_LCD_PARAM_BITS 8
|
||||||
|
|
||||||
|
extern void example_lvgl_demo_ui(lv_disp_t *disp);
|
||||||
|
|
||||||
|
void app_main(void)
|
||||||
|
{
|
||||||
|
ESP_LOGI(TAG, "Initialize I2C bus");
|
||||||
|
i2c_master_bus_handle_t i2c_bus = NULL;
|
||||||
|
i2c_master_bus_config_t bus_config = {
|
||||||
|
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||||
|
.glitch_ignore_cnt = 7,
|
||||||
|
.i2c_port = I2C_HOST,
|
||||||
|
.sda_io_num = EXAMPLE_PIN_NUM_SDA,
|
||||||
|
.scl_io_num = EXAMPLE_PIN_NUM_SCL,
|
||||||
|
.flags.enable_internal_pullup = true,
|
||||||
|
};
|
||||||
|
ESP_ERROR_CHECK(i2c_new_master_bus(&bus_config, &i2c_bus));
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "Install panel IO");
|
||||||
|
esp_lcd_panel_io_handle_t io_handle = NULL;
|
||||||
|
esp_lcd_panel_io_i2c_config_t io_config = {
|
||||||
|
.dev_addr = EXAMPLE_I2C_HW_ADDR,
|
||||||
|
.scl_speed_hz = EXAMPLE_LCD_PIXEL_CLOCK_HZ,
|
||||||
|
.control_phase_bytes = 1, // According to SSD1306 datasheet
|
||||||
|
.lcd_cmd_bits = EXAMPLE_LCD_CMD_BITS, // According to SSD1306 datasheet
|
||||||
|
.lcd_param_bits = EXAMPLE_LCD_PARAM_BITS, // According to SSD1306 datasheet
|
||||||
|
#if CONFIG_EXAMPLE_LCD_CONTROLLER_SSD1306
|
||||||
|
.dc_bit_offset = 6, // According to SSD1306 datasheet
|
||||||
|
#elif CONFIG_EXAMPLE_LCD_CONTROLLER_SH1107
|
||||||
|
.dc_bit_offset = 0, // According to SH1107 datasheet
|
||||||
|
.flags =
|
||||||
|
{
|
||||||
|
.disable_control_phase = 1,
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
ESP_ERROR_CHECK(esp_lcd_new_panel_io_i2c(i2c_bus, &io_config, &io_handle));
|
||||||
|
|
||||||
|
esp_lcd_panel_handle_t panel_handle = NULL;
|
||||||
|
esp_lcd_panel_dev_config_t panel_config = {
|
||||||
|
.bits_per_pixel = 1,
|
||||||
|
.reset_gpio_num = EXAMPLE_PIN_NUM_RST,
|
||||||
|
#if (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5,0,0))
|
||||||
|
.color_space = ESP_LCD_COLOR_SPACE_MONOCHROME,
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
#if CONFIG_EXAMPLE_LCD_CONTROLLER_SSD1306
|
||||||
|
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5,3,0))
|
||||||
|
esp_lcd_panel_ssd1306_config_t ssd1306_config = {
|
||||||
|
.height = EXAMPLE_LCD_V_RES,
|
||||||
|
};
|
||||||
|
panel_config.vendor_config = &ssd1306_config;
|
||||||
|
#endif
|
||||||
|
ESP_LOGI(TAG, "Install SSD1306 panel driver");
|
||||||
|
ESP_ERROR_CHECK(esp_lcd_new_panel_ssd1306(io_handle, &panel_config, &panel_handle));
|
||||||
|
#elif CONFIG_EXAMPLE_LCD_CONTROLLER_SH1107
|
||||||
|
ESP_LOGI(TAG, "Install SH1107 panel driver");
|
||||||
|
ESP_ERROR_CHECK(esp_lcd_new_panel_sh1107(io_handle, &panel_config, &panel_handle));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_handle));
|
||||||
|
ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle));
|
||||||
|
ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_handle, true));
|
||||||
|
|
||||||
|
#if CONFIG_EXAMPLE_LCD_CONTROLLER_SH1107
|
||||||
|
ESP_ERROR_CHECK(esp_lcd_panel_invert_color(panel_handle, true));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "Initialize LVGL");
|
||||||
|
const lvgl_port_cfg_t lvgl_cfg = ESP_LVGL_PORT_INIT_CONFIG();
|
||||||
|
lvgl_port_init(&lvgl_cfg);
|
||||||
|
|
||||||
|
const lvgl_port_display_cfg_t disp_cfg = {
|
||||||
|
.io_handle = io_handle,
|
||||||
|
.panel_handle = panel_handle,
|
||||||
|
.buffer_size = EXAMPLE_LCD_H_RES * EXAMPLE_LCD_V_RES,
|
||||||
|
.double_buffer = true,
|
||||||
|
.hres = EXAMPLE_LCD_H_RES,
|
||||||
|
.vres = EXAMPLE_LCD_V_RES,
|
||||||
|
.monochrome = true,
|
||||||
|
#if LVGL_VERSION_MAJOR >= 9
|
||||||
|
.color_format = LV_COLOR_FORMAT_RGB565,
|
||||||
|
#endif
|
||||||
|
.rotation = {
|
||||||
|
.swap_xy = false,
|
||||||
|
.mirror_x = false,
|
||||||
|
.mirror_y = false,
|
||||||
|
},
|
||||||
|
.flags = {
|
||||||
|
#if LVGL_VERSION_MAJOR >= 9
|
||||||
|
.swap_bytes = false,
|
||||||
|
#endif
|
||||||
|
.sw_rotate = false,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
lv_disp_t *disp = lvgl_port_add_disp(&disp_cfg);
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "Display LVGL Scroll Text");
|
||||||
|
// Lock the mutex due to the LVGL APIs are not thread-safe
|
||||||
|
if (lvgl_port_lock(0)) {
|
||||||
|
/* Rotation of the screen */
|
||||||
|
lv_disp_set_rotation(disp, LV_DISPLAY_ROTATION_0);
|
||||||
|
|
||||||
|
example_lvgl_demo_ui(disp);
|
||||||
|
// Release the mutex
|
||||||
|
lvgl_port_unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
dependencies:
|
||||||
|
idf: ">=4.4"
|
||||||
|
lvgl/lvgl: "^8"
|
||||||
|
esp_lcd_sh1107: "^1"
|
||||||
|
esp_lvgl_port:
|
||||||
|
version: "*"
|
||||||
|
override_path: "../../../"
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: CC0-1.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "lvgl.h"
|
||||||
|
|
||||||
|
void example_lvgl_demo_ui(lv_disp_t *disp)
|
||||||
|
{
|
||||||
|
lv_obj_t *scr = lv_disp_get_scr_act(disp);
|
||||||
|
lv_obj_t *label = lv_label_create(scr);
|
||||||
|
lv_label_set_long_mode(label, LV_LABEL_LONG_SCROLL_CIRCULAR); /* Circular scroll */
|
||||||
|
lv_label_set_text(label, "Hello Espressif, Hello LVGL.");
|
||||||
|
/* Size of the screen (if you use rotation 90 or 270, please set disp->driver->ver_res) */
|
||||||
|
#if LVGL_VERSION_MAJOR >= 9
|
||||||
|
lv_obj_set_width(label, lv_display_get_physical_horizontal_resolution(disp));
|
||||||
|
#else
|
||||||
|
lv_obj_set_width(label, disp->driver->hor_res);
|
||||||
|
#endif
|
||||||
|
lv_obj_align(label, LV_ALIGN_TOP_MID, 0, 0);
|
||||||
|
}
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
# This file was generated using idf.py save-defconfig. It can be edited manually.
|
||||||
|
# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration
|
||||||
|
#
|
||||||
|
CONFIG_LV_USE_USER_DATA=y
|
||||||
|
CONFIG_LV_COLOR_DEPTH_1=y
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
# The following lines of boilerplate have to be in your project's CMakeLists
|
||||||
|
# in this exact order for cmake to work correctly
|
||||||
|
cmake_minimum_required(VERSION 3.16)
|
||||||
|
|
||||||
|
# "Trim" the build. Include the minimal set of components, main and anything it depends on.
|
||||||
|
set(COMPONENTS main)
|
||||||
|
|
||||||
|
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||||
|
project(rgb_lcd)
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
# ESP LVGL RGB Screen Example
|
||||||
|
|
||||||
|
Very simple example for demonstration of initialization and usage of the `esp_lvgl_port` component with RGB LCD. This example contains four main parts:
|
||||||
|
|
||||||
|
## 1. LCD HW initialization - `app_lcd_init()`
|
||||||
|
|
||||||
|
Standard HW initialization of the LCD using [`esp_lcd`](https://github.com/espressif/esp-idf/tree/master/components/esp_lcd) component. Settings of this example are fully compatible with [ESP32-S3-LCD-EV-Board-2](https://github.com/espressif/esp-bsp/tree/master/bsp/esp32_s3_lcd_ev_board) board.
|
||||||
|
|
||||||
|
## 2. Touch HW initialization - `app_touch_init()`
|
||||||
|
|
||||||
|
Standard HW initialization of the LCD touch using [`esp_lcd_touch`](https://github.com/espressif/esp-bsp/tree/master/components/lcd_touch/esp_lcd_touch) component. Settings of this example are fully compatible with [ESP32-S3-LCD-EV-Board-2](https://github.com/espressif/esp-bsp/tree/master/bsp/esp32_s3_lcd_ev_board) board.
|
||||||
|
|
||||||
|
## 3. LVGL port initialization - `app_lvgl_init()`
|
||||||
|
|
||||||
|
Initialization of the LVGL port.
|
||||||
|
|
||||||
|
## 4. LVGL objects example usage - `app_main_display()`
|
||||||
|
|
||||||
|
Very simple demonstration code of using LVGL objects after LVGL port initialization.
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
idf_component_register(SRCS "main.c"
|
||||||
|
INCLUDE_DIRS "." ${LV_DEMO_DIR})
|
||||||
|
|
||||||
|
lvgl_port_create_c_image("images/esp_logo.png" "images/" "ARGB8888" "NONE")
|
||||||
|
lvgl_port_add_images(${COMPONENT_LIB} "images/")
|
||||||
|
|
||||||
|
set_source_files_properties(
|
||||||
|
PROPERTIES COMPILE_OPTIONS
|
||||||
|
"-DLV_LVGL_H_INCLUDE_SIMPLE;-Wno-format;"
|
||||||
|
)
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
dependencies:
|
||||||
|
idf: ">=5.0"
|
||||||
|
esp_lcd_touch_gt1151:
|
||||||
|
version: "^1"
|
||||||
|
override_path: "../../../../lcd_touch/esp_lcd_touch_gt1151/"
|
||||||
|
esp_lvgl_port:
|
||||||
|
version: "*"
|
||||||
|
override_path: "../../../"
|
||||||
1
managed_components/espressif__esp_lvgl_port/examples/rgb_lcd/main/images/.gitignore
vendored
Normal file
1
managed_components/espressif__esp_lvgl_port/examples/rgb_lcd/main/images/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
*.c
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 6.5 KiB |
@ -0,0 +1,312 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "esp_err.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "esp_check.h"
|
||||||
|
#include "driver/i2c.h"
|
||||||
|
#include "esp_lcd_panel_io.h"
|
||||||
|
#include "esp_lcd_panel_ops.h"
|
||||||
|
#include "esp_lcd_panel_rgb.h"
|
||||||
|
#include "esp_lvgl_port.h"
|
||||||
|
#include "lv_demos.h"
|
||||||
|
|
||||||
|
#include "esp_lcd_touch_gt1151.h"
|
||||||
|
|
||||||
|
/* LCD size */
|
||||||
|
#define EXAMPLE_LCD_H_RES (800)
|
||||||
|
#define EXAMPLE_LCD_V_RES (480)
|
||||||
|
|
||||||
|
/* LCD settings */
|
||||||
|
#define EXAMPLE_LCD_LVGL_FULL_REFRESH (0)
|
||||||
|
#define EXAMPLE_LCD_LVGL_DIRECT_MODE (1)
|
||||||
|
#define EXAMPLE_LCD_LVGL_AVOID_TEAR (1)
|
||||||
|
#define EXAMPLE_LCD_RGB_BOUNCE_BUFFER_MODE (1)
|
||||||
|
#define EXAMPLE_LCD_DRAW_BUFF_DOUBLE (0)
|
||||||
|
#define EXAMPLE_LCD_DRAW_BUFF_HEIGHT (100)
|
||||||
|
#define EXAMPLE_LCD_RGB_BUFFER_NUMS (2)
|
||||||
|
#define EXAMPLE_LCD_RGB_BOUNCE_BUFFER_HEIGHT (10)
|
||||||
|
|
||||||
|
/* LCD pins */
|
||||||
|
#define EXAMPLE_LCD_GPIO_VSYNC (GPIO_NUM_3)
|
||||||
|
#define EXAMPLE_LCD_GPIO_HSYNC (GPIO_NUM_46)
|
||||||
|
#define EXAMPLE_LCD_GPIO_DE (GPIO_NUM_17)
|
||||||
|
#define EXAMPLE_LCD_GPIO_PCLK (GPIO_NUM_9)
|
||||||
|
#define EXAMPLE_LCD_GPIO_DISP (GPIO_NUM_NC)
|
||||||
|
#define EXAMPLE_LCD_GPIO_DATA0 (GPIO_NUM_10)
|
||||||
|
#define EXAMPLE_LCD_GPIO_DATA1 (GPIO_NUM_11)
|
||||||
|
#define EXAMPLE_LCD_GPIO_DATA2 (GPIO_NUM_12)
|
||||||
|
#define EXAMPLE_LCD_GPIO_DATA3 (GPIO_NUM_13)
|
||||||
|
#define EXAMPLE_LCD_GPIO_DATA4 (GPIO_NUM_14)
|
||||||
|
#define EXAMPLE_LCD_GPIO_DATA5 (GPIO_NUM_21)
|
||||||
|
#define EXAMPLE_LCD_GPIO_DATA6 (GPIO_NUM_47)
|
||||||
|
#define EXAMPLE_LCD_GPIO_DATA7 (GPIO_NUM_48)
|
||||||
|
#define EXAMPLE_LCD_GPIO_DATA8 (GPIO_NUM_45)
|
||||||
|
#define EXAMPLE_LCD_GPIO_DATA9 (GPIO_NUM_38)
|
||||||
|
#define EXAMPLE_LCD_GPIO_DATA10 (GPIO_NUM_39)
|
||||||
|
#define EXAMPLE_LCD_GPIO_DATA11 (GPIO_NUM_40)
|
||||||
|
#define EXAMPLE_LCD_GPIO_DATA12 (GPIO_NUM_41)
|
||||||
|
#define EXAMPLE_LCD_GPIO_DATA13 (GPIO_NUM_42)
|
||||||
|
#define EXAMPLE_LCD_GPIO_DATA14 (GPIO_NUM_2)
|
||||||
|
#define EXAMPLE_LCD_GPIO_DATA15 (GPIO_NUM_1)
|
||||||
|
|
||||||
|
/* Touch settings */
|
||||||
|
#define EXAMPLE_TOUCH_I2C_NUM (0)
|
||||||
|
#define EXAMPLE_TOUCH_I2C_CLK_HZ (400000)
|
||||||
|
|
||||||
|
/* LCD touch pins */
|
||||||
|
#define EXAMPLE_TOUCH_I2C_SCL (GPIO_NUM_18)
|
||||||
|
#define EXAMPLE_TOUCH_I2C_SDA (GPIO_NUM_8)
|
||||||
|
|
||||||
|
#define EXAMPLE_LCD_PANEL_35HZ_RGB_TIMING() \
|
||||||
|
{ \
|
||||||
|
.pclk_hz = 18 * 1000 * 1000, \
|
||||||
|
.h_res = EXAMPLE_LCD_H_RES, \
|
||||||
|
.v_res = EXAMPLE_LCD_V_RES, \
|
||||||
|
.hsync_pulse_width = 40, \
|
||||||
|
.hsync_back_porch = 40, \
|
||||||
|
.hsync_front_porch = 48, \
|
||||||
|
.vsync_pulse_width = 23, \
|
||||||
|
.vsync_back_porch = 32, \
|
||||||
|
.vsync_front_porch = 13, \
|
||||||
|
.flags.pclk_active_neg = true, \
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *TAG = "EXAMPLE";
|
||||||
|
|
||||||
|
// LVGL image declare
|
||||||
|
LV_IMG_DECLARE(esp_logo)
|
||||||
|
|
||||||
|
/* 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_display_t *lvgl_disp = NULL;
|
||||||
|
static lv_indev_t *lvgl_touch_indev = NULL;
|
||||||
|
|
||||||
|
static esp_err_t app_lcd_init(void)
|
||||||
|
{
|
||||||
|
esp_err_t ret = ESP_OK;
|
||||||
|
|
||||||
|
/* LCD initialization */
|
||||||
|
ESP_LOGI(TAG, "Initialize RGB panel");
|
||||||
|
esp_lcd_rgb_panel_config_t panel_conf = {
|
||||||
|
.clk_src = LCD_CLK_SRC_PLL160M,
|
||||||
|
.psram_trans_align = 64,
|
||||||
|
.data_width = 16,
|
||||||
|
.bits_per_pixel = 16,
|
||||||
|
.de_gpio_num = EXAMPLE_LCD_GPIO_DE,
|
||||||
|
.pclk_gpio_num = EXAMPLE_LCD_GPIO_PCLK,
|
||||||
|
.vsync_gpio_num = EXAMPLE_LCD_GPIO_VSYNC,
|
||||||
|
.hsync_gpio_num = EXAMPLE_LCD_GPIO_HSYNC,
|
||||||
|
.disp_gpio_num = EXAMPLE_LCD_GPIO_DISP,
|
||||||
|
.data_gpio_nums = {
|
||||||
|
EXAMPLE_LCD_GPIO_DATA0,
|
||||||
|
EXAMPLE_LCD_GPIO_DATA1,
|
||||||
|
EXAMPLE_LCD_GPIO_DATA2,
|
||||||
|
EXAMPLE_LCD_GPIO_DATA3,
|
||||||
|
EXAMPLE_LCD_GPIO_DATA4,
|
||||||
|
EXAMPLE_LCD_GPIO_DATA5,
|
||||||
|
EXAMPLE_LCD_GPIO_DATA6,
|
||||||
|
EXAMPLE_LCD_GPIO_DATA7,
|
||||||
|
EXAMPLE_LCD_GPIO_DATA8,
|
||||||
|
EXAMPLE_LCD_GPIO_DATA9,
|
||||||
|
EXAMPLE_LCD_GPIO_DATA10,
|
||||||
|
EXAMPLE_LCD_GPIO_DATA11,
|
||||||
|
EXAMPLE_LCD_GPIO_DATA12,
|
||||||
|
EXAMPLE_LCD_GPIO_DATA13,
|
||||||
|
EXAMPLE_LCD_GPIO_DATA14,
|
||||||
|
EXAMPLE_LCD_GPIO_DATA15,
|
||||||
|
},
|
||||||
|
.timings = EXAMPLE_LCD_PANEL_35HZ_RGB_TIMING(),
|
||||||
|
.flags.fb_in_psram = 1,
|
||||||
|
.num_fbs = EXAMPLE_LCD_RGB_BUFFER_NUMS,
|
||||||
|
#if EXAMPLE_LCD_RGB_BOUNCE_BUFFER_MODE
|
||||||
|
.bounce_buffer_size_px = EXAMPLE_LCD_H_RES * EXAMPLE_LCD_RGB_BOUNCE_BUFFER_HEIGHT,
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
ESP_GOTO_ON_ERROR(esp_lcd_new_rgb_panel(&panel_conf, &lcd_panel), err, TAG, "RGB init failed");
|
||||||
|
ESP_GOTO_ON_ERROR(esp_lcd_panel_init(lcd_panel), err, TAG, "LCD init failed");
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
err:
|
||||||
|
if (lcd_panel) {
|
||||||
|
esp_lcd_panel_del(lcd_panel);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t app_touch_init(void)
|
||||||
|
{
|
||||||
|
/* Initilize I2C */
|
||||||
|
const i2c_config_t i2c_conf = {
|
||||||
|
.mode = I2C_MODE_MASTER,
|
||||||
|
.sda_io_num = EXAMPLE_TOUCH_I2C_SDA,
|
||||||
|
.sda_pullup_en = GPIO_PULLUP_DISABLE,
|
||||||
|
.scl_io_num = EXAMPLE_TOUCH_I2C_SCL,
|
||||||
|
.scl_pullup_en = GPIO_PULLUP_DISABLE,
|
||||||
|
.master.clk_speed = EXAMPLE_TOUCH_I2C_CLK_HZ
|
||||||
|
};
|
||||||
|
ESP_RETURN_ON_ERROR(i2c_param_config(EXAMPLE_TOUCH_I2C_NUM, &i2c_conf), TAG, "I2C configuration failed");
|
||||||
|
ESP_RETURN_ON_ERROR(i2c_driver_install(EXAMPLE_TOUCH_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 = EXAMPLE_LCD_H_RES,
|
||||||
|
.y_max = EXAMPLE_LCD_V_RES,
|
||||||
|
.rst_gpio_num = GPIO_NUM_NC,
|
||||||
|
.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_GT1151_CONFIG();
|
||||||
|
ESP_RETURN_ON_ERROR(esp_lcd_new_panel_io_i2c((esp_lcd_i2c_bus_handle_t)EXAMPLE_TOUCH_I2C_NUM, &tp_io_config, &tp_io_handle), TAG, "");
|
||||||
|
return esp_lcd_touch_new_i2c_gt1151(tp_io_handle, &tp_cfg, &touch_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t app_lvgl_init(void)
|
||||||
|
{
|
||||||
|
/* Initialize LVGL */
|
||||||
|
const lvgl_port_cfg_t lvgl_cfg = {
|
||||||
|
.task_priority = 4, /* LVGL task priority */
|
||||||
|
.task_stack = 6144, /* LVGL task stack size */
|
||||||
|
.task_affinity = -1, /* LVGL task pinned to core (-1 is no affinity) */
|
||||||
|
.task_max_sleep_ms = 500, /* Maximum sleep in LVGL task */
|
||||||
|
.timer_period_ms = 5 /* LVGL timer tick period in ms */
|
||||||
|
};
|
||||||
|
ESP_RETURN_ON_ERROR(lvgl_port_init(&lvgl_cfg), TAG, "LVGL port initialization failed");
|
||||||
|
|
||||||
|
uint32_t buff_size = EXAMPLE_LCD_H_RES * EXAMPLE_LCD_DRAW_BUFF_HEIGHT;
|
||||||
|
#if EXAMPLE_LCD_LVGL_FULL_REFRESH || EXAMPLE_LCD_LVGL_DIRECT_MODE
|
||||||
|
buff_size = EXAMPLE_LCD_H_RES * EXAMPLE_LCD_V_RES;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Add LCD screen */
|
||||||
|
ESP_LOGD(TAG, "Add LCD screen");
|
||||||
|
const lvgl_port_display_cfg_t disp_cfg = {
|
||||||
|
.panel_handle = lcd_panel,
|
||||||
|
.buffer_size = buff_size,
|
||||||
|
.double_buffer = EXAMPLE_LCD_DRAW_BUFF_DOUBLE,
|
||||||
|
.hres = EXAMPLE_LCD_H_RES,
|
||||||
|
.vres = EXAMPLE_LCD_V_RES,
|
||||||
|
.monochrome = false,
|
||||||
|
#if LVGL_VERSION_MAJOR >= 9
|
||||||
|
.color_format = LV_COLOR_FORMAT_RGB565,
|
||||||
|
#endif
|
||||||
|
.rotation = {
|
||||||
|
.swap_xy = false,
|
||||||
|
.mirror_x = false,
|
||||||
|
.mirror_y = false,
|
||||||
|
},
|
||||||
|
.flags = {
|
||||||
|
.buff_dma = false,
|
||||||
|
.buff_spiram = false,
|
||||||
|
#if EXAMPLE_LCD_LVGL_FULL_REFRESH
|
||||||
|
.full_refresh = true,
|
||||||
|
#elif EXAMPLE_LCD_LVGL_DIRECT_MODE
|
||||||
|
.direct_mode = true,
|
||||||
|
#endif
|
||||||
|
#if LVGL_VERSION_MAJOR >= 9
|
||||||
|
.swap_bytes = false,
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const lvgl_port_display_rgb_cfg_t rgb_cfg = {
|
||||||
|
.flags = {
|
||||||
|
#if EXAMPLE_LCD_RGB_BOUNCE_BUFFER_MODE
|
||||||
|
.bb_mode = true,
|
||||||
|
#else
|
||||||
|
.bb_mode = false,
|
||||||
|
#endif
|
||||||
|
#if EXAMPLE_LCD_LVGL_AVOID_TEAR
|
||||||
|
.avoid_tearing = true,
|
||||||
|
#else
|
||||||
|
.avoid_tearing = false,
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
};
|
||||||
|
lvgl_disp = lvgl_port_add_disp_rgb(&disp_cfg, &rgb_cfg);
|
||||||
|
|
||||||
|
/* Add touch input (for selected screen) */
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _app_button_cb(lv_event_t *e)
|
||||||
|
{
|
||||||
|
lv_disp_rotation_t rotation = lv_disp_get_rotation(lvgl_disp);
|
||||||
|
rotation++;
|
||||||
|
if (rotation > LV_DISPLAY_ROTATION_270) {
|
||||||
|
rotation = LV_DISPLAY_ROTATION_0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* LCD HW rotation */
|
||||||
|
lv_disp_set_rotation(lvgl_disp, rotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void app_main_display(void)
|
||||||
|
{
|
||||||
|
lv_obj_t *scr = lv_scr_act();
|
||||||
|
|
||||||
|
/* Your LVGL objects code here .... */
|
||||||
|
|
||||||
|
/* Create image */
|
||||||
|
lv_obj_t *img_logo = lv_img_create(scr);
|
||||||
|
lv_img_set_src(img_logo, &esp_logo);
|
||||||
|
lv_obj_align(img_logo, LV_ALIGN_TOP_MID, 0, 20);
|
||||||
|
|
||||||
|
/* Label */
|
||||||
|
lv_obj_t *label = lv_label_create(scr);
|
||||||
|
lv_obj_set_width(label, EXAMPLE_LCD_H_RES);
|
||||||
|
lv_obj_set_style_text_align(label, LV_TEXT_ALIGN_CENTER, 0);
|
||||||
|
#if LVGL_VERSION_MAJOR == 8
|
||||||
|
lv_label_set_recolor(label, true);
|
||||||
|
lv_label_set_text(label, "#FF0000 "LV_SYMBOL_BELL" Hello world Espressif and LVGL "LV_SYMBOL_BELL"#\n#FF9400 "LV_SYMBOL_WARNING" For simplier initialization, use BSP "LV_SYMBOL_WARNING" #");
|
||||||
|
#else
|
||||||
|
lv_label_set_text(label, LV_SYMBOL_BELL" Hello world Espressif and LVGL "LV_SYMBOL_BELL"\n "LV_SYMBOL_WARNING" For simplier initialization, use BSP "LV_SYMBOL_WARNING);
|
||||||
|
#endif
|
||||||
|
lv_obj_align(label, LV_ALIGN_CENTER, 0, 20);
|
||||||
|
|
||||||
|
/* Button */
|
||||||
|
lv_obj_t *btn = lv_btn_create(scr);
|
||||||
|
label = lv_label_create(btn);
|
||||||
|
lv_label_set_text_static(label, "Rotate screen");
|
||||||
|
lv_obj_align(btn, LV_ALIGN_BOTTOM_MID, 0, -30);
|
||||||
|
lv_obj_add_event_cb(btn, _app_button_cb, LV_EVENT_CLICKED, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void app_main(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());
|
||||||
|
|
||||||
|
/* Show LVGL objects */
|
||||||
|
lvgl_port_lock(0);
|
||||||
|
//app_main_display();
|
||||||
|
lv_demo_music();
|
||||||
|
lvgl_port_unlock();
|
||||||
|
}
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
# Name, Type, SubType, Offset, Size, Flags
|
||||||
|
# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild
|
||||||
|
nvs, data, nvs, 0x9000, 0x6000,
|
||||||
|
phy_init, data, phy, 0xf000, 0x1000,
|
||||||
|
factory, app, factory, 0x10000, 2M,
|
||||||
|
@ -0,0 +1,40 @@
|
|||||||
|
CONFIG_IDF_TARGET="esp32s3"
|
||||||
|
CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
|
||||||
|
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
|
||||||
|
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||||
|
CONFIG_COMPILER_OPTIMIZATION_PERF=y
|
||||||
|
CONFIG_SPIRAM=y
|
||||||
|
CONFIG_SPIRAM_MODE_OCT=y
|
||||||
|
CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y
|
||||||
|
CONFIG_SPIRAM_RODATA=y
|
||||||
|
CONFIG_SPIRAM_SPEED_80M=y
|
||||||
|
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y
|
||||||
|
CONFIG_ESP32S3_DATA_CACHE_LINE_64B=y
|
||||||
|
CONFIG_FREERTOS_HZ=1000
|
||||||
|
CONFIG_LV_MEM_CUSTOM=y
|
||||||
|
CONFIG_LV_MEMCPY_MEMSET_STD=y
|
||||||
|
CONFIG_LV_ATTRIBUTE_FAST_MEM_USE_IRAM=y
|
||||||
|
CONFIG_LV_FONT_MONTSERRAT_12=y
|
||||||
|
CONFIG_LV_FONT_MONTSERRAT_16=y
|
||||||
|
CONFIG_LV_USE_DEMO_WIDGETS=y
|
||||||
|
CONFIG_LV_USE_DEMO_BENCHMARK=y
|
||||||
|
CONFIG_LV_USE_DEMO_STRESS=y
|
||||||
|
CONFIG_LV_USE_DEMO_MUSIC=y
|
||||||
|
CONFIG_LV_DEMO_MUSIC_AUTO_PLAY=y
|
||||||
|
|
||||||
|
## LVGL8 ##
|
||||||
|
CONFIG_LV_MEM_SIZE_KILOBYTES=48
|
||||||
|
CONFIG_LV_USE_PERF_MONITOR=y
|
||||||
|
|
||||||
|
## LVGL9 ##
|
||||||
|
CONFIG_LV_CONF_SKIP=y
|
||||||
|
|
||||||
|
#CLIB default
|
||||||
|
CONFIG_LV_USE_CLIB_MALLOC=y
|
||||||
|
CONFIG_LV_USE_CLIB_SPRINTF=y
|
||||||
|
CONFIG_LV_USE_CLIB_STRING=y
|
||||||
|
|
||||||
|
# Performance monitor
|
||||||
|
CONFIG_LV_USE_OBSERVER=y
|
||||||
|
CONFIG_LV_USE_SYSMON=y
|
||||||
|
CONFIG_LV_USE_PERF_MONITOR=y
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
# The following lines of boilerplate have to be in your project's CMakeLists
|
||||||
|
# in this exact order for cmake to work correctly
|
||||||
|
cmake_minimum_required(VERSION 3.16)
|
||||||
|
|
||||||
|
# "Trim" the build. Include the minimal set of components, main and anything it depends on.
|
||||||
|
set(COMPONENTS main)
|
||||||
|
|
||||||
|
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||||
|
project(touchscreen)
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
# ESP LVGL Touch Screen Example
|
||||||
|
|
||||||
|
Very simple example for demonstration of initialization and usage of the `esp_lvgl_port` component. This example contains four main parts:
|
||||||
|
|
||||||
|
## 1. LCD HW initialization - `app_lcd_init()`
|
||||||
|
|
||||||
|
Standard HW initialization of the LCD using [`esp_lcd`](https://github.com/espressif/esp-idf/tree/master/components/esp_lcd) component. Settings of this example are fully compatible with [ESP-BOX](https://github.com/espressif/esp-bsp/tree/master/esp-box) board.
|
||||||
|
|
||||||
|
## 2. Touch HW initialization - `app_touch_init()`
|
||||||
|
|
||||||
|
Standard HW initialization of the LCD touch using [`esp_lcd_touch`](https://github.com/espressif/esp-bsp/tree/master/components/lcd_touch/esp_lcd_touch) component. Settings of this example are fully compatible with [ESP-BOX](https://github.com/espressif/esp-bsp/tree/master/esp-box) board.
|
||||||
|
|
||||||
|
## 3. LVGL port initialization - `app_lvgl_init()`
|
||||||
|
|
||||||
|
Initialization of the LVGL port.
|
||||||
|
|
||||||
|
## 4. LVGL objects example usage - `app_main_display()`
|
||||||
|
|
||||||
|
Very simple demonstration code of using LVGL objects after LVGL port initialization.
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
idf_component_register(SRCS "main.c"
|
||||||
|
INCLUDE_DIRS ".")
|
||||||
|
|
||||||
|
lvgl_port_create_c_image("images/esp_logo.png" "images/" "ARGB8888" "NONE")
|
||||||
|
lvgl_port_add_images(${COMPONENT_LIB} "images/")
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
dependencies:
|
||||||
|
idf: ">=4.4"
|
||||||
|
esp_lcd_touch_tt21100:
|
||||||
|
version: "^1"
|
||||||
|
override_path: "../../../../lcd_touch/esp_lcd_touch_tt21100/"
|
||||||
|
esp_lvgl_port:
|
||||||
|
version: "*"
|
||||||
|
override_path: "../../../"
|
||||||
1
managed_components/espressif__esp_lvgl_port/examples/touchscreen/main/images/.gitignore
vendored
Normal file
1
managed_components/espressif__esp_lvgl_port/examples/touchscreen/main/images/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
*.c
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 6.5 KiB |
@ -0,0 +1,277 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "esp_err.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "esp_check.h"
|
||||||
|
#include "driver/i2c.h"
|
||||||
|
#include "driver/gpio.h"
|
||||||
|
#include "driver/spi_master.h"
|
||||||
|
#include "esp_lcd_panel_io.h"
|
||||||
|
#include "esp_lcd_panel_vendor.h"
|
||||||
|
#include "esp_lcd_panel_ops.h"
|
||||||
|
#include "esp_lvgl_port.h"
|
||||||
|
|
||||||
|
#include "esp_lcd_touch_tt21100.h"
|
||||||
|
|
||||||
|
/* LCD size */
|
||||||
|
#define EXAMPLE_LCD_H_RES (320)
|
||||||
|
#define EXAMPLE_LCD_V_RES (240)
|
||||||
|
|
||||||
|
/* LCD settings */
|
||||||
|
#define EXAMPLE_LCD_SPI_NUM (SPI3_HOST)
|
||||||
|
#define EXAMPLE_LCD_PIXEL_CLK_HZ (40 * 1000 * 1000)
|
||||||
|
#define EXAMPLE_LCD_CMD_BITS (8)
|
||||||
|
#define EXAMPLE_LCD_PARAM_BITS (8)
|
||||||
|
#define EXAMPLE_LCD_COLOR_SPACE (ESP_LCD_COLOR_SPACE_BGR)
|
||||||
|
#define EXAMPLE_LCD_BITS_PER_PIXEL (16)
|
||||||
|
#define EXAMPLE_LCD_DRAW_BUFF_DOUBLE (1)
|
||||||
|
#define EXAMPLE_LCD_DRAW_BUFF_HEIGHT (50)
|
||||||
|
#define EXAMPLE_LCD_BL_ON_LEVEL (1)
|
||||||
|
|
||||||
|
/* LCD pins */
|
||||||
|
#define EXAMPLE_LCD_GPIO_SCLK (GPIO_NUM_7)
|
||||||
|
#define EXAMPLE_LCD_GPIO_MOSI (GPIO_NUM_6)
|
||||||
|
#define EXAMPLE_LCD_GPIO_RST (GPIO_NUM_48)
|
||||||
|
#define EXAMPLE_LCD_GPIO_DC (GPIO_NUM_4)
|
||||||
|
#define EXAMPLE_LCD_GPIO_CS (GPIO_NUM_5)
|
||||||
|
#define EXAMPLE_LCD_GPIO_BL (GPIO_NUM_45)
|
||||||
|
|
||||||
|
/* Touch settings */
|
||||||
|
#define EXAMPLE_TOUCH_I2C_NUM (0)
|
||||||
|
#define EXAMPLE_TOUCH_I2C_CLK_HZ (400000)
|
||||||
|
|
||||||
|
/* LCD touch pins */
|
||||||
|
#define EXAMPLE_TOUCH_I2C_SCL (GPIO_NUM_18)
|
||||||
|
#define EXAMPLE_TOUCH_I2C_SDA (GPIO_NUM_8)
|
||||||
|
#define EXAMPLE_TOUCH_GPIO_INT (GPIO_NUM_3)
|
||||||
|
|
||||||
|
static const char *TAG = "EXAMPLE";
|
||||||
|
|
||||||
|
// LVGL image declare
|
||||||
|
LV_IMG_DECLARE(esp_logo)
|
||||||
|
|
||||||
|
/* LCD IO and panel */
|
||||||
|
static esp_lcd_panel_io_handle_t lcd_io = NULL;
|
||||||
|
static esp_lcd_panel_handle_t lcd_panel = NULL;
|
||||||
|
static esp_lcd_touch_handle_t touch_handle = NULL;
|
||||||
|
|
||||||
|
/* LVGL display and touch */
|
||||||
|
static lv_display_t *lvgl_disp = NULL;
|
||||||
|
static lv_indev_t *lvgl_touch_indev = NULL;
|
||||||
|
|
||||||
|
static esp_err_t app_lcd_init(void)
|
||||||
|
{
|
||||||
|
esp_err_t ret = ESP_OK;
|
||||||
|
|
||||||
|
/* LCD backlight */
|
||||||
|
gpio_config_t bk_gpio_config = {
|
||||||
|
.mode = GPIO_MODE_OUTPUT,
|
||||||
|
.pin_bit_mask = 1ULL << EXAMPLE_LCD_GPIO_BL
|
||||||
|
};
|
||||||
|
ESP_ERROR_CHECK(gpio_config(&bk_gpio_config));
|
||||||
|
|
||||||
|
/* LCD initialization */
|
||||||
|
ESP_LOGD(TAG, "Initialize SPI bus");
|
||||||
|
const spi_bus_config_t buscfg = {
|
||||||
|
.sclk_io_num = EXAMPLE_LCD_GPIO_SCLK,
|
||||||
|
.mosi_io_num = EXAMPLE_LCD_GPIO_MOSI,
|
||||||
|
.miso_io_num = GPIO_NUM_NC,
|
||||||
|
.quadwp_io_num = GPIO_NUM_NC,
|
||||||
|
.quadhd_io_num = GPIO_NUM_NC,
|
||||||
|
.max_transfer_sz = EXAMPLE_LCD_H_RES * EXAMPLE_LCD_DRAW_BUFF_HEIGHT * sizeof(uint16_t),
|
||||||
|
};
|
||||||
|
ESP_RETURN_ON_ERROR(spi_bus_initialize(EXAMPLE_LCD_SPI_NUM, &buscfg, SPI_DMA_CH_AUTO), TAG, "SPI init failed");
|
||||||
|
|
||||||
|
ESP_LOGD(TAG, "Install panel IO");
|
||||||
|
const esp_lcd_panel_io_spi_config_t io_config = {
|
||||||
|
.dc_gpio_num = EXAMPLE_LCD_GPIO_DC,
|
||||||
|
.cs_gpio_num = EXAMPLE_LCD_GPIO_CS,
|
||||||
|
.pclk_hz = EXAMPLE_LCD_PIXEL_CLK_HZ,
|
||||||
|
.lcd_cmd_bits = EXAMPLE_LCD_CMD_BITS,
|
||||||
|
.lcd_param_bits = EXAMPLE_LCD_PARAM_BITS,
|
||||||
|
.spi_mode = 0,
|
||||||
|
.trans_queue_depth = 10,
|
||||||
|
};
|
||||||
|
ESP_GOTO_ON_ERROR(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)EXAMPLE_LCD_SPI_NUM, &io_config, &lcd_io), err, TAG, "New panel IO failed");
|
||||||
|
|
||||||
|
ESP_LOGD(TAG, "Install LCD driver");
|
||||||
|
const esp_lcd_panel_dev_config_t panel_config = {
|
||||||
|
.reset_gpio_num = EXAMPLE_LCD_GPIO_RST,
|
||||||
|
.color_space = EXAMPLE_LCD_COLOR_SPACE,
|
||||||
|
.bits_per_pixel = EXAMPLE_LCD_BITS_PER_PIXEL,
|
||||||
|
};
|
||||||
|
ESP_GOTO_ON_ERROR(esp_lcd_new_panel_st7789(lcd_io, &panel_config, &lcd_panel), err, TAG, "New panel failed");
|
||||||
|
|
||||||
|
esp_lcd_panel_reset(lcd_panel);
|
||||||
|
esp_lcd_panel_init(lcd_panel);
|
||||||
|
esp_lcd_panel_mirror(lcd_panel, true, true);
|
||||||
|
esp_lcd_panel_disp_on_off(lcd_panel, true);
|
||||||
|
|
||||||
|
/* LCD backlight on */
|
||||||
|
ESP_ERROR_CHECK(gpio_set_level(EXAMPLE_LCD_GPIO_BL, EXAMPLE_LCD_BL_ON_LEVEL));
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
err:
|
||||||
|
if (lcd_panel) {
|
||||||
|
esp_lcd_panel_del(lcd_panel);
|
||||||
|
}
|
||||||
|
if (lcd_io) {
|
||||||
|
esp_lcd_panel_io_del(lcd_io);
|
||||||
|
}
|
||||||
|
spi_bus_free(EXAMPLE_LCD_SPI_NUM);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t app_touch_init(void)
|
||||||
|
{
|
||||||
|
/* Initilize I2C */
|
||||||
|
const i2c_config_t i2c_conf = {
|
||||||
|
.mode = I2C_MODE_MASTER,
|
||||||
|
.sda_io_num = EXAMPLE_TOUCH_I2C_SDA,
|
||||||
|
.sda_pullup_en = GPIO_PULLUP_DISABLE,
|
||||||
|
.scl_io_num = EXAMPLE_TOUCH_I2C_SCL,
|
||||||
|
.scl_pullup_en = GPIO_PULLUP_DISABLE,
|
||||||
|
.master.clk_speed = EXAMPLE_TOUCH_I2C_CLK_HZ
|
||||||
|
};
|
||||||
|
ESP_RETURN_ON_ERROR(i2c_param_config(EXAMPLE_TOUCH_I2C_NUM, &i2c_conf), TAG, "I2C configuration failed");
|
||||||
|
ESP_RETURN_ON_ERROR(i2c_driver_install(EXAMPLE_TOUCH_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 = EXAMPLE_LCD_H_RES,
|
||||||
|
.y_max = EXAMPLE_LCD_V_RES,
|
||||||
|
.rst_gpio_num = GPIO_NUM_NC, // Shared with LCD reset
|
||||||
|
.int_gpio_num = EXAMPLE_TOUCH_GPIO_INT,
|
||||||
|
.levels = {
|
||||||
|
.reset = 0,
|
||||||
|
.interrupt = 0,
|
||||||
|
},
|
||||||
|
.flags = {
|
||||||
|
.swap_xy = 0,
|
||||||
|
.mirror_x = 1,
|
||||||
|
.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_TT21100_CONFIG();
|
||||||
|
ESP_RETURN_ON_ERROR(esp_lcd_new_panel_io_i2c((esp_lcd_i2c_bus_handle_t)EXAMPLE_TOUCH_I2C_NUM, &tp_io_config, &tp_io_handle), TAG, "");
|
||||||
|
return esp_lcd_touch_new_i2c_tt21100(tp_io_handle, &tp_cfg, &touch_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t app_lvgl_init(void)
|
||||||
|
{
|
||||||
|
/* Initialize LVGL */
|
||||||
|
const lvgl_port_cfg_t lvgl_cfg = {
|
||||||
|
.task_priority = 4, /* LVGL task priority */
|
||||||
|
.task_stack = 4096, /* LVGL task stack size */
|
||||||
|
.task_affinity = -1, /* LVGL task pinned to core (-1 is no affinity) */
|
||||||
|
.task_max_sleep_ms = 500, /* Maximum sleep in LVGL task */
|
||||||
|
.timer_period_ms = 5 /* LVGL timer tick period in ms */
|
||||||
|
};
|
||||||
|
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 = {
|
||||||
|
.io_handle = lcd_io,
|
||||||
|
.panel_handle = lcd_panel,
|
||||||
|
.buffer_size = EXAMPLE_LCD_H_RES * EXAMPLE_LCD_DRAW_BUFF_HEIGHT,
|
||||||
|
.double_buffer = EXAMPLE_LCD_DRAW_BUFF_DOUBLE,
|
||||||
|
.hres = EXAMPLE_LCD_H_RES,
|
||||||
|
.vres = EXAMPLE_LCD_V_RES,
|
||||||
|
.monochrome = false,
|
||||||
|
#if LVGL_VERSION_MAJOR >= 9
|
||||||
|
.color_format = LV_COLOR_FORMAT_RGB565,
|
||||||
|
#endif
|
||||||
|
.rotation = {
|
||||||
|
.swap_xy = false,
|
||||||
|
.mirror_x = true,
|
||||||
|
.mirror_y = true,
|
||||||
|
},
|
||||||
|
.flags = {
|
||||||
|
.buff_dma = true,
|
||||||
|
#if LVGL_VERSION_MAJOR >= 9
|
||||||
|
.swap_bytes = true,
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
};
|
||||||
|
lvgl_disp = lvgl_port_add_disp(&disp_cfg);
|
||||||
|
|
||||||
|
/* Add touch input (for selected screen) */
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _app_button_cb(lv_event_t *e)
|
||||||
|
{
|
||||||
|
lv_disp_rotation_t rotation = lv_disp_get_rotation(lvgl_disp);
|
||||||
|
rotation++;
|
||||||
|
if (rotation > LV_DISPLAY_ROTATION_270) {
|
||||||
|
rotation = LV_DISPLAY_ROTATION_0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* LCD HW rotation */
|
||||||
|
lv_disp_set_rotation(lvgl_disp, rotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void app_main_display(void)
|
||||||
|
{
|
||||||
|
lv_obj_t *scr = lv_scr_act();
|
||||||
|
|
||||||
|
/* Task lock */
|
||||||
|
lvgl_port_lock(0);
|
||||||
|
|
||||||
|
/* Your LVGL objects code here .... */
|
||||||
|
|
||||||
|
/* Create image */
|
||||||
|
lv_obj_t *img_logo = lv_img_create(scr);
|
||||||
|
lv_img_set_src(img_logo, &esp_logo);
|
||||||
|
lv_obj_align(img_logo, LV_ALIGN_TOP_MID, 0, 20);
|
||||||
|
|
||||||
|
/* Label */
|
||||||
|
lv_obj_t *label = lv_label_create(scr);
|
||||||
|
lv_obj_set_width(label, EXAMPLE_LCD_H_RES);
|
||||||
|
lv_obj_set_style_text_align(label, LV_TEXT_ALIGN_CENTER, 0);
|
||||||
|
#if LVGL_VERSION_MAJOR == 8
|
||||||
|
lv_label_set_recolor(label, true);
|
||||||
|
lv_label_set_text(label, "#FF0000 "LV_SYMBOL_BELL" Hello world Espressif and LVGL "LV_SYMBOL_BELL"#\n#FF9400 "LV_SYMBOL_WARNING" For simplier initialization, use BSP "LV_SYMBOL_WARNING" #");
|
||||||
|
#else
|
||||||
|
lv_label_set_text(label, LV_SYMBOL_BELL" Hello world Espressif and LVGL "LV_SYMBOL_BELL"\n "LV_SYMBOL_WARNING" For simplier initialization, use BSP "LV_SYMBOL_WARNING);
|
||||||
|
#endif
|
||||||
|
lv_obj_align(label, LV_ALIGN_CENTER, 0, 20);
|
||||||
|
|
||||||
|
/* Button */
|
||||||
|
lv_obj_t *btn = lv_btn_create(scr);
|
||||||
|
label = lv_label_create(btn);
|
||||||
|
lv_label_set_text_static(label, "Rotate screen");
|
||||||
|
lv_obj_align(btn, LV_ALIGN_BOTTOM_MID, 0, -30);
|
||||||
|
lv_obj_add_event_cb(btn, _app_button_cb, LV_EVENT_CLICKED, NULL);
|
||||||
|
|
||||||
|
/* Task unlock */
|
||||||
|
lvgl_port_unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void app_main(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());
|
||||||
|
|
||||||
|
/* Show LVGL objects */
|
||||||
|
app_main_display();
|
||||||
|
}
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
CONFIG_IDF_TARGET="esp32s3"
|
||||||
|
CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
|
||||||
|
CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y
|
||||||
|
CONFIG_LV_COLOR_16_SWAP=y
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
dependencies:
|
||||||
|
idf: '>=4.4'
|
||||||
|
lvgl/lvgl:
|
||||||
|
public: true
|
||||||
|
version: '>=8,<10'
|
||||||
|
description: ESP LVGL port
|
||||||
|
repository: git://github.com/espressif/esp-bsp.git
|
||||||
|
repository_info:
|
||||||
|
commit_sha: 8df198d8e2e5a44b4a1f3ef54afb7b029c2c5215
|
||||||
|
path: components/esp_lvgl_port
|
||||||
|
url: https://github.com/espressif/esp-bsp/tree/master/components/esp_lvgl_port
|
||||||
|
version: 2.5.0
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.6 KiB |
@ -0,0 +1,132 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef __has_include
|
||||||
|
#if __has_include("lvgl.h")
|
||||||
|
#ifndef LV_LVGL_H_INCLUDE_SIMPLE
|
||||||
|
#define LV_LVGL_H_INCLUDE_SIMPLE
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(LV_LVGL_H_INCLUDE_SIMPLE)
|
||||||
|
#include "lvgl.h"
|
||||||
|
#else
|
||||||
|
#include "lvgl/lvgl.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef LV_ATTRIBUTE_MEM_ALIGN
|
||||||
|
#define LV_ATTRIBUTE_MEM_ALIGN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef LV_ATTRIBUTE_IMG_IMG_CURSOR
|
||||||
|
#define LV_ATTRIBUTE_IMG_IMG_CURSOR
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_IMG_CURSOR uint8_t img_cursor_map[] = {
|
||||||
|
#if LV_COLOR_DEPTH == 1 || LV_COLOR_DEPTH == 8
|
||||||
|
/*Pixel format: Alpha 8 bit, Red: 3 bit, Green: 3 bit, Blue: 2 bit*/
|
||||||
|
0x00, 0xb2, 0x00, 0xcc, 0x00, 0x71, 0x00, 0x3a, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0xcc, 0x00, 0xff, 0x00, 0xfc, 0x00, 0xe4, 0x00, 0xae, 0x00, 0x6b, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x71, 0x00, 0xfc, 0x6d, 0xf1, 0xb6, 0xfc, 0x49, 0xf9, 0x24, 0xfe, 0x00, 0xf4, 0x00, 0xb9, 0x00, 0x5c, 0x00, 0x2e, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x3a, 0x00, 0xe4, 0xb6, 0xfc, 0xff, 0xff, 0xff, 0xf9, 0xdb, 0xfe, 0x6e, 0xf3, 0x25, 0xfe, 0x00, 0xf8, 0x00, 0xd8, 0x00, 0x9c, 0x00, 0x51, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x0c, 0x00, 0xae, 0x49, 0xf9, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfa, 0xb7, 0xf0, 0x6e, 0xfb, 0x25, 0xf9, 0x00, 0xff, 0x00, 0xe8, 0x00, 0x9e, 0x00, 0x4a, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x6b, 0x24, 0xfe, 0xdb, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xf9, 0xb7, 0xf6, 0x49, 0xf5, 0x24, 0xff, 0x00, 0xf0, 0x00, 0xcb, 0x00, 0x88, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x13, 0x00, 0xf4, 0x6e, 0xf3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf5, 0x92, 0xf5, 0x24, 0xfd, 0x00, 0xff, 0x00, 0xed, 0x00, 0x02, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0xb9, 0x25, 0xfe, 0xff, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf4, 0x92, 0xfc, 0x24, 0xfd, 0x00, 0xe7, 0x00, 0x78, 0x00, 0x01, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x00, 0xf8, 0xb7, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdb, 0xf9, 0x25, 0xfd, 0x00, 0xee, 0x00, 0x9d, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x00, 0xd7, 0x6e, 0xfb, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdb, 0xf9, 0x25, 0xfd, 0x00, 0xdd, 0x00, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x9c, 0x25, 0xf9, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdb, 0xfa, 0x25, 0xfc, 0x00, 0xdd, 0x00, 0x2c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0x00, 0xff, 0xb7, 0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdb, 0xfa, 0x25, 0xfc, 0x00, 0xc2, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0xe8, 0x49, 0xf5, 0xff, 0xff, 0xff, 0xff, 0xdb, 0xf9, 0xdb, 0xf9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdb, 0xfa, 0x25, 0xfd, 0x00, 0xdd, 0x00, 0x2c, 0x00, 0x01,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x24, 0xff, 0xff, 0xf5, 0xff, 0xf4, 0x25, 0xfd, 0x25, 0xfd, 0xdb, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdb, 0xfa, 0x25, 0xfc, 0x00, 0xc2, 0x00, 0x2c,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x00, 0xf0, 0x92, 0xf5, 0x92, 0xfc, 0x00, 0xee, 0x00, 0xdd, 0x25, 0xfc, 0xdb, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdb, 0xef, 0x00, 0xff, 0x00, 0xd7,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0xcb, 0x24, 0xfd, 0x24, 0xfd, 0x00, 0x9d, 0x00, 0x37, 0x00, 0xdd, 0x25, 0xfd, 0xdb, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x92, 0xf2, 0x00, 0xff, 0x00, 0xb6,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x88, 0x00, 0xff, 0x00, 0xe7, 0x00, 0x18, 0x00, 0x00, 0x00, 0x2c, 0x00, 0xc2, 0x25, 0xfc, 0xdb, 0xfa, 0xff, 0xff, 0xff, 0xfc, 0x92, 0xf8, 0x00, 0xfe, 0x00, 0x9d, 0x00, 0x16,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x00, 0xed, 0x00, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x2c, 0x00, 0xdd, 0x25, 0xfc, 0xdb, 0xef, 0x92, 0xf2, 0x00, 0xfe, 0x00, 0xb9, 0x00, 0x16, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0xc2, 0x00, 0xff, 0x00, 0xff, 0x00, 0x9d, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x2c, 0x00, 0xd7, 0x00, 0xb6, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
#endif
|
||||||
|
#if LV_COLOR_DEPTH == 16 && LV_COLOR_16_SWAP == 0
|
||||||
|
/*Pixel format: Alpha 8 bit, Red: 5 bit, Green: 6 bit, Blue: 5 bit*/
|
||||||
|
0x00, 0x00, 0xb2, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x71, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0xcc, 0x00, 0x00, 0xff, 0x00, 0x00, 0xfc, 0x00, 0x00, 0xe4, 0x00, 0x00, 0xae, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x71, 0x00, 0x00, 0xfc, 0xeb, 0x5a, 0xf1, 0xb2, 0x94, 0xfc, 0x08, 0x42, 0xf9, 0x04, 0x21, 0xfe, 0x41, 0x08, 0xf4, 0x00, 0x00, 0xb9, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x3a, 0x00, 0x00, 0xe4, 0xb2, 0x94, 0xfc, 0xff, 0xff, 0xff, 0x3c, 0xe7, 0xf9, 0x59, 0xce, 0xfe, 0x6e, 0x73, 0xf3, 0x04, 0x21, 0xfe, 0x00, 0x00, 0xf8, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x51, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x0c, 0x00, 0x00, 0xae, 0x08, 0x42, 0xf9, 0x3c, 0xe7, 0xf9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfa, 0x76, 0xb5, 0xf0, 0x8e, 0x73, 0xfb, 0x45, 0x29, 0xf9, 0x82, 0x10, 0xff, 0x00, 0x00, 0xe8, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x21, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x6b, 0x04, 0x21, 0xfe, 0x59, 0xce, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xbb, 0xde, 0xf9, 0x96, 0xb5, 0xf6, 0x49, 0x4a, 0xf5, 0x04, 0x21, 0xff, 0x00, 0x00, 0xf0, 0x00, 0x00, 0xcb, 0x00, 0x00, 0x88, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x41, 0x08, 0xf4, 0x6e, 0x73, 0xf3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbe, 0xf7, 0xf5, 0x10, 0x84, 0xf5, 0xa2, 0x10, 0xfd, 0x00, 0x00, 0xff, 0x00, 0x00, 0xed, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb9, 0x04, 0x21, 0xfe, 0xff, 0xff, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9e, 0xf7, 0xf4, 0xae, 0x73, 0xfc, 0xa2, 0x10, 0xfd, 0x00, 0x00, 0xe7, 0x00, 0x00, 0x78, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0xf8, 0x76, 0xb5, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x59, 0xce, 0xf9, 0x86, 0x31, 0xfd, 0x00, 0x00, 0xee, 0x00, 0x00, 0x9d, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0xd7, 0x8e, 0x73, 0xfb, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x59, 0xce, 0xf9, 0x86, 0x31, 0xfd, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x9c, 0x45, 0x29, 0xf9, 0xbb, 0xde, 0xf9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x79, 0xce, 0xfa, 0x65, 0x29, 0xfc, 0x20, 0x00, 0xdd, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0x82, 0x10, 0xff, 0x96, 0xb5, 0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x96, 0xb5, 0xfa, 0x65, 0x29, 0xfc, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0xe8, 0x49, 0x4a, 0xf5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x59, 0xce, 0xf9, 0x59, 0xce, 0xf9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x79, 0xce, 0xfa, 0x65, 0x29, 0xfd, 0x20, 0x00, 0xdd, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x01,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x04, 0x21, 0xff, 0xbe, 0xf7, 0xf5, 0x9e, 0xf7, 0xf4, 0x86, 0x31, 0xfd, 0x86, 0x31, 0xfd, 0x79, 0xce, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x96, 0xb5, 0xfa, 0x65, 0x29, 0xfc, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x2c,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0xf0, 0x10, 0x84, 0xf5, 0xae, 0x73, 0xfc, 0x00, 0x00, 0xee, 0x00, 0x00, 0xdd, 0x65, 0x29, 0xfc, 0x96, 0xb5, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x96, 0xb5, 0xef, 0x00, 0x00, 0xff, 0x00, 0x00, 0xd7,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0xcb, 0xa2, 0x10, 0xfd, 0xa2, 0x10, 0xfd, 0x00, 0x00, 0x9d, 0x00, 0x00, 0x37, 0x20, 0x00, 0xdd, 0x65, 0x29, 0xfd, 0x79, 0xce, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x51, 0x8c, 0xf2, 0x00, 0x00, 0xff, 0x00, 0x00, 0xb6,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x88, 0x00, 0x00, 0xff, 0x00, 0x00, 0xe7, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0xc2, 0x65, 0x29, 0xfc, 0x96, 0xb5, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xaf, 0x7b, 0xf8, 0x41, 0x08, 0xfe, 0x00, 0x00, 0x9d, 0x00, 0x00, 0x16,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0xed, 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x2c, 0x20, 0x00, 0xdd, 0x65, 0x29, 0xfc, 0x96, 0xb5, 0xef, 0x51, 0x8c, 0xf2, 0x41, 0x08, 0xfe, 0x00, 0x00, 0xb9, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0xc2, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x9d, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x2c, 0x00, 0x00, 0xd7, 0x00, 0x00, 0xb6, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
#endif
|
||||||
|
#if LV_COLOR_DEPTH == 16 && LV_COLOR_16_SWAP != 0
|
||||||
|
/*Pixel format: Alpha 8 bit, Red: 5 bit, Green: 6 bit, Blue: 5 bit BUT the 2 color bytes are swapped*/
|
||||||
|
0x00, 0x00, 0xb2, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x71, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0xcc, 0x00, 0x00, 0xff, 0x00, 0x00, 0xfc, 0x00, 0x00, 0xe4, 0x00, 0x00, 0xae, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x71, 0x00, 0x00, 0xfc, 0x5a, 0xeb, 0xf1, 0x94, 0xb2, 0xfc, 0x42, 0x08, 0xf9, 0x21, 0x04, 0xfe, 0x08, 0x41, 0xf4, 0x00, 0x00, 0xb9, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x3a, 0x00, 0x00, 0xe4, 0x94, 0xb2, 0xfc, 0xff, 0xff, 0xff, 0xe7, 0x3c, 0xf9, 0xce, 0x59, 0xfe, 0x73, 0x6e, 0xf3, 0x21, 0x04, 0xfe, 0x00, 0x00, 0xf8, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x51, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x0c, 0x00, 0x00, 0xae, 0x42, 0x08, 0xf9, 0xe7, 0x3c, 0xf9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfa, 0xb5, 0x76, 0xf0, 0x73, 0x8e, 0xfb, 0x29, 0x45, 0xf9, 0x10, 0x82, 0xff, 0x00, 0x00, 0xe8, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x21, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x6b, 0x21, 0x04, 0xfe, 0xce, 0x59, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xde, 0xbb, 0xf9, 0xb5, 0x96, 0xf6, 0x4a, 0x49, 0xf5, 0x21, 0x04, 0xff, 0x00, 0x00, 0xf0, 0x00, 0x00, 0xcb, 0x00, 0x00, 0x88, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x08, 0x41, 0xf4, 0x73, 0x6e, 0xf3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xbe, 0xf5, 0x84, 0x10, 0xf5, 0x10, 0xa2, 0xfd, 0x00, 0x00, 0xff, 0x00, 0x00, 0xed, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb9, 0x21, 0x04, 0xfe, 0xff, 0xff, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0x9e, 0xf4, 0x73, 0xae, 0xfc, 0x10, 0xa2, 0xfd, 0x00, 0x00, 0xe7, 0x00, 0x00, 0x78, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0xf8, 0xb5, 0x76, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0x59, 0xf9, 0x31, 0x86, 0xfd, 0x00, 0x00, 0xee, 0x00, 0x00, 0x9d, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0xd7, 0x73, 0x8e, 0xfb, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0x59, 0xf9, 0x31, 0x86, 0xfd, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x9c, 0x29, 0x45, 0xf9, 0xde, 0xbb, 0xf9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0x79, 0xfa, 0x29, 0x65, 0xfc, 0x00, 0x20, 0xdd, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0x10, 0x82, 0xff, 0xb5, 0x96, 0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb5, 0x96, 0xfa, 0x29, 0x65, 0xfc, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0xe8, 0x4a, 0x49, 0xf5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0x59, 0xf9, 0xce, 0x59, 0xf9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0x79, 0xfa, 0x29, 0x65, 0xfd, 0x00, 0x20, 0xdd, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x01,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x21, 0x04, 0xff, 0xf7, 0xbe, 0xf5, 0xf7, 0x9e, 0xf4, 0x31, 0x86, 0xfd, 0x31, 0x86, 0xfd, 0xce, 0x79, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb5, 0x96, 0xfa, 0x29, 0x65, 0xfc, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x2c,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0xf0, 0x84, 0x10, 0xf5, 0x73, 0xae, 0xfc, 0x00, 0x00, 0xee, 0x00, 0x00, 0xdd, 0x29, 0x65, 0xfc, 0xb5, 0x96, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb5, 0x96, 0xef, 0x00, 0x00, 0xff, 0x00, 0x00, 0xd7,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0xcb, 0x10, 0xa2, 0xfd, 0x10, 0xa2, 0xfd, 0x00, 0x00, 0x9d, 0x00, 0x00, 0x37, 0x00, 0x20, 0xdd, 0x29, 0x65, 0xfd, 0xce, 0x79, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x8c, 0x51, 0xf2, 0x00, 0x00, 0xff, 0x00, 0x00, 0xb6,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x88, 0x00, 0x00, 0xff, 0x00, 0x00, 0xe7, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0xc2, 0x29, 0x65, 0xfc, 0xb5, 0x96, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x7b, 0xaf, 0xf8, 0x08, 0x41, 0xfe, 0x00, 0x00, 0x9d, 0x00, 0x00, 0x16,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0xed, 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x2c, 0x00, 0x20, 0xdd, 0x29, 0x65, 0xfc, 0xb5, 0x96, 0xef, 0x8c, 0x51, 0xf2, 0x08, 0x41, 0xfe, 0x00, 0x00, 0xb9, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0xc2, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x9d, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x2c, 0x00, 0x00, 0xd7, 0x00, 0x00, 0xb6, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
#endif
|
||||||
|
#if LV_COLOR_DEPTH == 32
|
||||||
|
0x00, 0x00, 0x00, 0xb2, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0x00, 0xae, 0x00, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0xfc, 0x5b, 0x5b, 0x5b, 0xf1, 0x93, 0x93, 0x93, 0xfc, 0x41, 0x41, 0x41, 0xf9, 0x1e, 0x1e, 0x1e, 0xfe, 0x06, 0x06, 0x06, 0xf4, 0x00, 0x00, 0x00, 0xb9, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0xe4, 0x93, 0x93, 0x93, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xe3, 0xe3, 0xe3, 0xf9, 0xc8, 0xc8, 0xc8, 0xfe, 0x6c, 0x6c, 0x6c, 0xf3, 0x20, 0x20, 0x20, 0xfe, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0xae, 0x41, 0x41, 0x41, 0xf9, 0xe3, 0xe3, 0xe3, 0xf9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xfb, 0xfb, 0xfa, 0xac, 0xac, 0xac, 0xf0, 0x6f, 0x6f, 0x6f, 0xfb, 0x26, 0x26, 0x26, 0xf9, 0x0f, 0x0f, 0x0f, 0xff, 0x00, 0x00, 0x00, 0xe8, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6b, 0x1e, 0x1e, 0x1e, 0xfe, 0xc8, 0xc8, 0xc8, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xfc, 0xfc, 0xfb, 0xd4, 0xd4, 0xd4, 0xf9, 0xae, 0xae, 0xae, 0xf6, 0x48, 0x48, 0x48, 0xf5, 0x1f, 0x1f, 0x1f, 0xff, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0xcb, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x06, 0x06, 0x06, 0xf4, 0x6c, 0x6c, 0x6c, 0xf3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0xf3, 0xf3, 0xf5, 0x7e, 0x7e, 0x7e, 0xf5, 0x12, 0x12, 0x12, 0xfd, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xed, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb9, 0x20, 0x20, 0x20, 0xfe, 0xfb, 0xfb, 0xfb, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xef, 0xef, 0xf4, 0x73, 0x73, 0x73, 0xfc, 0x12, 0x12, 0x12, 0xfd, 0x00, 0x00, 0x00, 0xe7, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0xf8, 0xac, 0xac, 0xac, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc8, 0xc8, 0xc8, 0xf9, 0x2e, 0x2e, 0x2e, 0xfd, 0x00, 0x00, 0x00, 0xee, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0xd7, 0x6f, 0x6f, 0x6f, 0xfb, 0xfc, 0xfc, 0xfc, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc8, 0xc8, 0xc8, 0xf9, 0x2e, 0x2e, 0x2e, 0xfd, 0x00, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x9c, 0x26, 0x26, 0x26, 0xf9, 0xd4, 0xd4, 0xd4, 0xf9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xca, 0xca, 0xca, 0xfa, 0x2b, 0x2b, 0x2b, 0xfc, 0x03, 0x03, 0x03, 0xdd, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0x0f, 0x0f, 0x0f, 0xff, 0xae, 0xae, 0xae, 0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb0, 0xb0, 0xb0, 0xfa, 0x2b, 0x2b, 0x2b, 0xfc, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0xe8, 0x48, 0x48, 0x48, 0xf5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc8, 0xc8, 0xc8, 0xf9, 0xc8, 0xc8, 0xc8, 0xf9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xca, 0xca, 0xca, 0xfa, 0x2b, 0x2b, 0x2b, 0xfd, 0x03, 0x03, 0x03, 0xdd, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x01,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x1f, 0x1f, 0x1f, 0xff, 0xf3, 0xf3, 0xf3, 0xf5, 0xf0, 0xf0, 0xf0, 0xf4, 0x2e, 0x2e, 0x2e, 0xfd, 0x2e, 0x2e, 0x2e, 0xfd, 0xca, 0xca, 0xca, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb0, 0xb0, 0xb0, 0xfa, 0x2b, 0x2b, 0x2b, 0xfc, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, 0x2c,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0xf0, 0x7e, 0x7e, 0x7e, 0xf5, 0x73, 0x73, 0x73, 0xfc, 0x00, 0x00, 0x00, 0xee, 0x00, 0x00, 0x00, 0xdd, 0x2b, 0x2b, 0x2b, 0xfc, 0xb0, 0xb0, 0xb0, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb1, 0xb1, 0xb1, 0xef, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xd7,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0xcb, 0x12, 0x12, 0x12, 0xfd, 0x12, 0x12, 0x12, 0xfd, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x00, 0x00, 0x37, 0x03, 0x03, 0x03, 0xdd, 0x2b, 0x2b, 0x2b, 0xfd, 0xca, 0xca, 0xca, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xfc, 0xfc, 0xfc, 0x86, 0x86, 0x86, 0xf2, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xb6,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xe7, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0xc2, 0x2b, 0x2b, 0x2b, 0xfc, 0xb0, 0xb0, 0xb0, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xfc, 0xfc, 0xfc, 0x74, 0x74, 0x74, 0xf8, 0x06, 0x06, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x00, 0x00, 0x16,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0xed, 0x00, 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2c, 0x03, 0x03, 0x03, 0xdd, 0x2b, 0x2b, 0x2b, 0xfc, 0xb1, 0xb1, 0xb1, 0xef, 0x86, 0x86, 0x86, 0xf2, 0x06, 0x06, 0x06, 0xfe, 0x00, 0x00, 0x00, 0xb9, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0xd7, 0x00, 0x00, 0x00, 0xb6, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
const lv_img_dsc_t img_cursor = {
|
||||||
|
.header.cf = LV_IMG_CF_TRUE_COLOR_ALPHA,
|
||||||
|
.header.always_zero = 0,
|
||||||
|
.header.reserved = 0,
|
||||||
|
.header.w = 20,
|
||||||
|
.header.h = 20,
|
||||||
|
.data_size = 400 * LV_IMG_PX_SIZE_ALPHA_BYTE,
|
||||||
|
.data = img_cursor_map,
|
||||||
|
};
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user