Compare commits

...

9 Commits
v2.2.2 ... main

Author SHA1 Message Date
小林同志
6be351b5a0 Adjust jiuchuan-s3 UI (#1747)
* 修复SetupUI接口引入导致的屏幕适配失败问题

* 修正board中屏幕高度错误,调整偏移量

---------

Co-authored-by: smalllin0 <aslinqf@163.com>
Co-authored-by: Xiaoxia <terrence@tenclass.com>
2026-02-09 19:16:49 +08:00
Xiaoxia
d9447ad060 fix: Enhance UI setup across multiple boards (#1753)
* chore: Update component versions and enhance UI setup across multiple boards

- Bumped uart-eth-modem version from ~0.3.2 to ~0.3.3 in idf_component.yml.
- Added SetupUI method to various display classes to ensure proper UI initialization before usage.
- Improved error handling in display classes to prevent issues when UI is not set up.
- Ensured UI customization is performed in SetupUI rather than constructors for better reliability.

* remove pm config code
2026-02-09 19:13:14 +08:00
Xiaoxia
9215a04a7e Delay init success sound playback and remove gif playback delay (#1748)
* refactor: Remove hardcoded loop delay for GIF playback in LcdDisplay class

* chore: Update esp-ml307 and uart-eth-modem component versions in idf_component.yml

- Bump esp-ml307 version from ~3.6.3 to ~3.6.4
- Update uart-eth-modem version from ~0.3.1 to ~0.3.2

* feat: Add PrintPmLocks method to SystemInfo class

- Introduced PrintPmLocks method to display power management locks using esp_pm_dump_locks.
- Updated system_info.h to declare the new method.

* refactor: Streamline audio codec initialization and enablement

- Removed redundant channel enable checks from AudioCodec::Start.
- Added channel enablement in CreateDuplexChannels for various audio codecs.
- Implemented EnableInput and EnableOutput methods in NoAudioCodec for better control over input/output states.

* refactor: Delay audio success sound playback until after activation completion

- Moved the success sound playback to a scheduled task to ensure it occurs after the activation process is complete.
- This change improves the responsiveness of the application during activation events.

* refactor: Update camera integration from EspVideo to Esp32Camera

- Replaced EspVideo with Esp32Camera for improved camera configuration and initialization.
- Streamlined camera setup by utilizing a new configuration structure for better clarity and maintainability.
- Updated README.md to remove outdated camera sensor configuration instructions.

* refactor: Update audio demuxing process in AudioService

- Replaced the existing demuxer instance with a local unique pointer in the PlaySound method for better memory management.
- Moved the OnDemuxerFinished callback setup into the PlaySound method to ensure it is correctly associated with the new demuxer instance.
- Removed the member variable demuxer_ from AudioService to streamline the class structure.
2026-02-08 22:09:45 +08:00
Wang is proud
7b7d22c495 feat: modify CircularStrip constructor parameter types and add SetMultiColors method (#1750) 2026-02-08 11:17:12 +08:00
zczc365
b4eada876a feat&fix: 小智云聊增加蓝牙功能 (#1732) 2026-02-07 11:02:03 +08:00
小林同志
49cd6625f4 增加流式ogg解封装支持 (#1705)
* 增加流式ogg解封装支持

* 增加TF卡引脚连接说明

* 修复圆角图标屏幕导致的显示问题

* 优化聊天消息显示

* 修改解封装实现

---------

Co-authored-by: smalllin0 <aslinqf@163.com>
2026-02-05 00:12:40 +08:00
Y1hsiaochunnn
6f71868bad fix: Categorizing waveshare products (#1734)
content: Update the README.md

ci: Adapt to the lower directory

ci: the lower directory support

ci: board type errors fixed.

ci: board_type errors fixed to board_leaf.

fix: A naming error problem

fix: jd9365 member error

fix: Update product naming

feat: Add manufacturer parameters to the firmware name for 'release'

fix: Verification logic

fix: Verification logic
2026-02-04 21:03:23 +08:00
baidxi
173eaa7463 在Display基类中添加SetupUI虚函数 (#1742)
Signed-off-by: jeck.chen <jeck.chen@dbappsecurity.com.cn>
2026-02-04 21:03:08 +08:00
Xiaoxia
2b025c4ea6 Enhance audio processing and wake word detection (#1739)
* Enhance audio processing and wake word detection

- Set task priority in Application::Run to improve responsiveness.
- Log detected wake words with their state in HandleWakeWordDetectedEvent.
- Streamline audio feeding in AudioService to handle both wake word and audio processor events.
- Implement input buffering in AfeAudioProcessor, AfeWakeWord, CustomWakeWord, and EspWakeWord to manage audio data more efficiently.
- Clear input buffers on stop to prevent residual data issues.

* Refactor audio processing to enhance thread safety and state management

- Implement early return checks in Feed methods of AfeAudioProcessor, AfeWakeWord, CustomWakeWord, and EspWakeWord to prevent processing when not running.
- Introduce std::atomic for running state in CustomWakeWord and EspWakeWord to ensure thread-safe access.
- Consolidate input buffer management with mutex locks to avoid race conditions during Stop and Feed operations.

* Refactor listening mode handling and wake word detection configuration

- Replace direct mode setting logic with a new GetDefaultListeningMode method for improved clarity and maintainability.
- Update HandleToggleChatEvent, HandleWakeWordDetectedEvent, and ContinueWakeWordInvoke to utilize the new method for determining listening mode.
- Introduce Kconfig option WAKE_WORD_DETECTION_IN_LISTENING to enable or disable wake word detection during listening mode, enhancing configurability.
2026-02-04 14:28:21 +08:00
188 changed files with 3002 additions and 1628 deletions

View File

@@ -1,6 +1,7 @@
# Define source files
set(SOURCES "audio/audio_codec.cc"
"audio/audio_service.cc"
"audio/demuxer/ogg_demuxer.cc"
"audio/codecs/no_audio_codec.cc"
"audio/codecs/box_audio_codec.cc"
"audio/codecs/es8311_audio_codec.cc"
@@ -38,7 +39,7 @@ set(SOURCES "audio/audio_codec.cc"
"main.cc"
)
set(INCLUDE_DIRS "." "display" "display/lvgl_display" "display/lvgl_display/jpg" "audio" "protocols")
set(INCLUDE_DIRS "." "display" "display/lvgl_display" "display/lvgl_display/jpg" "audio" "audio/demuxer" "protocols")
# Add board common files
list(APPEND SOURCES
@@ -255,131 +256,181 @@ elseif(CONFIG_BOARD_TYPE_ESP_SENSAIRSHUTTLE)
set(BUILTIN_TEXT_FONT font_puhui_basic_16_4)
set(BUILTIN_ICON_FONT font_awesome_16_4)
set(DEFAULT_EMOJI_COLLECTION twemoji_32)
elseif(CONFIG_BOARD_TYPE_WAVESHARE_S3_AUDIO_BOARD)
set(BOARD_TYPE "waveshare-s3-audio-board")
elseif(CONFIG_BOARD_TYPE_WAVESHARE_ESP32_S3_AUDIO_BOARD)
set(MANUFACTURER "waveshare")
set(BOARD_TYPE "esp32-s3-audio-board")
set(BUILTIN_TEXT_FONT font_puhui_basic_16_4)
set(BUILTIN_ICON_FONT font_awesome_16_4)
set(DEFAULT_EMOJI_COLLECTION twemoji_32)
elseif(CONFIG_BOARD_TYPE_WAVESHARE_S3_TOUCH_AMOLED_1_8)
elseif(CONFIG_BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_AMOLED_1_8)
set(MANUFACTURER "waveshare")
set(BOARD_TYPE "esp32-s3-touch-amoled-1.8")
set(BUILTIN_TEXT_FONT font_puhui_basic_30_4)
set(BUILTIN_ICON_FONT font_awesome_30_4)
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
elseif(CONFIG_BOARD_TYPE_WAVESHARE_C6_TOUCH_AMOLED_1_8)
set(BOARD_TYPE "waveshare-c6-touch-amoled-1.8")
elseif(CONFIG_BOARD_TYPE_WAVESHARE_ESP32_C6_TOUCH_AMOLED_1_8)
set(MANUFACTURER "waveshare")
set(BOARD_TYPE "esp32-c6-touch-amoled-1.8")
set(BUILTIN_TEXT_FONT font_puhui_basic_30_4)
set(BUILTIN_ICON_FONT font_awesome_30_4)
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
elseif(CONFIG_BOARD_TYPE_WAVESHARE_S3_TOUCH_AMOLED_2_06)
set(BOARD_TYPE "waveshare-s3-touch-amoled-2.06")
elseif(CONFIG_BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_AMOLED_2_06)
set(MANUFACTURER "waveshare")
set(BOARD_TYPE "esp32-s3-touch-amoled-2.06")
set(BUILTIN_TEXT_FONT font_puhui_basic_30_4)
set(BUILTIN_ICON_FONT font_awesome_30_4)
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
elseif(CONFIG_BOARD_TYPE_WAVESHARE_C6_TOUCH_AMOLED_2_06)
set(BOARD_TYPE "waveshare-c6-touch-amoled-2.06")
elseif(CONFIG_BOARD_TYPE_WAVESHARE_ESP32_C6_TOUCH_AMOLED_2_06)
set(MANUFACTURER "waveshare")
set(BOARD_TYPE "esp32-c6-touch-amoled-2.06")
set(BUILTIN_TEXT_FONT font_puhui_basic_30_4)
set(BUILTIN_ICON_FONT font_awesome_30_4)
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
elseif(CONFIG_BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_4B)
set(BOARD_TYPE "waveshare-s3-touch-lcd-4b")
elseif(CONFIG_BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_LCD_4B)
set(MANUFACTURER "waveshare")
set(BOARD_TYPE "esp32-s3-touch-lcd-4b")
set(BUILTIN_TEXT_FONT font_puhui_basic_30_4)
set(BUILTIN_ICON_FONT font_awesome_30_4)
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
elseif(CONFIG_BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_4_3C)
set(BOARD_TYPE "waveshare-s3-touch-lcd-4.3c")
elseif(CONFIG_BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_LCD_4_3C)
set(MANUFACTURER "waveshare")
set(BOARD_TYPE "esp32-s3-touch-lcd-4.3c")
set(BUILTIN_TEXT_FONT font_puhui_basic_30_4)
set(BUILTIN_ICON_FONT font_awesome_30_4)
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
elseif(CONFIG_BOARD_TYPE_WAVESHARE_S3_TOUCH_AMOLED_1_75)
set(BOARD_TYPE "waveshare-s3-touch-amoled-1.75")
elseif(CONFIG_BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_AMOLED_1_75)
set(MANUFACTURER "waveshare")
set(BOARD_TYPE "esp32-s3-touch-amoled-1.75")
set(BUILTIN_TEXT_FONT font_puhui_basic_30_4)
set(BUILTIN_ICON_FONT font_awesome_30_4)
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
elseif(CONFIG_BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_1_83)
set(BOARD_TYPE "waveshare-s3-touch-lcd-1.83")
elseif(CONFIG_BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_LCD_1_83)
set(MANUFACTURER "waveshare")
set(BOARD_TYPE "esp32-s3-touch-lcd-1.83")
set(BUILTIN_TEXT_FONT font_puhui_basic_16_4)
set(BUILTIN_ICON_FONT font_awesome_16_4)
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
elseif(CONFIG_BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_1_85C)
elseif(CONFIG_BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_LCD_1_85C)
set(MANUFACTURER "waveshare")
set(BOARD_TYPE "esp32-s3-touch-lcd-1.85c")
set(BUILTIN_TEXT_FONT font_puhui_basic_16_4)
set(BUILTIN_ICON_FONT font_awesome_16_4)
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
elseif(CONFIG_BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_1_85)
elseif(CONFIG_BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_LCD_1_85)
set(MANUFACTURER "waveshare")
set(BOARD_TYPE "esp32-s3-touch-lcd-1.85")
set(BUILTIN_TEXT_FONT font_puhui_basic_16_4)
set(BUILTIN_ICON_FONT font_awesome_16_4)
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
elseif(CONFIG_BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_1_46)
elseif(CONFIG_BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_LCD_1_46)
set(MANUFACTURER "waveshare")
set(BOARD_TYPE "esp32-s3-touch-lcd-1.46")
set(BUILTIN_TEXT_FONT font_puhui_basic_16_4)
set(BUILTIN_ICON_FONT font_awesome_16_4)
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
elseif(CONFIG_BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_3_5)
elseif(CONFIG_BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_LCD_3_5)
set(MANUFACTURER "waveshare")
set(BOARD_TYPE "esp32-s3-touch-lcd-3.5")
set(BUILTIN_TEXT_FONT font_puhui_basic_20_4)
set(BUILTIN_ICON_FONT font_awesome_20_4)
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
elseif(CONFIG_BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_3_5B)
set(BOARD_TYPE "waveshare-s3-touch-lcd-3.5b")
elseif(CONFIG_BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_LCD_3_5B)
set(MANUFACTURER "waveshare")
set(BOARD_TYPE "esp32-s3-touch-lcd-3.5b")
set(BUILTIN_TEXT_FONT font_puhui_basic_16_4)
set(BUILTIN_ICON_FONT font_awesome_16_4)
set(DEFAULT_EMOJI_COLLECTION twemoji_32)
elseif(CONFIG_BOARD_TYPE_WAVESHARE_S3_ePaper_1_54)
set(BOARD_TYPE "waveshare-s3-epaper-1.54")
elseif(CONFIG_BOARD_TYPE_WAVESHARE_ESP32_S3_ePaper_1_54)
set(MANUFACTURER "waveshare")
set(BOARD_TYPE "esp32-s3-epaper-1.54")
set(BUILTIN_TEXT_FONT font_puhui_basic_20_4)
set(BUILTIN_ICON_FONT font_awesome_20_4)
elseif(CONFIG_BOARD_TYPE_WAVESHARE_S3_RLCD_4_2)
set(BOARD_TYPE "waveshare-s3-rlcd-4.2")
elseif(CONFIG_BOARD_TYPE_WAVESHARE_ESP32_S3_RLCD_4_2)
set(MANUFACTURER "waveshare")
set(BOARD_TYPE "esp32-s3-rlcd-4.2")
set(BUILTIN_TEXT_FONT font_puhui_basic_30_4)
set(BUILTIN_ICON_FONT font_awesome_30_4)
elseif(CONFIG_BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_3_49)
set(BOARD_TYPE "waveshare-s3-touch-lcd-3.49")
elseif(CONFIG_BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_LCD_3_49)
set(MANUFACTURER "waveshare")
set(BOARD_TYPE "esp32-s3-touch-lcd-3.49")
set(LVGL_TEXT_FONT font_puhui_basic_30_4)
set(LVGL_ICON_FONT font_awesome_30_4)
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
elseif(CONFIG_BOARD_TYPE_WAVESHARE_C6_LCD_1_69)
set(BOARD_TYPE "waveshare-c6-lcd-1.69")
elseif(CONFIG_BOARD_TYPE_WAVESHARE_ESP32_C6_LCD_1_69)
set(MANUFACTURER "waveshare")
set(BOARD_TYPE "esp32-c6-lcd-1.69")
set(BUILTIN_TEXT_FONT font_puhui_basic_20_4)
set(BUILTIN_ICON_FONT font_awesome_20_4)
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
elseif(CONFIG_BOARD_TYPE_WAVESHARE_C6_TOUCH_LCD_1_83)
set(BOARD_TYPE "waveshare-c6-touch-lcd-1.83")
elseif(CONFIG_BOARD_TYPE_WAVESHARE_ESP32_C6_TOUCH_LCD_1_83)
set(MANUFACTURER "waveshare")
set(BOARD_TYPE "esp32-c6-touch-lcd-1.83")
set(BUILTIN_TEXT_FONT font_puhui_basic_16_4)
set(BUILTIN_ICON_FONT font_awesome_16_4)
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
elseif(CONFIG_BOARD_TYPE_WAVESHARE_C6_TOUCH_AMOLED_1_43)
set(BOARD_TYPE "waveshare-c6-touch-amoled-1.43")
elseif(CONFIG_BOARD_TYPE_WAVESHARE_ESP32_C6_TOUCH_AMOLED_1_43)
set(MANUFACTURER "waveshare")
set(BOARD_TYPE "esp32-c6-touch-amoled-1.43")
set(BUILTIN_TEXT_FONT font_puhui_basic_30_4)
set(BUILTIN_ICON_FONT font_awesome_30_4)
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
elseif(CONFIG_BOARD_TYPE_WAVESHARE_C6_TOUCH_AMOLED_1_32)
set(BOARD_TYPE "waveshare-c6-touch-amoled-1.32")
elseif(CONFIG_BOARD_TYPE_WAVESHARE_ESP32_C6_TOUCH_AMOLED_1_32)
set(MANUFACTURER "waveshare")
set(BOARD_TYPE "esp32-c6-touch-amoled-1.32")
set(BUILTIN_TEXT_FONT font_puhui_basic_20_4)
set(BUILTIN_ICON_FONT font_awesome_20_4)
set(DEFAULT_EMOJI_COLLECTION twemoji_32)
elseif(CONFIG_BOARD_TYPE_WAVESHARE_S3_TOUCH_AMOLED_1_32)
set(BOARD_TYPE "waveshare-s3-touch-amoled-1.32")
elseif(CONFIG_BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_AMOLED_1_32)
set(MANUFACTURER "waveshare")
set(BOARD_TYPE "esp32-s3-touch-amoled-1.32")
set(BUILTIN_TEXT_FONT font_puhui_basic_20_4)
set(BUILTIN_ICON_FONT font_awesome_20_4)
set(DEFAULT_EMOJI_COLLECTION twemoji_32)
elseif(CONFIG_BOARD_TYPE_WAVESHARE_P4_NANO)
set(BOARD_TYPE "waveshare-p4-nano")
elseif(CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_NANO)
set(MANUFACTURER "waveshare")
set(BOARD_TYPE "esp32-p4-nano")
set(BUILTIN_TEXT_FONT font_puhui_basic_30_4)
set(BUILTIN_ICON_FONT font_awesome_30_4)
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
elseif(CONFIG_BOARD_TYPE_WAVESHARE_P4_WIFI6_TOUCH_LCD_4B)
set(BOARD_TYPE "waveshare-p4-wifi6-touch-lcd-4b")
elseif(CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_4B)
set(MANUFACTURER "waveshare")
set(BOARD_TYPE "esp32-p4-wifi6-touch-lcd")
set(BUILTIN_TEXT_FONT font_puhui_basic_30_4)
set(BUILTIN_ICON_FONT font_awesome_30_4)
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
elseif(CONFIG_BOARD_TYPE_WAVESHARE_P4_WIFI6_TOUCH_LCD_7B)
set(BOARD_TYPE "waveshare-p4-wifi6-touch-lcd-7b")
elseif(CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_7B)
set(MANUFACTURER "waveshare")
set(BOARD_TYPE "esp32-p4-wifi6-touch-lcd")
set(BUILTIN_TEXT_FONT font_puhui_basic_30_4)
set(BUILTIN_ICON_FONT font_awesome_30_4)
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
elseif(CONFIG_BOARD_TYPE_WAVESHARE_P4_WIFI6_TOUCH_LCD_XC)
set(BOARD_TYPE "waveshare-p4-wifi6-touch-lcd-xc")
elseif(CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_3_4C)
set(MANUFACTURER "waveshare")
set(BOARD_TYPE "esp32-p4-wifi6-touch-lcd")
set(BUILTIN_TEXT_FONT font_puhui_basic_30_4)
set(BUILTIN_ICON_FONT font_awesome_30_4)
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
elseif(CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_4C)
set(MANUFACTURER "waveshare")
set(BOARD_TYPE "esp32-p4-wifi6-touch-lcd")
set(BUILTIN_TEXT_FONT font_puhui_basic_30_4)
set(BUILTIN_ICON_FONT font_awesome_30_4)
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
elseif(CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_7)
set(MANUFACTURER "waveshare")
set(BOARD_TYPE "esp32-p4-wifi6-touch-lcd")
set(BUILTIN_TEXT_FONT font_puhui_basic_30_4)
set(BUILTIN_ICON_FONT font_awesome_30_4)
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
elseif(CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_8)
set(MANUFACTURER "waveshare")
set(BOARD_TYPE "esp32-p4-wifi6-touch-lcd")
set(BUILTIN_TEXT_FONT font_puhui_basic_30_4)
set(BUILTIN_ICON_FONT font_awesome_30_4)
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
elseif(CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_10_1)
set(MANUFACTURER "waveshare")
set(BOARD_TYPE "esp32-p4-wifi6-touch-lcd")
set(BUILTIN_TEXT_FONT font_puhui_basic_30_4)
set(BUILTIN_ICON_FONT font_awesome_30_4)
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
@@ -644,8 +695,15 @@ elseif(CONFIG_BOARD_TYPE_HU_087)
endif()
file(GLOB BOARD_SOURCES
if(MANUFACTURER)
${CMAKE_CURRENT_SOURCE_DIR}/boards/${MANUFACTURER}/${BOARD_TYPE}/*.cc
${CMAKE_CURRENT_SOURCE_DIR}/boards/${MANUFACTURER}/${BOARD_TYPE}/*.c
else
${CMAKE_CURRENT_SOURCE_DIR}/boards/${BOARD_TYPE}/*.cc
${CMAKE_CURRENT_SOURCE_DIR}/boards/${BOARD_TYPE}/*.c
endif()
)
list(APPEND SOURCES ${BOARD_SOURCES})

View File

@@ -257,83 +257,95 @@ choice BOARD_TYPE
config BOARD_TYPE_M5STACK_ATOM_MATRIX_ECHO_BASE
bool "M5Stack AtomMatrix + Echo Base"
depends on IDF_TARGET_ESP32
config BOARD_TYPE_WAVESHARE_S3_AUDIO_BOARD
config BOARD_TYPE_WAVESHARE_ESP32_S3_AUDIO_BOARD
bool "Waveshare ESP32-S3-Audio-Board"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_WAVESHARE_S3_TOUCH_AMOLED_1_8
config BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_AMOLED_1_8
bool "Waveshare ESP32-S3-Touch-AMOLED-1.8"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_WAVESHARE_S3_TOUCH_AMOLED_2_06
config BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_AMOLED_2_06
bool "Waveshare ESP32-S3-Touch-AMOLED-2.06"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_WAVESHARE_C6_TOUCH_AMOLED_2_06
config BOARD_TYPE_WAVESHARE_ESP32_C6_TOUCH_AMOLED_2_06
bool "Waveshare ESP32-C6-Touch-AMOLED-2.06"
depends on IDF_TARGET_ESP32C6
config BOARD_TYPE_WAVESHARE_S3_TOUCH_AMOLED_1_75
config BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_AMOLED_1_75
bool "Waveshare ESP32-S3-Touch-AMOLED-1.75"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_1_83
config BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_LCD_1_83
bool "Waveshare ESP32-S3-Touch-LCD-1.83"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_4B
config BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_LCD_4B
bool "Waveshare ESP32-S3-Touch-LCD-4B"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_4_3C
config BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_LCD_4_3C
bool "Waveshare ESP32-S3-Touch-LCD-4.3C"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_1_85C
config BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_LCD_1_85C
bool "Waveshare ESP32-S3-Touch-LCD-1.85C"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_1_85
config BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_LCD_1_85
bool "Waveshare ESP32-S3-Touch-LCD-1.85"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_1_46
config BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_LCD_1_46
bool "Waveshare ESP32-S3-Touch-LCD-1.46"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_WAVESHARE_C6_LCD_1_69
config BOARD_TYPE_WAVESHARE_ESP32_C6_LCD_1_69
bool "Waveshare ESP32-C6-LCD-1.69"
depends on IDF_TARGET_ESP32C6
config BOARD_TYPE_WAVESHARE_C6_TOUCH_LCD_1_83
config BOARD_TYPE_WAVESHARE_ESP32_C6_TOUCH_LCD_1_83
bool "Waveshare ESP32-C6-Touch-LCD-1.83"
depends on IDF_TARGET_ESP32C6
config BOARD_TYPE_WAVESHARE_C6_TOUCH_AMOLED_1_43
config BOARD_TYPE_WAVESHARE_ESP32_C6_TOUCH_AMOLED_1_43
bool "Waveshare ESP32-C6-Touch-AMOLOED-1.43"
depends on IDF_TARGET_ESP32C6
config BOARD_TYPE_WAVESHARE_C6_TOUCH_AMOLED_1_32
config BOARD_TYPE_WAVESHARE_ESP32_C6_TOUCH_AMOLED_1_32
bool "Waveshare ESP32-C6-Touch-AMOLOED-1.32"
depends on IDF_TARGET_ESP32C6
config BOARD_TYPE_WAVESHARE_C6_TOUCH_AMOLED_1_8
config BOARD_TYPE_WAVESHARE_ESP32_C6_TOUCH_AMOLED_1_8
bool "Waveshare ESP32-C6-Touch-AMOLED-1.8"
depends on IDF_TARGET_ESP32C6
config BOARD_TYPE_WAVESHARE_S3_TOUCH_AMOLED_1_32
config BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_AMOLED_1_32
bool "Waveshare ESP32-S3-Touch-AMOLOED-1.32"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_3_49
config BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_LCD_3_49
bool "Waveshare ESP32-S3-Touch-LCD-3.49"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_3_5
config BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_LCD_3_5
bool "Waveshare ESP32-S3-Touch-LCD-3.5"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_WAVESHARE_S3_ePaper_1_54
config BOARD_TYPE_WAVESHARE_ESP32_S3_ePaper_1_54
bool "Waveshare ESP32-S3-ePaper-1.54"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_WAVESHARE_S3_RLCD_4_2
config BOARD_TYPE_WAVESHARE_ESP32_S3_RLCD_4_2
bool "Waveshare ESP32-S3-RLCD-4.2"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_3_5B
config BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_LCD_3_5B
bool "Waveshare ESP32-S3-Touch-LCD-3.5B"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_WAVESHARE_P4_NANO
config BOARD_TYPE_WAVESHARE_ESP32_P4_NANO
bool "Waveshare ESP32-P4-NANO"
depends on IDF_TARGET_ESP32P4
config BOARD_TYPE_WAVESHARE_P4_WIFI6_TOUCH_LCD_4B
config BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_4B
bool "Waveshare ESP32-P4-WIFI6-Touch-LCD-4B"
depends on IDF_TARGET_ESP32P4
config BOARD_TYPE_WAVESHARE_P4_WIFI6_TOUCH_LCD_7B
config BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_7B
bool "Waveshare ESP32-P4-WIFI6-Touch-LCD-7B"
depends on IDF_TARGET_ESP32P4
config BOARD_TYPE_WAVESHARE_P4_WIFI6_TOUCH_LCD_XC
bool "Waveshare ESP32-P4-WIFI6-Touch-LCD-3.4C or ESP32-P4-WIFI6-Touch-LCD-4C"
config BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_3_4C
bool "Waveshare ESP32-P4-WIFI6-Touch-LCD-3.4C"
depends on IDF_TARGET_ESP32P4
config BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_4C
bool "Waveshare ESP32-P4-WIFI6-Touch-LCD-4C"
depends on IDF_TARGET_ESP32P4
config BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_7
bool "Waveshare ESP32-P4-WIFI6-Touch-LCD-7"
depends on IDF_TARGET_ESP32P4
config BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_8
bool "Waveshare ESP32-P4-WIFI6-Touch-LCD-8"
depends on IDF_TARGET_ESP32P4
config BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_10_1
bool "Waveshare ESP32-P4-WIFI6-Touch-LCD-10.1"
depends on IDF_TARGET_ESP32P4
config BOARD_TYPE_TUDOUZI
bool "土豆子"
@@ -529,7 +541,7 @@ choice DISPLAY_OLED_TYPE
endchoice
choice DISPLAY_LCD_TYPE
depends on BOARD_TYPE_BREAD_COMPACT_WIFI_LCD || BOARD_TYPE_BREAD_COMPACT_ESP32_LCD || BOARD_TYPE_CGC || BOARD_TYPE_WAVESHARE_P4_NANO || BOARD_TYPE_WAVESHARE_P4_WIFI6_TOUCH_LCD_XC || BOARD_TYPE_BREAD_COMPACT_WIFI_CAM
depends on BOARD_TYPE_BREAD_COMPACT_WIFI_LCD || BOARD_TYPE_BREAD_COMPACT_ESP32_LCD || BOARD_TYPE_CGC || BOARD_TYPE_BREAD_COMPACT_WIFI_CAM
prompt "LCD Type"
default LCD_ST7789_240X320
help
@@ -564,14 +576,6 @@ choice DISPLAY_LCD_TYPE
bool "ILI9341 240*320, Non-IPS"
config LCD_GC9A01_240X240
bool "GC9A01 240*240 Circle"
config LCD_TYPE_800_1280_10_1_INCH
bool "Waveshare 101M-8001280-IPS-CT-K Display"
config LCD_TYPE_800_1280_10_1_INCH_A
bool "Waveshare 10.1-DSI-TOUCH-A Display"
config LCD_TYPE_800_800_3_4_INCH
bool "Waveshare ESP32-P4-WIFI6-Touch-LCD-3.4C with 800*800 3.4inch round display"
config LCD_TYPE_720_720_4_INCH
bool "Waveshare ESP32-P4-WIFI6-Touch-LCD-4C with 720*720 4inch round display"
config LCD_CUSTOM
bool "Custom LCD (自定义屏幕参数)"
endchoice
@@ -589,7 +593,7 @@ choice DISPLAY_ESP32S3_KORVO2_V3
endchoice
choice DISPLAY_ESP32S3_AUDIO_BOARD
depends on BOARD_TYPE_WAVESHARE_S3_AUDIO_BOARD
depends on BOARD_TYPE_WAVESHARE_ESP32_S3_AUDIO_BOARD
prompt "ESP32S3_AUDIO_BOARD LCD Type"
default AUDIO_BOARD_LCD_JD9853
help
@@ -680,6 +684,16 @@ config SEND_WAKE_WORD_DATA
help
Send wake word data to the server as the first message of the conversation and wait for response
config WAKE_WORD_DETECTION_IN_LISTENING
bool "Enable Wake Word Detection in Listening Mode"
default n
depends on USE_AFE_WAKE_WORD || USE_CUSTOM_WAKE_WORD
help
Enable wake word detection while in listening mode.
When enabled, the device can detect wake word during listening,
which allows interrupting the current conversation.
When disabled (default), wake word detection is turned off during listening.
config USE_AUDIO_PROCESSOR
bool "Enable Audio Noise Reduction"
default y
@@ -691,11 +705,12 @@ config USE_DEVICE_AEC
bool "Enable Device-Side AEC"
default n
depends on USE_AUDIO_PROCESSOR && (BOARD_TYPE_ESP_BOX_3 || BOARD_TYPE_ESP_BOX || BOARD_TYPE_ESP_BOX_LITE \
|| BOARD_TYPE_LICHUANG_DEV_S3 || BOARD_TYPE_ESP_KORVO2_V3 || BOARD_TYPE_WAVESHARE_S3_TOUCH_AMOLED_1_75 || BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_1_83\
|| BOARD_TYPE_WAVESHARE_S3_TOUCH_AMOLED_2_06 || BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_4B || BOARD_TYPE_WAVESHARE_P4_WIFI6_TOUCH_LCD_4B || BOARD_TYPE_WAVESHARE_P4_WIFI6_TOUCH_LCD_7B \
|| BOARD_TYPE_WAVESHARE_P4_WIFI6_TOUCH_LCD_XC || BOARD_TYPE_ESP_S3_LCD_EV_Board_2 || BOARD_TYPE_YUNLIAO_S3 \
|| BOARD_TYPE_ECHOEAR || BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_3_49 || BOARD_TYPE_WAVESHARE_S3_RLCD_4_2 || BOARD_TYPE_ZHENGCHEN_CAM || BOARD_TYPE_ZHENGCHEN_CAM_ML307 \
|| BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_4_3C)
|| BOARD_TYPE_LICHUANG_DEV_S3 || BOARD_TYPE_ESP_KORVO2_V3 || BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_AMOLED_1_75 || BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_LCD_1_83\
|| BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_AMOLED_2_06 || BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_LCD_4B || BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_4B || BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_7B \
|| BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_3_4C || BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_4C || BOARD_TYPE_ESP_S3_LCD_EV_Board_2 || BOARD_TYPE_YUNLIAO_S3 \
|| BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_7 || BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_8 || BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_10_1 \
|| BOARD_TYPE_ECHOEAR || BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_LCD_3_49 || BOARD_TYPE_WAVESHARE_ESP32_S3_RLCD_4_2 || BOARD_TYPE_ZHENGCHEN_CAM || BOARD_TYPE_ZHENGCHEN_CAM_ML307 \
|| BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_LCD_4_3C)
help
To work properly, device-side AEC requires a clean output reference path from the speaker signal and physical acoustic isolation between the microphone and speaker.

View File

@@ -64,7 +64,7 @@ void Application::Initialize() {
// Setup the display
auto display = board.GetDisplay();
display->SetupUI();
// Print board name/version info
display->SetChatMessage("system", SystemInfo::GetUserAgent().c_str());
@@ -309,13 +309,15 @@ void Application::HandleActivationDoneEvent() {
display->ShowNotification(message.c_str());
display->SetChatMessage("system", "");
// Play the success sound to indicate the device is ready
audio_service_.PlaySound(Lang::Sounds::OGG_SUCCESS);
// Release OTA object after activation is complete
ota_.reset();
auto& board = Board::GetInstance();
board.SetPowerSaveLevel(PowerSaveLevel::LOW_POWER);
Schedule([this]() {
// Play the success sound to indicate the device is ready
audio_service_.PlaySound(Lang::Sounds::OGG_SUCCESS);
});
}
void Application::ActivationTask() {
@@ -691,7 +693,7 @@ void Application::HandleToggleChatEvent() {
}
if (state == kDeviceStateIdle) {
ListeningMode mode = aec_mode_ == kAecOff ? kListeningModeAutoStop : kListeningModeRealtime;
ListeningMode mode = GetDefaultListeningMode();
if (!protocol_->IsAudioChannelOpened()) {
SetDeviceState(kDeviceStateConnecting);
// Schedule to let the state change be processed first (UI update)
@@ -777,7 +779,9 @@ void Application::HandleWakeWordDetectedEvent() {
}
auto state = GetDeviceState();
auto wake_word = audio_service_.GetLastWakeWord();
ESP_LOGI(TAG, "Wake word detected: %s (state: %d)", wake_word.c_str(), (int)state);
if (state == kDeviceStateIdle) {
audio_service_.EncodeWakeWord();
auto wake_word = audio_service_.GetLastWakeWord();
@@ -793,8 +797,22 @@ void Application::HandleWakeWordDetectedEvent() {
}
// Channel already opened, continue directly
ContinueWakeWordInvoke(wake_word);
} else if (state == kDeviceStateSpeaking) {
} else if (state == kDeviceStateSpeaking || state == kDeviceStateListening) {
AbortSpeaking(kAbortReasonWakeWordDetected);
// Clear send queue to avoid sending residues to server
while (audio_service_.PopPacketFromSendQueue());
if (state == kDeviceStateListening) {
protocol_->SendStartListening(GetDefaultListeningMode());
audio_service_.ResetDecoder();
audio_service_.PlaySound(Lang::Sounds::OGG_POPUP);
// Re-enable wake word detection as it was stopped by the detection itself
audio_service_.EnableWakeWordDetection(true);
} else {
// Play popup sound and start listening again
play_popup_on_listening_ = true;
SetListeningMode(GetDefaultListeningMode());
}
} else if (state == kDeviceStateActivating) {
// Restart the activation check if the wake word is detected during activation
SetDeviceState(kDeviceStateIdle);
@@ -822,12 +840,15 @@ void Application::ContinueWakeWordInvoke(const std::string& wake_word) {
}
// Set the chat state to wake word detected
protocol_->SendWakeWordDetected(wake_word);
SetListeningMode(aec_mode_ == kAecOff ? kListeningModeAutoStop : kListeningModeRealtime);
// Set flag to play popup sound after state changes to listening
play_popup_on_listening_ = true;
SetListeningMode(GetDefaultListeningMode());
#else
// Set flag to play popup sound after state changes to listening
// (PlaySound here would be cleared by ResetDecoder in EnableVoiceProcessing)
play_popup_on_listening_ = true;
SetListeningMode(aec_mode_ == kAecOff ? kListeningModeAutoStop : kListeningModeRealtime);
SetListeningMode(GetDefaultListeningMode());
#endif
}
@@ -859,7 +880,7 @@ void Application::HandleStateChangedEvent() {
display->SetEmotion("neutral");
// Make sure the audio processor is running
if (!audio_service_.IsAudioProcessorRunning()) {
if (play_popup_on_listening_ || !audio_service_.IsAudioProcessorRunning()) {
// For auto mode, wait for playback queue to be empty before enabling voice processing
// This prevents audio truncation when STOP arrives late due to network jitter
if (listening_mode_ == kListeningModeAutoStop) {
@@ -869,9 +890,16 @@ void Application::HandleStateChangedEvent() {
// Send the start listening command
protocol_->SendStartListening(listening_mode_);
audio_service_.EnableVoiceProcessing(true);
audio_service_.EnableWakeWordDetection(false);
}
#ifdef CONFIG_WAKE_WORD_DETECTION_IN_LISTENING
// Enable wake word detection in listening mode (configured via Kconfig)
audio_service_.EnableWakeWordDetection(audio_service_.IsAfeWakeWord());
#else
// Disable wake word detection in listening mode
audio_service_.EnableWakeWordDetection(false);
#endif
// Play popup sound after ResetDecoder (in EnableVoiceProcessing) has been called
if (play_popup_on_listening_) {
play_popup_on_listening_ = false;
@@ -919,6 +947,10 @@ void Application::SetListeningMode(ListeningMode mode) {
SetDeviceState(kDeviceStateListening);
}
ListeningMode Application::GetDefaultListeningMode() const {
return aec_mode_ == kAecOff ? kListeningModeAutoStop : kListeningModeRealtime;
}
void Application::Reboot() {
ESP_LOGI(TAG, "Rebooting...");
// Disconnect the audio channel

View File

@@ -165,6 +165,7 @@ private:
void InitializeProtocol();
void ShowActivationCode(const std::string& code, const std::string& message);
void SetListeningMode(ListeningMode mode);
ListeningMode GetDefaultListeningMode() const;
// State change handler called by state machine
void OnStateChanged(DeviceState old_state, DeviceState new_state);

View File

@@ -34,16 +34,6 @@ void AudioCodec::Start() {
output_volume_ = 10;
}
if (tx_handle_ != nullptr) {
ESP_ERROR_CHECK(i2s_channel_enable(tx_handle_));
}
if (rx_handle_ != nullptr) {
ESP_ERROR_CHECK(i2s_channel_enable(rx_handle_));
}
EnableInput(true);
EnableOutput(true);
ESP_LOGI(TAG, "Audio codec started");
}

View File

@@ -265,27 +265,18 @@ void AudioService::AudioInputTask() {
}
}
/* Feed the wake word */
if (bits & AS_EVENT_WAKE_WORD_RUNNING) {
/* Feed the wake word and/or audio processor */
if (bits & (AS_EVENT_WAKE_WORD_RUNNING | AS_EVENT_AUDIO_PROCESSOR_RUNNING)) {
int samples = 160; // 10ms
std::vector<int16_t> data;
int samples = wake_word_->GetFeedSize();
if (samples > 0) {
if (ReadAudioData(data, 16000, samples)) {
if (ReadAudioData(data, 16000, samples)) {
if (bits & AS_EVENT_WAKE_WORD_RUNNING) {
wake_word_->Feed(data);
continue;
}
}
}
/* Feed the audio processor */
if (bits & AS_EVENT_AUDIO_PROCESSOR_RUNNING) {
std::vector<int16_t> data;
int samples = audio_processor_->GetFeedSize();
if (samples > 0) {
if (ReadAudioData(data, 16000, samples)) {
if (bits & AS_EVENT_AUDIO_PROCESSOR_RUNNING) {
audio_processor_->Feed(std::move(data));
continue;
}
continue;
}
}
@@ -314,6 +305,7 @@ void AudioService::AudioOutputTask() {
esp_timer_start_periodic(audio_power_timer_, AUDIO_POWER_CHECK_INTERVAL_MS * 1000);
codec_->EnableOutput(true);
}
codec_->OutputData(task->pcm);
/* Update the last output time */
@@ -645,94 +637,20 @@ void AudioService::PlaySound(const std::string_view& ogg) {
codec_->EnableOutput(true);
}
const uint8_t* buf = reinterpret_cast<const uint8_t*>(ogg.data());
const auto* buf = reinterpret_cast<const uint8_t*>(ogg.data());
size_t size = ogg.size();
size_t offset = 0;
auto find_page = [&](size_t start)->size_t {
for (size_t i = start; i + 4 <= size; ++i) {
if (buf[i] == 'O' && buf[i+1] == 'g' && buf[i+2] == 'g' && buf[i+3] == 'S') return i;
}
return static_cast<size_t>(-1);
};
bool seen_head = false;
bool seen_tags = false;
int sample_rate = 16000; // 默认值
while (true) {
size_t pos = find_page(offset);
if (pos == static_cast<size_t>(-1)) break;
offset = pos;
if (offset + 27 > size) break;
const uint8_t* page = buf + offset;
uint8_t page_segments = page[26];
size_t seg_table_off = offset + 27;
if (seg_table_off + page_segments > size) break;
size_t body_size = 0;
for (size_t i = 0; i < page_segments; ++i) body_size += page[27 + i];
size_t body_off = seg_table_off + page_segments;
if (body_off + body_size > size) break;
// Parse packets using lacing
size_t cur = body_off;
size_t seg_idx = 0;
while (seg_idx < page_segments) {
size_t pkt_len = 0;
size_t pkt_start = cur;
bool continued = false;
do {
uint8_t l = page[27 + seg_idx++];
pkt_len += l;
cur += l;
continued = (l == 255);
} while (continued && seg_idx < page_segments);
if (pkt_len == 0) continue;
const uint8_t* pkt_ptr = buf + pkt_start;
if (!seen_head) {
// 解析OpusHead包
if (pkt_len >= 19 && std::memcmp(pkt_ptr, "OpusHead", 8) == 0) {
seen_head = true;
// OpusHead结构[0-7] "OpusHead", [8] version, [9] channel_count, [10-11] pre_skip
// [12-15] input_sample_rate, [16-17] output_gain, [18] mapping_family
if (pkt_len >= 12) {
uint8_t version = pkt_ptr[8];
uint8_t channel_count = pkt_ptr[9];
if (pkt_len >= 16) {
// 读取输入采样率 (little-endian)
sample_rate = pkt_ptr[12] | (pkt_ptr[13] << 8) |
(pkt_ptr[14] << 16) | (pkt_ptr[15] << 24);
ESP_LOGI(TAG, "OpusHead: version=%d, channels=%d, sample_rate=%d",
version, channel_count, sample_rate);
}
}
}
continue;
}
if (!seen_tags) {
// Expect OpusTags in second packet
if (pkt_len >= 8 && std::memcmp(pkt_ptr, "OpusTags", 8) == 0) {
seen_tags = true;
}
continue;
}
// Audio packet (Opus)
auto packet = std::make_unique<AudioStreamPacket>();
packet->sample_rate = sample_rate;
packet->frame_duration = 60;
packet->payload.resize(pkt_len);
std::memcpy(packet->payload.data(), pkt_ptr, pkt_len);
PushPacketToDecodeQueue(std::move(packet), true);
}
offset = body_off + body_size;
}
auto demuxer = std::make_unique<OggDemuxer>();
demuxer->OnDemuxerFinished([this](const uint8_t* data, int sample_rate, size_t size){
auto packet = std::make_unique<AudioStreamPacket>();
packet->sample_rate = sample_rate;
packet->frame_duration = 60;
packet->payload.resize(size);
std::memcpy(packet->payload.data(), data, size);
PushPacketToDecodeQueue(std::move(packet), true);
});
demuxer->Reset();
demuxer->Process(buf, size);
}
bool AudioService::IsIdle() {

View File

@@ -23,7 +23,7 @@
#include "processors/audio_debugger.h"
#include "wake_word.h"
#include "protocol.h"
#include "ogg_demuxer.h"
/*
* There are two types of audio data flow:

View File

@@ -176,6 +176,8 @@ void BoxAudioCodec::CreateDuplexChannels(gpio_num_t mclk, gpio_num_t bclk, gpio_
ESP_ERROR_CHECK(i2s_channel_init_std_mode(tx_handle_, &std_cfg));
ESP_ERROR_CHECK(i2s_channel_init_tdm_mode(rx_handle_, &tdm_cfg));
ESP_ERROR_CHECK(i2s_channel_enable(tx_handle_));
ESP_ERROR_CHECK(i2s_channel_enable(rx_handle_));
ESP_LOGI(TAG, "Duplex channels created");
}

View File

@@ -150,6 +150,8 @@ void Es8311AudioCodec::CreateDuplexChannels(gpio_num_t mclk, gpio_num_t bclk, gp
ESP_ERROR_CHECK(i2s_channel_init_std_mode(tx_handle_, &std_cfg));
ESP_ERROR_CHECK(i2s_channel_init_std_mode(rx_handle_, &std_cfg));
ESP_ERROR_CHECK(i2s_channel_enable(tx_handle_));
ESP_ERROR_CHECK(i2s_channel_enable(rx_handle_));
ESP_LOGI(TAG, "Duplex channels created");
}

View File

@@ -126,6 +126,8 @@ void Es8374AudioCodec::CreateDuplexChannels(gpio_num_t mclk, gpio_num_t bclk, gp
ESP_ERROR_CHECK(i2s_channel_init_std_mode(tx_handle_, &std_cfg));
ESP_ERROR_CHECK(i2s_channel_init_std_mode(rx_handle_, &std_cfg));
ESP_ERROR_CHECK(i2s_channel_enable(tx_handle_));
ESP_ERROR_CHECK(i2s_channel_enable(rx_handle_));
ESP_LOGI(TAG, "Duplex channels created");
}

View File

@@ -131,6 +131,8 @@ void Es8388AudioCodec::CreateDuplexChannels(gpio_num_t mclk, gpio_num_t bclk, gp
ESP_ERROR_CHECK(i2s_channel_init_std_mode(tx_handle_, &std_cfg));
ESP_ERROR_CHECK(i2s_channel_init_std_mode(rx_handle_, &std_cfg));
ESP_ERROR_CHECK(i2s_channel_enable(tx_handle_));
ESP_ERROR_CHECK(i2s_channel_enable(rx_handle_));
ESP_LOGI(TAG, "Duplex channels created");
}
@@ -186,9 +188,6 @@ void Es8388AudioCodec::EnableOutput(bool enable) {
// Set analog output volume to 0dB, default is -45dB
uint8_t reg_val = 30; // 0dB
if(input_reference_){
reg_val = 27;
}
uint8_t regs[] = { 46, 47, 48, 49 }; // HP_LVOL, HP_RVOL, SPK_LVOL, SPK_RVOL
for (uint8_t reg : regs) {
ctrl_if_->write_reg(ctrl_if_, reg, 1, &reg_val, 1);

View File

@@ -132,6 +132,8 @@ void Es8389AudioCodec::CreateDuplexChannels(gpio_num_t mclk, gpio_num_t bclk, gp
ESP_ERROR_CHECK(i2s_channel_init_std_mode(tx_handle_, &std_cfg));
ESP_ERROR_CHECK(i2s_channel_init_std_mode(rx_handle_, &std_cfg));
ESP_ERROR_CHECK(i2s_channel_enable(tx_handle_));
ESP_ERROR_CHECK(i2s_channel_enable(rx_handle_));
ESP_LOGI(TAG, "Duplex channels created");
}

View File

@@ -254,6 +254,32 @@ int NoAudioCodec::Read(int16_t* dest, int samples) {
return samples;
}
void NoAudioCodec::EnableInput(bool enable) {
std::lock_guard<std::mutex> lock(data_if_mutex_);
if (enable == input_enabled_) {
return;
}
if (enable) {
ESP_ERROR_CHECK(i2s_channel_enable(rx_handle_));
} else {
ESP_ERROR_CHECK(i2s_channel_disable(rx_handle_));
}
AudioCodec::EnableInput(enable);
}
void NoAudioCodec::EnableOutput(bool enable) {
std::lock_guard<std::mutex> lock(data_if_mutex_);
if (enable == output_enabled_) {
return;
}
if (enable) {
ESP_ERROR_CHECK(i2s_channel_enable(tx_handle_));
} else {
ESP_ERROR_CHECK(i2s_channel_disable(tx_handle_));
}
AudioCodec::EnableOutput(enable);
}
// Delegating constructor: calls the main constructor with default slot mask
NoAudioCodecSimplexPdm::NoAudioCodecSimplexPdm(int input_sample_rate, int output_sample_rate, gpio_num_t spk_bclk, gpio_num_t spk_ws, gpio_num_t spk_dout, gpio_num_t mic_sck, gpio_num_t mic_din)
: NoAudioCodecSimplexPdm(input_sample_rate, output_sample_rate, spk_bclk, spk_ws, spk_dout, I2S_STD_SLOT_LEFT, mic_sck, mic_din) {

View File

@@ -13,6 +13,8 @@ protected:
virtual int Write(const int16_t* data, int samples) override;
virtual int Read(int16_t* dest, int samples) override;
virtual void EnableInput(bool enable) override;
virtual void EnableOutput(bool enable) override;
public:
virtual ~NoAudioCodec();

View File

@@ -0,0 +1,311 @@
#include "ogg_demuxer.h"
#include "esp_log.h"
#define TAG "OggDemuxer"
/// @brief 重置解封器
void OggDemuxer::Reset()
{
opus_info_ = {
.head_seen = false,
.tags_seen = false,
.sample_rate = 48000
};
state_ = ParseState::FIND_PAGE;
ctx_.packet_len = 0;
ctx_.seg_count = 0;
ctx_.seg_index = 0;
ctx_.data_offset = 0;
ctx_.bytes_needed = 4; // 需要4字节"OggS"
ctx_.seg_remaining = 0;
ctx_.body_size = 0;
ctx_.body_offset = 0;
ctx_.packet_continued = false;
// 清空缓冲区数据
memset(ctx_.header, 0, sizeof(ctx_.header));
memset(ctx_.seg_table, 0, sizeof(ctx_.seg_table));
memset(ctx_.packet_buf, 0, sizeof(ctx_.packet_buf));
}
/// @brief 处理数据块
/// @param data 输入数据
/// @param size 输入数据大小
/// @return 已处理的字节数
size_t OggDemuxer::Process(const uint8_t* data, size_t size)
{
size_t processed = 0; // 已处理的字节数
while (processed < size) {
switch (state_) {
case ParseState::FIND_PAGE: {
// 寻找页头"OggS"
if (ctx_.bytes_needed < 4) {
// 处理不完整的"OggS"匹配(跨数据块)
size_t to_copy = std::min(size - processed, ctx_.bytes_needed);
memcpy(ctx_.header + (4 - ctx_.bytes_needed), data + processed, to_copy);
processed += to_copy;
ctx_.bytes_needed -= to_copy;
if (ctx_.bytes_needed == 0) {
// 检查是否匹配"OggS"
if (memcmp(ctx_.header, "OggS", 4) == 0) {
state_ = ParseState::PARSE_HEADER;
ctx_.data_offset = 4;
ctx_.bytes_needed = 27 - 4; // 还需要23字节完成页头
} else {
// 匹配失败滑动1字节继续匹配
memmove(ctx_.header, ctx_.header + 1, 3);
ctx_.bytes_needed = 1;
}
} else {
// 数据不足,等待更多数据
return processed;
}
} else if (ctx_.bytes_needed == 4) {
// 在数据块中查找完整的"OggS"
bool found = false;
size_t i = 0;
size_t remaining = size - processed;
// 搜索"OggS"
for (; i + 4 <= remaining; i++) {
if (memcmp(data + processed + i, "OggS", 4) == 0) {
found = true;
break;
}
}
if (found) {
// 找到"OggS",跳过已搜索的字节
processed += i;
// 不记录找到的"OggS",无必要
// memcpy(ctx_.header, data + processed, 4);
processed += 4;
state_ = ParseState::PARSE_HEADER;
ctx_.data_offset = 4;
ctx_.bytes_needed = 27 - 4; // 还需要23字节
} else {
// 没有找到完整"OggS",保存可能的部分匹配
size_t partial_len = remaining - i;
if (partial_len > 0) {
memcpy(ctx_.header, data + processed + i, partial_len);
ctx_.bytes_needed = 4 - partial_len;
processed += i + partial_len;
} else {
processed += i; // 已搜索所有字节
}
return processed; // 返回已处理的字节数
}
} else {
ESP_LOGE(TAG, "OggDemuxer run in error state: bytes_needed=%zu", ctx_.bytes_needed);
Reset();
return processed;
}
break;
}
case ParseState::PARSE_HEADER: {
size_t available = size - processed;
if (available < ctx_.bytes_needed) {
// 数据不足,复制可用的部分
memcpy(ctx_.header + ctx_.data_offset,
data + processed, available);
ctx_.data_offset += available;
ctx_.bytes_needed -= available;
processed += available;
return processed; // 等待更多数据
} else {
// 有足够的数据完成页头
size_t to_copy = ctx_.bytes_needed;
memcpy(ctx_.header + ctx_.data_offset,
data + processed, to_copy);
processed += to_copy;
ctx_.data_offset += to_copy;
ctx_.bytes_needed = 0;
// 验证页头
if (ctx_.header[4] != 0) {
ESP_LOGE(TAG, "无效的Ogg版本: %d", ctx_.header[4]);
state_ = ParseState::FIND_PAGE;
ctx_.bytes_needed = 4;
ctx_.data_offset = 0;
break;
}
ctx_.seg_count = ctx_.header[26];
if (ctx_.seg_count > 0 && ctx_.seg_count <= 255) {
state_ = ParseState::PARSE_SEGMENTS;
ctx_.bytes_needed = ctx_.seg_count;
ctx_.data_offset = 0;
} else if (ctx_.seg_count == 0) {
// 没有段,直接跳到下一个页面
state_ = ParseState::FIND_PAGE;
ctx_.bytes_needed = 4;
ctx_.data_offset = 0;
} else {
ESP_LOGE(TAG, "无效的段数: %u", ctx_.seg_count);
state_ = ParseState::FIND_PAGE;
ctx_.bytes_needed = 4;
ctx_.data_offset = 0;
}
}
break;
}
case ParseState::PARSE_SEGMENTS: {
size_t available = size - processed;
if (available < ctx_.bytes_needed) {
memcpy(ctx_.seg_table + ctx_.data_offset,
data + processed, available);
ctx_.data_offset += available;
ctx_.bytes_needed -= available;
processed += available;
return processed; // 等待更多数据
} else {
size_t to_copy = ctx_.bytes_needed;
memcpy(ctx_.seg_table + ctx_.data_offset,
data + processed, to_copy);
processed += to_copy;
ctx_.data_offset += to_copy;
ctx_.bytes_needed = 0;
state_ = ParseState::PARSE_DATA;
ctx_.seg_index = 0;
ctx_.data_offset = 0;
// 计算数据体总大小
ctx_.body_size = 0;
for (size_t i = 0; i < ctx_.seg_count; ++i) {
ctx_.body_size += ctx_.seg_table[i];
}
ctx_.body_offset = 0;
ctx_.seg_remaining = 0;
}
break;
}
case ParseState::PARSE_DATA: {
while (ctx_.seg_index < ctx_.seg_count && processed < size) {
uint8_t seg_len = ctx_.seg_table[ctx_.seg_index];
// 检查段数据是否已经部分读取
if (ctx_.seg_remaining > 0) {
seg_len = ctx_.seg_remaining;
} else {
ctx_.seg_remaining = seg_len;
}
// 检查缓冲区是否足够
if (ctx_.packet_len + seg_len > sizeof(ctx_.packet_buf)) {
ESP_LOGE(TAG, "包缓冲区溢出: %zu + %u > %zu", ctx_.packet_len, seg_len, sizeof(ctx_.packet_buf));
state_ = ParseState::FIND_PAGE;
ctx_.packet_len = 0;
ctx_.packet_continued = false;
ctx_.seg_remaining = 0;
ctx_.bytes_needed = 4;
return processed;
}
// 复制数据
size_t to_copy = std::min(size - processed, (size_t)seg_len);
memcpy(ctx_.packet_buf + ctx_.packet_len, data + processed, to_copy);
processed += to_copy;
ctx_.packet_len += to_copy;
ctx_.body_offset += to_copy;
ctx_.seg_remaining -= to_copy;
// 检查段是否完整
if (ctx_.seg_remaining > 0) {
// 段不完整,等待更多数据
return processed;
}
// 段完整
bool seg_continued = (ctx_.seg_table[ctx_.seg_index] == 255);
if (!seg_continued) {
// 包结束
if (ctx_.packet_len) {
if (!opus_info_.head_seen) {
if (ctx_.packet_len >=8 && memcmp(ctx_.packet_buf, "OpusHead", 8) == 0) {
opus_info_.head_seen = true;
if (ctx_.packet_len >= 19) {
opus_info_.sample_rate = ctx_.packet_buf[12] |
(ctx_.packet_buf[13] << 8) |
(ctx_.packet_buf[14] << 16) |
(ctx_.packet_buf[15] << 24);
ESP_LOGI(TAG, "OpusHead found, sample_rate=%d", opus_info_.sample_rate);
}
ctx_.packet_len = 0;
ctx_.packet_continued = false;
ctx_.seg_index++;
ctx_.seg_remaining = 0;
continue;
}
}
if (!opus_info_.tags_seen) {
if (ctx_.packet_len >= 8 && memcmp(ctx_.packet_buf, "OpusTags", 8) == 0) {
opus_info_.tags_seen = true;
ESP_LOGI(TAG, "OpusTags found.");
ctx_.packet_len = 0;
ctx_.packet_continued = false;
ctx_.seg_index++;
ctx_.seg_remaining = 0;
continue;
}
}
if (opus_info_.head_seen && opus_info_.tags_seen) {
if (on_demuxer_finished_) {
on_demuxer_finished_(ctx_.packet_buf, opus_info_.sample_rate, ctx_.packet_len);
}
} else {
ESP_LOGW(TAG, "当前Ogg容器未解析到OpusHead/OpusTags丢弃");
}
}
ctx_.packet_len = 0;
ctx_.packet_continued = false;
} else {
ctx_.packet_continued = true;
}
ctx_.seg_index++;
ctx_.seg_remaining = 0;
}
if (ctx_.seg_index == ctx_.seg_count) {
// 检查是否所有数据体都已读取
if (ctx_.body_offset < ctx_.body_size) {
ESP_LOGW(TAG, "数据体不完整: %zu/%zu",
ctx_.body_offset, ctx_.body_size);
}
// 如果包跨页保持packet_len和packet_continued
if (!ctx_.packet_continued) {
ctx_.packet_len = 0;
}
// 进入下一页面
state_ = ParseState::FIND_PAGE;
ctx_.bytes_needed = 4;
ctx_.data_offset = 0;
}
break;
}
}
}
return processed;
}

View File

@@ -0,0 +1,63 @@
#ifndef OGG_DEMUXER_H_
#define OGG_DEMUXER_H_
#include <functional>
#include <cstdint>
#include <cstring>
#include <vector>
class OggDemuxer {
private:
enum ParseState : int8_t {
FIND_PAGE,
PARSE_HEADER,
PARSE_SEGMENTS,
PARSE_DATA
};
struct Opus_t {
bool head_seen{false};
bool tags_seen{false};
int sample_rate{48000};
};
// 使用固定大小的缓冲区避免动态分配
struct context_t {
bool packet_continued{false}; // 当前包是否跨多个段
uint8_t header[27]; // Ogg页头
uint8_t seg_table[255]; // 当前存储的段表
uint8_t packet_buf[8192]; // 8KB包缓冲区
size_t packet_len = 0; // 缓冲区中累计的数据长度
size_t seg_count = 0; // 当前页段数
size_t seg_index = 0; // 当前处理的段索引
size_t data_offset = 0; // 解析当前阶段已读取的字节数
size_t bytes_needed = 0; // 解析当前字段还需要读取的字节数
size_t seg_remaining = 0; // 当前段剩余需要读取的字节数
size_t body_size = 0; // 数据体总大小
size_t body_offset = 0; // 数据体已读取的字节数
};
public:
OggDemuxer() {
Reset();
}
void Reset();
size_t Process(const uint8_t* data, size_t size);
/// @brief 设置解封装完毕后回调处理函数
/// @param on_demuxer_finished
void OnDemuxerFinished(std::function<void(const uint8_t* data, int sample_rate, size_t len)> on_demuxer_finished) {
on_demuxer_finished_ = on_demuxer_finished;
}
private:
ParseState state_ = ParseState::FIND_PAGE;
context_t ctx_;
Opus_t opus_info_;
std::function<void(const uint8_t*, int, size_t)> on_demuxer_finished_;
};
#endif

View File

@@ -92,7 +92,18 @@ void AfeAudioProcessor::Feed(std::vector<int16_t>&& data) {
if (afe_data_ == nullptr) {
return;
}
afe_iface_->feed(afe_data_, data.data());
std::lock_guard<std::mutex> lock(input_buffer_mutex_);
// Check running state inside lock to avoid TOCTOU race with Stop()
if (!IsRunning()) {
return;
}
input_buffer_.insert(input_buffer_.end(), data.begin(), data.end());
size_t chunk_size = afe_iface_->get_feed_chunksize(afe_data_) * codec_->input_channels();
while (input_buffer_.size() >= chunk_size) {
afe_iface_->feed(afe_data_, input_buffer_.data());
input_buffer_.erase(input_buffer_.begin(), input_buffer_.begin() + chunk_size);
}
}
void AfeAudioProcessor::Start() {
@@ -101,9 +112,12 @@ void AfeAudioProcessor::Start() {
void AfeAudioProcessor::Stop() {
xEventGroupClearBits(event_group_, PROCESSOR_RUNNING);
std::lock_guard<std::mutex> lock(input_buffer_mutex_);
if (afe_data_ != nullptr) {
afe_iface_->reset_buffer(afe_data_);
}
input_buffer_.clear();
}
bool AfeAudioProcessor::IsRunning() {

View File

@@ -9,6 +9,7 @@
#include <string>
#include <vector>
#include <functional>
#include <mutex>
#include "audio_processor.h"
#include "audio_codec.h"
@@ -37,6 +38,8 @@ private:
AudioCodec* codec_ = nullptr;
int frame_samples_ = 0;
bool is_speaking_ = false;
std::vector<int16_t> input_buffer_;
std::mutex input_buffer_mutex_;
std::vector<int16_t> output_buffer_;
void AudioProcessorTask();

View File

@@ -3,6 +3,7 @@
#include <vector>
#include <functional>
#include <atomic>
#include "audio_processor.h"
#include "audio_codec.h"
@@ -27,7 +28,7 @@ private:
int frame_samples_ = 0;
std::function<void(std::vector<int16_t>&& data)> output_callback_;
std::function<void(bool speaking)> vad_state_change_callback_;
bool is_running_ = false;
std::atomic<bool> is_running_ = false;
};
#endif

View File

@@ -99,19 +99,30 @@ void AfeWakeWord::Start() {
void AfeWakeWord::Stop() {
xEventGroupClearBits(event_group_, DETECTION_RUNNING_EVENT);
std::lock_guard<std::mutex> lock(input_buffer_mutex_);
if (afe_data_ != nullptr) {
afe_iface_->reset_buffer(afe_data_);
}
input_buffer_.clear();
}
void AfeWakeWord::Feed(const std::vector<int16_t>& data) {
if (afe_data_ == nullptr) {
return;
}
std::lock_guard<std::mutex> lock(input_buffer_mutex_);
// Check running state inside lock to avoid TOCTOU race with Stop()
if (!(xEventGroupGetBits(event_group_) & DETECTION_RUNNING_EVENT)) {
return;
}
afe_iface_->feed(afe_data_, data.data());
input_buffer_.insert(input_buffer_.end(), data.begin(), data.end());
size_t chunk_size = afe_iface_->get_feed_chunksize(afe_data_) * codec_->input_channels();
while (input_buffer_.size() >= chunk_size) {
afe_iface_->feed(afe_data_, input_buffer_.data());
input_buffer_.erase(input_buffer_.begin(), input_buffer_.begin() + chunk_size);
}
}
size_t AfeWakeWord::GetFeedSize() {

View File

@@ -44,6 +44,8 @@ private:
std::function<void(const std::string& wake_word)> wake_word_detected_callback_;
AudioCodec* codec_ = nullptr;
std::string last_detected_wake_word_;
std::vector<int16_t> input_buffer_;
std::mutex input_buffer_mutex_;
TaskHandle_t wake_word_encode_task_ = nullptr;
StaticTask_t* wake_word_encode_task_buffer_ = nullptr;

View File

@@ -138,49 +138,64 @@ void CustomWakeWord::Start() {
void CustomWakeWord::Stop() {
running_ = false;
std::lock_guard<std::mutex> lock(input_buffer_mutex_);
input_buffer_.clear();
}
void CustomWakeWord::Feed(const std::vector<int16_t>& data) {
if (multinet_model_data_ == nullptr || !running_) {
if (multinet_model_data_ == nullptr) {
return;
}
std::lock_guard<std::mutex> lock(input_buffer_mutex_);
// Check running state inside lock to avoid TOCTOU race with Stop()
if (!running_) {
return;
}
esp_mn_state_t mn_state;
// If input channels is 2, we need to fetch the left channel data
if (codec_->input_channels() == 2) {
auto mono_data = std::vector<int16_t>(data.size() / 2);
for (size_t i = 0, j = 0; i < mono_data.size(); ++i, j += 2) {
mono_data[i] = data[j];
for (size_t i = 0; i < data.size(); i += 2) {
input_buffer_.push_back(data[i]);
}
StoreWakeWordData(mono_data);
mn_state = multinet_->detect(multinet_model_data_, const_cast<int16_t*>(mono_data.data()));
} else {
StoreWakeWordData(data);
mn_state = multinet_->detect(multinet_model_data_, const_cast<int16_t*>(data.data()));
input_buffer_.insert(input_buffer_.end(), data.begin(), data.end());
}
if (mn_state == ESP_MN_STATE_DETECTING) {
return;
} else if (mn_state == ESP_MN_STATE_DETECTED) {
esp_mn_results_t *mn_result = multinet_->get_results(multinet_model_data_);
for (int i = 0; i < mn_result->num && running_; i++) {
ESP_LOGI(TAG, "Custom wake word detected: command_id=%d, string=%s, prob=%f",
mn_result->command_id[i], mn_result->string, mn_result->prob[i]);
auto& command = commands_[mn_result->command_id[i] - 1];
if (command.action == "wake") {
last_detected_wake_word_ = command.text;
running_ = false;
if (wake_word_detected_callback_) {
wake_word_detected_callback_(last_detected_wake_word_);
int chunksize = multinet_->get_samp_chunksize(multinet_model_data_);
while (input_buffer_.size() >= chunksize) {
std::vector<int16_t> chunk(input_buffer_.begin(), input_buffer_.begin() + chunksize);
StoreWakeWordData(chunk);
esp_mn_state_t mn_state = multinet_->detect(multinet_model_data_, chunk.data());
if (mn_state == ESP_MN_STATE_DETECTED) {
esp_mn_results_t *mn_result = multinet_->get_results(multinet_model_data_);
for (int i = 0; i < mn_result->num && running_; i++) {
ESP_LOGI(TAG, "Custom wake word detected: command_id=%d, string=%s, prob=%f",
mn_result->command_id[i], mn_result->string, mn_result->prob[i]);
auto& command = commands_[mn_result->command_id[i] - 1];
if (command.action == "wake") {
last_detected_wake_word_ = command.text;
running_ = false;
input_buffer_.clear();
if (wake_word_detected_callback_) {
wake_word_detected_callback_(last_detected_wake_word_);
}
}
}
multinet_->clean(multinet_model_data_);
} else if (mn_state == ESP_MN_STATE_TIMEOUT) {
ESP_LOGD(TAG, "Command word detection timeout, cleaning state");
multinet_->clean(multinet_model_data_);
}
multinet_->clean(multinet_model_data_);
} else if (mn_state == ESP_MN_STATE_TIMEOUT) {
ESP_LOGD(TAG, "Command word detection timeout, cleaning state");
multinet_->clean(multinet_model_data_);
if (!running_) {
break;
}
input_buffer_.erase(input_buffer_.begin(), input_buffer_.begin() + chunksize);
}
}

View File

@@ -53,6 +53,8 @@ private:
AudioCodec* codec_ = nullptr;
std::string last_detected_wake_word_;
std::atomic<bool> running_ = false;
std::vector<int16_t> input_buffer_;
std::mutex input_buffer_mutex_;
TaskHandle_t wake_word_encode_task_ = nullptr;
StaticTask_t* wake_word_encode_task_buffer_ = nullptr;

View File

@@ -54,21 +54,44 @@ void EspWakeWord::Start() {
void EspWakeWord::Stop() {
running_ = false;
std::lock_guard<std::mutex> lock(input_buffer_mutex_);
input_buffer_.clear();
}
void EspWakeWord::Feed(const std::vector<int16_t>& data) {
if (wakenet_data_ == nullptr || !running_) {
if (wakenet_data_ == nullptr) {
return;
}
int res = wakenet_iface_->detect(wakenet_data_, (int16_t *)data.data());
if (res > 0) {
last_detected_wake_word_ = wakenet_iface_->get_word_name(wakenet_data_, res);
running_ = false;
std::lock_guard<std::mutex> lock(input_buffer_mutex_);
// Check running state inside lock to avoid TOCTOU race with Stop()
if (!running_) {
return;
}
if (wake_word_detected_callback_) {
wake_word_detected_callback_(last_detected_wake_word_);
if (codec_->input_channels() == 2) {
for (size_t i = 0; i < data.size(); i += 2) {
input_buffer_.push_back(data[i]);
}
} else {
input_buffer_.insert(input_buffer_.end(), data.begin(), data.end());
}
int chunksize = wakenet_iface_->get_samp_chunksize(wakenet_data_);
while (input_buffer_.size() >= chunksize) {
int res = wakenet_iface_->detect(wakenet_data_, input_buffer_.data());
if (res > 0) {
last_detected_wake_word_ = wakenet_iface_->get_word_name(wakenet_data_, res);
running_ = false;
input_buffer_.clear();
if (wake_word_detected_callback_) {
wake_word_detected_callback_(last_detected_wake_word_);
}
break;
}
input_buffer_.erase(input_buffer_.begin(), input_buffer_.begin() + chunksize);
}
}

View File

@@ -9,6 +9,7 @@
#include <vector>
#include <functional>
#include <atomic>
#include <mutex>
#include "audio_codec.h"
#include "wake_word.h"
@@ -37,6 +38,8 @@ private:
std::function<void(const std::string& wake_word)> wake_word_detected_callback_;
std::string last_detected_wake_word_;
std::vector<int16_t> input_buffer_;
std::mutex input_buffer_mutex_;
};
#endif

View File

@@ -106,6 +106,10 @@ private:
InitializeGc9107Display();
InitializeButtons();
GetBacklight()->SetBrightness(100);
// Ensure UI is set up before displaying error
display_->SetupUI();
display_->SetStatus(Lang::Strings::ERROR);
display_->SetEmotion("triangle_exclamation");
display_->SetChatMessage("system", "Echo Base\nnot connected");

View File

@@ -173,6 +173,10 @@ private:
InitializeGc9107Display();
InitializeButtons();
GetBacklight()->SetBrightness(100);
// Ensure UI is set up before displaying error
display_->SetupUI();
display_->SetStatus(Lang::Strings::ERROR);
display_->SetEmotion("triangle_exclamation");
display_->SetChatMessage("system", "Echo Base\nnot connected");

View File

@@ -24,26 +24,6 @@ idf.py menuconfig
Xiaozhi Assistant -> Board Type ->面包板新版接线WiFi+ LCD + Camera
```
**配置摄像头传感器:**
> **注意:** 确认摄像头传感器型号,确定型号在 esp_cam_sensor 支持的范围内。当前板子用的是 OV2640是符合支持范围。
在 menuconfig 中按以下步骤启用对应型号的支持:
1. **导航到传感器配置:**
```
(Top) → Component config → Espressif Camera Sensors Configurations → Camera Sensor Configuration → Select and Set Camera Sensor
```
2. **选择传感器型号:**
- 选中所需的传感器型号OV2640
3. **配置传感器参数:**
- 按 → 进入传感器详细设置
- 启用 **Auto detect**
- 推荐将 **default output format** 调整为 **YUV422** 及合适的分辨率大小
- (目前支持 YUV422、RGB565YUV422 更节省内存空间)
**编译烧入:**
```bash

View File

@@ -8,7 +8,7 @@
#include "mcp_server.h"
#include "lamp_controller.h"
#include "led/single_led.h"
#include "esp_video.h"
#include "esp32_camera.h"
#include <esp_log.h>
#include <driver/i2c_master.h>
@@ -65,7 +65,7 @@ private:
Button boot_button_;
LcdDisplay* display_;
EspVideo* camera_;
Esp32Camera* camera_;
void InitializeSpi() {
spi_bus_config_t buscfg = {};
@@ -125,47 +125,32 @@ private:
}
void InitializeCamera() {
static esp_cam_ctlr_dvp_pin_config_t dvp_pin_config = {
.data_width = CAM_CTLR_DATA_WIDTH_8,
.data_io = {
[0] = CAMERA_PIN_D0,
[1] = CAMERA_PIN_D1,
[2] = CAMERA_PIN_D2,
[3] = CAMERA_PIN_D3,
[4] = CAMERA_PIN_D4,
[5] = CAMERA_PIN_D5,
[6] = CAMERA_PIN_D6,
[7] = CAMERA_PIN_D7,
},
.vsync_io = CAMERA_PIN_VSYNC,
.de_io = CAMERA_PIN_HREF,
.pclk_io = CAMERA_PIN_PCLK,
.xclk_io = CAMERA_PIN_XCLK,
};
esp_video_init_sccb_config_t sccb_config = {
.init_sccb = true,
.i2c_config = {
.port = 0,
.scl_pin = CAMERA_PIN_SIOC,
.sda_pin = CAMERA_PIN_SIOD,
},
.freq = 100000,
};
esp_video_init_dvp_config_t dvp_config = {
.sccb_config = sccb_config,
.reset_pin = CAMERA_PIN_RESET,
.pwdn_pin = CAMERA_PIN_PWDN,
.dvp_pin = dvp_pin_config,
.xclk_freq = XCLK_FREQ_HZ,
};
esp_video_init_config_t video_config = {
.dvp = &dvp_config,
};
camera_ = new EspVideo(video_config);
camera_config_t config = {};
config.pin_d0 = CAMERA_PIN_D0;
config.pin_d1 = CAMERA_PIN_D1;
config.pin_d2 = CAMERA_PIN_D2;
config.pin_d3 = CAMERA_PIN_D3;
config.pin_d4 = CAMERA_PIN_D4;
config.pin_d5 = CAMERA_PIN_D5;
config.pin_d6 = CAMERA_PIN_D6;
config.pin_d7 = CAMERA_PIN_D7;
config.pin_xclk = CAMERA_PIN_XCLK;
config.pin_pclk = CAMERA_PIN_PCLK;
config.pin_vsync = CAMERA_PIN_VSYNC;
config.pin_href = CAMERA_PIN_HREF;
config.pin_sccb_sda = CAMERA_PIN_SIOD;
config.pin_sccb_scl = CAMERA_PIN_SIOC;
config.sccb_i2c_port = 0;
config.pin_pwdn = CAMERA_PIN_PWDN;
config.pin_reset = CAMERA_PIN_RESET;
config.xclk_freq_hz = XCLK_FREQ_HZ;
config.pixel_format = PIXFORMAT_RGB565;
config.frame_size = FRAMESIZE_VGA;
config.jpeg_quality = 12;
config.fb_count = 1;
config.fb_location = CAMERA_FB_IN_PSRAM;
config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
camera_ = new Esp32Camera(config);
camera_->SetHMirror(false);
}

View File

@@ -152,6 +152,8 @@ void K10AudioCodec::CreateDuplexChannels(gpio_num_t mclk, gpio_num_t bclk, gpio_
ESP_ERROR_CHECK(i2s_channel_init_std_mode(tx_handle_, &std_cfg));
ESP_ERROR_CHECK(i2s_channel_init_tdm_mode(rx_handle_, &tdm_cfg));
ESP_ERROR_CHECK(i2s_channel_enable(tx_handle_));
ESP_ERROR_CHECK(i2s_channel_enable(rx_handle_));
ESP_LOGI(TAG, "Duplex channels created");
}

View File

@@ -15,17 +15,28 @@
ElectronEmojiDisplay::ElectronEmojiDisplay(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_handle_t panel, int width, int height, int offset_x, int offset_y, bool mirror_x, bool mirror_y,
bool swap_xy)
: SpiLcdDisplay(panel_io, panel, width, height, offset_x, offset_y, mirror_x, mirror_y, swap_xy) {
InitializeElectronEmojis();
SetupChatLabel();
}
void ElectronEmojiDisplay::SetupUI() {
// Prevent duplicate calls - parent SetupUI() will also check, but check here for early return
if (setup_ui_called_) {
ESP_LOGW(TAG, "SetupUI() called multiple times, skipping duplicate call");
return;
}
// Call parent SetupUI() first to create all lvgl objects
SpiLcdDisplay::SetupUI();
// Set default emotion after UI is initialized
SetEmotion("staticstate");
}
void ElectronEmojiDisplay::InitializeElectronEmojis() {
ESP_LOGI(TAG, "Electron表情初始化将由Assets系统处理");
// 表情初始化已移至assets系统,通过DEFAULT_EMOJI_COLLECTION=otto-gif配置
// assets.cc会从assets分区加载GIF表情并设置到theme
// 设置默认表情为staticstate
SetEmotion("staticstate");
// Note: Default emotion is now set in SetupUI() after LVGL objects are created
}
void ElectronEmojiDisplay::SetupChatLabel() {

View File

@@ -15,6 +15,7 @@ class ElectronEmojiDisplay : public SpiLcdDisplay {
virtual ~ElectronEmojiDisplay() = default;
virtual void SetStatus(const char* status) override;
virtual void SetupUI() override;
private:
void InitializeElectronEmojis();

View File

@@ -165,6 +165,8 @@ void BoxAudioCodecLite::CreateDuplexChannels(gpio_num_t mclk, gpio_num_t bclk, g
ESP_ERROR_CHECK(i2s_channel_init_std_mode(tx_handle_, &std_cfg));
ESP_ERROR_CHECK(i2s_channel_init_tdm_mode(rx_handle_, &tdm_cfg));
ESP_ERROR_CHECK(i2s_channel_enable(tx_handle_));
ESP_ERROR_CHECK(i2s_channel_enable(rx_handle_));
ESP_LOGI(TAG, "Duplex channels created");
}

View File

@@ -81,6 +81,7 @@ AdcPdmAudioCodec::AdcPdmAudioCodec(int input_sample_rate, int output_sample_rate
const i2s_pdm_tx_config_t *p_i2s_cfg = &pdm_cfg_default;
ESP_ERROR_CHECK(i2s_channel_init_pdm_tx_mode(tx_handle_, p_i2s_cfg));
ESP_ERROR_CHECK(i2s_channel_enable(tx_handle_));
audio_codec_i2s_cfg_t i2s_cfg = {
.port = I2S_NUM_0,

View File

@@ -81,6 +81,7 @@ AdcPdmAudioCodec::AdcPdmAudioCodec(int input_sample_rate, int output_sample_rate
const i2s_pdm_tx_config_t *p_i2s_cfg = &pdm_cfg_default;
ESP_ERROR_CHECK(i2s_channel_init_pdm_tx_mode(tx_handle_, p_i2s_cfg));
ESP_ERROR_CHECK(i2s_channel_enable(tx_handle_));
audio_codec_i2s_cfg_t i2s_cfg = {
.port = I2S_NUM_0,

View File

@@ -21,4 +21,19 @@
2. 关闭设备电源后,长按电源键不松手;
3. 在烧录工具中选择对应的串口COM Port
4. 点击烧录按钮,选择 UART 模式;
5. 烧录完成前请勿松开电源键。
5. 烧录完成前请勿松开电源键。
## 引脚
- 1-9
- 1. DAT2 NC
- 2. CD/DAT3 片选,低电平有效。(未知)
- 3. CMD IO48Command/Response Line主机通过此线向TF卡发送命令和数据
- 4. VDD 供电
- 5. CLX IO47时钟由主机产生同步数据通信
- 6. VSS GND
- 7. DAT0 IO21SPI_MISOTF卡通过此线向主机返回响应和数据
- 8. DAT1 NC
依次为从右向左为1-9

View File

@@ -37,7 +37,7 @@
#define DISPLAY_SPI_CS_PIN GPIO_NUM_9
#define DISPLAY_WIDTH 240
#define DISPLAY_HEIGHT 320
#define DISPLAY_HEIGHT 296
#define DISPLAY_MIRROR_X true
#define DISPLAY_MIRROR_Y false
#define DISPLAY_SWAP_XY false

View File

@@ -39,10 +39,23 @@ public:
bool swap_xy)
: SpiLcdDisplay(io_handle, panel_handle, width, height, offset_x, offset_y, mirror_x, mirror_y, swap_xy)
{
// Note: UI customization should be done in SetupUI(), not in constructor
// to ensure lvgl objects are created before accessing them
}
virtual void SetupUI() override {
// Call parent SetupUI() first to create all lvgl objects
SpiLcdDisplay::SetupUI();
DisplayLockGuard lock(this);
lv_obj_set_style_pad_left(status_bar_, LV_HOR_RES * 0.167, 0);
lv_obj_set_style_pad_right(status_bar_, LV_HOR_RES * 0.167, 0);
// 状态栏容器适配
lv_obj_set_style_pad_left(top_bar_, LV_HOR_RES * 0.12, 0); // 左侧填充12%
lv_obj_set_style_pad_right(top_bar_, LV_HOR_RES * 0.12, 0); // 右侧填充12%
// 表情容器上移适配
lv_obj_align(emoji_box_, LV_ALIGN_CENTER, 0, -30); // 向上偏移30
// 消息栏适配
lv_obj_align(bottom_bar_, LV_ALIGN_BOTTOM_MID, 0, -20); // 向上偏移20
}
};

View File

@@ -230,7 +230,7 @@ private:
config.pin_reset = CAMERA_PIN_RESET;
config.xclk_freq_hz = XCLK_FREQ_HZ;
config.pixel_format = PIXFORMAT_RGB565;
config.frame_size = FRAMESIZE_VGA;
config.frame_size = FRAMESIZE_QVGA;
config.jpeg_quality = 12;
config.fb_count = 1;
config.fb_location = CAMERA_FB_IN_PSRAM;

View File

@@ -177,6 +177,8 @@ void CoreS3AudioCodec::CreateDuplexChannels(gpio_num_t mclk, gpio_num_t bclk, gp
ESP_ERROR_CHECK(i2s_channel_init_std_mode(tx_handle_, &std_cfg));
ESP_ERROR_CHECK(i2s_channel_init_tdm_mode(rx_handle_, &tdm_cfg));
ESP_ERROR_CHECK(i2s_channel_enable(tx_handle_));
ESP_ERROR_CHECK(i2s_channel_enable(rx_handle_));
ESP_LOGI(TAG, "Duplex channels created");
}

View File

@@ -176,6 +176,8 @@ void Tab5AudioCodec::CreateDuplexChannels(gpio_num_t mclk, gpio_num_t bclk, gpio
ESP_ERROR_CHECK(i2s_channel_init_std_mode(tx_handle_, &std_cfg));
ESP_ERROR_CHECK(i2s_channel_init_tdm_mode(rx_handle_, &tdm_cfg));
ESP_ERROR_CHECK(i2s_channel_enable(tx_handle_));
ESP_ERROR_CHECK(i2s_channel_enable(rx_handle_));
ESP_LOGI(TAG, "Duplex channels created");
}

View File

@@ -31,6 +31,13 @@ public:
bool mirror_y,
bool swap_xy)
: SpiLcdDisplay(io_handle, panel_handle, width, height, offset_x, offset_y, mirror_x, mirror_y, swap_xy) {
// Note: UI customization should be done in SetupUI(), not in constructor
// to ensure lvgl objects are created before accessing them
}
virtual void SetupUI() override {
// Call parent SetupUI() first to create all lvgl objects
SpiLcdDisplay::SetupUI();
DisplayLockGuard lock(this);
// 由于屏幕是圆的,所以状态栏需要增加左右内边距

View File

@@ -14,13 +14,33 @@
#define TAG "OttoEmojiDisplay"
OttoEmojiDisplay::OttoEmojiDisplay(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_handle_t panel, int width, int height, int offset_x, int offset_y, bool mirror_x, bool mirror_y, bool swap_xy)
: SpiLcdDisplay(panel_io, panel, width, height, offset_x, offset_y, mirror_x, mirror_y, swap_xy) {
InitializeOttoEmojis();
SetupPreviewImage();
SetTheme(LvglThemeManager::GetInstance().GetTheme("dark"));
}
void OttoEmojiDisplay::SetupUI() {
// Prevent duplicate calls - parent SetupUI() will also check, but check here for early return
if (setup_ui_called_) {
ESP_LOGW(TAG, "SetupUI() called multiple times, skipping duplicate call");
return;
}
// Call parent SetupUI() first to create all lvgl objects
SpiLcdDisplay::SetupUI();
// Setup preview image after UI is initialized
DisplayLockGuard lock(this);
lv_obj_set_size(preview_image_, width_ , height_ );
// Set default emotion after UI is initialized
SetEmotion("staticstate");
}
void OttoEmojiDisplay::SetupPreviewImage() {
DisplayLockGuard lock(this);
if (preview_image_ == nullptr) {
ESP_LOGW(TAG, "SetupPreviewImage called but preview_image_ is nullptr (UI not initialized yet)");
return;
}
lv_obj_set_size(preview_image_, width_ , height_ );
}
@@ -28,9 +48,7 @@ void OttoEmojiDisplay::InitializeOttoEmojis() {
ESP_LOGI(TAG, "Otto表情初始化将由Assets系统处理");
// 表情初始化已移至assets系统,通过DEFAULT_EMOJI_COLLECTION=otto-gif配置
// assets.cc会从assets分区加载GIF表情并设置到theme
// 设置默认表情为staticstate
SetEmotion("staticstate");
// Note: Default emotion is now set in SetupUI() after LVGL objects are created
}
LV_FONT_DECLARE(OTTO_ICON_FONT);

View File

@@ -16,6 +16,7 @@ class OttoEmojiDisplay : public SpiLcdDisplay {
virtual ~OttoEmojiDisplay() = default;
virtual void SetStatus(const char* status) override;
virtual void SetPreviewImage(std::unique_ptr<LvglImage> image) override;
virtual void SetupUI() override;
private:
void InitializeOttoEmojis();

View File

@@ -143,6 +143,8 @@ void SensecapAudioCodec::CreateDuplexChannels(gpio_num_t mclk, gpio_num_t bclk,
std_cfg.slot_cfg.slot_mask = I2S_STD_SLOT_RIGHT;
ESP_ERROR_CHECK(i2s_channel_init_std_mode(rx_handle_, &std_cfg));
ESP_ERROR_CHECK(i2s_channel_enable(tx_handle_));
ESP_ERROR_CHECK(i2s_channel_enable(rx_handle_));
ESP_LOGI(TAG, "Duplex channels created");
}

View File

@@ -45,7 +45,14 @@ class CustomLcdDisplay : public SpiLcdDisplay {
bool mirror_y,
bool swap_xy)
: SpiLcdDisplay(io_handle, panel_handle, width, height, offset_x, offset_y, mirror_x, mirror_y, swap_xy) {
// Note: UI customization should be done in SetupUI(), not in constructor
// to ensure lvgl objects are created before accessing them
}
virtual void SetupUI() override {
// Call parent SetupUI() first to create all lvgl objects
SpiLcdDisplay::SetupUI();
DisplayLockGuard lock(this);
auto lvgl_theme = static_cast<LvglTheme*>(current_theme_);
auto text_font = lvgl_theme->text_font()->font();

View File

@@ -115,6 +115,13 @@ public:
bool mirror_y,
bool swap_xy)
: SpiLcdDisplay(io_handle, panel_handle, width, height, offset_x, offset_y, mirror_x, mirror_y, swap_xy) {
// Note: UI customization should be done in SetupUI(), not in constructor
// to ensure lvgl objects are created before accessing them
}
virtual void SetupUI() override {
// Call parent SetupUI() first to create all lvgl objects
SpiLcdDisplay::SetupUI();
DisplayLockGuard lock(this);
// 由于屏幕是圆的,所以状态栏需要增加左右内边距

View File

@@ -1,12 +0,0 @@
# Waveshare ESP32-P4-WIFI6-Touch-LCD-4B
[ESP32-P4-WIFI6-Touch-LCD-4B](https://www.waveshare.com/esp32-p4-wifi6-touch-lcd-4b.htm) is waveshare electronics designed an intelligent 86 box based on ESP32-P4 module equipped with a 720*720 IPS capacitive touch screen
## Configuration
Configuration in `menuconfig`.
Selection Board Type `Xiaozhi Assistant --> Board Type`
- Waveshare ESP32-P4-WIFI6-Touch-LCD-4B

View File

@@ -1,47 +0,0 @@
#ifndef _BOARD_CONFIG_H_
#define _BOARD_CONFIG_H_
#include <driver/gpio.h>
#define AUDIO_INPUT_SAMPLE_RATE 24000
#define AUDIO_OUTPUT_SAMPLE_RATE 24000
#define AUDIO_INPUT_REFERENCE true
#define AUDIO_I2S_GPIO_MCLK GPIO_NUM_13
#define AUDIO_I2S_GPIO_WS GPIO_NUM_10
#define AUDIO_I2S_GPIO_BCLK GPIO_NUM_12
#define AUDIO_I2S_GPIO_DIN GPIO_NUM_11
#define AUDIO_I2S_GPIO_DOUT GPIO_NUM_9
#define AUDIO_CODEC_PA_PIN GPIO_NUM_53
#define AUDIO_CODEC_I2C_SDA_PIN GPIO_NUM_7
#define AUDIO_CODEC_I2C_SCL_PIN GPIO_NUM_8
#define AUDIO_CODEC_ES8311_ADDR ES8311_CODEC_DEFAULT_ADDR
#define AUDIO_CODEC_ES7210_ADDR ES7210_CODEC_DEFAULT_ADDR
#define BOOT_BUTTON_GPIO GPIO_NUM_35
#define DISPLAY_WIDTH 720
#define DISPLAY_HEIGHT 720
#define LCD_BIT_PER_PIXEL (16)
#define PIN_NUM_LCD_RST GPIO_NUM_27
#define DELAY_TIME_MS (3000)
#define LCD_MIPI_DSI_LANE_NUM (2) // 2 data lanes
#define MIPI_DSI_PHY_PWR_LDO_CHAN (3)
#define MIPI_DSI_PHY_PWR_LDO_VOLTAGE_MV (2500)
#define DISPLAY_SWAP_XY false
#define DISPLAY_MIRROR_X false
#define DISPLAY_MIRROR_Y false
#define DISPLAY_OFFSET_X 0
#define DISPLAY_OFFSET_Y 0
#define DISPLAY_BACKLIGHT_PIN GPIO_NUM_26
#define DISPLAY_BACKLIGHT_OUTPUT_INVERT true
#endif // _BOARD_CONFIG_H_

View File

@@ -1,16 +0,0 @@
{
"target": "esp32p4",
"builds": [
{
"name": "waveshare-p4-wifi6-touch-lcd-4b",
"sdkconfig_append": [
"CONFIG_USE_WECHAT_MESSAGE_STYLE=n",
"CONFIG_USE_DEVICE_AEC=y",
"CONFIG_CAMERA_OV5647=y",
"CONFIG_CAMERA_OV5647_AUTO_DETECT_MIPI_INTERFACE_SENSOR=y",
"CONFIG_CAMERA_OV5647_MIPI_RAW8_800X800_50FPS=y",
"CONFIG_XIAOZHI_ENABLE_CAMERA_ENDIANNESS_SWAP=y"
]
}
]
}

View File

@@ -1,228 +0,0 @@
#include "wifi_board.h"
#include "codecs/box_audio_codec.h"
#include "application.h"
#include "display/lcd_display.h"
// #include "display/no_display.h"
#include "button.h"
#include "config.h"
#include "esp_video.h"
#include "esp_video_init.h"
#include "esp_cam_sensor_xclk.h"
#include "esp_lcd_panel_ops.h"
#include "esp_lcd_mipi_dsi.h"
#include "esp_ldo_regulator.h"
#include "esp_lcd_st7703.h"
#include <esp_log.h>
#include <driver/i2c_master.h>
#include <esp_lvgl_port.h>
#include "esp_lcd_touch_gt911.h"
#define TAG "WaveshareEsp32p44b"
class WaveshareEsp32p44b : public WifiBoard {
private:
i2c_master_bus_handle_t i2c_bus_;
Button boot_button_;
LcdDisplay *display_;
EspVideo* camera_ = nullptr;
void InitializeCodecI2c() {
// Initialize I2C peripheral
i2c_master_bus_config_t i2c_bus_cfg = {
.i2c_port = I2C_NUM_1,
.sda_io_num = AUDIO_CODEC_I2C_SDA_PIN,
.scl_io_num = AUDIO_CODEC_I2C_SCL_PIN,
.clk_source = I2C_CLK_SRC_DEFAULT,
.glitch_ignore_cnt = 7,
.intr_priority = 0,
.trans_queue_depth = 0,
.flags = {
.enable_internal_pullup = 1,
},
};
ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_cfg, &i2c_bus_));
}
static esp_err_t bsp_enable_dsi_phy_power(void) {
#if MIPI_DSI_PHY_PWR_LDO_CHAN > 0
// Turn on the power for MIPI DSI PHY, so it can go from "No Power" state to "Shutdown" state
static esp_ldo_channel_handle_t phy_pwr_chan = NULL;
esp_ldo_channel_config_t ldo_cfg = {
.chan_id = MIPI_DSI_PHY_PWR_LDO_CHAN,
.voltage_mv = MIPI_DSI_PHY_PWR_LDO_VOLTAGE_MV,
};
esp_ldo_acquire_channel(&ldo_cfg, &phy_pwr_chan);
ESP_LOGI(TAG, "MIPI DSI PHY Powered on");
#endif // BSP_MIPI_DSI_PHY_PWR_LDO_CHAN > 0
return ESP_OK;
}
void InitializeLCD() {
bsp_enable_dsi_phy_power();
esp_lcd_panel_io_handle_t io = NULL;
esp_lcd_panel_handle_t disp_panel = NULL;
esp_lcd_dsi_bus_handle_t mipi_dsi_bus = NULL;
esp_lcd_dsi_bus_config_t bus_config = {
.bus_id = 0,
.num_data_lanes = 2,
.lane_bit_rate_mbps = 480,
};
esp_lcd_new_dsi_bus(&bus_config, &mipi_dsi_bus);
ESP_LOGI(TAG, "Install MIPI DSI LCD control panel");
// we use DBI interface to send LCD commands and parameters
esp_lcd_dbi_io_config_t dbi_config = ST7703_PANEL_IO_DBI_CONFIG();
esp_lcd_new_panel_io_dbi(mipi_dsi_bus, &dbi_config, &io);
esp_lcd_dpi_panel_config_t dpi_config = {
.dpi_clk_src = MIPI_DSI_DPI_CLK_SRC_DEFAULT,
.dpi_clock_freq_mhz = 46,
.pixel_format = LCD_COLOR_PIXEL_FORMAT_RGB565,
.num_fbs = 1,
.video_timing = {
.h_size = 720,
.v_size = 720,
.hsync_pulse_width = 20,
.hsync_back_porch = 80,
.hsync_front_porch = 80,
.vsync_pulse_width = 4,
.vsync_back_porch = 12,
.vsync_front_porch = 30,
},
.flags = {
.use_dma2d = true,
},
};
st7703_vendor_config_t vendor_config = {
.mipi_config = {
.dsi_bus = mipi_dsi_bus,
.dpi_config = &dpi_config,
},
.flags = {
.use_mipi_interface = 1,
},
};
const esp_lcd_panel_dev_config_t lcd_dev_config = {
.reset_gpio_num = PIN_NUM_LCD_RST,
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,
.bits_per_pixel = 16,
.vendor_config = &vendor_config,
};
esp_lcd_new_panel_st7703(io, &lcd_dev_config, &disp_panel);
esp_lcd_panel_reset(disp_panel);
esp_lcd_panel_init(disp_panel);
display_ = new MipiLcdDisplay(io, disp_panel, DISPLAY_WIDTH, DISPLAY_HEIGHT,
DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY);
}
void InitializeTouch()
{
esp_lcd_touch_handle_t tp;
esp_lcd_touch_config_t tp_cfg = {
.x_max = DISPLAY_WIDTH,
.y_max = DISPLAY_HEIGHT,
.rst_gpio_num = GPIO_NUM_23,
.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;
esp_lcd_panel_io_i2c_config_t tp_io_config = ESP_LCD_TOUCH_IO_I2C_GT911_CONFIG();
tp_io_config.scl_speed_hz = 400 * 1000;
ESP_ERROR_CHECK(esp_lcd_new_panel_io_i2c(i2c_bus_, &tp_io_config, &tp_io_handle));
ESP_LOGI(TAG, "Initialize touch controller");
ESP_ERROR_CHECK(esp_lcd_touch_new_i2c_gt911(tp_io_handle, &tp_cfg, &tp));
const lvgl_port_touch_cfg_t touch_cfg = {
.disp = lv_display_get_default(),
.handle = tp,
};
lvgl_port_add_touch(&touch_cfg);
ESP_LOGI(TAG, "Touch panel initialized successfully");
}
void InitializeCamera() {
esp_video_init_csi_config_t base_csi_config = {
.sccb_config = {
.init_sccb = false,
.i2c_handle = i2c_bus_,
.freq = 400000,
},
.reset_pin = GPIO_NUM_NC,
.pwdn_pin = GPIO_NUM_NC,
};
esp_video_init_config_t cam_config = {
.csi = &base_csi_config,
};
camera_ = new EspVideo(cam_config);
}
void InitializeButtons() {
boot_button_.OnClick([this]() {
auto& app = Application::GetInstance();
// During startup (before connected), pressing BOOT button enters Wi-Fi config mode without reboot
if (app.GetDeviceState() == kDeviceStateStarting) {
EnterWifiConfigMode();
return;
}
app.ToggleChatState();
});
}
public:
WaveshareEsp32p44b() :
boot_button_(BOOT_BUTTON_GPIO) {
InitializeCodecI2c();
InitializeLCD();
InitializeTouch();
InitializeCamera();
InitializeButtons();
GetBacklight()->RestoreBrightness();
}
virtual AudioCodec* GetAudioCodec() override {
static BoxAudioCodec audio_codec(
i2c_bus_,
AUDIO_INPUT_SAMPLE_RATE,
AUDIO_OUTPUT_SAMPLE_RATE,
AUDIO_I2S_GPIO_MCLK,
AUDIO_I2S_GPIO_BCLK,
AUDIO_I2S_GPIO_WS,
AUDIO_I2S_GPIO_DOUT,
AUDIO_I2S_GPIO_DIN,
AUDIO_CODEC_PA_PIN,
AUDIO_CODEC_ES8311_ADDR,
AUDIO_CODEC_ES7210_ADDR,
AUDIO_INPUT_REFERENCE);
return &audio_codec;
}
virtual Display *GetDisplay() override {
return display_;
}
virtual Camera* GetCamera() override {
return camera_;
}
virtual Backlight* GetBacklight() override {
static PwmBacklight backlight(DISPLAY_BACKLIGHT_PIN, DISPLAY_BACKLIGHT_OUTPUT_INVERT);
return &backlight;
}
};
DECLARE_BOARD(WaveshareEsp32p44b);

View File

@@ -1,12 +0,0 @@
# Waveshare ESP32-P4-WIFI6-Touch-LCD-7B
[ESP32-P4-WIFI6-Touch-LCD-7B](https://www.waveshare.com/esp32-p4-wifi6-touch-lcd-7b.htm) is waveshare electronics designed an intelligent 86 box based on ESP32-P4 module equipped with a 1024*600 IPS capacitive touch screen
## Configuration
Configuration in `menuconfig`.
Selection Board Type `Xiaozhi Assistant --> Board Type`
- Waveshare ESP32-P4-WIFI6-Touch-LCD-7B

View File

@@ -1,47 +0,0 @@
#ifndef _BOARD_CONFIG_H_
#define _BOARD_CONFIG_H_
#include <driver/gpio.h>
#define AUDIO_INPUT_SAMPLE_RATE 24000
#define AUDIO_OUTPUT_SAMPLE_RATE 24000
#define AUDIO_INPUT_REFERENCE true
#define AUDIO_I2S_GPIO_MCLK GPIO_NUM_13
#define AUDIO_I2S_GPIO_WS GPIO_NUM_10
#define AUDIO_I2S_GPIO_BCLK GPIO_NUM_12
#define AUDIO_I2S_GPIO_DIN GPIO_NUM_11
#define AUDIO_I2S_GPIO_DOUT GPIO_NUM_9
#define AUDIO_CODEC_PA_PIN GPIO_NUM_53
#define AUDIO_CODEC_I2C_SDA_PIN GPIO_NUM_7
#define AUDIO_CODEC_I2C_SCL_PIN GPIO_NUM_8
#define AUDIO_CODEC_ES8311_ADDR ES8311_CODEC_DEFAULT_ADDR
#define AUDIO_CODEC_ES7210_ADDR ES7210_CODEC_DEFAULT_ADDR
#define BOOT_BUTTON_GPIO GPIO_NUM_35
#define DISPLAY_WIDTH 1024
#define DISPLAY_HEIGHT 600
#define LCD_BIT_PER_PIXEL (16)
#define PIN_NUM_LCD_RST GPIO_NUM_33
#define DELAY_TIME_MS (3000)
#define LCD_MIPI_DSI_LANE_NUM (2) // 2 data lanes
#define MIPI_DSI_PHY_PWR_LDO_CHAN (3)
#define MIPI_DSI_PHY_PWR_LDO_VOLTAGE_MV (2500)
#define DISPLAY_SWAP_XY false
#define DISPLAY_MIRROR_X false
#define DISPLAY_MIRROR_Y false
#define DISPLAY_OFFSET_X 0
#define DISPLAY_OFFSET_Y 0
#define DISPLAY_BACKLIGHT_PIN GPIO_NUM_32
#define DISPLAY_BACKLIGHT_OUTPUT_INVERT true
#endif // _BOARD_CONFIG_H_

View File

@@ -1,16 +0,0 @@
{
"target": "esp32p4",
"builds": [
{
"name": "waveshare-p4-wifi6-touch-lcd-7b",
"sdkconfig_append": [
"CONFIG_USE_WECHAT_MESSAGE_STYLE=n",
"CONFIG_USE_DEVICE_AEC=y",
"CONFIG_CAMERA_OV5647=y",
"CONFIG_CAMERA_OV5647_AUTO_DETECT_MIPI_INTERFACE_SENSOR=y",
"CONFIG_CAMERA_OV5647_MIPI_RAW8_800X800_50FPS=y",
"CONFIG_XIAOZHI_ENABLE_CAMERA_ENDIANNESS_SWAP=y"
]
}
]
}

View File

@@ -1,22 +0,0 @@
# Waveshare ESP32-P4-WIFI6-Touch-LCD-XC
[ESP32-P4-WIFI6-Touch-LCD-XC](https://www.waveshare.com/esp32-p4-wifi6-touch-lcd-3.4c.htm) is waveshare electronics designed a 3.4-inch, 4-inch circular screen, highly integrated development board
## Configuration
Configuration in `menuconfig`.
Selection Board Type `Xiaozhi Assistant --> Board Type`
- Waveshare ESP32-P4-WIFI6-Touch-LCD-3.4C or ESP32-P4-WIFI6-Touch-LCD-4C
Selection Display LCD Type `Xiaozhi Assistant --> LCD Type`
- Waveshare ESP32-P4-WIFI6-Touch-LCD-3.4C with 800*800 3.4inch round display
- Waveshare ESP32-P4-WIFI6-Touch-LCD-4C with 720*720 4inch round display
| [ESP32-P4-WIFI6-Touch-LCD-3.4C](https://www.waveshare.com/esp32-p4-wifi6-touch-lcd-3.4c.htm) | [ESP32-P4-WIFI6-Touch-LCD-4C](https://www.waveshare.com/esp32-p4-wifi6-touch-lcd-4c.htm) |
|----------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------|
| <img style="width: 150px; height: auto; display: block; margin: 0 auto;" src= "https://www.waveshare.com/media/catalog/product/cache/1/image/800x800/9df78eab33525d08d6e5fb8d27136e95/e/s/esp32-p4-wifi6-touch-lcd-3.4c-1.jpg"> | <img style="width: 150px; height: auto; display: block; margin: 0 auto;" src= "https://www.waveshare.com/media/catalog/product/cache/1/image/800x800/9df78eab33525d08d6e5fb8d27136e95/e/s/esp32-p4-wifi6-touch-lcd-4c-1.jpg"> |

View File

@@ -1,490 +0,0 @@
#ifndef _BOARD_CONFIG_H_
#define _BOARD_CONFIG_H_
#include <driver/gpio.h>
#define AUDIO_INPUT_SAMPLE_RATE 24000
#define AUDIO_OUTPUT_SAMPLE_RATE 24000
#define AUDIO_INPUT_REFERENCE true
#define AUDIO_I2S_GPIO_MCLK GPIO_NUM_13
#define AUDIO_I2S_GPIO_WS GPIO_NUM_10
#define AUDIO_I2S_GPIO_BCLK GPIO_NUM_12
#define AUDIO_I2S_GPIO_DIN GPIO_NUM_11
#define AUDIO_I2S_GPIO_DOUT GPIO_NUM_9
#define AUDIO_CODEC_PA_PIN GPIO_NUM_53
#define AUDIO_CODEC_I2C_SDA_PIN GPIO_NUM_7
#define AUDIO_CODEC_I2C_SCL_PIN GPIO_NUM_8
#define AUDIO_CODEC_ES8311_ADDR ES8311_CODEC_DEFAULT_ADDR
#define AUDIO_CODEC_ES7210_ADDR ES7210_CODEC_DEFAULT_ADDR
#define BOOT_BUTTON_GPIO GPIO_NUM_35
#define LCD_BIT_PER_PIXEL (16)
#define PIN_NUM_LCD_RST GPIO_NUM_27
#define DELAY_TIME_MS (3000)
#define LCD_MIPI_DSI_LANE_NUM (2) // 2 data lanes
#define MIPI_DSI_PHY_PWR_LDO_CHAN (3)
#define MIPI_DSI_PHY_PWR_LDO_VOLTAGE_MV (2500)
#define DISPLAY_SWAP_XY false
#define DISPLAY_MIRROR_X false
#define DISPLAY_MIRROR_Y false
#define DISPLAY_OFFSET_X 0
#define DISPLAY_OFFSET_Y 0
#define DISPLAY_BACKLIGHT_PIN GPIO_NUM_26
#define DISPLAY_BACKLIGHT_OUTPUT_INVERT true
#if CONFIG_LCD_TYPE_800_800_3_4_INCH
#define DISPLAY_WIDTH 800
#define DISPLAY_HEIGHT 800
static const jd9365_lcd_init_cmd_t lcd_init_cmds[] = {
{0xE0, (uint8_t[]){0x00}, 1, 0},
{0xE1, (uint8_t[]){0x93}, 1, 0},
{0xE2, (uint8_t[]){0x65}, 1, 0},
{0xE3, (uint8_t[]){0xF8}, 1, 0},
{0x80, (uint8_t[]){0x01}, 1, 0},
{0xE0, (uint8_t[]){0x01}, 1, 0},
{0x00, (uint8_t[]){0x00}, 1, 0},
{0x01, (uint8_t[]){0x41}, 1, 0},
{0x03, (uint8_t[]){0x10}, 1, 0},
{0x04, (uint8_t[]){0x44}, 1, 0},
{0x17, (uint8_t[]){0x00}, 1, 0},
{0x18, (uint8_t[]){0xD0}, 1, 0},
{0x19, (uint8_t[]){0x00}, 1, 0},
{0x1A, (uint8_t[]){0x00}, 1, 0},
{0x1B, (uint8_t[]){0xD0}, 1, 0},
{0x1C, (uint8_t[]){0x00}, 1, 0},
{0x24, (uint8_t[]){0xFE}, 1, 0},
{0x35, (uint8_t[]){0x26}, 1, 0},
{0x37, (uint8_t[]){0x09}, 1, 0},
{0x38, (uint8_t[]){0x04}, 1, 0},
{0x39, (uint8_t[]){0x08}, 1, 0},
{0x3A, (uint8_t[]){0x0A}, 1, 0},
{0x3C, (uint8_t[]){0x78}, 1, 0},
{0x3D, (uint8_t[]){0xFF}, 1, 0},
{0x3E, (uint8_t[]){0xFF}, 1, 0},
{0x3F, (uint8_t[]){0xFF}, 1, 0},
{0x40, (uint8_t[]){0x00}, 1, 0},
{0x41, (uint8_t[]){0x64}, 1, 0},
{0x42, (uint8_t[]){0xC7}, 1, 0},
{0x43, (uint8_t[]){0x18}, 1, 0},
{0x44, (uint8_t[]){0x0B}, 1, 0},
{0x45, (uint8_t[]){0x14}, 1, 0},
{0x55, (uint8_t[]){0x02}, 1, 0},
{0x57, (uint8_t[]){0x49}, 1, 0},
{0x59, (uint8_t[]){0x0A}, 1, 0},
{0x5A, (uint8_t[]){0x1B}, 1, 0},
{0x5B, (uint8_t[]){0x19}, 1, 0},
{0x5D, (uint8_t[]){0x7F}, 1, 0},
{0x5E, (uint8_t[]){0x56}, 1, 0},
{0x5F, (uint8_t[]){0x43}, 1, 0},
{0x60, (uint8_t[]){0x37}, 1, 0},
{0x61, (uint8_t[]){0x33}, 1, 0},
{0x62, (uint8_t[]){0x25}, 1, 0},
{0x63, (uint8_t[]){0x2A}, 1, 0},
{0x64, (uint8_t[]){0x16}, 1, 0},
{0x65, (uint8_t[]){0x30}, 1, 0},
{0x66, (uint8_t[]){0x2F}, 1, 0},
{0x67, (uint8_t[]){0x32}, 1, 0},
{0x68, (uint8_t[]){0x53}, 1, 0},
{0x69, (uint8_t[]){0x43}, 1, 0},
{0x6A, (uint8_t[]){0x4C}, 1, 0},
{0x6B, (uint8_t[]){0x40}, 1, 0},
{0x6C, (uint8_t[]){0x3D}, 1, 0},
{0x6D, (uint8_t[]){0x31}, 1, 0},
{0x6E, (uint8_t[]){0x20}, 1, 0},
{0x6F, (uint8_t[]){0x0F}, 1, 0},
{0x70, (uint8_t[]){0x7F}, 1, 0},
{0x71, (uint8_t[]){0x56}, 1, 0},
{0x72, (uint8_t[]){0x43}, 1, 0},
{0x73, (uint8_t[]){0x37}, 1, 0},
{0x74, (uint8_t[]){0x33}, 1, 0},
{0x75, (uint8_t[]){0x25}, 1, 0},
{0x76, (uint8_t[]){0x2A}, 1, 0},
{0x77, (uint8_t[]){0x16}, 1, 0},
{0x78, (uint8_t[]){0x30}, 1, 0},
{0x79, (uint8_t[]){0x2F}, 1, 0},
{0x7A, (uint8_t[]){0x32}, 1, 0},
{0x7B, (uint8_t[]){0x53}, 1, 0},
{0x7C, (uint8_t[]){0x43}, 1, 0},
{0x7D, (uint8_t[]){0x4C}, 1, 0},
{0x7E, (uint8_t[]){0x40}, 1, 0},
{0x7F, (uint8_t[]){0x3D}, 1, 0},
{0x80, (uint8_t[]){0x31}, 1, 0},
{0x81, (uint8_t[]){0x20}, 1, 0},
{0x82, (uint8_t[]){0x0F}, 1, 0},
{0xE0, (uint8_t[]){0x02}, 1, 0},
{0x00, (uint8_t[]){0x5F}, 1, 0},
{0x01, (uint8_t[]){0x5F}, 1, 0},
{0x02, (uint8_t[]){0x5E}, 1, 0},
{0x03, (uint8_t[]){0x5E}, 1, 0},
{0x04, (uint8_t[]){0x50}, 1, 0},
{0x05, (uint8_t[]){0x48}, 1, 0},
{0x06, (uint8_t[]){0x48}, 1, 0},
{0x07, (uint8_t[]){0x4A}, 1, 0},
{0x08, (uint8_t[]){0x4A}, 1, 0},
{0x09, (uint8_t[]){0x44}, 1, 0},
{0x0A, (uint8_t[]){0x44}, 1, 0},
{0x0B, (uint8_t[]){0x46}, 1, 0},
{0x0C, (uint8_t[]){0x46}, 1, 0},
{0x0D, (uint8_t[]){0x5F}, 1, 0},
{0x0E, (uint8_t[]){0x5F}, 1, 0},
{0x0F, (uint8_t[]){0x57}, 1, 0},
{0x10, (uint8_t[]){0x57}, 1, 0},
{0x11, (uint8_t[]){0x77}, 1, 0},
{0x12, (uint8_t[]){0x77}, 1, 0},
{0x13, (uint8_t[]){0x40}, 1, 0},
{0x14, (uint8_t[]){0x42}, 1, 0},
{0x15, (uint8_t[]){0x5F}, 1, 0},
{0x16, (uint8_t[]){0x5F}, 1, 0},
{0x17, (uint8_t[]){0x5F}, 1, 0},
{0x18, (uint8_t[]){0x5E}, 1, 0},
{0x19, (uint8_t[]){0x5E}, 1, 0},
{0x1A, (uint8_t[]){0x50}, 1, 0},
{0x1B, (uint8_t[]){0x49}, 1, 0},
{0x1C, (uint8_t[]){0x49}, 1, 0},
{0x1D, (uint8_t[]){0x4B}, 1, 0},
{0x1E, (uint8_t[]){0x4B}, 1, 0},
{0x1F, (uint8_t[]){0x45}, 1, 0},
{0x20, (uint8_t[]){0x45}, 1, 0},
{0x21, (uint8_t[]){0x47}, 1, 0},
{0x22, (uint8_t[]){0x47}, 1, 0},
{0x23, (uint8_t[]){0x5F}, 1, 0},
{0x24, (uint8_t[]){0x5F}, 1, 0},
{0x25, (uint8_t[]){0x57}, 1, 0},
{0x26, (uint8_t[]){0x57}, 1, 0},
{0x27, (uint8_t[]){0x77}, 1, 0},
{0x28, (uint8_t[]){0x77}, 1, 0},
{0x29, (uint8_t[]){0x41}, 1, 0},
{0x2A, (uint8_t[]){0x43}, 1, 0},
{0x2B, (uint8_t[]){0x5F}, 1, 0},
{0x2C, (uint8_t[]){0x1E}, 1, 0},
{0x2D, (uint8_t[]){0x1E}, 1, 0},
{0x2E, (uint8_t[]){0x1F}, 1, 0},
{0x2F, (uint8_t[]){0x1F}, 1, 0},
{0x30, (uint8_t[]){0x10}, 1, 0},
{0x31, (uint8_t[]){0x07}, 1, 0},
{0x32, (uint8_t[]){0x07}, 1, 0},
{0x33, (uint8_t[]){0x05}, 1, 0},
{0x34, (uint8_t[]){0x05}, 1, 0},
{0x35, (uint8_t[]){0x0B}, 1, 0},
{0x36, (uint8_t[]){0x0B}, 1, 0},
{0x37, (uint8_t[]){0x09}, 1, 0},
{0x38, (uint8_t[]){0x09}, 1, 0},
{0x39, (uint8_t[]){0x1F}, 1, 0},
{0x3A, (uint8_t[]){0x1F}, 1, 0},
{0x3B, (uint8_t[]){0x17}, 1, 0},
{0x3C, (uint8_t[]){0x17}, 1, 0},
{0x3D, (uint8_t[]){0x17}, 1, 0},
{0x3E, (uint8_t[]){0x17}, 1, 0},
{0x3F, (uint8_t[]){0x03}, 1, 0},
{0x40, (uint8_t[]){0x01}, 1, 0},
{0x41, (uint8_t[]){0x1F}, 1, 0},
{0x42, (uint8_t[]){0x1E}, 1, 0},
{0x43, (uint8_t[]){0x1E}, 1, 0},
{0x44, (uint8_t[]){0x1F}, 1, 0},
{0x45, (uint8_t[]){0x1F}, 1, 0},
{0x46, (uint8_t[]){0x10}, 1, 0},
{0x47, (uint8_t[]){0x06}, 1, 0},
{0x48, (uint8_t[]){0x06}, 1, 0},
{0x49, (uint8_t[]){0x04}, 1, 0},
{0x4A, (uint8_t[]){0x04}, 1, 0},
{0x4B, (uint8_t[]){0x0A}, 1, 0},
{0x4C, (uint8_t[]){0x0A}, 1, 0},
{0x4D, (uint8_t[]){0x08}, 1, 0},
{0x4E, (uint8_t[]){0x08}, 1, 0},
{0x4F, (uint8_t[]){0x1F}, 1, 0},
{0x50, (uint8_t[]){0x1F}, 1, 0},
{0x51, (uint8_t[]){0x17}, 1, 0},
{0x52, (uint8_t[]){0x17}, 1, 0},
{0x53, (uint8_t[]){0x17}, 1, 0},
{0x54, (uint8_t[]){0x17}, 1, 0},
{0x55, (uint8_t[]){0x02}, 1, 0},
{0x56, (uint8_t[]){0x00}, 1, 0},
{0x57, (uint8_t[]){0x1F}, 1, 0},
{0xE0, (uint8_t[]){0x02}, 1, 0},
{0x58, (uint8_t[]){0x40}, 1, 0},
{0x59, (uint8_t[]){0x00}, 1, 0},
{0x5A, (uint8_t[]){0x00}, 1, 0},
{0x5B, (uint8_t[]){0x30}, 1, 0},
{0x5C, (uint8_t[]){0x01}, 1, 0},
{0x5D, (uint8_t[]){0x30}, 1, 0},
{0x5E, (uint8_t[]){0x01}, 1, 0},
{0x5F, (uint8_t[]){0x02}, 1, 0},
{0x60, (uint8_t[]){0x30}, 1, 0},
{0x61, (uint8_t[]){0x03}, 1, 0},
{0x62, (uint8_t[]){0x04}, 1, 0},
{0x63, (uint8_t[]){0x04}, 1, 0},
{0x64, (uint8_t[]){0xA6}, 1, 0},
{0x65, (uint8_t[]){0x43}, 1, 0},
{0x66, (uint8_t[]){0x30}, 1, 0},
{0x67, (uint8_t[]){0x73}, 1, 0},
{0x68, (uint8_t[]){0x05}, 1, 0},
{0x69, (uint8_t[]){0x04}, 1, 0},
{0x6A, (uint8_t[]){0x7F}, 1, 0},
{0x6B, (uint8_t[]){0x08}, 1, 0},
{0x6C, (uint8_t[]){0x00}, 1, 0},
{0x6D, (uint8_t[]){0x04}, 1, 0},
{0x6E, (uint8_t[]){0x04}, 1, 0},
{0x6F, (uint8_t[]){0x88}, 1, 0},
{0x75, (uint8_t[]){0xD9}, 1, 0},
{0x76, (uint8_t[]){0x00}, 1, 0},
{0x77, (uint8_t[]){0x33}, 1, 0},
{0x78, (uint8_t[]){0x43}, 1, 0},
{0xE0, (uint8_t[]){0x00}, 1, 0},
{0x11, (uint8_t[]){0x00}, 1, 120},
{0x29, (uint8_t[]){0x00}, 1, 20},
{0x35, (uint8_t[]){0x00}, 1, 0},
};
#else
#define DISPLAY_WIDTH 720
#define DISPLAY_HEIGHT 720
static const jd9365_lcd_init_cmd_t lcd_init_cmds[] = {
{0xE0, (uint8_t[]){0x00}, 1, 0},
{0xE1, (uint8_t[]){0x93}, 1, 0},
{0xE2, (uint8_t[]){0x65}, 1, 0},
{0xE3, (uint8_t[]){0xF8}, 1, 0},
{0x80, (uint8_t[]){0x01}, 1, 0},
{0xE0, (uint8_t[]){0x01}, 1, 0},
{0x00, (uint8_t[]){0x00}, 1, 0},
{0x01, (uint8_t[]){0x41}, 1, 0},
{0x03, (uint8_t[]){0x10}, 1, 0},
{0x04, (uint8_t[]){0x44}, 1, 0},
{0x17, (uint8_t[]){0x00}, 1, 0},
{0x18, (uint8_t[]){0xD0}, 1, 0},
{0x19, (uint8_t[]){0x00}, 1, 0},
{0x1A, (uint8_t[]){0x00}, 1, 0},
{0x1B, (uint8_t[]){0xD0}, 1, 0},
{0x1C, (uint8_t[]){0x00}, 1, 0},
{0x24, (uint8_t[]){0xFE}, 1, 0},
{0x35, (uint8_t[]){0x26}, 1, 0},
{0x37, (uint8_t[]){0x09}, 1, 0},
{0x38, (uint8_t[]){0x04}, 1, 0},
{0x39, (uint8_t[]){0x08}, 1, 0},
{0x3A, (uint8_t[]){0x0A}, 1, 0},
{0x3C, (uint8_t[]){0x78}, 1, 0},
{0x3D, (uint8_t[]){0xFF}, 1, 0},
{0x3E, (uint8_t[]){0xFF}, 1, 0},
{0x3F, (uint8_t[]){0xFF}, 1, 0},
{0x40, (uint8_t[]){0x04}, 1, 0},
{0x41, (uint8_t[]){0x64}, 1, 0},
{0x42, (uint8_t[]){0xC7}, 1, 0},
{0x43, (uint8_t[]){0x18}, 1, 0},
{0x44, (uint8_t[]){0x0B}, 1, 0},
{0x45, (uint8_t[]){0x14}, 1, 0},
{0x55, (uint8_t[]){0x02}, 1, 0},
{0x57, (uint8_t[]){0x49}, 1, 0},
{0x59, (uint8_t[]){0x0A}, 1, 0},
{0x5A, (uint8_t[]){0x1B}, 1, 0},
{0x5B, (uint8_t[]){0x19}, 1, 0},
{0x5D, (uint8_t[]){0x7F}, 1, 0},
{0x5E, (uint8_t[]){0x56}, 1, 0},
{0x5F, (uint8_t[]){0x43}, 1, 0},
{0x60, (uint8_t[]){0x37}, 1, 0},
{0x61, (uint8_t[]){0x33}, 1, 0},
{0x62, (uint8_t[]){0x25}, 1, 0},
{0x63, (uint8_t[]){0x2A}, 1, 0},
{0x64, (uint8_t[]){0x16}, 1, 0},
{0x65, (uint8_t[]){0x30}, 1, 0},
{0x66, (uint8_t[]){0x2F}, 1, 0},
{0x67, (uint8_t[]){0x32}, 1, 0},
{0x68, (uint8_t[]){0x53}, 1, 0},
{0x69, (uint8_t[]){0x43}, 1, 0},
{0x6A, (uint8_t[]){0x4C}, 1, 0},
{0x6B, (uint8_t[]){0x40}, 1, 0},
{0x6C, (uint8_t[]){0x3D}, 1, 0},
{0x6D, (uint8_t[]){0x31}, 1, 0},
{0x6E, (uint8_t[]){0x20}, 1, 0},
{0x6F, (uint8_t[]){0x0F}, 1, 0},
{0x70, (uint8_t[]){0x7F}, 1, 0},
{0x71, (uint8_t[]){0x56}, 1, 0},
{0x72, (uint8_t[]){0x43}, 1, 0},
{0x73, (uint8_t[]){0x37}, 1, 0},
{0x74, (uint8_t[]){0x33}, 1, 0},
{0x75, (uint8_t[]){0x25}, 1, 0},
{0x76, (uint8_t[]){0x2A}, 1, 0},
{0x77, (uint8_t[]){0x16}, 1, 0},
{0x78, (uint8_t[]){0x30}, 1, 0},
{0x79, (uint8_t[]){0x2F}, 1, 0},
{0x7A, (uint8_t[]){0x32}, 1, 0},
{0x7B, (uint8_t[]){0x53}, 1, 0},
{0x7C, (uint8_t[]){0x43}, 1, 0},
{0x7D, (uint8_t[]){0x4C}, 1, 0},
{0x7E, (uint8_t[]){0x40}, 1, 0},
{0x7F, (uint8_t[]){0x3D}, 1, 0},
{0x80, (uint8_t[]){0x31}, 1, 0},
{0x81, (uint8_t[]){0x20}, 1, 0},
{0x82, (uint8_t[]){0x0F}, 1, 0},
{0xE0, (uint8_t[]){0x02}, 1, 0},
{0x00, (uint8_t[]){0x5F}, 1, 0},
{0x01, (uint8_t[]){0x5F}, 1, 0},
{0x02, (uint8_t[]){0x5E}, 1, 0},
{0x03, (uint8_t[]){0x5E}, 1, 0},
{0x04, (uint8_t[]){0x50}, 1, 0},
{0x05, (uint8_t[]){0x48}, 1, 0},
{0x06, (uint8_t[]){0x48}, 1, 0},
{0x07, (uint8_t[]){0x4A}, 1, 0},
{0x08, (uint8_t[]){0x4A}, 1, 0},
{0x09, (uint8_t[]){0x44}, 1, 0},
{0x0A, (uint8_t[]){0x44}, 1, 0},
{0x0B, (uint8_t[]){0x46}, 1, 0},
{0x0C, (uint8_t[]){0x46}, 1, 0},
{0x0D, (uint8_t[]){0x5F}, 1, 0},
{0x0E, (uint8_t[]){0x5F}, 1, 0},
{0x0F, (uint8_t[]){0x57}, 1, 0},
{0x10, (uint8_t[]){0x57}, 1, 0},
{0x11, (uint8_t[]){0x77}, 1, 0},
{0x12, (uint8_t[]){0x77}, 1, 0},
{0x13, (uint8_t[]){0x40}, 1, 0},
{0x14, (uint8_t[]){0x42}, 1, 0},
{0x15, (uint8_t[]){0x5F}, 1, 0},
{0x16, (uint8_t[]){0x5F}, 1, 0},
{0x17, (uint8_t[]){0x5F}, 1, 0},
{0x18, (uint8_t[]){0x5E}, 1, 0},
{0x19, (uint8_t[]){0x5E}, 1, 0},
{0x1A, (uint8_t[]){0x50}, 1, 0},
{0x1B, (uint8_t[]){0x49}, 1, 0},
{0x1C, (uint8_t[]){0x49}, 1, 0},
{0x1D, (uint8_t[]){0x4B}, 1, 0},
{0x1E, (uint8_t[]){0x4B}, 1, 0},
{0x1F, (uint8_t[]){0x45}, 1, 0},
{0x20, (uint8_t[]){0x45}, 1, 0},
{0x21, (uint8_t[]){0x47}, 1, 0},
{0x22, (uint8_t[]){0x47}, 1, 0},
{0x23, (uint8_t[]){0x5F}, 1, 0},
{0x24, (uint8_t[]){0x5F}, 1, 0},
{0x25, (uint8_t[]){0x57}, 1, 0},
{0x26, (uint8_t[]){0x57}, 1, 0},
{0x27, (uint8_t[]){0x77}, 1, 0},
{0x28, (uint8_t[]){0x77}, 1, 0},
{0x29, (uint8_t[]){0x41}, 1, 0},
{0x2A, (uint8_t[]){0x43}, 1, 0},
{0x2B, (uint8_t[]){0x5F}, 1, 0},
{0x2C, (uint8_t[]){0x1E}, 1, 0},
{0x2D, (uint8_t[]){0x1E}, 1, 0},
{0x2E, (uint8_t[]){0x1F}, 1, 0},
{0x2F, (uint8_t[]){0x1F}, 1, 0},
{0x30, (uint8_t[]){0x10}, 1, 0},
{0x31, (uint8_t[]){0x07}, 1, 0},
{0x32, (uint8_t[]){0x07}, 1, 0},
{0x33, (uint8_t[]){0x05}, 1, 0},
{0x34, (uint8_t[]){0x05}, 1, 0},
{0x35, (uint8_t[]){0x0B}, 1, 0},
{0x36, (uint8_t[]){0x0B}, 1, 0},
{0x37, (uint8_t[]){0x09}, 1, 0},
{0x38, (uint8_t[]){0x09}, 1, 0},
{0x39, (uint8_t[]){0x1F}, 1, 0},
{0x3A, (uint8_t[]){0x1F}, 1, 0},
{0x3B, (uint8_t[]){0x17}, 1, 0},
{0x3C, (uint8_t[]){0x17}, 1, 0},
{0x3D, (uint8_t[]){0x17}, 1, 0},
{0x3E, (uint8_t[]){0x17}, 1, 0},
{0x3F, (uint8_t[]){0x03}, 1, 0},
{0x40, (uint8_t[]){0x01}, 1, 0},
{0x41, (uint8_t[]){0x1F}, 1, 0},
{0x42, (uint8_t[]){0x1E}, 1, 0},
{0x43, (uint8_t[]){0x1E}, 1, 0},
{0x44, (uint8_t[]){0x1F}, 1, 0},
{0x45, (uint8_t[]){0x1F}, 1, 0},
{0x46, (uint8_t[]){0x10}, 1, 0},
{0x47, (uint8_t[]){0x06}, 1, 0},
{0x48, (uint8_t[]){0x06}, 1, 0},
{0x49, (uint8_t[]){0x04}, 1, 0},
{0x4A, (uint8_t[]){0x04}, 1, 0},
{0x4B, (uint8_t[]){0x0A}, 1, 0},
{0x4C, (uint8_t[]){0x0A}, 1, 0},
{0x4D, (uint8_t[]){0x08}, 1, 0},
{0x4E, (uint8_t[]){0x08}, 1, 0},
{0x4F, (uint8_t[]){0x1F}, 1, 0},
{0x50, (uint8_t[]){0x1F}, 1, 0},
{0x51, (uint8_t[]){0x17}, 1, 0},
{0x52, (uint8_t[]){0x17}, 1, 0},
{0x53, (uint8_t[]){0x17}, 1, 0},
{0x54, (uint8_t[]){0x17}, 1, 0},
{0x55, (uint8_t[]){0x02}, 1, 0},
{0x56, (uint8_t[]){0x00}, 1, 0},
{0x57, (uint8_t[]){0x1F}, 1, 0},
{0xE0, (uint8_t[]){0x02}, 1, 0},
{0x58, (uint8_t[]){0x40}, 1, 0},
{0x59, (uint8_t[]){0x00}, 1, 0},
{0x5A, (uint8_t[]){0x00}, 1, 0},
{0x5B, (uint8_t[]){0x30}, 1, 0},
{0x5C, (uint8_t[]){0x01}, 1, 0},
{0x5D, (uint8_t[]){0x30}, 1, 0},
{0x5E, (uint8_t[]){0x01}, 1, 0},
{0x5F, (uint8_t[]){0x02}, 1, 0},
{0x60, (uint8_t[]){0x30}, 1, 0},
{0x61, (uint8_t[]){0x03}, 1, 0},
{0x62, (uint8_t[]){0x04}, 1, 0},
{0x63, (uint8_t[]){0x04}, 1, 0},
{0x64, (uint8_t[]){0xA6}, 1, 0},
{0x65, (uint8_t[]){0x43}, 1, 0},
{0x66, (uint8_t[]){0x30}, 1, 0},
{0x67, (uint8_t[]){0x73}, 1, 0},
{0x68, (uint8_t[]){0x05}, 1, 0},
{0x69, (uint8_t[]){0x04}, 1, 0},
{0x6A, (uint8_t[]){0x7F}, 1, 0},
{0x6B, (uint8_t[]){0x08}, 1, 0},
{0x6C, (uint8_t[]){0x00}, 1, 0},
{0x6D, (uint8_t[]){0x04}, 1, 0},
{0x6E, (uint8_t[]){0x04}, 1, 0},
{0x6F, (uint8_t[]){0x88}, 1, 0},
{0x75, (uint8_t[]){0xD9}, 1, 0},
{0x76, (uint8_t[]){0x00}, 1, 0},
{0x77, (uint8_t[]){0x33}, 1, 0},
{0x78, (uint8_t[]){0x43}, 1, 0},
{0xE0, (uint8_t[]){0x00}, 1, 0},
{0x11, (uint8_t[]){0x00}, 1, 120},
{0x29, (uint8_t[]){0x00}, 1, 20},
{0x35, (uint8_t[]){0x00}, 1, 0},
};
#endif
#endif // _BOARD_CONFIG_H_

View File

@@ -1,29 +0,0 @@
{
"target": "esp32p4",
"builds": [
{
"name": "waveshare-p4-wifi6-touch-lcd-xc-3.4c",
"sdkconfig_append": [
"CONFIG_USE_WECHAT_MESSAGE_STYLE=n",
"CONFIG_USE_DEVICE_AEC=y",
"CONFIG_LCD_TYPE_800_800_3_4_INCH=y",
"CONFIG_CAMERA_OV5647=y",
"CONFIG_CAMERA_OV5647_AUTO_DETECT_MIPI_INTERFACE_SENSOR=y",
"CONFIG_CAMERA_OV5647_MIPI_RAW8_800X800_50FPS=y",
"CONFIG_XIAOZHI_ENABLE_CAMERA_ENDIANNESS_SWAP=y"
]
},
{
"name": "waveshare-p4-wifi6-touch-lcd-xc-4c",
"sdkconfig_append": [
"CONFIG_USE_WECHAT_MESSAGE_STYLE=n",
"CONFIG_USE_DEVICE_AEC=y",
"CONFIG_LCD_TYPE_720_720_4_INCH=y",
"CONFIG_CAMERA_OV5647=y",
"CONFIG_CAMERA_OV5647_AUTO_DETECT_MIPI_INTERFACE_SENSOR=y",
"CONFIG_CAMERA_OV5647_MIPI_RAW8_800X800_50FPS=y",
"CONFIG_XIAOZHI_ENABLE_CAMERA_ENDIANNESS_SWAP=y"
]
}
]
}

View File

@@ -1,229 +0,0 @@
#include "wifi_board.h"
#include "codecs/box_audio_codec.h"
#include "application.h"
#include "display/lcd_display.h"
// #include "display/no_display.h"
#include "button.h"
#include "esp_video.h"
#include "esp_video_init.h"
#include "esp_cam_sensor_xclk.h"
#include "esp_lcd_panel_ops.h"
#include "esp_lcd_mipi_dsi.h"
#include "esp_ldo_regulator.h"
#include "esp_lcd_jd9365_10_1.h"
#include "config.h"
#include <esp_log.h>
#include <driver/i2c_master.h>
#include <esp_lvgl_port.h>
#include "esp_lcd_touch_gt911.h"
#define TAG "WaveshareEsp32p4xc"
class WaveshareEsp32p4xc : public WifiBoard {
private:
i2c_master_bus_handle_t i2c_bus_;
Button boot_button_;
LcdDisplay *display_;
EspVideo* camera_ = nullptr;
void InitializeCodecI2c() {
// Initialize I2C peripheral
i2c_master_bus_config_t i2c_bus_cfg = {
.i2c_port = I2C_NUM_1,
.sda_io_num = AUDIO_CODEC_I2C_SDA_PIN,
.scl_io_num = AUDIO_CODEC_I2C_SCL_PIN,
.clk_source = I2C_CLK_SRC_DEFAULT,
.glitch_ignore_cnt = 7,
.intr_priority = 0,
.trans_queue_depth = 0,
.flags = {
.enable_internal_pullup = 1,
},
};
ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_cfg, &i2c_bus_));
}
static esp_err_t bsp_enable_dsi_phy_power(void) {
#if MIPI_DSI_PHY_PWR_LDO_CHAN > 0
// Turn on the power for MIPI DSI PHY, so it can go from "No Power" state to "Shutdown" state
static esp_ldo_channel_handle_t phy_pwr_chan = NULL;
esp_ldo_channel_config_t ldo_cfg = {
.chan_id = MIPI_DSI_PHY_PWR_LDO_CHAN,
.voltage_mv = MIPI_DSI_PHY_PWR_LDO_VOLTAGE_MV,
};
esp_ldo_acquire_channel(&ldo_cfg, &phy_pwr_chan);
ESP_LOGI(TAG, "MIPI DSI PHY Powered on");
#endif // BSP_MIPI_DSI_PHY_PWR_LDO_CHAN > 0
return ESP_OK;
}
void InitializeLCD() {
bsp_enable_dsi_phy_power();
esp_lcd_panel_io_handle_t io = NULL;
esp_lcd_panel_handle_t disp_panel = NULL;
esp_lcd_dsi_bus_handle_t mipi_dsi_bus = NULL;
esp_lcd_dsi_bus_config_t bus_config = {
.bus_id = 0,
.num_data_lanes = 2,
.lane_bit_rate_mbps = 1500,
};
esp_lcd_new_dsi_bus(&bus_config, &mipi_dsi_bus);
ESP_LOGI(TAG, "Install MIPI DSI LCD control panel");
// we use DBI interface to send LCD commands and parameters
esp_lcd_dbi_io_config_t dbi_config = JD9365_PANEL_IO_DBI_CONFIG();
esp_lcd_new_panel_io_dbi(mipi_dsi_bus, &dbi_config, &io);
esp_lcd_dpi_panel_config_t dpi_config = {
.dpi_clk_src = MIPI_DSI_DPI_CLK_SRC_DEFAULT,
.dpi_clock_freq_mhz = 46,
.pixel_format = LCD_COLOR_PIXEL_FORMAT_RGB565,
.num_fbs = 1,
.video_timing = {
.h_size = DISPLAY_WIDTH,
.v_size = DISPLAY_HEIGHT,
.hsync_pulse_width = 20,
.hsync_back_porch = 20,
.hsync_front_porch = 40,
.vsync_pulse_width = 4,
.vsync_back_porch = 12,
.vsync_front_porch = 24,
},
.flags = {
.use_dma2d = true,
},
};
jd9365_vendor_config_t vendor_config = {
.init_cmds = lcd_init_cmds,
.init_cmds_size = sizeof(lcd_init_cmds) / sizeof(lcd_init_cmds[0]),
.mipi_config = {
.dsi_bus = mipi_dsi_bus,
.dpi_config = &dpi_config,
.lane_num = 2,
},
.flags = {
.use_mipi_interface = 1,
},
};
const esp_lcd_panel_dev_config_t lcd_dev_config = {
.reset_gpio_num = PIN_NUM_LCD_RST,
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,
.bits_per_pixel = 16,
.vendor_config = &vendor_config,
};
esp_lcd_new_panel_jd9365(io, &lcd_dev_config, &disp_panel);
esp_lcd_panel_reset(disp_panel);
esp_lcd_panel_init(disp_panel);
display_ = new MipiLcdDisplay(io, disp_panel, DISPLAY_WIDTH, DISPLAY_HEIGHT,
DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY);
}
void InitializeTouch()
{
esp_lcd_touch_handle_t tp;
esp_lcd_touch_config_t tp_cfg = {
.x_max = DISPLAY_WIDTH,
.y_max = DISPLAY_HEIGHT,
.rst_gpio_num = GPIO_NUM_23,
.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;
esp_lcd_panel_io_i2c_config_t tp_io_config = ESP_LCD_TOUCH_IO_I2C_GT911_CONFIG();
tp_io_config.scl_speed_hz = 400 * 1000;
ESP_ERROR_CHECK(esp_lcd_new_panel_io_i2c(i2c_bus_, &tp_io_config, &tp_io_handle));
ESP_LOGI(TAG, "Initialize touch controller");
ESP_ERROR_CHECK(esp_lcd_touch_new_i2c_gt911(tp_io_handle, &tp_cfg, &tp));
const lvgl_port_touch_cfg_t touch_cfg = {
.disp = lv_display_get_default(),
.handle = tp,
};
lvgl_port_add_touch(&touch_cfg);
ESP_LOGI(TAG, "Touch panel initialized successfully");
}
void InitializeCamera() {
esp_video_init_csi_config_t base_csi_config = {
.sccb_config = {
.init_sccb = false,
.i2c_handle = i2c_bus_,
.freq = 400000,
},
.reset_pin = GPIO_NUM_NC,
.pwdn_pin = GPIO_NUM_NC,
};
esp_video_init_config_t cam_config = {
.csi = &base_csi_config,
};
camera_ = new EspVideo(cam_config);
}
void InitializeButtons() {
boot_button_.OnClick([this]() {
auto& app = Application::GetInstance();
// During startup (before connected), pressing BOOT button enters Wi-Fi config mode without reboot
if (app.GetDeviceState() == kDeviceStateStarting) {
EnterWifiConfigMode();
return;
}
app.ToggleChatState();
});
}
public:
WaveshareEsp32p4xc() :
boot_button_(BOOT_BUTTON_GPIO) {
InitializeCodecI2c();
InitializeLCD();
InitializeTouch();
InitializeCamera();
InitializeButtons();
GetBacklight()->RestoreBrightness();
}
virtual AudioCodec* GetAudioCodec() override {
static BoxAudioCodec audio_codec(
i2c_bus_,
AUDIO_INPUT_SAMPLE_RATE,
AUDIO_OUTPUT_SAMPLE_RATE,
AUDIO_I2S_GPIO_MCLK,
AUDIO_I2S_GPIO_BCLK,
AUDIO_I2S_GPIO_WS,
AUDIO_I2S_GPIO_DOUT,
AUDIO_I2S_GPIO_DIN,
AUDIO_CODEC_PA_PIN,
AUDIO_CODEC_ES8311_ADDR,
AUDIO_CODEC_ES7210_ADDR,
AUDIO_INPUT_REFERENCE);
return &audio_codec;
}
virtual Display *GetDisplay() override {
return display_;
}
virtual Camera* GetCamera() override {
return camera_;
}
virtual Backlight* GetBacklight() override {
static PwmBacklight backlight(DISPLAY_BACKLIGHT_PIN, DISPLAY_BACKLIGHT_OUTPUT_INVERT);
return &backlight;
}
};
DECLARE_BOARD(WaveshareEsp32p4xc);

View File

@@ -1,12 +0,0 @@
{
"target": "esp32s3",
"builds": [
{
"name": "waveshare-s3-touch-lcd-3.49",
"sdkconfig_append": [
"CONFIG_USE_WECHAT_MESSAGE_STYLE=n",
"CONFIG_USE_DEVICE_AEC=y"
]
}
]
}

View File

@@ -1,12 +0,0 @@
{
"target": "esp32s3",
"builds": [
{
"name": "waveshare-s3-touch-lcd-4b",
"sdkconfig_append": [
"CONFIG_USE_WECHAT_MESSAGE_STYLE=n",
"CONFIG_USE_DEVICE_AEC=y"
]
}
]
}

View File

@@ -1,8 +1,9 @@
{
"manufacturer": "waveshare",
"target": "esp32c6",
"builds": [
{
"name": "waveshare-c6-touch-amoled-1.8",
"name": "esp32-c6-lcd-1.69",
"sdkconfig_append": [
"CONFIG_USE_ESP_WAKE_WORD=y"
]

View File

@@ -32,6 +32,14 @@ public:
bool swap_xy)
: SpiLcdDisplay(io_handle, panel_handle,
width, height, offset_x, offset_y, mirror_x, mirror_y, swap_xy) {
// Note: UI customization should be done in SetupUI(), not in constructor
// to ensure lvgl objects are created before accessing them
}
virtual void SetupUI() override {
// Call parent SetupUI() first to create all lvgl objects
SpiLcdDisplay::SetupUI();
DisplayLockGuard lock(this);
lv_obj_set_style_pad_left(status_bar_, LV_HOR_RES * 0.1, 0);
lv_obj_set_style_pad_right(status_bar_, LV_HOR_RES * 0.1, 0);

View File

@@ -1,8 +1,9 @@
{
"manufacturer": "waveshare",
"target": "esp32c6",
"builds": [
{
"name": "waveshare-c6-touch-amoled-1.32",
"name": "esp32-c6-touch-amoled-1.32",
"sdkconfig_append": [
"CONFIG_USE_ESP_WAKE_WORD=y"
]

View File

@@ -61,9 +61,17 @@ class CustomLcdDisplay : public SpiLcdDisplay {
CustomLcdDisplay(esp_lcd_panel_io_handle_t io_handle, esp_lcd_panel_handle_t panel_handle, int width, int height, int offset_x, int offset_y, bool mirror_x, bool mirror_y, bool swap_xy) :
SpiLcdDisplay(io_handle, panel_handle, width, height, offset_x, offset_y, mirror_x, mirror_y, swap_xy),
io_handle_(io_handle) {
// Note: UI customization should be done in SetupUI(), not in constructor
// to ensure lvgl objects are created before accessing them
SetMIRROR_XY(0xC0); // Rotate 180 degrees - this is safe as it only operates on hardware
}
virtual void SetupUI() override {
// Call parent SetupUI() first to create all lvgl objects
SpiLcdDisplay::SetupUI();
DisplayLockGuard lock(this);
lv_display_add_event_cb(display_, my_draw_event_cb, LV_EVENT_INVALIDATE_AREA, NULL);
SetMIRROR_XY(0xC0); // Rotate 180 degrees
lv_obj_invalidate(lv_screen_active());
}
};

View File

@@ -1,8 +1,9 @@
{
"manufacturer": "waveshare",
"target": "esp32c6",
"builds": [
{
"name": "waveshare-c6-touch-amoled-1.43",
"name": "esp32-c6-touch-amoled-1.43",
"sdkconfig_append": [
"CONFIG_USE_ESP_WAKE_WORD=y"
]

View File

@@ -54,6 +54,14 @@ public:
bool swap_xy)
: SpiLcdDisplay(io_handle, panel_handle,
width, height, offset_x, offset_y, mirror_x, mirror_y, swap_xy) {
// Note: UI customization should be done in SetupUI(), not in constructor
// to ensure lvgl objects are created before accessing them
}
virtual void SetupUI() override {
// Call parent SetupUI() first to create all lvgl objects
SpiLcdDisplay::SetupUI();
DisplayLockGuard lock(this);
lv_display_add_event_cb(display_, MyDrawEventCb, LV_EVENT_INVALIDATE_AREA, NULL);
}

View File

@@ -1,8 +1,9 @@
{
"manufacturer": "waveshare",
"target": "esp32c6",
"builds": [
{
"name": "waveshare-c6-lcd-1.69",
"name": "esp32-c6-touch-amoled-1.8",
"sdkconfig_append": [
"CONFIG_USE_ESP_WAKE_WORD=y"
]

View File

@@ -83,6 +83,14 @@ public:
bool swap_xy)
: SpiLcdDisplay(io_handle, panel_handle,
width, height, offset_x, offset_y, mirror_x, mirror_y, swap_xy) {
// Note: UI customization should be done in SetupUI(), not in constructor
// to ensure lvgl objects are created before accessing them
}
virtual void SetupUI() override {
// Call parent SetupUI() first to create all lvgl objects
SpiLcdDisplay::SetupUI();
DisplayLockGuard lock(this);
lv_obj_set_style_pad_left(status_bar_, LV_HOR_RES * 0.1, 0);
lv_obj_set_style_pad_right(status_bar_, LV_HOR_RES * 0.1, 0);

View File

@@ -1,8 +1,9 @@
{
"manufacturer": "waveshare",
"target": "esp32s3",
"builds": [
{
"name": "waveshare-c6-touch-amoled-2.06",
"name": "esp32-c6-touch-amoled-2.06",
"sdkconfig_append": [
"CONFIG_USE_ESP_WAKE_WORD=y"
]

View File

@@ -102,6 +102,14 @@ public:
bool swap_xy)
: SpiLcdDisplay(io_handle, panel_handle,
width, height, offset_x, offset_y, mirror_x, mirror_y, swap_xy) {
// Note: UI customization should be done in SetupUI(), not in constructor
// to ensure lvgl objects are created before accessing them
}
virtual void SetupUI() override {
// Call parent SetupUI() first to create all lvgl objects
SpiLcdDisplay::SetupUI();
DisplayLockGuard lock(this);
lv_obj_set_style_pad_left(status_bar_, LV_HOR_RES* 0.1, 0);
lv_obj_set_style_pad_right(status_bar_, LV_HOR_RES* 0.1, 0);

View File

@@ -1,8 +1,9 @@
{
"manufacturer": "waveshare",
"target": "esp32c6",
"builds": [
{
"name": "waveshare-c6-touch-lcd-1.83",
"name": "esp32-c6-touch-lcd-1.83",
"sdkconfig_append": [
"CONFIG_USE_WECHAT_MESSAGE_STYLE=n",
"CONFIG_USE_DEVICE_AEC=y"

View File

@@ -12,32 +12,32 @@
| Product ID | Dependency | tested |
|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------|--------|
| [10.1-DSI-TOUCH-A](https://www.waveshare.com/10.1-dsi-touch-a.htm) <br/><img style="width: 150px; height: auto; display: block; margin: 0 auto;" src="https://www.waveshare.com/media/catalog/product/cache/1/image/800x800/9df78eab33525d08d6e5fb8d27136e95/1/0/10.1-dsi-touch-a-1.jpg"> | [waveshare/esp_lcd_jd9365_10_1](https://github.com/waveshareteam/Waveshare-ESP32-components/tree/master/display/lcd/esp_lcd_jd9365_10_1) | ✅ |
| [101M-8001280-IPS-CT-K](https://www.waveshare.com/101m-8001280-ips-ct-k.htm) <br/><img style="width: 150px; height: auto; display: block; margin: 0 auto;" src="https://www.waveshare.com/media/catalog/product/cache/1/image/800x800/9df78eab33525d08d6e5fb8d27136e95/1/0/101m-8001280-ips-ct-k-1.jpg"> | [waveshare/esp_lcd_jd9365_10_1](https://github.com/waveshareteam/Waveshare-ESP32-components/tree/master/display/lcd/esp_lcd_jd9365_10_1) | ✅ |
| [10.1-DSI-TOUCH-A](https://www.waveshare.com/10.1-dsi-touch-a.htm) <br/><img style="width: 150px; height: auto; display: block; margin: 0 auto;" src="https://www.waveshare.com/media/catalog/product/cache/1/image/800x800/9df78eab33525d08d6e5fb8d27136e95/1/0/10.1-dsi-touch-a-1.jpg"> | [waveshare/esp_lcd_jd9365_10_1](https://github.com/waveshareteam/waveshare-ESP32-components/tree/master/display/lcd/esp_lcd_jd9365_10_1) | ✅ |
| [101M-8001280-IPS-CT-K](https://www.waveshare.com/101m-8001280-ips-ct-k.htm) <br/><img style="width: 150px; height: auto; display: block; margin: 0 auto;" src="https://www.waveshare.com/media/catalog/product/cache/1/image/800x800/9df78eab33525d08d6e5fb8d27136e95/1/0/101m-8001280-ips-ct-k-1.jpg"> | [waveshare/esp_lcd_jd9365_10_1](https://github.com/waveshareteam/waveshare-ESP32-components/tree/master/display/lcd/esp_lcd_jd9365_10_1) | ✅ |
### Common Raspberry adapter screen
**These displays are supported on [ESP32-P4-NANO BSP](https://github.com/waveshareteam/Waveshare-ESP32-components/tree/master/bsp/esp32_p4_nano), but not on xiaozhi-esp32**
**These displays are supported on [ESP32-P4-NANO BSP](https://github.com/waveshareteam/waveshare-ESP32-components/tree/master/bsp/esp32_p4_nano), but not on xiaozhi-esp32**
<details open>
<summary>View full display</summary>
| Product ID | Dependency | tested |
|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------|--------|
| [2.8inch DSI LCD](https://www.waveshare.com/2.8inch-dsi-lcd.htm) <br/><img style="width: 150px; height: auto; display: block; margin: 0 auto;" src="https://www.waveshare.com/media/catalog/product/cache/1/thumbnail/122x122/9df78eab33525d08d6e5fb8d27136e95/2/_/2.8inch-dsi-lcd-3.jpg"> | [waveshare/esp_lcd_dsi](https://github.com/waveshareteam/Waveshare-ESP32-components/tree/master/display/lcd/esp_lcd_dsi) | 🕒 |
| [3.4inch DSI LCD (C)](https://www.waveshare.com/3.4inch-dsi-lcd-c.htm) <br/><img style="width: 150px; height: auto; display: block; margin: 0 auto;" src="https://www.waveshare.com/media/catalog/product/cache/1/image/800x800/9df78eab33525d08d6e5fb8d27136e95/3/_/3.4inch-dsi-lcd-c-1.jpg"> | [waveshare/esp_lcd_dsi](https://github.com/waveshareteam/Waveshare-ESP32-components/tree/master/display/lcd/esp_lcd_dsi) | 🕒 |
| [4inch DSI LCD (C)](https://www.waveshare.com/4inch-dsi-lcd-c.htm) <br/><img style="width: 150px; height: auto; display: block; margin: 0 auto;" src="https://www.waveshare.com/media/catalog/product/cache/1/image/800x800/9df78eab33525d08d6e5fb8d27136e95/4/i/4inch-dsi-lcd-c-1.jpg"> | [waveshare/esp_lcd_dsi](https://github.com/waveshareteam/Waveshare-ESP32-components/tree/master/display/lcd/esp_lcd_dsi) | 🕒 |
| [4inch DSI LCD](https://www.waveshare.com/4inch-dsi-lcd.htm) <br/><img style="width: 150px; height: auto; display: block; margin: 0 auto;" src="https://www.waveshare.com/media/catalog/product/cache/1/image/800x800/9df78eab33525d08d6e5fb8d27136e95/4/i/4inch-dsi-lcd-1.jpg"> | [waveshare/esp_lcd_dsi](https://github.com/waveshareteam/Waveshare-ESP32-components/tree/master/display/lcd/esp_lcd_dsi) | 🕒 |
| [5inch DSI LCD (D)](https://www.waveshare.com/5inch-dsi-lcd-d.htm) <br/><img style="width: 150px; height: auto; display: block; margin: 0 auto;" src="https://www.waveshare.com/media/catalog/product/cache/1/image/800x800/9df78eab33525d08d6e5fb8d27136e95/5/i/5inch-dsi-lcd-d-2.jpg"> | [waveshare/esp_lcd_dsi](https://github.com/waveshareteam/Waveshare-ESP32-components/tree/master/display/lcd/esp_lcd_dsi) | 🕒 |
| [6.25inch DSI LCD](https://www.waveshare.com/6.25inch-dsi-lcd.htm) <br/><img style="width: 150px; height: auto; display: block; margin: 0 auto;" src="https://www.waveshare.com/media/catalog/product/cache/1/image/800x800/9df78eab33525d08d6e5fb8d27136e95/6/_/6.25inch-dsi-lcd-2.jpg"> | [waveshare/esp_lcd_dsi](https://github.com/waveshareteam/Waveshare-ESP32-components/tree/master/display/lcd/esp_lcd_dsi) | 🕒 |
| [5inch DSI LCD (C)](https://www.waveshare.com/5inch-dsi-lcd-c.htm) <br/><img style="width: 150px; height: auto; display: block; margin: 0 auto;" src="https://www.waveshare.com/media/catalog/product/cache/1/image/800x800/9df78eab33525d08d6e5fb8d27136e95/5/i/5inch-dsi-lcd-c-2.jpg"> | [waveshare/esp_lcd_dsi](https://github.com/waveshareteam/Waveshare-ESP32-components/tree/master/display/lcd/esp_lcd_dsi) | 🕒 |
| [7inch DSI LCD (C)](https://www.waveshare.com/7inch-dsi-lcd-c-with-case-a.htm) <br/><img style="width: 150px; height: auto; display: block; margin: 0 auto;" src="https://www.waveshare.com/media/catalog/product/cache/1/image/800x800/9df78eab33525d08d6e5fb8d27136e95/7/i/7inch-dsi-lcd-c-4.jpg"> | [waveshare/esp_lcd_dsi](https://github.com/waveshareteam/Waveshare-ESP32-components/tree/master/display/lcd/esp_lcd_dsi) | 🕒 |
| [7.9inch DSI LCD](https://www.waveshare.com/7.9inch-dsi-lcd.htm) <br/><img style="width: 150px; height: auto; display: block; margin: 0 auto;" src="https://www.waveshare.com/media/catalog/product/cache/1/image/800x800/9df78eab33525d08d6e5fb8d27136e95/7/_/7.9inch-dsi-lcd-2.jpg"> | [waveshare/esp_lcd_dsi](https://github.com/waveshareteam/Waveshare-ESP32-components/tree/master/display/lcd/esp_lcd_dsi) | 🕒 |
| [7inch DSI LCD (E)](https://www.waveshare.com/7inch-dsi-lcd-e.htm) <br/><img style="width: 150px; height: auto; display: block; margin: 0 auto;" src="https://www.waveshare.com/media/catalog/product/cache/1/image/800x800/9df78eab33525d08d6e5fb8d27136e95/7/i/7inch-dsi-lcd-e-2.jpg"> | [waveshare/esp_lcd_dsi](https://github.com/waveshareteam/Waveshare-ESP32-components/tree/master/display/lcd/esp_lcd_dsi) | 🕒 |
| [8inch DSI LCD (C)](https://www.waveshare.com/8inch-dsi-lcd-c.htm) <br/><img style="width: 150px; height: auto; display: block; margin: 0 auto;" src="https://www.waveshare.com/media/catalog/product/cache/1/image/800x800/9df78eab33525d08d6e5fb8d27136e95/8/i/8inch-dsi-lcd-c-2.jpg"> | [waveshare/esp_lcd_dsi](https://github.com/waveshareteam/Waveshare-ESP32-components/tree/master/display/lcd/esp_lcd_dsi) | 🕒 |
| [10.1inch DSI LCD (C)](https://www.waveshare.com/10.1inch-dsi-lcd-c.htm) <br/><img style="width: 150px; height: auto; display: block; margin: 0 auto;" src="https://www.waveshare.com/media/catalog/product/cache/1/image/800x800/9df78eab33525d08d6e5fb8d27136e95/1/0/10.1inch-dsi-lcd-c-2.jpg"> | [waveshare/esp_lcd_dsi](https://github.com/waveshareteam/Waveshare-ESP32-components/tree/master/display/lcd/esp_lcd_dsi) | 🕒 |
| [8.8inch DSI LCD](https://www.waveshare.com/8.8inch-dsi-lcd.htm) <br/><img style="width: 150px; height: auto; display: block; margin: 0 auto;" src="https://www.waveshare.com/media/catalog/product/cache/1/image/800x800/9df78eab33525d08d6e5fb8d27136e95/8/_/8.8inch-dsi-lcd-2.jpg"> | [waveshare/esp_lcd_dsi](https://github.com/waveshareteam/Waveshare-ESP32-components/tree/master/display/lcd/esp_lcd_dsi) | 🕒 |
| [11.9inch DSI LCD](https://www.waveshare.com/11.9inch-dsi-lcd.htm) <br/><img style="width: 150px; height: auto; display: block; margin: 0 auto;" src="https://www.waveshare.com/media/catalog/product/cache/1/image/800x800/9df78eab33525d08d6e5fb8d27136e95/1/1/11.9inch-dsi-lcd-3.jpg"> | [waveshare/esp_lcd_dsi](https://github.com/waveshareteam/Waveshare-ESP32-components/tree/master/display/lcd/esp_lcd_dsi) | 🕒 |
| [7-DSI-TOUCH-A](https://www.waveshare.com/7-dsi-touch-a.htm) <br/><img style="width: 150px; height: auto; display: block; margin: 0 auto;" src="https://www.waveshare.com/media/catalog/product/cache/1/image/800x800/9df78eab33525d08d6e5fb8d27136e95/7/-/7-dsi-touch-a-1.jpg"> | [waveshare/esp_lcd_ili9881c](https://github.com/waveshareteam/Waveshare-ESP32-components/tree/master/display/lcd/esp_lcd_ili9881c) | 🕒 |
| [2.8inch DSI LCD](https://www.waveshare.com/2.8inch-dsi-lcd.htm) <br/><img style="width: 150px; height: auto; display: block; margin: 0 auto;" src="https://www.waveshare.com/media/catalog/product/cache/1/thumbnail/122x122/9df78eab33525d08d6e5fb8d27136e95/2/_/2.8inch-dsi-lcd-3.jpg"> | [waveshare/esp_lcd_dsi](https://github.com/waveshareteam/waveshare-ESP32-components/tree/master/display/lcd/esp_lcd_dsi) | 🕒 |
| [3.4inch DSI LCD (C)](https://www.waveshare.com/3.4inch-dsi-lcd-c.htm) <br/><img style="width: 150px; height: auto; display: block; margin: 0 auto;" src="https://www.waveshare.com/media/catalog/product/cache/1/image/800x800/9df78eab33525d08d6e5fb8d27136e95/3/_/3.4inch-dsi-lcd-c-1.jpg"> | [waveshare/esp_lcd_dsi](https://github.com/waveshareteam/waveshare-ESP32-components/tree/master/display/lcd/esp_lcd_dsi) | 🕒 |
| [4inch DSI LCD (C)](https://www.waveshare.com/4inch-dsi-lcd-c.htm) <br/><img style="width: 150px; height: auto; display: block; margin: 0 auto;" src="https://www.waveshare.com/media/catalog/product/cache/1/image/800x800/9df78eab33525d08d6e5fb8d27136e95/4/i/4inch-dsi-lcd-c-1.jpg"> | [waveshare/esp_lcd_dsi](https://github.com/waveshareteam/waveshare-ESP32-components/tree/master/display/lcd/esp_lcd_dsi) | 🕒 |
| [4inch DSI LCD](https://www.waveshare.com/4inch-dsi-lcd.htm) <br/><img style="width: 150px; height: auto; display: block; margin: 0 auto;" src="https://www.waveshare.com/media/catalog/product/cache/1/image/800x800/9df78eab33525d08d6e5fb8d27136e95/4/i/4inch-dsi-lcd-1.jpg"> | [waveshare/esp_lcd_dsi](https://github.com/waveshareteam/waveshare-ESP32-components/tree/master/display/lcd/esp_lcd_dsi) | 🕒 |
| [5inch DSI LCD (D)](https://www.waveshare.com/5inch-dsi-lcd-d.htm) <br/><img style="width: 150px; height: auto; display: block; margin: 0 auto;" src="https://www.waveshare.com/media/catalog/product/cache/1/image/800x800/9df78eab33525d08d6e5fb8d27136e95/5/i/5inch-dsi-lcd-d-2.jpg"> | [waveshare/esp_lcd_dsi](https://github.com/waveshareteam/waveshare-ESP32-components/tree/master/display/lcd/esp_lcd_dsi) | 🕒 |
| [6.25inch DSI LCD](https://www.waveshare.com/6.25inch-dsi-lcd.htm) <br/><img style="width: 150px; height: auto; display: block; margin: 0 auto;" src="https://www.waveshare.com/media/catalog/product/cache/1/image/800x800/9df78eab33525d08d6e5fb8d27136e95/6/_/6.25inch-dsi-lcd-2.jpg"> | [waveshare/esp_lcd_dsi](https://github.com/waveshareteam/waveshare-ESP32-components/tree/master/display/lcd/esp_lcd_dsi) | 🕒 |
| [5inch DSI LCD (C)](https://www.waveshare.com/5inch-dsi-lcd-c.htm) <br/><img style="width: 150px; height: auto; display: block; margin: 0 auto;" src="https://www.waveshare.com/media/catalog/product/cache/1/image/800x800/9df78eab33525d08d6e5fb8d27136e95/5/i/5inch-dsi-lcd-c-2.jpg"> | [waveshare/esp_lcd_dsi](https://github.com/waveshareteam/waveshare-ESP32-components/tree/master/display/lcd/esp_lcd_dsi) | 🕒 |
| [7inch DSI LCD (C)](https://www.waveshare.com/7inch-dsi-lcd-c-with-case-a.htm) <br/><img style="width: 150px; height: auto; display: block; margin: 0 auto;" src="https://www.waveshare.com/media/catalog/product/cache/1/image/800x800/9df78eab33525d08d6e5fb8d27136e95/7/i/7inch-dsi-lcd-c-4.jpg"> | [waveshare/esp_lcd_dsi](https://github.com/waveshareteam/waveshare-ESP32-components/tree/master/display/lcd/esp_lcd_dsi) | 🕒 |
| [7.9inch DSI LCD](https://www.waveshare.com/7.9inch-dsi-lcd.htm) <br/><img style="width: 150px; height: auto; display: block; margin: 0 auto;" src="https://www.waveshare.com/media/catalog/product/cache/1/image/800x800/9df78eab33525d08d6e5fb8d27136e95/7/_/7.9inch-dsi-lcd-2.jpg"> | [waveshare/esp_lcd_dsi](https://github.com/waveshareteam/waveshare-ESP32-components/tree/master/display/lcd/esp_lcd_dsi) | 🕒 |
| [7inch DSI LCD (E)](https://www.waveshare.com/7inch-dsi-lcd-e.htm) <br/><img style="width: 150px; height: auto; display: block; margin: 0 auto;" src="https://www.waveshare.com/media/catalog/product/cache/1/image/800x800/9df78eab33525d08d6e5fb8d27136e95/7/i/7inch-dsi-lcd-e-2.jpg"> | [waveshare/esp_lcd_dsi](https://github.com/waveshareteam/waveshare-ESP32-components/tree/master/display/lcd/esp_lcd_dsi) | 🕒 |
| [8inch DSI LCD (C)](https://www.waveshare.com/8inch-dsi-lcd-c.htm) <br/><img style="width: 150px; height: auto; display: block; margin: 0 auto;" src="https://www.waveshare.com/media/catalog/product/cache/1/image/800x800/9df78eab33525d08d6e5fb8d27136e95/8/i/8inch-dsi-lcd-c-2.jpg"> | [waveshare/esp_lcd_dsi](https://github.com/waveshareteam/waveshare-ESP32-components/tree/master/display/lcd/esp_lcd_dsi) | 🕒 |
| [10.1inch DSI LCD (C)](https://www.waveshare.com/10.1inch-dsi-lcd-c.htm) <br/><img style="width: 150px; height: auto; display: block; margin: 0 auto;" src="https://www.waveshare.com/media/catalog/product/cache/1/image/800x800/9df78eab33525d08d6e5fb8d27136e95/1/0/10.1inch-dsi-lcd-c-2.jpg"> | [waveshare/esp_lcd_dsi](https://github.com/waveshareteam/waveshare-ESP32-components/tree/master/display/lcd/esp_lcd_dsi) | 🕒 |
| [8.8inch DSI LCD](https://www.waveshare.com/8.8inch-dsi-lcd.htm) <br/><img style="width: 150px; height: auto; display: block; margin: 0 auto;" src="https://www.waveshare.com/media/catalog/product/cache/1/image/800x800/9df78eab33525d08d6e5fb8d27136e95/8/_/8.8inch-dsi-lcd-2.jpg"> | [waveshare/esp_lcd_dsi](https://github.com/waveshareteam/waveshare-ESP32-components/tree/master/display/lcd/esp_lcd_dsi) | 🕒 |
| [11.9inch DSI LCD](https://www.waveshare.com/11.9inch-dsi-lcd.htm) <br/><img style="width: 150px; height: auto; display: block; margin: 0 auto;" src="https://www.waveshare.com/media/catalog/product/cache/1/image/800x800/9df78eab33525d08d6e5fb8d27136e95/1/1/11.9inch-dsi-lcd-3.jpg"> | [waveshare/esp_lcd_dsi](https://github.com/waveshareteam/waveshare-ESP32-components/tree/master/display/lcd/esp_lcd_dsi) | 🕒 |
| [7-DSI-TOUCH-A](https://www.waveshare.com/7-dsi-touch-a.htm) <br/><img style="width: 150px; height: auto; display: block; margin: 0 auto;" src="https://www.waveshare.com/media/catalog/product/cache/1/image/800x800/9df78eab33525d08d6e5fb8d27136e95/7/-/7-dsi-touch-a-1.jpg"> | [waveshare/esp_lcd_ili9881c](https://github.com/waveshareteam/waveshare-ESP32-components/tree/master/display/lcd/esp_lcd_ili9881c) | 🕒 |
</details>

View File

@@ -1,11 +1,11 @@
{
"manufacturer": "waveshare",
"target": "esp32p4",
"builds": [
{
"name": "waveshare-p4-nano-10.1-a",
"name": "esp32-p4-nano-10.1-a",
"sdkconfig_append": [
"CONFIG_USE_WECHAT_MESSAGE_STYLE=y",
"CONFIG_LCD_TYPE_800_1280_10_1_INCH_A=y",
"CONFIG_CAMERA_OV5647=y",
"CONFIG_CAMERA_OV5647_AUTO_DETECT_MIPI_INTERFACE_SENSOR=y",
"CONFIG_CAMERA_OV5647_MIPI_RAW8_800X800_50FPS=y",

View File

@@ -4,7 +4,6 @@
#include "display/lcd_display.h"
// #include "display/no_display.h"
#include "button.h"
#include "config.h"
#include "esp_video.h"
#include "esp_video_init.h"
@@ -15,7 +14,8 @@
#include "esp_ldo_regulator.h"
#include "esp_lcd_mipi_dsi.h"
#include "esp_lcd_jd9365_10_1.h"
#include "esp_lcd_jd9365.h"
#include "config.h"
#include <esp_log.h>
#include <driver/i2c_master.h>
@@ -33,11 +33,7 @@ protected:
virtual void SetBrightnessImpl(uint8_t brightness) override {
uint8_t i2c_address = 0x45; // 7-bit address
#if CONFIG_LCD_TYPE_800_1280_10_1_INCH
uint8_t reg = 0x86;
#elif CONFIG_LCD_TYPE_800_1280_10_1_INCH_A
uint8_t reg = 0x96;
#endif
uint8_t data[2] = {reg, brightness};
i2c_master_dev_handle_t dev_handle;
@@ -105,6 +101,23 @@ private:
}
void InitializeLCD() {
uint8_t chip_addr = 0x45;
uint8_t write_cmds[4][2] = {{0x95, 0x11}, {0x95, 0x17}, {0x96, 0x00}, {0x96, 0xFF}};
i2c_device_config_t i2c_dev_conf = {
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
.device_address = chip_addr,
.scl_speed_hz = 100000,
};
i2c_master_dev_handle_t dev_handle = NULL;
if (i2c_master_bus_add_device(codec_i2c_bus_, &i2c_dev_conf, &dev_handle) == ESP_OK)
{
for (uint8_t i = 0; i < 4; i++)
{
i2c_master_transmit(dev_handle, write_cmds[i], 2, 50);
}
i2c_master_bus_rm_device(dev_handle);
}
bsp_enable_dsi_phy_power();
esp_lcd_panel_io_handle_t io = NULL;
esp_lcd_panel_handle_t disp_panel = NULL;
@@ -143,15 +156,13 @@ private:
};
jd9365_vendor_config_t vendor_config = {
.init_cmds = lcd_init_cmds,
.init_cmds_size = sizeof(lcd_init_cmds) / sizeof(lcd_init_cmds[0]),
.mipi_config = {
.dsi_bus = mipi_dsi_bus,
.dpi_config = &dpi_config,
.lane_num = 2,
},
.flags = {
.use_mipi_interface = 1,
},
};
const esp_lcd_panel_dev_config_t lcd_dev_config = {

View File

@@ -0,0 +1,224 @@
static const jd9365_lcd_init_cmd_t lcd_init_cmds[] = {
{0xE0, (uint8_t[]){0x00}, 1, 0},
{0xE1, (uint8_t[]){0x93}, 1, 0},
{0xE2, (uint8_t[]){0x65}, 1, 0},
{0xE3, (uint8_t[]){0xF8}, 1, 0},
{0x80, (uint8_t[]){0x01}, 1, 0},
{0xE0, (uint8_t[]){0x01}, 1, 0},
{0x00, (uint8_t[]){0x00}, 1, 0},
{0x01, (uint8_t[]){0x38}, 1, 0},
{0x03, (uint8_t[]){0x10}, 1, 0},
{0x04, (uint8_t[]){0x38}, 1, 0},
{0x0C, (uint8_t[]){0x74}, 1, 0},
{0x17, (uint8_t[]){0x00}, 1, 0},
{0x18, (uint8_t[]){0xAF}, 1, 0},
{0x19, (uint8_t[]){0x00}, 1, 0},
{0x1A, (uint8_t[]){0x00}, 1, 0},
{0x1B, (uint8_t[]){0xAF}, 1, 0},
{0x1C, (uint8_t[]){0x00}, 1, 0},
{0x35, (uint8_t[]){0x26}, 1, 0},
{0x37, (uint8_t[]){0x09}, 1, 0},
{0x38, (uint8_t[]){0x04}, 1, 0},
{0x39, (uint8_t[]){0x00}, 1, 0},
{0x3A, (uint8_t[]){0x01}, 1, 0},
{0x3C, (uint8_t[]){0x78}, 1, 0},
{0x3D, (uint8_t[]){0xFF}, 1, 0},
{0x3E, (uint8_t[]){0xFF}, 1, 0},
{0x3F, (uint8_t[]){0x7F}, 1, 0},
{0x40, (uint8_t[]){0x06}, 1, 0},
{0x41, (uint8_t[]){0xA0}, 1, 0},
{0x42, (uint8_t[]){0x81}, 1, 0},
{0x43, (uint8_t[]){0x1E}, 1, 0},
{0x44, (uint8_t[]){0x0D}, 1, 0},
{0x45, (uint8_t[]){0x28}, 1, 0},
//{0x4A, (uint8_t[]){0x35}, 1, 0},//bist
{0x55, (uint8_t[]){0x02}, 1, 0},
{0x57, (uint8_t[]){0x69}, 1, 0},
{0x59, (uint8_t[]){0x0A}, 1, 0},
{0x5A, (uint8_t[]){0x2A}, 1, 0},
{0x5B, (uint8_t[]){0x17}, 1, 0},
{0x5D, (uint8_t[]){0x7F}, 1, 0},
{0x5E, (uint8_t[]){0x6A}, 1, 0},
{0x5F, (uint8_t[]){0x5B}, 1, 0},
{0x60, (uint8_t[]){0x4F}, 1, 0},
{0x61, (uint8_t[]){0x4A}, 1, 0},
{0x62, (uint8_t[]){0x3D}, 1, 0},
{0x63, (uint8_t[]){0x41}, 1, 0},
{0x64, (uint8_t[]){0x2A}, 1, 0},
{0x65, (uint8_t[]){0x44}, 1, 0},
{0x66, (uint8_t[]){0x43}, 1, 0},
{0x67, (uint8_t[]){0x44}, 1, 0},
{0x68, (uint8_t[]){0x62}, 1, 0},
{0x69, (uint8_t[]){0x52}, 1, 0},
{0x6A, (uint8_t[]){0x59}, 1, 0},
{0x6B, (uint8_t[]){0x4C}, 1, 0},
{0x6C, (uint8_t[]){0x48}, 1, 0},
{0x6D, (uint8_t[]){0x3A}, 1, 0},
{0x6E, (uint8_t[]){0x26}, 1, 0},
{0x6F, (uint8_t[]){0x00}, 1, 0},
{0x70, (uint8_t[]){0x7F}, 1, 0},
{0x71, (uint8_t[]){0x6A}, 1, 0},
{0x72, (uint8_t[]){0x5B}, 1, 0},
{0x73, (uint8_t[]){0x4F}, 1, 0},
{0x74, (uint8_t[]){0x4A}, 1, 0},
{0x75, (uint8_t[]){0x3D}, 1, 0},
{0x76, (uint8_t[]){0x41}, 1, 0},
{0x77, (uint8_t[]){0x2A}, 1, 0},
{0x78, (uint8_t[]){0x44}, 1, 0},
{0x79, (uint8_t[]){0x43}, 1, 0},
{0x7A, (uint8_t[]){0x44}, 1, 0},
{0x7B, (uint8_t[]){0x62}, 1, 0},
{0x7C, (uint8_t[]){0x52}, 1, 0},
{0x7D, (uint8_t[]){0x59}, 1, 0},
{0x7E, (uint8_t[]){0x4C}, 1, 0},
{0x7F, (uint8_t[]){0x48}, 1, 0},
{0x80, (uint8_t[]){0x3A}, 1, 0},
{0x81, (uint8_t[]){0x26}, 1, 0},
{0x82, (uint8_t[]){0x00}, 1, 0},
{0xE0, (uint8_t[]){0x02}, 1, 0},
{0x00, (uint8_t[]){0x42}, 1, 0},
{0x01, (uint8_t[]){0x42}, 1, 0},
{0x02, (uint8_t[]){0x40}, 1, 0},
{0x03, (uint8_t[]){0x40}, 1, 0},
{0x04, (uint8_t[]){0x5E}, 1, 0},
{0x05, (uint8_t[]){0x5E}, 1, 0},
{0x06, (uint8_t[]){0x5F}, 1, 0},
{0x07, (uint8_t[]){0x5F}, 1, 0},
{0x08, (uint8_t[]){0x5F}, 1, 0},
{0x09, (uint8_t[]){0x57}, 1, 0},
{0x0A, (uint8_t[]){0x57}, 1, 0},
{0x0B, (uint8_t[]){0x77}, 1, 0},
{0x0C, (uint8_t[]){0x77}, 1, 0},
{0x0D, (uint8_t[]){0x47}, 1, 0},
{0x0E, (uint8_t[]){0x47}, 1, 0},
{0x0F, (uint8_t[]){0x45}, 1, 0},
{0x10, (uint8_t[]){0x45}, 1, 0},
{0x11, (uint8_t[]){0x4B}, 1, 0},
{0x12, (uint8_t[]){0x4B}, 1, 0},
{0x13, (uint8_t[]){0x49}, 1, 0},
{0x14, (uint8_t[]){0x49}, 1, 0},
{0x15, (uint8_t[]){0x5F}, 1, 0},
{0x16, (uint8_t[]){0x41}, 1, 0},
{0x17, (uint8_t[]){0x41}, 1, 0},
{0x18, (uint8_t[]){0x40}, 1, 0},
{0x19, (uint8_t[]){0x40}, 1, 0},
{0x1A, (uint8_t[]){0x5E}, 1, 0},
{0x1B, (uint8_t[]){0x5E}, 1, 0},
{0x1C, (uint8_t[]){0x5F}, 1, 0},
{0x1D, (uint8_t[]){0x5F}, 1, 0},
{0x1E, (uint8_t[]){0x5F}, 1, 0},
{0x1F, (uint8_t[]){0x57}, 1, 0},
{0x20, (uint8_t[]){0x57}, 1, 0},
{0x21, (uint8_t[]){0x77}, 1, 0},
{0x22, (uint8_t[]){0x77}, 1, 0},
{0x23, (uint8_t[]){0x46}, 1, 0},
{0x24, (uint8_t[]){0x46}, 1, 0},
{0x25, (uint8_t[]){0x44}, 1, 0},
{0x26, (uint8_t[]){0x44}, 1, 0},
{0x27, (uint8_t[]){0x4A}, 1, 0},
{0x28, (uint8_t[]){0x4A}, 1, 0},
{0x29, (uint8_t[]){0x48}, 1, 0},
{0x2A, (uint8_t[]){0x48}, 1, 0},
{0x2B, (uint8_t[]){0x5F}, 1, 0},
{0x2C, (uint8_t[]){0x01}, 1, 0},
{0x2D, (uint8_t[]){0x01}, 1, 0},
{0x2E, (uint8_t[]){0x00}, 1, 0},
{0x2F, (uint8_t[]){0x00}, 1, 0},
{0x30, (uint8_t[]){0x1F}, 1, 0},
{0x31, (uint8_t[]){0x1F}, 1, 0},
{0x32, (uint8_t[]){0x1E}, 1, 0},
{0x33, (uint8_t[]){0x1E}, 1, 0},
{0x34, (uint8_t[]){0x1F}, 1, 0},
{0x35, (uint8_t[]){0x17}, 1, 0},
{0x36, (uint8_t[]){0x17}, 1, 0},
{0x37, (uint8_t[]){0x37}, 1, 0},
{0x38, (uint8_t[]){0x37}, 1, 0},
{0x39, (uint8_t[]){0x08}, 1, 0},
{0x3A, (uint8_t[]){0x08}, 1, 0},
{0x3B, (uint8_t[]){0x0A}, 1, 0},
{0x3C, (uint8_t[]){0x0A}, 1, 0},
{0x3D, (uint8_t[]){0x04}, 1, 0},
{0x3E, (uint8_t[]){0x04}, 1, 0},
{0x3F, (uint8_t[]){0x06}, 1, 0},
{0x40, (uint8_t[]){0x06}, 1, 0},
{0x41, (uint8_t[]){0x1F}, 1, 0},
{0x42, (uint8_t[]){0x02}, 1, 0},
{0x43, (uint8_t[]){0x02}, 1, 0},
{0x44, (uint8_t[]){0x00}, 1, 0},
{0x45, (uint8_t[]){0x00}, 1, 0},
{0x46, (uint8_t[]){0x1F}, 1, 0},
{0x47, (uint8_t[]){0x1F}, 1, 0},
{0x48, (uint8_t[]){0x1E}, 1, 0},
{0x49, (uint8_t[]){0x1E}, 1, 0},
{0x4A, (uint8_t[]){0x1F}, 1, 0},
{0x4B, (uint8_t[]){0x17}, 1, 0},
{0x4C, (uint8_t[]){0x17}, 1, 0},
{0x4D, (uint8_t[]){0x37}, 1, 0},
{0x4E, (uint8_t[]){0x37}, 1, 0},
{0x4F, (uint8_t[]){0x09}, 1, 0},
{0x50, (uint8_t[]){0x09}, 1, 0},
{0x51, (uint8_t[]){0x0B}, 1, 0},
{0x52, (uint8_t[]){0x0B}, 1, 0},
{0x53, (uint8_t[]){0x05}, 1, 0},
{0x54, (uint8_t[]){0x05}, 1, 0},
{0x55, (uint8_t[]){0x07}, 1, 0},
{0x56, (uint8_t[]){0x07}, 1, 0},
{0x57, (uint8_t[]){0x1F}, 1, 0},
{0x58, (uint8_t[]){0x40}, 1, 0},
{0x5B, (uint8_t[]){0x30}, 1, 0},
{0x5C, (uint8_t[]){0x00}, 1, 0},
{0x5D, (uint8_t[]){0x34}, 1, 0},
{0x5E, (uint8_t[]){0x05}, 1, 0},
{0x5F, (uint8_t[]){0x02}, 1, 0},
{0x63, (uint8_t[]){0x00}, 1, 0},
{0x64, (uint8_t[]){0x6A}, 1, 0},
{0x67, (uint8_t[]){0x73}, 1, 0},
{0x68, (uint8_t[]){0x07}, 1, 0},
{0x69, (uint8_t[]){0x08}, 1, 0},
{0x6A, (uint8_t[]){0x6A}, 1, 0},
{0x6B, (uint8_t[]){0x08}, 1, 0},
{0x6C, (uint8_t[]){0x00}, 1, 0},
{0x6D, (uint8_t[]){0x00}, 1, 0},
{0x6E, (uint8_t[]){0x00}, 1, 0},
{0x6F, (uint8_t[]){0x88}, 1, 0},
{0x75, (uint8_t[]){0xFF}, 1, 0},
{0x77, (uint8_t[]){0xDD}, 1, 0},
{0x78, (uint8_t[]){0x2C}, 1, 0},
{0x79, (uint8_t[]){0x15}, 1, 0},
{0x7A, (uint8_t[]){0x17}, 1, 0},
{0x7D, (uint8_t[]){0x14}, 1, 0},
{0x7E, (uint8_t[]){0x82}, 1, 0},
{0xE0, (uint8_t[]){0x04}, 1, 0},
{0x00, (uint8_t[]){0x0E}, 1, 0},
{0x02, (uint8_t[]){0xB3}, 1, 0},
{0x09, (uint8_t[]){0x61}, 1, 0},
{0x0E, (uint8_t[]){0x48}, 1, 0},
{0x37, (uint8_t[]){0x58}, 1, 0}, // 全志
{0x2B, (uint8_t[]){0x0F}, 1, 0}, // 全志
{0xE0, (uint8_t[]){0x00}, 1, 0},
{0xE6, (uint8_t[]){0x02}, 1, 0},
{0xE7, (uint8_t[]){0x0C}, 1, 0},
{0x11, (uint8_t[]){0x00}, 1, 120},
{0x29, (uint8_t[]){0x00}, 1, 20},
};

View File

@@ -0,0 +1,17 @@
# Waveshare ESP32-P4-WIFI6-Touch-LCD
**ESP32-P4-WIFI6-Touch-LCD** series is the ESP32-P4 +ESP32-C6 screen development board launched by waveshare
## Configuration
Configuration in `menuconfig`.
Selection Board Type `Xiaozhi Assistant --> Board Type`
- Waveshare ESP32-P4-WIFI6-Touch-LCD-4B
- Waveshare ESP32-P4-WIFI6-Touch-LCD-7B
- Waveshare ESP32-P4-WIFI6-Touch-LCD-3.4C
- Waveshare ESP32-P4-WIFI6-Touch-LCD-4C
- Waveshare ESP32-P4-WIFI6-Touch-LCD-7
- Waveshare ESP32-P4-WIFI6-Touch-LCD-8
- Waveshare ESP32-P4-WIFI6-Touch-LCD-10.1

View File

@@ -0,0 +1,91 @@
#ifndef _BOARD_CONFIG_H_
#define _BOARD_CONFIG_H_
#include <driver/gpio.h>
#define AUDIO_INPUT_SAMPLE_RATE 24000
#define AUDIO_OUTPUT_SAMPLE_RATE 24000
#define AUDIO_INPUT_REFERENCE true
#define AUDIO_I2S_GPIO_MCLK GPIO_NUM_13
#define AUDIO_I2S_GPIO_WS GPIO_NUM_10
#define AUDIO_I2S_GPIO_BCLK GPIO_NUM_12
#define AUDIO_I2S_GPIO_DIN GPIO_NUM_11
#define AUDIO_I2S_GPIO_DOUT GPIO_NUM_9
#define AUDIO_CODEC_PA_PIN GPIO_NUM_53
#define AUDIO_CODEC_I2C_SDA_PIN GPIO_NUM_7
#define AUDIO_CODEC_I2C_SCL_PIN GPIO_NUM_8
#define AUDIO_CODEC_ES8311_ADDR ES8311_CODEC_DEFAULT_ADDR
#define AUDIO_CODEC_ES7210_ADDR ES7210_CODEC_DEFAULT_ADDR
#define BOOT_BUTTON_GPIO GPIO_NUM_35
#if CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_4B
#define DISPLAY_WIDTH (720)
#define DISPLAY_HEIGHT (720)
#define PIN_NUM_LCD_RST GPIO_NUM_27
#define DISPLAY_BACKLIGHT_PIN GPIO_NUM_26
#define DISPLAY_BACKLIGHT_OUTPUT_INVERT true
#define LCD_MIPI_DSI_LANE_BITRATE_MBPS (480)
#elif CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_7B
#define DISPLAY_WIDTH (1024)
#define DISPLAY_HEIGHT (600)
#define PIN_NUM_LCD_RST GPIO_NUM_33
#define DISPLAY_BACKLIGHT_PIN GPIO_NUM_32
#define DISPLAY_BACKLIGHT_OUTPUT_INVERT true
#define LCD_MIPI_DSI_LANE_BITRATE_MBPS (900)
#elif CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_3_4C
#define DISPLAY_WIDTH (800)
#define DISPLAY_HEIGHT (800)
#define PIN_NUM_LCD_RST GPIO_NUM_27
#define DISPLAY_BACKLIGHT_PIN GPIO_NUM_26
#define DISPLAY_BACKLIGHT_OUTPUT_INVERT true
#define LCD_MIPI_DSI_LANE_BITRATE_MBPS (1500)
#elif CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_4C
#define DISPLAY_WIDTH (720)
#define DISPLAY_HEIGHT (720)
#define PIN_NUM_LCD_RST GPIO_NUM_27
#define DISPLAY_BACKLIGHT_PIN GPIO_NUM_26
#define DISPLAY_BACKLIGHT_OUTPUT_INVERT true
#define LCD_MIPI_DSI_LANE_BITRATE_MBPS (1500)
#elif CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_7
#define DISPLAY_WIDTH (720)
#define DISPLAY_HEIGHT (1280)
#define PIN_NUM_LCD_RST GPIO_NUM_27
#define DISPLAY_BACKLIGHT_PIN GPIO_NUM_26
#define DISPLAY_BACKLIGHT_OUTPUT_INVERT false
#define LCD_MIPI_DSI_LANE_BITRATE_MBPS (1000)
#elif CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_8
#define DISPLAY_WIDTH (800)
#define DISPLAY_HEIGHT (1280)
#define PIN_NUM_LCD_RST GPIO_NUM_27
#define DISPLAY_BACKLIGHT_PIN GPIO_NUM_26
#define DISPLAY_BACKLIGHT_OUTPUT_INVERT false
#define LCD_MIPI_DSI_LANE_BITRATE_MBPS (1500)
#elif CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_10_1
#define DISPLAY_WIDTH (800)
#define DISPLAY_HEIGHT (1280)
#define PIN_NUM_LCD_RST GPIO_NUM_27
#define DISPLAY_BACKLIGHT_PIN GPIO_NUM_26
#define DISPLAY_BACKLIGHT_OUTPUT_INVERT false
#define LCD_MIPI_DSI_LANE_BITRATE_MBPS (1500)
#endif
#define LCD_BIT_PER_PIXEL (16)
#define DELAY_TIME_MS (3000)
#define LCD_MIPI_DSI_LANE_NUM (2) // 2 data lanes
#define MIPI_DSI_PHY_PWR_LDO_CHAN (3)
#define MIPI_DSI_PHY_PWR_LDO_VOLTAGE_MV (2500)
#define DISPLAY_SWAP_XY false
#define DISPLAY_MIRROR_X false
#define DISPLAY_MIRROR_Y false
#define DISPLAY_OFFSET_X 0
#define DISPLAY_OFFSET_Y 0
#endif // _BOARD_CONFIG_H_

View File

@@ -0,0 +1,104 @@
{
"manufacturer": "waveshare",
"target": "esp32p4",
"builds": [
{
"name": "esp32-p4-wifi6-touch-lcd-4b",
"sdkconfig_append": [
"CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=0",
"CONFIG_BOOTLOADER_CACHE_32BIT_ADDR_QUAD_FLASH=y",
"CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_4B=y",
"CONFIG_USE_WECHAT_MESSAGE_STYLE=n",
"CONFIG_USE_DEVICE_AEC=y",
"CONFIG_CAMERA_OV5647=y",
"CONFIG_CAMERA_OV5647_AUTO_DETECT_MIPI_INTERFACE_SENSOR=y",
"CONFIG_CAMERA_OV5647_MIPI_RAW8_800X800_50FPS=y",
"CONFIG_XIAOZHI_ENABLE_CAMERA_ENDIANNESS_SWAP=y"
]
},
{
"name": "esp32-p4-wifi6-touch-lcd-7b",
"sdkconfig_append": [
"CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=0",
"CONFIG_BOOTLOADER_CACHE_32BIT_ADDR_QUAD_FLASH=y",
"CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_7B=y",
"CONFIG_USE_WECHAT_MESSAGE_STYLE=n",
"CONFIG_USE_DEVICE_AEC=y",
"CONFIG_CAMERA_OV5647=y",
"CONFIG_CAMERA_OV5647_AUTO_DETECT_MIPI_INTERFACE_SENSOR=y",
"CONFIG_CAMERA_OV5647_MIPI_RAW8_800X800_50FPS=y",
"CONFIG_XIAOZHI_ENABLE_CAMERA_ENDIANNESS_SWAP=y"
]
},
{
"name": "esp32-p4-wifi6-touch-lcd-3.4c",
"sdkconfig_append": [
"CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=0",
"CONFIG_BOOTLOADER_CACHE_32BIT_ADDR_QUAD_FLASH=y",
"CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_3_4C=y",
"CONFIG_USE_WECHAT_MESSAGE_STYLE=n",
"CONFIG_USE_DEVICE_AEC=y",
"CONFIG_CAMERA_OV5647=y",
"CONFIG_CAMERA_OV5647_AUTO_DETECT_MIPI_INTERFACE_SENSOR=y",
"CONFIG_CAMERA_OV5647_MIPI_RAW8_800X800_50FPS=y",
"CONFIG_XIAOZHI_ENABLE_CAMERA_ENDIANNESS_SWAP=y"
]
},
{
"name": "esp32-p4-wifi6-touch-lcd-4c",
"sdkconfig_append": [
"CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=0",
"CONFIG_BOOTLOADER_CACHE_32BIT_ADDR_QUAD_FLASH=y",
"CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_4C=y",
"CONFIG_USE_WECHAT_MESSAGE_STYLE=n",
"CONFIG_USE_DEVICE_AEC=y",
"CONFIG_CAMERA_OV5647=y",
"CONFIG_CAMERA_OV5647_AUTO_DETECT_MIPI_INTERFACE_SENSOR=y",
"CONFIG_CAMERA_OV5647_MIPI_RAW8_800X800_50FPS=y",
"CONFIG_XIAOZHI_ENABLE_CAMERA_ENDIANNESS_SWAP=y"
]
},
{
"name": "esp32-p4-wifi6-touch-lcd-7",
"sdkconfig_append": [
"CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=0",
"CONFIG_BOOTLOADER_CACHE_32BIT_ADDR_QUAD_FLASH=y",
"CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_7=y",
"CONFIG_USE_WECHAT_MESSAGE_STYLE=n",
"CONFIG_USE_DEVICE_AEC=y",
"CONFIG_CAMERA_OV5647=y",
"CONFIG_CAMERA_OV5647_AUTO_DETECT_MIPI_INTERFACE_SENSOR=y",
"CONFIG_CAMERA_OV5647_MIPI_RAW8_800X800_50FPS=y",
"CONFIG_XIAOZHI_ENABLE_CAMERA_ENDIANNESS_SWAP=y"
]
},
{
"name": "esp32-p4-wifi6-touch-lcd-8",
"sdkconfig_append": [
"CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=0",
"CONFIG_BOOTLOADER_CACHE_32BIT_ADDR_QUAD_FLASH=y",
"CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_8=y",
"CONFIG_USE_WECHAT_MESSAGE_STYLE=n",
"CONFIG_USE_DEVICE_AEC=y",
"CONFIG_CAMERA_OV5647=y",
"CONFIG_CAMERA_OV5647_AUTO_DETECT_MIPI_INTERFACE_SENSOR=y",
"CONFIG_CAMERA_OV5647_MIPI_RAW8_800X800_50FPS=y",
"CONFIG_XIAOZHI_ENABLE_CAMERA_ENDIANNESS_SWAP=y"
]
},
{
"name": "esp32-p4-wifi6-touch-lcd-10.1",
"sdkconfig_append": [
"CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=0",
"CONFIG_BOOTLOADER_CACHE_32BIT_ADDR_QUAD_FLASH=y",
"CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_10_1=y",
"CONFIG_USE_WECHAT_MESSAGE_STYLE=n",
"CONFIG_USE_DEVICE_AEC=y",
"CONFIG_CAMERA_OV5647=y",
"CONFIG_CAMERA_OV5647_AUTO_DETECT_MIPI_INTERFACE_SENSOR=y",
"CONFIG_CAMERA_OV5647_MIPI_RAW8_800X800_50FPS=y",
"CONFIG_XIAOZHI_ENABLE_CAMERA_ENDIANNESS_SWAP=y"
]
}
]
}

View File

@@ -4,7 +4,6 @@
#include "display/lcd_display.h"
// #include "display/no_display.h"
#include "button.h"
#include "config.h"
#include "esp_video.h"
#include "esp_video_init.h"
@@ -14,21 +13,34 @@
#include "esp_lcd_mipi_dsi.h"
#include "esp_ldo_regulator.h"
#if CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_4B
#include "esp_lcd_st7703.h"
#elif CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_7B
#include "esp_lcd_ek79007.h"
#elif CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_3_4C || CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_4C \
|| CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_8 || CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_10_1
#include "esp_lcd_jd9365.h"
#elif CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_7
#include "esp_lcd_ili9881c.h"
#endif
#include "config.h"
#include "lcd_init_cmds.h"
#include <esp_log.h>
#include <driver/i2c_master.h>
#include <esp_lvgl_port.h>
#include "esp_lcd_touch_gt911.h"
#define TAG "WaveshareEsp32p47b"
#define TAG "WaveshareEsp32p4"
class WaveshareEsp32p47b : public WifiBoard {
class WaveshareEsp32p4 : public WifiBoard {
private:
i2c_master_bus_handle_t i2c_bus_;
Button boot_button_;
LcdDisplay *display_;
EspVideo* camera_ = nullptr;
esp_err_t i2c_device_probe(uint8_t addr) {
return i2c_master_probe(i2c_bus_, addr, 100);
}
@@ -74,16 +86,58 @@ private:
esp_lcd_dsi_bus_config_t bus_config = {
.bus_id = 0,
.num_data_lanes = 2,
.lane_bit_rate_mbps = 900,
.lane_bit_rate_mbps = LCD_MIPI_DSI_LANE_BITRATE_MBPS,
};
esp_lcd_new_dsi_bus(&bus_config, &mipi_dsi_bus);
ESP_LOGI(TAG, "Install MIPI DSI LCD control panel");
// we use DBI interface to send LCD commands and parameters
esp_lcd_dbi_io_config_t dbi_config = EK79007_PANEL_IO_DBI_CONFIG();
esp_lcd_dbi_io_config_t dbi_config = {
.virtual_channel = 0,
.lcd_cmd_bits = 8,
.lcd_param_bits = 8,
};
esp_lcd_new_panel_io_dbi(mipi_dsi_bus, &dbi_config, &io);
#if CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_4B
esp_lcd_dpi_panel_config_t dpi_config = {
.dpi_clk_src = MIPI_DSI_DPI_CLK_SRC_DEFAULT,
.dpi_clock_freq_mhz = 46,
.pixel_format = LCD_COLOR_PIXEL_FORMAT_RGB565,
.num_fbs = 1,
.video_timing = {
.h_size = 720,
.v_size = 720,
.hsync_pulse_width = 20,
.hsync_back_porch = 80,
.hsync_front_porch = 80,
.vsync_pulse_width = 4,
.vsync_back_porch = 12,
.vsync_front_porch = 30,
},
.flags = {
.use_dma2d = true,
},
};
st7703_vendor_config_t vendor_config = {
.mipi_config = {
.dsi_bus = mipi_dsi_bus,
.dpi_config = &dpi_config,
},
.flags = {
.use_mipi_interface = 1,
},
};
const esp_lcd_panel_dev_config_t lcd_dev_config = {
.reset_gpio_num = PIN_NUM_LCD_RST,
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,
.bits_per_pixel = 16,
.vendor_config = &vendor_config,
};
esp_lcd_new_panel_st7703(io, &lcd_dev_config, &disp_panel);
#elif CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_7B
esp_lcd_dpi_panel_config_t dpi_config = {
.dpi_clk_src = MIPI_DSI_DPI_CLK_SRC_DEFAULT,
.dpi_clock_freq_mhz = 52,
.pixel_format = LCD_COLOR_PIXEL_FORMAT_RGB565,
@@ -116,19 +170,123 @@ private:
.vendor_config = &vendor_config,
};
esp_lcd_new_panel_ek79007(io, &lcd_dev_config, &disp_panel);
#elif CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_3_4C || CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_4C
esp_lcd_dpi_panel_config_t dpi_config = {
.dpi_clk_src = MIPI_DSI_DPI_CLK_SRC_DEFAULT,
.dpi_clock_freq_mhz = 46,
.pixel_format = LCD_COLOR_PIXEL_FORMAT_RGB565,
.num_fbs = 1,
.video_timing = {
.h_size = DISPLAY_WIDTH,
.v_size = DISPLAY_HEIGHT,
.hsync_pulse_width = 20,
.hsync_back_porch = 20,
.hsync_front_porch = 40,
.vsync_pulse_width = 4,
.vsync_back_porch = 12,
.vsync_front_porch = 24,
},
.flags = {
.use_dma2d = true,
},
};
jd9365_vendor_config_t vendor_config = {
.init_cmds = lcd_init_cmds,
.init_cmds_size = sizeof(lcd_init_cmds) / sizeof(lcd_init_cmds[0]),
.mipi_config = {
.dsi_bus = mipi_dsi_bus,
.dpi_config = &dpi_config,
.lane_num = 2,
},
};
const esp_lcd_panel_dev_config_t lcd_dev_config = {
.reset_gpio_num = PIN_NUM_LCD_RST,
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,
.bits_per_pixel = 16,
.vendor_config = &vendor_config,
};
esp_lcd_new_panel_jd9365(io, &lcd_dev_config, &disp_panel);
#elif CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_8 || CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_10_1
esp_lcd_dpi_panel_config_t dpi_config = {
.dpi_clk_src = MIPI_DSI_DPI_CLK_SRC_DEFAULT,
.dpi_clock_freq_mhz = 52,
.pixel_format = LCD_COLOR_PIXEL_FORMAT_RGB565,
.num_fbs = 1,
.video_timing = {
.h_size = DISPLAY_WIDTH,
.v_size = DISPLAY_HEIGHT,
.hsync_pulse_width = 20,
.hsync_back_porch = 20,
.hsync_front_porch = 40,
.vsync_pulse_width = 4,
.vsync_back_porch = 10,
.vsync_front_porch = 30,
},
.flags = {
.use_dma2d = true,
},
};
jd9365_vendor_config_t vendor_config = {
.init_cmds = lcd_init_cmds,
.init_cmds_size = sizeof(lcd_init_cmds) / sizeof(lcd_init_cmds[0]),
.mipi_config = {
.dsi_bus = mipi_dsi_bus,
.dpi_config = &dpi_config,
.lane_num = 2,
},
};
const esp_lcd_panel_dev_config_t lcd_dev_config = {
.reset_gpio_num = PIN_NUM_LCD_RST,
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,
.bits_per_pixel = 16,
.vendor_config = &vendor_config,
};
esp_lcd_new_panel_jd9365(io, &lcd_dev_config, &disp_panel);
#elif CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_7
esp_lcd_dpi_panel_config_t dpi_config = {
.dpi_clk_src = MIPI_DSI_DPI_CLK_SRC_DEFAULT,
.dpi_clock_freq_mhz = 80,
.pixel_format = LCD_COLOR_PIXEL_FORMAT_RGB565,
.num_fbs = 1,
.video_timing = {
.h_size = DISPLAY_WIDTH,
.v_size = DISPLAY_HEIGHT,
.hsync_pulse_width = 50,
.hsync_back_porch = 239,
.hsync_front_porch = 33,
.vsync_pulse_width = 30,
.vsync_back_porch = 20,
.vsync_front_porch = 2,
},
.flags = {
.use_dma2d = true,
},
};
ili9881c_vendor_config_t vendor_config = {
.init_cmds = lcd_init_cmds,
.init_cmds_size = sizeof(lcd_init_cmds) / sizeof(lcd_init_cmds[0]),
.mipi_config = {
.dsi_bus = mipi_dsi_bus,
.dpi_config = &dpi_config,
.lane_num = 2,
},
};
const esp_lcd_panel_dev_config_t lcd_dev_config = {
.reset_gpio_num = PIN_NUM_LCD_RST,
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,
.bits_per_pixel = 16,
.vendor_config = &vendor_config,
};
esp_lcd_new_panel_ili9881c(io, &lcd_dev_config, &disp_panel);
#endif
esp_lcd_panel_reset(disp_panel);
esp_lcd_panel_init(disp_panel);
display_ = new MipiLcdDisplay(io, disp_panel, DISPLAY_WIDTH, DISPLAY_HEIGHT,
DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY);
lv_display_t *disp = lv_display_get_default();
if (disp) {
lv_disp_set_rotation(disp, LV_DISPLAY_ROTATION_180);
ESP_LOGI(TAG, "Display rotated 180 degrees");
} else {
ESP_LOGE(TAG, "Failed to get default display for rotation");
}
}
void InitializeTouch()
{
@@ -204,7 +362,7 @@ private:
}
public:
WaveshareEsp32p47b() :
WaveshareEsp32p4() :
boot_button_(BOOT_BUTTON_GPIO) {
InitializeCodecI2c();
InitializeLCD();
@@ -246,4 +404,4 @@ public:
};
DECLARE_BOARD(WaveshareEsp32p47b);
DECLARE_BOARD(WaveshareEsp32p4);

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,9 @@
{
"manufacturer": "waveshare",
"target": "esp32s3",
"builds": [
{
"name": "waveshare-s3-audio-board",
"name": "esp32-s3-audio-board",
"sdkconfig_append": [
"CONFIG_USE_WECHAT_MESSAGE_STYLE=y",
"CONFIG_CAMERA_OV2640=y",

Some files were not shown because too many files have changed in this diff Show More