Compare commits
38 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 969dde0d10 | |||
| 20d91a3507 | |||
| 7a7c74a747 | |||
| cc7cbe78ba | |||
| 314edc5c51 | |||
| 7e7890183e | |||
| 2c5d7757e5 | |||
| 43b4d35b2e | |||
| 33ed917172 | |||
| 89d51fdc23 | |||
| 022d9848de | |||
| 8afebe560a | |||
| a63f8bc08b | |||
| 4dc1a8c75f | |||
| 121a2d45e7 | |||
| 06b3b7613c | |||
| addf5fcc64 | |||
| a877d95f74 | |||
| 76a5c19000 | |||
| 7d63797dfa | |||
| 0f3199a812 | |||
| 6d51b9dbde | |||
| d340efe58d | |||
| d9f0ef13aa | |||
| 358819bf2e | |||
| cef581d723 | |||
| dbb8e1d409 | |||
| 78008ab9d3 | |||
| cab8a7cecf | |||
| 74fa5413fc | |||
| cc4e12fa74 | |||
| 1c195fea4f | |||
| a4bf13b30d | |||
| 619dd2801c | |||
| 280b2ff856 | |||
| 527cd1fd58 | |||
| 55698b2d74 | |||
| e503a32d84 |
@@ -20,7 +20,7 @@ jobs:
|
||||
variants: ${{ steps.select.outputs.variants }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
|
||||
+1
-1
@@ -9,5 +9,5 @@ include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
# "Trim" the build. Include the minimal set of components, main, and anything it depends on.
|
||||
idf_build_set_property(MINIMAL_BUILD ON)
|
||||
|
||||
set(PROJECT_VER "2.2.4")
|
||||
set(PROJECT_VER "2.2.5")
|
||||
project(xiaozhi)
|
||||
|
||||
@@ -160,7 +160,7 @@ This is an open-source ESP32 project, released under the MIT license, allowing a
|
||||
|
||||
We hope this project helps everyone understand AI hardware development and apply rapidly evolving large language models to real hardware devices.
|
||||
|
||||
If you have any ideas or suggestions, please feel free to raise Issues or join our [Discord](https://discord.gg/bXqgAfRm) or QQ group: 994694848
|
||||
If you have any ideas or suggestions, please feel free to raise Issues or join our [Discord](https://discord.gg/C759fGMBcZ) or QQ group: 994694848
|
||||
|
||||
## Star History
|
||||
|
||||
@@ -170,4 +170,4 @@ If you have any ideas or suggestions, please feel free to raise Issues or join o
|
||||
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=78/xiaozhi-esp32&type=Date" />
|
||||
<img alt="Star History Chart" src="https://api.star-history.com/svg?repos=78/xiaozhi-esp32&type=Date" />
|
||||
</picture>
|
||||
</a>
|
||||
</a>
|
||||
+1
-1
@@ -156,7 +156,7 @@ Feishuドキュメントチュートリアルをご覧ください:
|
||||
|
||||
このプロジェクトを通じて、AIハードウェア開発を理解し、急速に進化する大規模言語モデルを実際のハードウェアデバイスに応用できるようになることを目指しています。
|
||||
|
||||
ご意見やご提案があれば、いつでもIssueを提出するか、[Discord](https://discord.gg/bXqgAfRm) または QQグループ:1011329060 にご参加ください。
|
||||
ご意見やご提案があれば、いつでもIssueを提出するか、[Discord](https://discord.gg/C759fGMBcZ) または QQグループ:1011329060 にご参加ください。
|
||||
|
||||
## スター履歴
|
||||
|
||||
|
||||
+1
-1
@@ -156,7 +156,7 @@ v1 的稳定版本为 1.9.2,可以通过 `git checkout v1` 来切换到 v1 版
|
||||
|
||||
我们希望通过这个项目,能够帮助大家了解 AI 硬件开发,将当下飞速发展的大语言模型应用到实际的硬件设备中。
|
||||
|
||||
如果你有任何想法或建议,请随时提出 Issues 或加入 [Discord](https://discord.gg/bXqgAfRm) 或 QQ 群:1011329060
|
||||
如果你有任何想法或建议,请随时提出 Issues 或加入 [Discord](https://discord.gg/C759fGMBcZ) 或 QQ 群:1011329060
|
||||
|
||||
## Star History
|
||||
|
||||
|
||||
@@ -273,6 +273,12 @@ elseif(CONFIG_BOARD_TYPE_WAVESHARE_ESP32_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_ESP32_S3_CAM_XXXX)
|
||||
set(MANUFACTURER "waveshare")
|
||||
set(BOARD_TYPE "esp32-s3-cam")
|
||||
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_ESP32_S3_AUDIO_BOARD)
|
||||
set(MANUFACTURER "waveshare")
|
||||
set(BOARD_TYPE "esp32-s3-audio-board")
|
||||
@@ -303,6 +309,12 @@ elseif(CONFIG_BOARD_TYPE_WAVESHARE_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_ESP32_C6_TOUCH_AMOLED_2_16)
|
||||
set(MANUFACTURER "waveshare")
|
||||
set(BOARD_TYPE "esp32-c6-touch-amoled-2.16")
|
||||
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_S3_TOUCH_LCD_4B)
|
||||
set(MANUFACTURER "waveshare")
|
||||
set(BOARD_TYPE "esp32-s3-touch-lcd-4b")
|
||||
@@ -387,6 +399,18 @@ elseif(CONFIG_BOARD_TYPE_WAVESHARE_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_ESP32_S3_TOUCH_LCD_1_54)
|
||||
set(MANUFACTURER "waveshare")
|
||||
set(BOARD_TYPE "esp32-s3-touch-lcd-1.54")
|
||||
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_ESP32_S3_LCD_0_85)
|
||||
set(MANUFACTURER "waveshare")
|
||||
set(BOARD_TYPE "esp32-s3-lcd-0.85")
|
||||
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_ESP32_C6_LCD_1_69)
|
||||
set(MANUFACTURER "waveshare")
|
||||
set(BOARD_TYPE "esp32-c6-lcd-1.69")
|
||||
@@ -429,6 +453,12 @@ elseif(CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_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_ESP32_P4_WIFI6_TOUCH_LCD_4_3)
|
||||
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_7B)
|
||||
set(MANUFACTURER "waveshare")
|
||||
set(BOARD_TYPE "esp32-p4-wifi6-touch-lcd")
|
||||
@@ -441,6 +471,12 @@ elseif(CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_3_4C)
|
||||
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_3_5)
|
||||
set(MANUFACTURER "waveshare")
|
||||
set(BOARD_TYPE "esp32-p4-wifi6-touch-lcd-3.5")
|
||||
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")
|
||||
@@ -728,6 +764,11 @@ elseif(CONFIG_BOARD_TYPE_HU_087)
|
||||
set(BOARD_TYPE "hu-087")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_14_1)
|
||||
set(BUILTIN_ICON_FONT font_awesome_14_1)
|
||||
elseif(CONFIG_BOARD_TYPE_Freenove_ESP32S3_DISPLAY_2_8_LCD)
|
||||
set(BOARD_TYPE "freenove-esp32s3-display-2.8-lcd")
|
||||
set(BUILTIN_TEXT_FONT font_puhui_basic_20_4)
|
||||
set(BUILTIN_ICON_FONT font_awesome_20_4)
|
||||
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
|
||||
endif()
|
||||
|
||||
if(MANUFACTURER)
|
||||
|
||||
+43
-2
@@ -269,6 +269,9 @@ choice BOARD_TYPE
|
||||
config BOARD_TYPE_WAVESHARE_ESP32_TOUCH_LCD_3_5
|
||||
bool "Waveshare ESP32-Touch-LCD-3.5"
|
||||
depends on IDF_TARGET_ESP32
|
||||
config BOARD_TYPE_WAVESHARE_ESP32_S3_CAM_XXXX
|
||||
bool "Waveshare ESP32-S3-CAM"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_WAVESHARE_ESP32_S3_AUDIO_BOARD
|
||||
bool "Waveshare ESP32-S3-Audio-Board"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
@@ -281,6 +284,9 @@ choice BOARD_TYPE
|
||||
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_ESP32_C6_TOUCH_AMOLED_2_16
|
||||
bool "Waveshare ESP32-C6-Touch-AMOLED-2.16"
|
||||
depends on IDF_TARGET_ESP32C6
|
||||
config BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_AMOLED_1_75
|
||||
bool "Waveshare ESP32-S3-Touch-AMOLED-1.75"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
@@ -344,18 +350,30 @@ choice BOARD_TYPE
|
||||
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_ESP32_S3_TOUCH_LCD_1_54
|
||||
bool "Waveshare ESP32-S3-Touch-LCD-1.54"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_WAVESHARE_ESP32_S3_LCD_0_85
|
||||
bool "Waveshare ESP32-S3-LCD-0.85"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_WAVESHARE_ESP32_P4_NANO
|
||||
bool "Waveshare ESP32-P4-NANO"
|
||||
depends on IDF_TARGET_ESP32P4
|
||||
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_ESP32_P4_WIFI6_TOUCH_LCD_4_3
|
||||
bool "Waveshare ESP32-P4-WIFI6-Touch-LCD-4.3"
|
||||
depends on IDF_TARGET_ESP32P4
|
||||
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_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_3_5
|
||||
bool "Waveshare ESP32-P4-WIFI6-Touch-LCD-3.5"
|
||||
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
|
||||
@@ -518,6 +536,9 @@ choice BOARD_TYPE
|
||||
config BOARD_TYPE_HU_087
|
||||
bool "HU-087"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_Freenove_ESP32S3_DISPLAY_2_8_LCD
|
||||
bool "Freenove ESP32S3 Display 2.8 LCD"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
endchoice
|
||||
|
||||
choice
|
||||
@@ -616,6 +637,25 @@ choice DISPLAY_ESP32S3_KORVO2_V3
|
||||
bool "ILI9341 240*320"
|
||||
endchoice
|
||||
|
||||
choice DISPLAY_ESP32S3_CAM_XXXX
|
||||
depends on BOARD_TYPE_WAVESHARE_ESP32_S3_CAM_XXXX
|
||||
prompt "ESP32S3_CAM LCD Type"
|
||||
default BSP_LCD_SIZE_2INCH
|
||||
help
|
||||
LCD Display Type
|
||||
config BSP_LCD_SIZE_2INCH
|
||||
bool "2inch Touch LCD Module"
|
||||
|
||||
config BSP_LCD_SIZE_2_8INCH
|
||||
bool "2.8inch Touch LCD Module"
|
||||
|
||||
config BSP_LCD_SIZE_3_5INCH
|
||||
bool "3.5inch Touch LCD Module"
|
||||
|
||||
config BSP_LCD_SIZE_1_83INCH
|
||||
bool "1.83inch Touch LCD Module"
|
||||
endchoice
|
||||
|
||||
choice DISPLAY_ESP32S3_AUDIO_BOARD
|
||||
depends on BOARD_TYPE_WAVESHARE_ESP32_S3_AUDIO_BOARD
|
||||
prompt "ESP32S3_AUDIO_BOARD LCD Type"
|
||||
@@ -754,11 +794,12 @@ config USE_DEVICE_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_ESP32_S3_TOUCH_AMOLED_1_75|| BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_AMOLED_1_75C || 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_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_4_3 \
|
||||
|| 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_ESP_VOCAT || 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)
|
||||
|| BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_LCD_4_3C || BOARD_TYPE_WAVESHARE_ESP32_S3_TOUCH_LCD_1_54 || BOARD_TYPE_WAVESHARE_ESP32_S3_LCD_0_85)
|
||||
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.
|
||||
|
||||
|
||||
@@ -840,9 +840,6 @@ void Application::ContinueWakeWordInvoke(const std::string& wake_word) {
|
||||
}
|
||||
// Set the chat state to wake word detected
|
||||
protocol_->SendWakeWordDetected(wake_word);
|
||||
|
||||
// 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
|
||||
|
||||
+20
-18
@@ -50,8 +50,8 @@ bool Assets::FindPartition(Assets* assets) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Assets::Apply() {
|
||||
return strategy_ ? strategy_->Apply(this) : false;
|
||||
bool Assets::Apply(bool refresh_display_theme) {
|
||||
return strategy_ ? strategy_->Apply(this, refresh_display_theme) : false;
|
||||
}
|
||||
|
||||
bool Assets::InitializePartition() {
|
||||
@@ -211,7 +211,7 @@ bool Assets::LvglStrategy::GetAssetData(Assets* assets, const std::string& name,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Assets::LvglStrategy::Apply(Assets* assets) {
|
||||
bool Assets::LvglStrategy::Apply(Assets* assets, bool refresh_display_theme) {
|
||||
void* ptr = nullptr;
|
||||
size_t size = 0;
|
||||
if (!assets->GetAssetData("index.json", ptr, size)) {
|
||||
@@ -332,22 +332,24 @@ bool Assets::LvglStrategy::Apply(Assets* assets) {
|
||||
}
|
||||
}
|
||||
|
||||
auto display = Board::GetInstance().GetDisplay();
|
||||
ESP_LOGI(TAG, "Refreshing display theme...");
|
||||
if (refresh_display_theme) {
|
||||
auto display = Board::GetInstance().GetDisplay();
|
||||
ESP_LOGI(TAG, "Refreshing display theme...");
|
||||
|
||||
auto current_theme = display->GetTheme();
|
||||
if (current_theme != nullptr) {
|
||||
display->SetTheme(current_theme);
|
||||
}
|
||||
auto current_theme = display->GetTheme();
|
||||
if (current_theme != nullptr) {
|
||||
display->SetTheme(current_theme);
|
||||
}
|
||||
|
||||
// Parse hide_subtitle configuration
|
||||
cJSON* hide_subtitle = cJSON_GetObjectItem(root, "hide_subtitle");
|
||||
if (cJSON_IsBool(hide_subtitle)) {
|
||||
bool hide = cJSON_IsTrue(hide_subtitle);
|
||||
auto lcd_display = dynamic_cast<LcdDisplay*>(display);
|
||||
if (lcd_display != nullptr) {
|
||||
lcd_display->SetHideSubtitle(hide);
|
||||
ESP_LOGI(TAG, "Set hide_subtitle to %s", hide ? "true" : "false");
|
||||
// Parse hide_subtitle configuration
|
||||
cJSON* hide_subtitle = cJSON_GetObjectItem(root, "hide_subtitle");
|
||||
if (cJSON_IsBool(hide_subtitle)) {
|
||||
bool hide = cJSON_IsTrue(hide_subtitle);
|
||||
auto lcd_display = dynamic_cast<LcdDisplay*>(display);
|
||||
if (lcd_display != nullptr) {
|
||||
lcd_display->SetHideSubtitle(hide);
|
||||
ESP_LOGI(TAG, "Set hide_subtitle to %s", hide ? "true" : "false");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -411,7 +413,7 @@ bool Assets::EmoteStrategy::GetAssetData(Assets* assets, const std::string& name
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Assets::EmoteStrategy::Apply(Assets* assets) {
|
||||
bool Assets::EmoteStrategy::Apply(Assets* assets, bool refresh_display_theme) {
|
||||
Assets::LoadSrmodelsFromIndex(assets);
|
||||
|
||||
auto display = Board::GetInstance().GetDisplay();
|
||||
|
||||
+4
-4
@@ -29,7 +29,7 @@ public:
|
||||
~Assets();
|
||||
|
||||
bool Download(std::string url, std::function<void(int progress, size_t speed)> progress_callback);
|
||||
bool Apply();
|
||||
bool Apply(bool refresh_display_theme = true);
|
||||
bool GetAssetData(const std::string& name, void*& ptr, size_t& size);
|
||||
|
||||
inline bool partition_valid() const { return partition_valid_; }
|
||||
@@ -48,7 +48,7 @@ private:
|
||||
class AssetStrategy {
|
||||
public:
|
||||
virtual ~AssetStrategy() = default;
|
||||
virtual bool Apply(Assets* assets) = 0;
|
||||
virtual bool Apply(Assets* assets, bool refresh_display_theme = true) = 0;
|
||||
virtual bool InitializePartition(Assets* assets) = 0;
|
||||
virtual void UnApplyPartition(Assets* assets) = 0;
|
||||
virtual bool GetAssetData(Assets* assets, const std::string& name, void*& ptr, size_t& size) = 0;
|
||||
@@ -56,7 +56,7 @@ private:
|
||||
|
||||
class LvglStrategy : public AssetStrategy {
|
||||
public:
|
||||
bool Apply(Assets* assets) override;
|
||||
bool Apply(Assets* assets, bool refresh_display_theme = true) override;
|
||||
bool InitializePartition(Assets* assets) override;
|
||||
void UnApplyPartition(Assets* assets) override;
|
||||
bool GetAssetData(Assets* assets, const std::string& name, void*& ptr, size_t& size) override;
|
||||
@@ -70,7 +70,7 @@ private:
|
||||
|
||||
class EmoteStrategy : public AssetStrategy {
|
||||
public:
|
||||
bool Apply(Assets* assets) override;
|
||||
bool Apply(Assets* assets, bool refresh_display_theme = true) override;
|
||||
bool InitializePartition(Assets* assets) override;
|
||||
void UnApplyPartition(Assets* assets) override;
|
||||
bool GetAssetData(Assets* assets, const std::string& name, void*& ptr, size_t& size) override;
|
||||
|
||||
@@ -156,7 +156,10 @@ void Es8311AudioCodec::CreateDuplexChannels(gpio_num_t mclk, gpio_num_t bclk, gp
|
||||
}
|
||||
|
||||
void Es8311AudioCodec::SetOutputVolume(int volume) {
|
||||
ESP_ERROR_CHECK(esp_codec_dev_set_out_vol(dev_, volume));
|
||||
std::lock_guard<std::mutex> lock(data_if_mutex_);
|
||||
if (dev_ != nullptr) {
|
||||
ESP_ERROR_CHECK(esp_codec_dev_set_out_vol(dev_, volume));
|
||||
}
|
||||
AudioCodec::SetOutputVolume(volume);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,10 @@ private:
|
||||
|
||||
public:
|
||||
LampController(gpio_num_t gpio_num) : gpio_num_(gpio_num) {
|
||||
if (gpio_num_ == GPIO_NUM_NC) {
|
||||
return;
|
||||
}
|
||||
|
||||
gpio_config_t config = {
|
||||
.pin_bit_mask = (1ULL << gpio_num_),
|
||||
.mode = GPIO_MODE_OUTPUT,
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include <driver/i2c.h>
|
||||
#include <driver/i2c_master.h>
|
||||
#include <driver/i2s_tdm.h>
|
||||
#include "adc_mic.h"
|
||||
#include "driver/i2s_pdm.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
@@ -44,18 +43,19 @@ AdcPdmAudioCodec::AdcPdmAudioCodec(int input_sample_rate, int output_sample_rate
|
||||
input_sample_rate_ = input_sample_rate;
|
||||
output_sample_rate_ = output_sample_rate;
|
||||
|
||||
uint8_t adc_channel[1] = {0};
|
||||
adc_channel[0] = adc_mic_channel;
|
||||
|
||||
audio_codec_adc_cfg_t cfg = {
|
||||
.handle = NULL,
|
||||
.max_store_buf_size = 1024 * 2,
|
||||
.conv_frame_size = 1024,
|
||||
.unit_id = ADC_UNIT_1,
|
||||
.adc_channel_list = adc_channel,
|
||||
.adc_channel_num = sizeof(adc_channel) / sizeof(adc_channel[0]),
|
||||
.sample_rate_hz = (uint32_t)input_sample_rate,
|
||||
};
|
||||
audio_codec_adc_cfg_t cfg = {};
|
||||
cfg.handle = NULL;
|
||||
cfg.continuous_cfg.max_store_buf_size = 1024 * 2;
|
||||
cfg.continuous_cfg.conv_frame_size = 1024;
|
||||
cfg.continuous_cfg.sample_freq_hz = (uint32_t)input_sample_rate;
|
||||
cfg.continuous_cfg.conv_mode = ADC_CONV_SINGLE_UNIT_1;
|
||||
cfg.continuous_cfg.format = ADC_DIGI_OUTPUT_FORMAT_TYPE2;
|
||||
cfg.continuous_cfg.pattern_num = 1;
|
||||
cfg.continuous_cfg.cfg_mode = AUDIO_CODEC_ADC_CFG_MODE_SINGLE_UNIT;
|
||||
cfg.continuous_cfg.cfg.single_unit.unit_id = ADC_UNIT_1;
|
||||
cfg.continuous_cfg.cfg.single_unit.atten = ADC_ATTEN_DB_12;
|
||||
cfg.continuous_cfg.cfg.single_unit.bit_width = ADC_BITWIDTH_12;
|
||||
cfg.continuous_cfg.cfg.single_unit.channel_id[0] = (uint8_t)adc_mic_channel;
|
||||
const audio_codec_data_if_t *adc_if = audio_codec_new_adc_data(&cfg);
|
||||
|
||||
esp_codec_dev_cfg_t codec_dev_cfg = {
|
||||
|
||||
@@ -26,7 +26,8 @@
|
||||
"CONFIG_NEWLIB_NANO_FORMAT=y",
|
||||
"CONFIG_ESP_CONSOLE_NONE=y",
|
||||
"CONFIG_USE_ESP_WAKE_WORD=y",
|
||||
"CONFIG_COMPILER_OPTIMIZATION_SIZE=y"
|
||||
"CONFIG_COMPILER_OPTIMIZATION_SIZE=y",
|
||||
"CONFIG_CODEC_DATA_ADC_SUPPORT=y"
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
@@ -186,7 +186,16 @@ private:
|
||||
},
|
||||
};
|
||||
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_GT1151_CONFIG();
|
||||
esp_lcd_panel_io_i2c_config_t tp_io_config = {
|
||||
.dev_addr = ESP_LCD_TOUCH_IO_I2C_GT1151_ADDRESS,
|
||||
.control_phase_bytes = 1,
|
||||
.dc_bit_offset = 0,
|
||||
.lcd_cmd_bits = 16,
|
||||
.flags =
|
||||
{
|
||||
.disable_control_phase = 1,
|
||||
}
|
||||
};
|
||||
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_ERROR_CHECK(esp_lcd_touch_new_i2c_gt1151(tp_io_handle, &tp_cfg, &tp));
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include <driver/i2c.h>
|
||||
#include <driver/i2c_master.h>
|
||||
#include <driver/i2s_tdm.h>
|
||||
#include "adc_mic.h"
|
||||
#include "driver/i2s_pdm.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
@@ -44,18 +43,19 @@ AdcPdmAudioCodec::AdcPdmAudioCodec(int input_sample_rate, int output_sample_rate
|
||||
input_sample_rate_ = input_sample_rate;
|
||||
output_sample_rate_ = output_sample_rate;
|
||||
|
||||
uint8_t adc_channel[1] = {0};
|
||||
adc_channel[0] = adc_mic_channel;
|
||||
|
||||
audio_codec_adc_cfg_t cfg = {
|
||||
.handle = NULL,
|
||||
.max_store_buf_size = 1024 * 2,
|
||||
.conv_frame_size = 1024,
|
||||
.unit_id = ADC_UNIT_1,
|
||||
.adc_channel_list = adc_channel,
|
||||
.adc_channel_num = sizeof(adc_channel) / sizeof(adc_channel[0]),
|
||||
.sample_rate_hz = (uint32_t)input_sample_rate,
|
||||
};
|
||||
audio_codec_adc_cfg_t cfg = {};
|
||||
cfg.handle = NULL;
|
||||
cfg.continuous_cfg.max_store_buf_size = 1024 * 2;
|
||||
cfg.continuous_cfg.conv_frame_size = 1024;
|
||||
cfg.continuous_cfg.sample_freq_hz = (uint32_t)input_sample_rate;
|
||||
cfg.continuous_cfg.conv_mode = ADC_CONV_SINGLE_UNIT_1;
|
||||
cfg.continuous_cfg.format = ADC_DIGI_OUTPUT_FORMAT_TYPE2;
|
||||
cfg.continuous_cfg.pattern_num = 1;
|
||||
cfg.continuous_cfg.cfg_mode = AUDIO_CODEC_ADC_CFG_MODE_SINGLE_UNIT;
|
||||
cfg.continuous_cfg.cfg.single_unit.unit_id = ADC_UNIT_1;
|
||||
cfg.continuous_cfg.cfg.single_unit.atten = ADC_ATTEN_DB_12;
|
||||
cfg.continuous_cfg.cfg.single_unit.bit_width = ADC_BITWIDTH_12;
|
||||
cfg.continuous_cfg.cfg.single_unit.channel_id[0] = (uint8_t)adc_mic_channel;
|
||||
const audio_codec_data_if_t *adc_if = audio_codec_new_adc_data(&cfg);
|
||||
|
||||
esp_codec_dev_cfg_t codec_dev_cfg = {
|
||||
|
||||
@@ -21,7 +21,8 @@
|
||||
"CONFIG_SR_WN_WN9S_HIESP=y",
|
||||
"CONFIG_USE_EMOTE_MESSAGE_STYLE=y",
|
||||
"CONFIG_FLASH_CUSTOM_ASSETS=y",
|
||||
"CONFIG_CUSTOM_ASSETS_FILE=\"https://dl.espressif.com/AE/wn9_nihaoxiaozhi_tts-font_puhui_common_20_4-echoear.bin\""
|
||||
"CONFIG_CUSTOM_ASSETS_FILE=\"https://dl.espressif.com/AE/wn9_nihaoxiaozhi_tts-font_puhui_common_20_4-echoear.bin\"",
|
||||
"CONFIG_CODEC_DATA_ADC_SUPPORT=y"
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
# Freenove ESP32-S3 ESP32 S3 Capacitive Touch Display CYD WiFi BT, 2.8 Inch 240x320 IPS Screen
|
||||
|
||||
[product](https://store.freenove.com/products/fnk0104)
|
||||
|
||||
Official github: [freenove-esp32s3-display-2.8-lcd](https://github.com/Freenove/Freenove_ESP32_S3_Display)
|
||||
@@ -0,0 +1,53 @@
|
||||
#ifndef _BOARD_CONFIG_H_
|
||||
#define _BOARD_CONFIG_H_
|
||||
|
||||
#include <driver/gpio.h>
|
||||
|
||||
#define AUDIO_INPUT_SAMPLE_RATE 24000
|
||||
#define AUDIO_OUTPUT_SAMPLE_RATE 24000
|
||||
|
||||
//音频iis部分
|
||||
#define AUDIO_I2S_GPIO_MCLK GPIO_NUM_4 //MCLK
|
||||
#define AUDIO_I2S_GPIO_BCLK GPIO_NUM_5 //SCK
|
||||
#define AUDIO_I2S_GPIO_DIN GPIO_NUM_6 //DIN
|
||||
#define AUDIO_I2S_GPIO_WS GPIO_NUM_7 //LRC
|
||||
#define AUDIO_I2S_GPIO_DOUT GPIO_NUM_8 //DOUT
|
||||
#define AUDIO_CODEC_PA_PIN GPIO_NUM_1 //PA
|
||||
|
||||
//音频iic部分
|
||||
#define AUDIO_CODEC_I2C_NUM I2C_NUM_0
|
||||
#define AUDIO_CODEC_I2C_SCL_PIN GPIO_NUM_15
|
||||
#define AUDIO_CODEC_I2C_SDA_PIN GPIO_NUM_16
|
||||
#define AUDIO_CODEC_ES8311_ADDR ES8311_CODEC_DEFAULT_ADDR
|
||||
|
||||
//boot引脚
|
||||
#define BOOT_BUTTON_GPIO GPIO_NUM_0
|
||||
#define BUILTIN_LED_GPIO GPIO_NUM_42
|
||||
|
||||
//屏幕显示部分
|
||||
#define DISPLAY_BACKLIGHT_PIN GPIO_NUM_45
|
||||
|
||||
#define DISPLAY_RST_PIN GPIO_NUM_NC
|
||||
#define DISPLAY_SCK_PIN GPIO_NUM_12
|
||||
#define DISPLAY_DC_PIN GPIO_NUM_46
|
||||
#define DISPLAY_CS_PIN GPIO_NUM_10
|
||||
#define DISPLAY_MOSI_PIN GPIO_NUM_11
|
||||
#define DISPLAY_MIS0_PIN GPIO_NUM_13
|
||||
#define DISPLAY_SPI_SCLK_HZ (20 * 1000 * 1000)
|
||||
|
||||
#define LCD_SPI_HOST SPI3_HOST
|
||||
|
||||
#define LCD_TYPE_ILI9341_SERIAL
|
||||
#define DISPLAY_WIDTH 320
|
||||
#define DISPLAY_HEIGHT 240
|
||||
#define DISPLAY_MIRROR_X false
|
||||
#define DISPLAY_MIRROR_Y false
|
||||
#define DISPLAY_SWAP_XY true
|
||||
#define DISPLAY_INVERT_COLOR true
|
||||
#define DISPLAY_RGB_ORDER LCD_RGB_ELEMENT_ORDER_BGR
|
||||
#define DISPLAY_OFFSET_X 0
|
||||
#define DISPLAY_OFFSET_Y 0
|
||||
#define DISPLAY_BACKLIGHT_OUTPUT_INVERT false
|
||||
#define DISPLAY_SPI_MODE 0
|
||||
|
||||
#endif // _BOARD_CONFIG_H_
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"target": "esp32s3",
|
||||
"builds": [
|
||||
{
|
||||
"name": "freenove-esp32s3-display-2.8-lcd",
|
||||
"sdkconfig_append": [
|
||||
"CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y",
|
||||
"CONFIG_PARTITION_TABLE_CUSTOM_FILENAME=\"partitions/v2/16m.csv\"",
|
||||
"CONFIG_LANGUAGE_EN_US=y"
|
||||
"CONFIG_SR_WN_WN9S_HIESP=y",
|
||||
"CONFIG_SR_WN_WN9_HIESP=y"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,229 @@
|
||||
#include <esp_lcd_panel_vendor.h>
|
||||
#include <esp_lcd_panel_io.h>
|
||||
#include <esp_lcd_panel_ops.h>
|
||||
|
||||
#include <wifi_station.h>
|
||||
#include "wifi_board.h"
|
||||
#include "codecs/es8311_audio_codec.h"
|
||||
#include "display/lcd_display.h"
|
||||
#include "application.h"
|
||||
#include "button.h"
|
||||
#include "config.h"
|
||||
#include "mcp_server.h"
|
||||
|
||||
#include <esp_log.h>
|
||||
#include <driver/i2c_master.h>
|
||||
#include <driver/spi_common.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include <esp_timer.h>
|
||||
|
||||
#include "led/single_led.h"
|
||||
#include "system_reset.h"
|
||||
#include "esp_lcd_ili9341.h"
|
||||
|
||||
#define TAG "FreenoveESP32S3Display"
|
||||
|
||||
class TouchDriver {
|
||||
public:
|
||||
TouchDriver() : dev_(nullptr) {}
|
||||
|
||||
bool Init(i2c_master_bus_handle_t bus, uint8_t addr) {
|
||||
i2c_device_config_t cfg = {
|
||||
.device_address = addr,
|
||||
.scl_speed_hz = 400000,
|
||||
.scl_wait_us = 0,
|
||||
};
|
||||
return i2c_master_bus_add_device(bus, &cfg, &dev_) == ESP_OK;
|
||||
}
|
||||
|
||||
bool Read(bool &touched, uint16_t &x, uint16_t &y) {
|
||||
touched = false;
|
||||
x = y = 0;
|
||||
if (!dev_) return false;
|
||||
|
||||
uint8_t reg = 0x02;
|
||||
uint8_t buf[5];
|
||||
if (i2c_master_transmit_receive(dev_, ®, 1, buf, 5, 50) != ESP_OK) return false;
|
||||
|
||||
uint8_t points = buf[0] & 0x0F;
|
||||
if (points == 0) return true;
|
||||
|
||||
touched = true;
|
||||
x = ((buf[1] & 0x0F) << 8) | buf[2];
|
||||
y = ((buf[3] & 0x0F) << 8) | buf[4];
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
i2c_master_dev_handle_t dev_;
|
||||
};
|
||||
|
||||
class FreenoveESP32S3Display : public WifiBoard {
|
||||
private:
|
||||
Button boot_button_;
|
||||
LcdDisplay *display_;
|
||||
i2c_master_bus_handle_t codec_i2c_bus_;
|
||||
TouchDriver touch_;
|
||||
|
||||
static void TouchTask(void *arg) {
|
||||
auto *self = static_cast<FreenoveESP32S3Display*>(arg);
|
||||
auto &app = Application::GetInstance();
|
||||
|
||||
uint32_t last_tap = 0;
|
||||
uint32_t down_start = 0;
|
||||
bool down = false;
|
||||
|
||||
while (true) {
|
||||
bool t;
|
||||
uint16_t x, y;
|
||||
self->touch_.Read(t, x, y);
|
||||
|
||||
uint32_t now = esp_timer_get_time() / 1000;
|
||||
|
||||
if (t) {
|
||||
if (!down) {
|
||||
down = true;
|
||||
down_start = now;
|
||||
}
|
||||
}
|
||||
|
||||
if (!t && down) {
|
||||
down = false;
|
||||
|
||||
uint32_t press = now - down_start;
|
||||
|
||||
// long tap
|
||||
if (press > 3000) {
|
||||
self->EnterWifiConfigMode();
|
||||
} else {
|
||||
// double tap
|
||||
if (now - last_tap < 250) {
|
||||
app.StartListening();
|
||||
last_tap = 0;
|
||||
} else {
|
||||
// single tap
|
||||
app.ToggleChatState();
|
||||
last_tap = now;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(50));
|
||||
}
|
||||
}
|
||||
|
||||
void InitializeTouch() {
|
||||
if (!touch_.Init(codec_i2c_bus_, 0x38)) return;
|
||||
xTaskCreatePinnedToCore(TouchTask, "touch_task", 4096, this, 5, nullptr, 0);
|
||||
}
|
||||
|
||||
void InitializeI2c() {
|
||||
i2c_master_bus_config_t i2c_bus_cfg = {
|
||||
.i2c_port = AUDIO_CODEC_I2C_NUM,
|
||||
.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, &codec_i2c_bus_));
|
||||
}
|
||||
|
||||
void InitializeSpi() {
|
||||
spi_bus_config_t buscfg = {};
|
||||
buscfg.mosi_io_num = DISPLAY_MOSI_PIN;
|
||||
buscfg.miso_io_num = DISPLAY_MIS0_PIN;
|
||||
buscfg.sclk_io_num = DISPLAY_SCK_PIN;
|
||||
buscfg.quadwp_io_num = GPIO_NUM_NC;
|
||||
buscfg.quadhd_io_num = GPIO_NUM_NC;
|
||||
buscfg.max_transfer_sz = DISPLAY_WIDTH * DISPLAY_HEIGHT * sizeof(uint16_t);
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(LCD_SPI_HOST, &buscfg, SPI_DMA_CH_AUTO));
|
||||
}
|
||||
|
||||
void InitializeButtons() {
|
||||
boot_button_.OnClick([this]() {
|
||||
auto &app = Application::GetInstance();
|
||||
if (app.GetDeviceState() == kDeviceStateStarting) {
|
||||
EnterWifiConfigMode();
|
||||
}
|
||||
app.ToggleChatState();
|
||||
});
|
||||
}
|
||||
|
||||
void InitializeLcdDisplay() {
|
||||
esp_lcd_panel_io_handle_t panel_io = nullptr;
|
||||
esp_lcd_panel_handle_t panel = nullptr;
|
||||
// 液晶屏控制IO初始化
|
||||
ESP_LOGD(TAG, "Install panel IO");
|
||||
esp_lcd_panel_io_spi_config_t io_config = {};
|
||||
io_config.cs_gpio_num = DISPLAY_CS_PIN;
|
||||
io_config.dc_gpio_num = DISPLAY_DC_PIN;
|
||||
io_config.spi_mode = DISPLAY_SPI_MODE;
|
||||
io_config.pclk_hz = DISPLAY_SPI_SCLK_HZ;
|
||||
io_config.trans_queue_depth = 10;
|
||||
io_config.lcd_cmd_bits = 8;
|
||||
io_config.lcd_param_bits = 8;
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi(LCD_SPI_HOST, &io_config, &panel_io));
|
||||
|
||||
// 初始化液晶屏驱动芯片
|
||||
ESP_LOGD(TAG, "Install LCD driver");
|
||||
esp_lcd_panel_dev_config_t panel_config = {};
|
||||
panel_config.reset_gpio_num = DISPLAY_RST_PIN;
|
||||
panel_config.rgb_ele_order = DISPLAY_RGB_ORDER;
|
||||
panel_config.bits_per_pixel = 16;
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_ili9341(panel_io, &panel_config, &panel));
|
||||
ESP_LOGI(TAG, "Install LCD driver ILI9341");
|
||||
esp_lcd_panel_reset(panel);
|
||||
|
||||
esp_lcd_panel_init(panel);
|
||||
esp_lcd_panel_invert_color(panel, DISPLAY_INVERT_COLOR);
|
||||
esp_lcd_panel_swap_xy(panel, DISPLAY_SWAP_XY);
|
||||
esp_lcd_panel_mirror(panel, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y);
|
||||
display_ = new SpiLcdDisplay(panel_io, panel,
|
||||
DISPLAY_WIDTH, DISPLAY_HEIGHT,
|
||||
DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y,
|
||||
DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY);
|
||||
}
|
||||
|
||||
void InitializeTools() {
|
||||
}
|
||||
|
||||
public:
|
||||
FreenoveESP32S3Display(): boot_button_(BOOT_BUTTON_GPIO)
|
||||
{
|
||||
InitializeI2c();
|
||||
InitializeSpi();
|
||||
InitializeLcdDisplay();
|
||||
InitializeTouch();
|
||||
InitializeButtons();
|
||||
InitializeTools();
|
||||
GetBacklight()->SetBrightness(100);
|
||||
}
|
||||
|
||||
virtual Led *GetLed() override {
|
||||
static SingleLed led(BUILTIN_LED_GPIO);
|
||||
return &led;
|
||||
}
|
||||
|
||||
virtual AudioCodec* GetAudioCodec() override {
|
||||
static Es8311AudioCodec audio_codec(codec_i2c_bus_, AUDIO_CODEC_I2C_NUM,
|
||||
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, true, true);
|
||||
return &audio_codec;
|
||||
}
|
||||
|
||||
virtual Display *GetDisplay() override { return display_; }
|
||||
|
||||
virtual Backlight *GetBacklight() override {
|
||||
static PwmBacklight backlight(DISPLAY_BACKLIGHT_PIN, DISPLAY_BACKLIGHT_OUTPUT_INVERT);
|
||||
return &backlight;
|
||||
}
|
||||
};
|
||||
|
||||
DECLARE_BOARD(FreenoveESP32S3Display);
|
||||
@@ -327,251 +327,164 @@ void EDARobotDog::LiftRightRearLeg(int period, int height) {
|
||||
//-- DOG GAIT MOVEMENTS -----------------------------------------//
|
||||
///////////////////////////////////////////////////////////////////
|
||||
|
||||
void EDARobotDog::Turn(float steps, int period, int dir) {
|
||||
|
||||
if (GetRestState() == true) {
|
||||
SetRestState(false);
|
||||
}
|
||||
|
||||
for (int step = 0; step < (int)steps; step++) {
|
||||
if (dir == LEFT) {
|
||||
|
||||
int current_pos[SERVO_COUNT];
|
||||
for (int i = 0; i < SERVO_COUNT; i++) {
|
||||
if (servo_pins_[i] != -1) {
|
||||
current_pos[i] = servo_[i].GetPosition();
|
||||
} else {
|
||||
current_pos[i] = LEG_HOME_POSITION;
|
||||
}
|
||||
}
|
||||
|
||||
current_pos[RIGHT_REAR_LEG] = 140; // servo3
|
||||
current_pos[LEFT_REAR_LEG] = 40; // servo2
|
||||
MoveServos(100, current_pos);
|
||||
|
||||
current_pos[RIGHT_FRONT_LEG] = 40; // servo4
|
||||
current_pos[LEFT_FRONT_LEG] = 140; // servo1
|
||||
MoveServos(100, current_pos);
|
||||
|
||||
current_pos[RIGHT_REAR_LEG] = 90; // servo3
|
||||
current_pos[LEFT_REAR_LEG] = 90; // servo2
|
||||
MoveServos(100, current_pos);
|
||||
|
||||
current_pos[RIGHT_FRONT_LEG] = 90; // servo4
|
||||
current_pos[LEFT_FRONT_LEG] = 90; // servo1
|
||||
MoveServos(100, current_pos);
|
||||
|
||||
|
||||
current_pos[RIGHT_FRONT_LEG] = 140; // servo4
|
||||
current_pos[LEFT_FRONT_LEG] = 40; // servo1
|
||||
MoveServos(100, current_pos);
|
||||
|
||||
|
||||
current_pos[RIGHT_REAR_LEG] = 40; // servo3
|
||||
current_pos[LEFT_REAR_LEG] = 140; // servo2
|
||||
MoveServos(100, current_pos);
|
||||
|
||||
|
||||
current_pos[RIGHT_FRONT_LEG] = 90; // servo4
|
||||
current_pos[LEFT_FRONT_LEG] = 90; // servo1
|
||||
MoveServos(100, current_pos);
|
||||
|
||||
|
||||
current_pos[RIGHT_REAR_LEG] = 90; // servo3
|
||||
current_pos[LEFT_REAR_LEG] = 90; // servo2
|
||||
MoveServos(100, current_pos);
|
||||
|
||||
// 舵机方向分析(从 Stretch/Sleep 推断物理前后方向):
|
||||
//
|
||||
// Stretch: LF=0, LR=180, RF=180, RR=0
|
||||
// → 前腿向前伸,后腿向后伸
|
||||
//
|
||||
// LEFT_FRONT_LEG (0): 减小=向前, 增大=向后
|
||||
// LEFT_REAR_LEG (1): 减小=向前, 增大=向后
|
||||
// RIGHT_FRONT_LEG (2): 增大=向前, 减小=向后
|
||||
// RIGHT_REAR_LEG (3): 增大=向前, 减小=向后
|
||||
//
|
||||
// 即:左侧两腿同向(减=前),右侧两腿同向(增=前)
|
||||
// 对角线A: 左前 + 右后 → 前进时左前减小, 右后减小(都是各自的"向前")
|
||||
// 对角线B: 左后 + 右前 → 前进时左后减小, 右前增大(都是各自的"向前")
|
||||
//
|
||||
// 抬腿方向(从 Lift 函数):
|
||||
// LEFT_FRONT_LEG: 0° (减小=抬)
|
||||
// LEFT_REAR_LEG: 180° (增大=抬)
|
||||
// RIGHT_FRONT_LEG: 180° (增大=抬)
|
||||
// RIGHT_REAR_LEG: 0° (减小=抬)
|
||||
|
||||
// 辅助:获取当前所有舵机位置
|
||||
void EDARobotDog::GetCurrentPositions(int pos[SERVO_COUNT]) {
|
||||
for (int i = 0; i < SERVO_COUNT; i++) {
|
||||
if (servo_pins_[i] != -1) {
|
||||
pos[i] = servo_[i].GetPosition();
|
||||
} else {
|
||||
|
||||
// 获取当前位置
|
||||
int current_pos[SERVO_COUNT];
|
||||
for (int i = 0; i < SERVO_COUNT; i++) {
|
||||
if (servo_pins_[i] != -1) {
|
||||
current_pos[i] = servo_[i].GetPosition();
|
||||
} else {
|
||||
current_pos[i] = LEG_HOME_POSITION;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
current_pos[LEFT_REAR_LEG] = 140; // servo2
|
||||
current_pos[RIGHT_REAR_LEG] = 40; // servo3
|
||||
MoveServos(100, current_pos);
|
||||
|
||||
current_pos[LEFT_FRONT_LEG] = 40; // servo1
|
||||
current_pos[RIGHT_FRONT_LEG] = 140; // servo4
|
||||
MoveServos(100, current_pos);
|
||||
|
||||
current_pos[LEFT_REAR_LEG] = 90; // servo2
|
||||
current_pos[RIGHT_REAR_LEG] = 90; // servo3
|
||||
MoveServos(100, current_pos);
|
||||
|
||||
current_pos[LEFT_FRONT_LEG] = 90; // servo1
|
||||
current_pos[RIGHT_FRONT_LEG] = 90; // servo4
|
||||
MoveServos(100, current_pos);
|
||||
|
||||
|
||||
current_pos[LEFT_FRONT_LEG] = 140; // servo1
|
||||
current_pos[RIGHT_FRONT_LEG] = 40; // servo4
|
||||
MoveServos(100, current_pos);
|
||||
|
||||
|
||||
current_pos[LEFT_REAR_LEG] = 40; // servo2
|
||||
current_pos[RIGHT_REAR_LEG] = 140; // servo3
|
||||
MoveServos(100, current_pos);
|
||||
|
||||
|
||||
current_pos[LEFT_FRONT_LEG] = 90; // servo1
|
||||
current_pos[RIGHT_FRONT_LEG] = 90; // servo4
|
||||
MoveServos(100, current_pos);
|
||||
|
||||
|
||||
current_pos[LEFT_REAR_LEG] = 90; // servo2
|
||||
current_pos[RIGHT_REAR_LEG] = 90; // servo3
|
||||
MoveServos(100, current_pos);
|
||||
|
||||
pos[i] = LEG_HOME_POSITION;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EDARobotDog::Walk(float steps, int period, int dir) {
|
||||
|
||||
void EDARobotDog::Turn(float steps, int period, int dir) {
|
||||
if (GetRestState() == true) {
|
||||
SetRestState(false);
|
||||
}
|
||||
|
||||
// 转弯 = 左侧后退 + 右侧前进(左转),或反过来(右转)
|
||||
// 从 Walk 的已验证方向推导:
|
||||
// 前进: LF=90-s, LR=90-s, RF=90+s, RR=90+s
|
||||
// 后退: LF=90+s, LR=90+s, RF=90-s, RR=90-s
|
||||
//
|
||||
// 左转(d=1): 左侧后退+右侧前进
|
||||
// LF=90+s, LR=90+s, RF=90+s, RR=90+s → 全部 90+s
|
||||
// 地面反推: 全部 90-s
|
||||
//
|
||||
// 右转(d=-1): 左侧前进+右侧后退
|
||||
// LF=90-s, LR=90-s, RF=90-s, RR=90-s → 全部 90-s
|
||||
// 地面反推: 全部 90+s
|
||||
|
||||
const int swing = 60;
|
||||
const int lift = 25;
|
||||
int t = period / 6;
|
||||
if (t < 50) t = 50;
|
||||
|
||||
int d = (dir == LEFT) ? -1 : 1;
|
||||
|
||||
for (int step = 0; step < (int)steps; step++) {
|
||||
if (dir == FORWARD) {
|
||||
int pos[SERVO_COUNT];
|
||||
GetCurrentPositions(pos);
|
||||
|
||||
// 获取当前位置
|
||||
int current_pos[SERVO_COUNT];
|
||||
for (int i = 0; i < SERVO_COUNT; i++) {
|
||||
if (servo_pins_[i] != -1) {
|
||||
current_pos[i] = servo_[i].GetPosition();
|
||||
} else {
|
||||
current_pos[i] = LEG_HOME_POSITION;
|
||||
}
|
||||
}
|
||||
// 拍1: 抬A(LF+RR)
|
||||
pos[LEFT_FRONT_LEG] = 90 - lift;
|
||||
pos[RIGHT_REAR_LEG] = 90 - lift;
|
||||
MoveServos(t, pos);
|
||||
|
||||
|
||||
current_pos[LEFT_FRONT_LEG] = 100; // servo1
|
||||
current_pos[RIGHT_FRONT_LEG] = 100; // servo4
|
||||
MoveServos(100, current_pos);
|
||||
// 拍2: A空中摆 + B地面反推
|
||||
pos[LEFT_FRONT_LEG] = 90 - lift + d * swing; // LF空中
|
||||
pos[RIGHT_REAR_LEG] = 90 - lift + d * swing; // RR空中
|
||||
pos[LEFT_REAR_LEG] = 90 - d * swing; // LR地面反推
|
||||
pos[RIGHT_FRONT_LEG] = 90 - d * swing; // RF地面反推
|
||||
MoveServos(t, pos);
|
||||
|
||||
|
||||
current_pos[RIGHT_REAR_LEG] = 60; // servo3
|
||||
current_pos[LEFT_REAR_LEG] = 60; // servo2
|
||||
MoveServos(100, current_pos);
|
||||
// 拍3: 放下A
|
||||
pos[LEFT_FRONT_LEG] = 90 + d * swing;
|
||||
pos[RIGHT_REAR_LEG] = 90 + d * swing;
|
||||
MoveServos(t / 2, pos);
|
||||
|
||||
|
||||
current_pos[LEFT_FRONT_LEG] = 140; // servo1
|
||||
current_pos[RIGHT_FRONT_LEG] = 140; // servo4
|
||||
MoveServos(100, current_pos);
|
||||
// 拍4: 抬B(LR+RF)
|
||||
pos[LEFT_REAR_LEG] = 90 + lift;
|
||||
pos[RIGHT_FRONT_LEG] = 90 + lift;
|
||||
MoveServos(t, pos);
|
||||
|
||||
|
||||
current_pos[RIGHT_REAR_LEG] = 40; // servo3
|
||||
current_pos[LEFT_REAR_LEG] = 40; // servo2
|
||||
MoveServos(100, current_pos);
|
||||
// 拍5: B空中摆 + A地面反推
|
||||
pos[LEFT_REAR_LEG] = 90 + lift + d * swing; // LR空中
|
||||
pos[RIGHT_FRONT_LEG] = 90 + lift + d * swing; // RF空中
|
||||
pos[LEFT_FRONT_LEG] = 90 - d * swing; // LF地面反推
|
||||
pos[RIGHT_REAR_LEG] = 90 - d * swing; // RR地面反推
|
||||
MoveServos(t, pos);
|
||||
|
||||
|
||||
|
||||
current_pos[RIGHT_REAR_LEG] = 90; // servo3
|
||||
current_pos[LEFT_REAR_LEG] = 90; // servo2
|
||||
current_pos[LEFT_FRONT_LEG] = 90; // servo1
|
||||
current_pos[RIGHT_FRONT_LEG] = 90; // servo4
|
||||
MoveServos(100, current_pos);
|
||||
|
||||
|
||||
current_pos[LEFT_FRONT_LEG] = 80; // servo1
|
||||
current_pos[RIGHT_FRONT_LEG] = 80; // servo4
|
||||
MoveServos(100, current_pos);
|
||||
|
||||
|
||||
current_pos[RIGHT_REAR_LEG] = 120; // servo3
|
||||
current_pos[LEFT_REAR_LEG] = 120; // servo2
|
||||
MoveServos(100, current_pos);
|
||||
|
||||
|
||||
current_pos[LEFT_FRONT_LEG] = 90; // servo1
|
||||
current_pos[RIGHT_FRONT_LEG] = 90; // servo4
|
||||
MoveServos(100, current_pos);
|
||||
|
||||
|
||||
current_pos[RIGHT_REAR_LEG] = 140; // servo3
|
||||
current_pos[LEFT_REAR_LEG] = 140; // servo2
|
||||
MoveServos(100, current_pos);
|
||||
|
||||
|
||||
current_pos[RIGHT_REAR_LEG] = 90; // servo3
|
||||
current_pos[LEFT_REAR_LEG] = 90; // servo2
|
||||
MoveServos(100, current_pos);
|
||||
} else {
|
||||
|
||||
// 每次只移动指定的舵机,然后延时100ms
|
||||
// 获取当前位置
|
||||
int current_pos[SERVO_COUNT];
|
||||
for (int i = 0; i < SERVO_COUNT; i++) {
|
||||
if (servo_pins_[i] != -1) {
|
||||
current_pos[i] = servo_[i].GetPosition();
|
||||
} else {
|
||||
current_pos[i] = LEG_HOME_POSITION;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
current_pos[LEFT_FRONT_LEG] = 80; // servo1
|
||||
current_pos[RIGHT_FRONT_LEG] = 80; // servo4
|
||||
MoveServos(100, current_pos);
|
||||
|
||||
|
||||
current_pos[RIGHT_REAR_LEG] = 120; // servo3
|
||||
current_pos[LEFT_REAR_LEG] = 120; // servo2
|
||||
MoveServos(100, current_pos);
|
||||
|
||||
|
||||
current_pos[LEFT_FRONT_LEG] = 40; // servo1
|
||||
current_pos[RIGHT_FRONT_LEG] = 40; // servo4
|
||||
MoveServos(100, current_pos);
|
||||
|
||||
|
||||
current_pos[RIGHT_REAR_LEG] = 140; // servo3
|
||||
current_pos[LEFT_REAR_LEG] = 140; // servo2
|
||||
MoveServos(100, current_pos);
|
||||
|
||||
current_pos[RIGHT_REAR_LEG] = 90; // servo3
|
||||
current_pos[LEFT_REAR_LEG] = 90; // servo2
|
||||
current_pos[LEFT_FRONT_LEG] = 90; // servo1
|
||||
current_pos[RIGHT_FRONT_LEG] = 90; // servo4
|
||||
MoveServos(100, current_pos);
|
||||
|
||||
|
||||
current_pos[LEFT_FRONT_LEG] = 100; // servo1
|
||||
current_pos[RIGHT_FRONT_LEG] = 100; // servo4
|
||||
MoveServos(100, current_pos);
|
||||
|
||||
|
||||
current_pos[RIGHT_REAR_LEG] = 60; // servo3
|
||||
current_pos[LEFT_REAR_LEG] = 60; // servo2
|
||||
MoveServos(100, current_pos);
|
||||
|
||||
|
||||
current_pos[LEFT_FRONT_LEG] = 90; // servo1
|
||||
current_pos[RIGHT_FRONT_LEG] = 90; // servo4
|
||||
MoveServos(100, current_pos);
|
||||
|
||||
current_pos[RIGHT_REAR_LEG] = 40; // servo3
|
||||
current_pos[LEFT_REAR_LEG] = 40; // servo2
|
||||
MoveServos(100, current_pos);
|
||||
|
||||
|
||||
current_pos[RIGHT_REAR_LEG] = 90; // servo3
|
||||
current_pos[LEFT_REAR_LEG] = 90; // servo2
|
||||
MoveServos(100, current_pos);
|
||||
|
||||
}
|
||||
// 拍6: 放下B
|
||||
pos[LEFT_REAR_LEG] = 90 + d * swing;
|
||||
pos[RIGHT_FRONT_LEG] = 90 + d * swing;
|
||||
MoveServos(t / 2, pos);
|
||||
}
|
||||
|
||||
// 结束回中
|
||||
int home[SERVO_COUNT] = {90, 90, 90, 90};
|
||||
MoveServos(150, home);
|
||||
}
|
||||
|
||||
void EDARobotDog::Walk(float steps, int period, int dir) {
|
||||
if (GetRestState() == true) {
|
||||
SetRestState(false);
|
||||
}
|
||||
|
||||
// Trot 对角步态
|
||||
// 方向: LF减=前, LR减=前, RF增=前, RR增=前
|
||||
// 抬腿: LF减=抬, LR增=抬, RF增=抬, RR减=抬
|
||||
|
||||
const int lift = 25;
|
||||
const int swing = 30;
|
||||
int t = period / 6;
|
||||
if (t < 50) t = 50;
|
||||
|
||||
int fwd = (dir == FORWARD) ? 1 : -1;
|
||||
|
||||
for (int step = 0; step < (int)steps; step++) {
|
||||
int pos[SERVO_COUNT];
|
||||
GetCurrentPositions(pos);
|
||||
|
||||
// 拍1: 抬起对角线A(LF+RR)
|
||||
pos[LEFT_FRONT_LEG] = 90 - lift;
|
||||
pos[RIGHT_REAR_LEG] = 90 - lift;
|
||||
MoveServos(t, pos);
|
||||
|
||||
// 拍2: A空中前摆 + B地面后推(同时)
|
||||
pos[LEFT_FRONT_LEG] = 90 - lift - fwd * swing; // LF: 保持抬 + 前摆
|
||||
pos[RIGHT_REAR_LEG] = 90 - lift + fwd * swing; // RR: 保持抬 + 前摆(增=前)
|
||||
pos[LEFT_REAR_LEG] = 90 + fwd * swing; // LR: 地面后推(增=后)
|
||||
pos[RIGHT_FRONT_LEG] = 90 - fwd * swing; // RF: 地面后推(减=后)
|
||||
MoveServos(t, pos);
|
||||
|
||||
// 拍3: 放下A(着地到前摆位置)
|
||||
pos[LEFT_FRONT_LEG] = 90 - fwd * swing;
|
||||
pos[RIGHT_REAR_LEG] = 90 + fwd * swing;
|
||||
MoveServos(t / 2, pos);
|
||||
|
||||
// 拍4: 抬起对角线B(LR+RF)
|
||||
pos[LEFT_REAR_LEG] = 90 + lift;
|
||||
pos[RIGHT_FRONT_LEG] = 90 + lift;
|
||||
MoveServos(t, pos);
|
||||
|
||||
// 拍5: B空中前摆 + A地面后推(同时)
|
||||
pos[LEFT_REAR_LEG] = 90 + lift - fwd * swing; // LR: 保持抬 + 前摆(减=前)
|
||||
pos[RIGHT_FRONT_LEG] = 90 + lift + fwd * swing; // RF: 保持抬 + 前摆(增=前)
|
||||
pos[LEFT_FRONT_LEG] = 90 + fwd * swing; // LF: 地面后推(增=后)
|
||||
pos[RIGHT_REAR_LEG] = 90 - fwd * swing; // RR: 地面后推(减=后)
|
||||
MoveServos(t, pos);
|
||||
|
||||
// 拍6: 放下B(不回中,直接衔接下一步)
|
||||
pos[LEFT_REAR_LEG] = 90 - fwd * swing;
|
||||
pos[RIGHT_FRONT_LEG] = 90 + fwd * swing;
|
||||
MoveServos(t / 2, pos);
|
||||
}
|
||||
|
||||
// 结束回中
|
||||
int home[SERVO_COUNT] = {90, 90, 90, 90};
|
||||
MoveServos(150, home);
|
||||
}
|
||||
|
||||
void EDARobotDog::Sit(int period) {
|
||||
|
||||
@@ -60,6 +60,7 @@ public:
|
||||
void LiftRightRearLeg(int period = 1000, int height = 45); // 抬起右后腿
|
||||
|
||||
//-- Dog gait movements
|
||||
void GetCurrentPositions(int pos[SERVO_COUNT]);
|
||||
void Walk(float steps = 4, int period = 1000, int dir = FORWARD);
|
||||
void Turn(float steps = 4, int period = 2000, int dir = LEFT);
|
||||
void Sit(int period = 1500);
|
||||
|
||||
@@ -184,7 +184,16 @@ private:
|
||||
},
|
||||
};
|
||||
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_FT5x06_CONFIG();
|
||||
esp_lcd_panel_io_i2c_config_t tp_io_config = {
|
||||
.dev_addr = ESP_LCD_TOUCH_IO_I2C_FT5x06_ADDRESS,
|
||||
.control_phase_bytes = 1,
|
||||
.dc_bit_offset = 0,
|
||||
.lcd_cmd_bits = 8,
|
||||
.flags =
|
||||
{
|
||||
.disable_control_phase = 1,
|
||||
}
|
||||
};
|
||||
tp_io_config.scl_speed_hz = 400000;
|
||||
|
||||
esp_lcd_new_panel_io_i2c(i2c_bus_, &tp_io_config, &tp_io_handle);
|
||||
|
||||
@@ -178,7 +178,16 @@ private:
|
||||
},
|
||||
};
|
||||
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();
|
||||
esp_lcd_panel_io_i2c_config_t tp_io_config = {
|
||||
.dev_addr = ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS,
|
||||
.control_phase_bytes = 1,
|
||||
.dc_bit_offset = 0,
|
||||
.lcd_cmd_bits = 16,
|
||||
.flags =
|
||||
{
|
||||
.disable_control_phase = 1,
|
||||
}
|
||||
};
|
||||
tp_io_config.dev_addr = ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS_BACKUP; // 更改 GT911 地址
|
||||
tp_io_config.scl_speed_hz = 100000;
|
||||
esp_lcd_new_panel_io_i2c(i2c_bus_, &tp_io_config, &tp_io_handle);
|
||||
|
||||
@@ -265,7 +265,16 @@ private:
|
||||
},
|
||||
};
|
||||
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_FT5x06_CONFIG();
|
||||
esp_lcd_panel_io_i2c_config_t tp_io_config = {
|
||||
.dev_addr = ESP_LCD_TOUCH_IO_I2C_FT5x06_ADDRESS,
|
||||
.control_phase_bytes = 1,
|
||||
.dc_bit_offset = 0,
|
||||
.lcd_cmd_bits = 8,
|
||||
.flags =
|
||||
{
|
||||
.disable_control_phase = 1,
|
||||
}
|
||||
};
|
||||
tp_io_config.scl_speed_hz = 400 * 1000;
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_i2c(codec_i2c_bus_, &tp_io_config, &tp_io_handle));
|
||||
ESP_LOGI(TAG, "Initialize touch controller");
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
# 产品链接
|
||||
|
||||
[微雪电子 ESP32-C6-Touch-AMOLED-2.16](https://www.waveshare.net/shop/ESP32-C6-Touch-AMOLED-2.16.htm)
|
||||
|
||||
# 编译配置命令
|
||||
|
||||
**克隆工程**
|
||||
|
||||
```bash
|
||||
git clone https://github.com/78/xiaozhi-esp32.git
|
||||
```
|
||||
|
||||
**进入工程**
|
||||
|
||||
```bash
|
||||
cd xiaozhi-esp32
|
||||
```
|
||||
|
||||
**配置编译目标为 ESP32C6**
|
||||
|
||||
```bash
|
||||
idf.py set-target esp32c6
|
||||
```
|
||||
|
||||
**打开 menuconfig**
|
||||
|
||||
```bash
|
||||
idf.py menuconfig
|
||||
```
|
||||
|
||||
**选择板子**
|
||||
|
||||
```bash
|
||||
Xiaozhi Assistant -> Board Type -> Waveshare ESP32-C6-Touch-AMOLED-2.16
|
||||
```
|
||||
|
||||
**编译**
|
||||
|
||||
```ba
|
||||
idf.py build
|
||||
```
|
||||
|
||||
**下载并打开串口终端**
|
||||
|
||||
```bash
|
||||
idf.py build flash monitor
|
||||
```
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
#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 false
|
||||
#define AUDIO_I2S_GPIO_MCLK GPIO_NUM_19
|
||||
#define AUDIO_I2S_GPIO_WS GPIO_NUM_22
|
||||
#define AUDIO_I2S_GPIO_BCLK GPIO_NUM_20
|
||||
#define AUDIO_I2S_GPIO_DIN GPIO_NUM_21
|
||||
#define AUDIO_I2S_GPIO_DOUT GPIO_NUM_23
|
||||
|
||||
#define AUDIO_CODEC_PA_PIN GPIO_NUM_NC
|
||||
#define AUDIO_CODEC_I2C_SDA_PIN GPIO_NUM_8
|
||||
#define AUDIO_CODEC_I2C_SCL_PIN GPIO_NUM_7
|
||||
#define AUDIO_CODEC_ES8311_ADDR ES8311_CODEC_DEFAULT_ADDR
|
||||
#define AUDIO_CODEC_ES7210_ADDR ES7210_CODEC_DEFAULT_ADDR
|
||||
|
||||
#define BOOT_BUTTON_GPIO GPIO_NUM_9
|
||||
|
||||
|
||||
#define LCD_CS GPIO_NUM_15
|
||||
#define LCD_PCLK GPIO_NUM_0
|
||||
#define LCD_D0 GPIO_NUM_1
|
||||
#define LCD_D1 GPIO_NUM_2
|
||||
#define LCD_D2 GPIO_NUM_3
|
||||
#define LCD_D3 GPIO_NUM_4
|
||||
#define LCD_RST GPIO_NUM_NC
|
||||
|
||||
#define TP_RST_GPIO GPIO_NUM_11
|
||||
#define TP_INT_GPIO GPIO_NUM_5
|
||||
|
||||
#define LCD_H_RES 480
|
||||
#define LCD_V_RES 480
|
||||
|
||||
#define DISPLAY_MIRROR_X false
|
||||
#define DISPLAY_MIRROR_Y false
|
||||
#define DISPLAY_SWAP_XY false
|
||||
|
||||
#define DISPLAY_OFFSET_X 0
|
||||
#define DISPLAY_OFFSET_Y 0
|
||||
|
||||
#endif // _BOARD_CONFIG_H_
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"manufacturer": "waveshare",
|
||||
"target": "esp32c6",
|
||||
"builds": [
|
||||
{
|
||||
"name": "esp32-c6-touch-amoled-2.16",
|
||||
"sdkconfig_append": [
|
||||
"CONFIG_USE_ESP_WAKE_WORD=y",
|
||||
"CONFIG_USE_DEFAULT_MESSAGE_STYLE=y",
|
||||
"CONFIG_USE_MULTILINE_CHAT_MESSAGE=y"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,352 @@
|
||||
#include "display/lcd_display.h"
|
||||
#include "esp_lcd_sh8601.h"
|
||||
#include "wifi_board.h"
|
||||
|
||||
#include "application.h"
|
||||
#include "axp2101.h"
|
||||
#include "button.h"
|
||||
#include "codecs/box_audio_codec.h"
|
||||
#include "config.h"
|
||||
#include "i2c_device.h"
|
||||
#include "led/single_led.h"
|
||||
#include "mcp_server.h"
|
||||
#include "power_save_timer.h"
|
||||
|
||||
#include <driver/i2c_master.h>
|
||||
#include <driver/spi_master.h>
|
||||
#include <esp_lcd_panel_vendor.h>
|
||||
#include <esp_log.h>
|
||||
#include <esp_ota_ops.h>
|
||||
#include <esp_partition.h>
|
||||
#include "settings.h"
|
||||
|
||||
#include <esp_lcd_touch_cst9217.h>
|
||||
#include <esp_lvgl_port.h>
|
||||
#include <lvgl.h>
|
||||
|
||||
#define TAG "WaveshareEsp32c6TouchAMOLED2inch16"
|
||||
|
||||
class Pmic : public Axp2101 {
|
||||
public:
|
||||
Pmic(i2c_master_bus_handle_t i2c_bus, uint8_t addr) : Axp2101(i2c_bus, addr) {
|
||||
WriteReg(0x22, 0b110); // PWRON > OFFLEVEL as POWEROFF Source enable
|
||||
WriteReg(0x27, 0x10); // hold 4s to power off
|
||||
|
||||
// Disable All DCs but DC1
|
||||
WriteReg(0x80, 0x01);
|
||||
// Disable All LDOs
|
||||
WriteReg(0x90, 0x00);
|
||||
WriteReg(0x91, 0x00);
|
||||
|
||||
// Set DC1 to 3.3V
|
||||
WriteReg(0x82, (3300 - 1500) / 100);
|
||||
|
||||
// Set ALDO1 to 3.3V
|
||||
WriteReg(0x92, (3300 - 500) / 100);
|
||||
WriteReg(0x93, (3300 - 500) / 100);
|
||||
WriteReg(0x94, (3300 - 500) / 100);
|
||||
WriteReg(0x95, (3300 - 500) / 100);
|
||||
|
||||
// Enable ALDO1(MIC)
|
||||
WriteReg(0x90, 0x0F);
|
||||
|
||||
WriteReg(0x64, 0x02); // CV charger voltage setting to 4.1V
|
||||
|
||||
WriteReg(0x61, 0x02); // set Main battery precharge current to 50mA
|
||||
WriteReg(0x62, 0x0A); // set Main battery charger current to 400mA ( 0x08-200mA,
|
||||
// 0x09-300mA, 0x0A-400mA )
|
||||
WriteReg(0x63, 0x01); // set Main battery term charge current to 25mA
|
||||
}
|
||||
|
||||
void Pmic_SetAldo3(bool enable) {
|
||||
uint8_t reg = ReadReg(0x90);
|
||||
if (enable) {
|
||||
reg |= 0x04;
|
||||
} else {
|
||||
reg &= ~0x04;
|
||||
}
|
||||
WriteReg(0x90, reg);
|
||||
}
|
||||
|
||||
void Pmic_SetAldo2(bool enable) {
|
||||
uint8_t reg = ReadReg(0x90);
|
||||
if (enable) {
|
||||
reg |= 0x02;
|
||||
} else {
|
||||
reg &= ~0x02;
|
||||
}
|
||||
WriteReg(0x90, reg);
|
||||
}
|
||||
};
|
||||
|
||||
static const sh8601_lcd_init_cmd_t vendor_specific_init[] = {
|
||||
{0x11, (uint8_t[]){0x00}, 0, 120},
|
||||
{0xC4, (uint8_t[]){0x80}, 1, 0},
|
||||
{0x44, (uint8_t[]){0x01, 0xD1}, 2, 0},
|
||||
{0x35, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x36, (uint8_t[]){0xA0}, 1, 0},
|
||||
{0x53, (uint8_t[]){0x20}, 1, 10},
|
||||
{0x63, (uint8_t[]){0xFF}, 1, 10},
|
||||
{0x51, (uint8_t[]){0x00}, 1, 10},
|
||||
{0x2A, (uint8_t[]){0x00, 0x16, 0x01, 0xAF}, 4, 0},
|
||||
{0x2B, (uint8_t[]){0x00, 0x00, 0x01, 0xF5}, 4, 0},
|
||||
{0x29, (uint8_t[]){0x00}, 0, 10},
|
||||
{0x51, (uint8_t[]){0xFF}, 1, 0},
|
||||
};
|
||||
|
||||
// 在waveshare_amoled_2_16类之前添加新的显示类
|
||||
class CustomLcdDisplay : public SpiLcdDisplay {
|
||||
public:
|
||||
static void rounder_event_cb(lv_event_t* e) {
|
||||
lv_area_t* area = (lv_area_t*)lv_event_get_param(e);
|
||||
uint16_t x1 = area->x1;
|
||||
uint16_t x2 = area->x2;
|
||||
|
||||
uint16_t y1 = area->y1;
|
||||
uint16_t y2 = area->y2;
|
||||
|
||||
// round the start of coordinate down to the nearest 2M number
|
||||
area->x1 = (x1 >> 1) << 1;
|
||||
area->y1 = (y1 >> 1) << 1;
|
||||
// round the end of coordinate up to the nearest 2N+1 number
|
||||
area->x2 = ((x2 >> 1) << 1) + 1;
|
||||
area->y2 = ((y2 >> 1) << 1) + 1;
|
||||
}
|
||||
|
||||
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) {}
|
||||
|
||||
virtual void SetupUI() override {
|
||||
// Call parent SetupUI() first to create all lvgl objects
|
||||
SpiLcdDisplay::SetupUI();
|
||||
|
||||
DisplayLockGuard lock(this);
|
||||
lv_obj_set_style_pad_left(top_bar_, 60, 0);
|
||||
lv_obj_set_style_pad_right(top_bar_, 60, 0);
|
||||
lv_display_add_event_cb(display_, rounder_event_cb, LV_EVENT_INVALIDATE_AREA, NULL);
|
||||
}
|
||||
};
|
||||
|
||||
class CustomBacklight : public Backlight {
|
||||
public:
|
||||
CustomBacklight(esp_lcd_panel_io_handle_t panel_io) : Backlight(), panel_io_(panel_io) {}
|
||||
|
||||
protected:
|
||||
esp_lcd_panel_io_handle_t panel_io_;
|
||||
|
||||
virtual void SetBrightnessImpl(uint8_t brightness) override {
|
||||
auto display = Board::GetInstance().GetDisplay();
|
||||
DisplayLockGuard lock(display);
|
||||
uint8_t data[1] = {((uint8_t)((255 * brightness) / 100))};
|
||||
int lcd_cmd = 0x51;
|
||||
lcd_cmd &= 0xff;
|
||||
lcd_cmd <<= 8;
|
||||
lcd_cmd |= 0x02UL << 24;
|
||||
esp_lcd_panel_io_tx_param(panel_io_, lcd_cmd, &data, sizeof(data));
|
||||
}
|
||||
};
|
||||
|
||||
class WaveshareEsp32c6TouchAMOLED2inch16 : public WifiBoard {
|
||||
private:
|
||||
i2c_master_bus_handle_t i2c_bus_;
|
||||
Pmic* pmic_ = nullptr;
|
||||
Button boot_button_;
|
||||
CustomLcdDisplay* display_;
|
||||
CustomBacklight* backlight_;
|
||||
PowerSaveTimer* power_save_timer_;
|
||||
|
||||
void InitializePowerSaveTimer() {
|
||||
power_save_timer_ = new PowerSaveTimer(-1, 120, 1200);
|
||||
power_save_timer_->OnEnterSleepMode([this]() {
|
||||
GetDisplay()->SetPowerSaveMode(true);
|
||||
GetBacklight()->SetBrightness(20);
|
||||
});
|
||||
power_save_timer_->OnExitSleepMode([this]() {
|
||||
GetDisplay()->SetPowerSaveMode(false);
|
||||
GetBacklight()->RestoreBrightness();
|
||||
});
|
||||
power_save_timer_->OnShutdownRequest([this]() { pmic_->PowerOff(); });
|
||||
power_save_timer_->SetEnabled(true);
|
||||
}
|
||||
|
||||
void InitializeCodecI2c() {
|
||||
// Initialize I2C peripheral
|
||||
i2c_master_bus_config_t i2c_bus_cfg = {
|
||||
.i2c_port = I2C_NUM_0,
|
||||
.sda_io_num = AUDIO_CODEC_I2C_SDA_PIN,
|
||||
.scl_io_num = AUDIO_CODEC_I2C_SCL_PIN,
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
.flags =
|
||||
{
|
||||
.enable_internal_pullup = 1,
|
||||
},
|
||||
};
|
||||
ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_cfg, &i2c_bus_));
|
||||
}
|
||||
|
||||
void InitializeAxp2101() {
|
||||
ESP_LOGI(TAG, "Init AXP2101");
|
||||
pmic_ = new Pmic(i2c_bus_, 0x34);
|
||||
}
|
||||
|
||||
void InitializeSpi() {
|
||||
spi_bus_config_t buscfg = {};
|
||||
buscfg.sclk_io_num = LCD_PCLK;
|
||||
buscfg.data0_io_num = LCD_D0;
|
||||
buscfg.data1_io_num = LCD_D1;
|
||||
buscfg.data2_io_num = LCD_D2;
|
||||
buscfg.data3_io_num = LCD_D3;
|
||||
buscfg.max_transfer_sz = LCD_H_RES * LCD_V_RES * sizeof(uint16_t);
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(SPI2_HOST, &buscfg, SPI_DMA_CH_AUTO));
|
||||
}
|
||||
|
||||
void InitializeButtons() {
|
||||
boot_button_.OnClick([this]() {
|
||||
auto& app = Application::GetInstance();
|
||||
if (app.GetDeviceState() == kDeviceStateStarting) {
|
||||
EnterWifiConfigMode();
|
||||
return;
|
||||
}
|
||||
app.ToggleChatState();
|
||||
});
|
||||
}
|
||||
|
||||
int DisplayPort_DispReset() {
|
||||
pmic_->Pmic_SetAldo3(1);
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
pmic_->Pmic_SetAldo3(0);
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
pmic_->Pmic_SetAldo3(1);
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void InitializeSH8601Display() {
|
||||
esp_lcd_panel_io_handle_t panel_io = nullptr;
|
||||
esp_lcd_panel_handle_t panel = nullptr;
|
||||
|
||||
// 液晶屏控制IO初始化
|
||||
ESP_LOGD(TAG, "Install panel IO");
|
||||
esp_lcd_panel_io_spi_config_t io_config =
|
||||
SH8601_PANEL_IO_QSPI_CONFIG(LCD_CS, nullptr, nullptr);
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi(SPI2_HOST, &io_config, &panel_io));
|
||||
|
||||
// 初始化液晶屏驱动芯片
|
||||
ESP_LOGD(TAG, "Install LCD driver");
|
||||
const sh8601_vendor_config_t vendor_config = {
|
||||
.init_cmds = &vendor_specific_init[0],
|
||||
.init_cmds_size = sizeof(vendor_specific_init) / sizeof(sh8601_lcd_init_cmd_t),
|
||||
.flags = {
|
||||
.use_qspi_interface = 1,
|
||||
}};
|
||||
|
||||
esp_lcd_panel_dev_config_t panel_config = {};
|
||||
panel_config.reset_gpio_num = LCD_RST;
|
||||
panel_config.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB;
|
||||
panel_config.bits_per_pixel = 16;
|
||||
panel_config.vendor_config = (void*)&vendor_config;
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_sh8601(panel_io, &panel_config, &panel));
|
||||
ESP_ERROR_CHECK(DisplayPort_DispReset());
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_init(panel));
|
||||
display_ = new CustomLcdDisplay(panel_io, panel, LCD_H_RES, LCD_V_RES, DISPLAY_OFFSET_X,
|
||||
DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y,
|
||||
DISPLAY_SWAP_XY);
|
||||
backlight_ = new CustomBacklight(panel_io);
|
||||
backlight_->RestoreBrightness();
|
||||
}
|
||||
|
||||
void InitializeTouch() {
|
||||
esp_lcd_touch_handle_t tp;
|
||||
esp_lcd_touch_config_t tp_cfg = {
|
||||
.x_max = LCD_H_RES - 1,
|
||||
.y_max = LCD_V_RES - 1,
|
||||
.rst_gpio_num = TP_RST_GPIO,
|
||||
.int_gpio_num = TP_INT_GPIO,
|
||||
.levels =
|
||||
{
|
||||
.reset = 0,
|
||||
.interrupt = 0,
|
||||
},
|
||||
.flags =
|
||||
{
|
||||
.swap_xy = 1,
|
||||
.mirror_x = 0,
|
||||
.mirror_y = 1,
|
||||
},
|
||||
};
|
||||
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_CST9217_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_cst9217(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 InitializeTools() {
|
||||
auto& mcp_server = McpServer::GetInstance();
|
||||
mcp_server.AddTool("self.system.reconfigure_wifi",
|
||||
"End this conversation and enter WiFi configuration mode.\n"
|
||||
"**CAUTION** You must ask the user to confirm this action.",
|
||||
PropertyList(), [this](const PropertyList& properties) {
|
||||
EnterWifiConfigMode();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
public:
|
||||
WaveshareEsp32c6TouchAMOLED2inch16() : boot_button_(BOOT_BUTTON_GPIO) {
|
||||
InitializePowerSaveTimer();
|
||||
InitializeCodecI2c();
|
||||
InitializeAxp2101();
|
||||
InitializeSpi();
|
||||
InitializeSH8601Display();
|
||||
InitializeTouch();
|
||||
InitializeButtons();
|
||||
InitializeTools();
|
||||
}
|
||||
|
||||
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 Backlight* GetBacklight() override { return backlight_; }
|
||||
|
||||
virtual bool GetBatteryLevel(int& level, bool& charging, bool& discharging) override {
|
||||
static bool last_discharging = false;
|
||||
charging = pmic_->IsCharging();
|
||||
discharging = pmic_->IsDischarging();
|
||||
if (discharging != last_discharging) {
|
||||
power_save_timer_->SetEnabled(discharging);
|
||||
last_discharging = discharging;
|
||||
}
|
||||
|
||||
level = pmic_->GetBatteryLevel();
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void SetPowerSaveLevel(PowerSaveLevel level) override {
|
||||
if (level != PowerSaveLevel::LOW_POWER) {
|
||||
power_save_timer_->WakeUp();
|
||||
}
|
||||
WifiBoard::SetPowerSaveLevel(level);
|
||||
}
|
||||
};
|
||||
|
||||
DECLARE_BOARD(WaveshareEsp32c6TouchAMOLED2inch16);
|
||||
@@ -171,7 +171,20 @@ private:
|
||||
},
|
||||
};
|
||||
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_CST816S_CONFIG();
|
||||
esp_lcd_panel_io_i2c_config_t tp_io_config = {
|
||||
.dev_addr = ESP_LCD_TOUCH_IO_I2C_CST816S_ADDRESS,
|
||||
.on_color_trans_done = 0,
|
||||
.user_ctx = 0,
|
||||
.control_phase_bytes = 1,
|
||||
.dc_bit_offset = 0,
|
||||
.lcd_cmd_bits = 8,
|
||||
.lcd_param_bits = 0,
|
||||
.flags =
|
||||
{
|
||||
.dc_low_on_data = 0,
|
||||
.disable_control_phase = 1,
|
||||
},
|
||||
};
|
||||
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");
|
||||
|
||||
@@ -200,7 +200,16 @@ private:
|
||||
},
|
||||
};
|
||||
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();
|
||||
esp_lcd_panel_io_i2c_config_t tp_io_config = {
|
||||
.dev_addr = ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS,
|
||||
.control_phase_bytes = 1,
|
||||
.dc_bit_offset = 0,
|
||||
.lcd_cmd_bits = 16,
|
||||
.flags =
|
||||
{
|
||||
.disable_control_phase = 1,
|
||||
}
|
||||
};
|
||||
tp_io_config.scl_speed_hz = 100 * 1000;
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_i2c(codec_i2c_bus_, &tp_io_config, &tp_io_handle));
|
||||
ESP_LOGI(TAG, "Initialize touch controller");
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
# Waveshare ESP32-P4-WIFI6-Touch-LCD-3.5
|
||||
|
||||
**ESP32-P4-WIFI6-Touch-LCD-3.5** 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-3.5
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
#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 (320)
|
||||
#define DISPLAY_HEIGHT (480)
|
||||
#define PIN_NUM_LCD_RST GPIO_NUM_27
|
||||
#define DISPLAY_BACKLIGHT_PIN GPIO_NUM_28
|
||||
#define DISPLAY_BACKLIGHT_OUTPUT_INVERT false
|
||||
#define TOUCH_RST_PIN GPIO_NUM_29
|
||||
#define TOUCH_INT_PIN GPIO_NUM_50
|
||||
#define LCD_SPI_MOSI_PIN GPIO_NUM_20
|
||||
#define LCD_SPI_CLK_PIN GPIO_NUM_21
|
||||
#define LCD_SPI_CS_PIN GPIO_NUM_23
|
||||
#define LCD_SPI_DC_PIN GPIO_NUM_26
|
||||
|
||||
#define DISPLAY_SWAP_XY false
|
||||
#define DISPLAY_MIRROR_X true
|
||||
#define DISPLAY_MIRROR_Y false
|
||||
|
||||
#define DISPLAY_OFFSET_X 0
|
||||
#define DISPLAY_OFFSET_Y 0
|
||||
|
||||
|
||||
#endif // _BOARD_CONFIG_H_
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"manufacturer": "waveshare",
|
||||
"target": "esp32p4",
|
||||
"builds": [
|
||||
{
|
||||
"name": "esp32-p4-wifi6-touch-lcd-3.5",
|
||||
"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_5=y",
|
||||
"CONFIG_CAMERA_OV5647=y",
|
||||
"CONFIG_CAMERA_OV5647_AUTO_DETECT_MIPI_INTERFACE_SENSOR=y",
|
||||
"CONFIG_XIAOZHI_ENABLE_CAMERA_ENDIANNESS_SWAP=y"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
#include "wifi_board.h"
|
||||
#include "codecs/es8311_audio_codec.h"
|
||||
#include "application.h"
|
||||
#include "display/lcd_display.h"
|
||||
#include "button.h"
|
||||
#include "esp_video.h"
|
||||
#include "esp_video_init.h"
|
||||
#include "esp_lcd_panel_ops.h"
|
||||
#include <driver/spi_master.h>
|
||||
#include "esp_lcd_st7796.h"
|
||||
#include "config.h"
|
||||
#include <esp_log.h>
|
||||
#include <driver/i2c_master.h>
|
||||
#include <esp_lvgl_port.h>
|
||||
#include "esp_lcd_touch_ft5x06.h"
|
||||
|
||||
#define TAG "WaveshareEsp32p4"
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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_));
|
||||
}
|
||||
|
||||
void InitializeLCD() {
|
||||
esp_lcd_panel_io_handle_t io = NULL;
|
||||
esp_lcd_panel_handle_t disp_panel = NULL;
|
||||
spi_bus_config_t buscfg = {};
|
||||
buscfg.sclk_io_num = LCD_SPI_CLK_PIN;
|
||||
buscfg.mosi_io_num = LCD_SPI_MOSI_PIN;
|
||||
buscfg.miso_io_num = GPIO_NUM_NC;
|
||||
buscfg.quadwp_io_num = GPIO_NUM_NC;
|
||||
buscfg.quadhd_io_num = GPIO_NUM_NC;
|
||||
buscfg.max_transfer_sz = (DISPLAY_WIDTH * DISPLAY_HEIGHT);
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(SPI2_HOST, &buscfg, SPI_DMA_CH_AUTO));
|
||||
esp_lcd_panel_io_spi_config_t io_config = {};
|
||||
io_config.dc_gpio_num = LCD_SPI_DC_PIN;
|
||||
io_config.cs_gpio_num = LCD_SPI_CS_PIN;
|
||||
io_config.pclk_hz = (80 * 1000 * 1000);
|
||||
io_config.lcd_cmd_bits = 8;
|
||||
io_config.lcd_param_bits = 8;
|
||||
io_config.spi_mode = 3;
|
||||
io_config.trans_queue_depth = 10;
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)SPI2_HOST, &io_config, &io));
|
||||
const esp_lcd_panel_dev_config_t lcd_dev_config = {
|
||||
.reset_gpio_num = PIN_NUM_LCD_RST,
|
||||
.color_space = ESP_LCD_COLOR_SPACE_BGR,
|
||||
.bits_per_pixel = 16,
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_st7796(io, &lcd_dev_config, &disp_panel));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_reset(disp_panel));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_init(disp_panel));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_invert_color(disp_panel, true));
|
||||
esp_lcd_panel_disp_on_off(disp_panel, true);
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_mirror(disp_panel, true, false));
|
||||
display_ = new SpiLcdDisplay(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 = TOUCH_RST_PIN,
|
||||
.int_gpio_num = TOUCH_INT_PIN,
|
||||
.levels = {
|
||||
.reset = 0,
|
||||
.interrupt = 0,
|
||||
},
|
||||
.flags = {
|
||||
.swap_xy = 1,
|
||||
.mirror_x = 1,
|
||||
.mirror_y = 0,
|
||||
},
|
||||
};
|
||||
esp_lcd_panel_io_handle_t tp_io_handle = NULL;
|
||||
esp_lcd_panel_io_i2c_config_t tp_io_config = {};
|
||||
tp_io_config.dev_addr = ESP_LCD_TOUCH_IO_I2C_FT5x06_ADDRESS;
|
||||
tp_io_config.control_phase_bytes = 1;
|
||||
tp_io_config.dc_bit_offset = 0;
|
||||
tp_io_config.lcd_cmd_bits = 8;
|
||||
tp_io_config.flags.disable_control_phase = 1;
|
||||
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_ERROR_CHECK(esp_lcd_touch_new_i2c_ft5x06(tp_io_handle, &tp_cfg, &tp));
|
||||
lvgl_port_touch_cfg_t touch_cfg = {};
|
||||
touch_cfg.disp = lv_display_get_default();
|
||||
touch_cfg.handle = tp;
|
||||
lvgl_port_add_touch(&touch_cfg);
|
||||
}
|
||||
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();
|
||||
auto state = app.GetDeviceState();
|
||||
if (state == kDeviceStateStarting ||
|
||||
state == kDeviceStateConnecting ||
|
||||
state == kDeviceStateWifiConfiguring) {
|
||||
EnterWifiConfigMode();
|
||||
return;
|
||||
}
|
||||
esp_restart();
|
||||
});
|
||||
Application::GetInstance().StartListening();
|
||||
}
|
||||
|
||||
public:
|
||||
WaveshareEsp32p4() :
|
||||
boot_button_(BOOT_BUTTON_GPIO) {
|
||||
InitializeCodecI2c();
|
||||
InitializeLCD();
|
||||
InitializeTouch();
|
||||
InitializeCamera();
|
||||
InitializeButtons();
|
||||
GetBacklight()->RestoreBrightness();
|
||||
}
|
||||
|
||||
virtual AudioCodec* GetAudioCodec() override {
|
||||
static Es8311AudioCodec audio_codec(
|
||||
i2c_bus_,
|
||||
I2C_NUM_1,
|
||||
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,
|
||||
true,
|
||||
false);
|
||||
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(WaveshareEsp32p4);
|
||||
@@ -9,6 +9,7 @@ Configuration in `menuconfig`.
|
||||
|
||||
Selection Board Type `Xiaozhi Assistant --> Board Type`
|
||||
- Waveshare ESP32-P4-WIFI6-Touch-LCD-4B
|
||||
- Waveshare ESP32-P4-WIFI6-Touch-LCD-4.3
|
||||
- Waveshare ESP32-P4-WIFI6-Touch-LCD-7B
|
||||
- Waveshare ESP32-P4-WIFI6-Touch-LCD-3.4C
|
||||
- Waveshare ESP32-P4-WIFI6-Touch-LCD-4C
|
||||
|
||||
@@ -29,6 +29,13 @@
|
||||
#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_4_3
|
||||
#define DISPLAY_WIDTH (480)
|
||||
#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 (500)
|
||||
#elif CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_7B
|
||||
#define DISPLAY_WIDTH (1024)
|
||||
#define DISPLAY_HEIGHT (600)
|
||||
|
||||
@@ -16,6 +16,20 @@
|
||||
"CONFIG_XIAOZHI_ENABLE_CAMERA_ENDIANNESS_SWAP=y"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "esp32-p4-wifi6-touch-lcd-4.3",
|
||||
"sdkconfig_append": [
|
||||
"CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=0",
|
||||
"CONFIG_BOOTLOADER_CACHE_32BIT_ADDR_QUAD_FLASH=y",
|
||||
"CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_4_3=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": [
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
|
||||
#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_4_3
|
||||
#include "esp_lcd_st7701.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 \
|
||||
@@ -136,6 +138,46 @@ private:
|
||||
.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_4_3
|
||||
esp_lcd_dpi_panel_config_t dpi_config = {
|
||||
.dpi_clk_src = MIPI_DSI_DPI_CLK_SRC_DEFAULT,
|
||||
.dpi_clock_freq_mhz = 30,
|
||||
.pixel_format = LCD_COLOR_PIXEL_FORMAT_RGB565,
|
||||
.num_fbs = 1,
|
||||
.video_timing = {
|
||||
.h_size = 480,
|
||||
.v_size = 800,
|
||||
.hsync_pulse_width = 12,
|
||||
.hsync_back_porch = 42,
|
||||
.hsync_front_porch = 42,
|
||||
.vsync_pulse_width = 8,
|
||||
.vsync_back_porch = 2,
|
||||
.vsync_front_porch = 60,
|
||||
},
|
||||
.flags = {
|
||||
.use_dma2d = true,
|
||||
},
|
||||
};
|
||||
st7701_vendor_config_t vendor_config = {
|
||||
.init_cmds = vendor_specific_init_default,
|
||||
.init_cmds_size = sizeof(vendor_specific_init_default) / sizeof(st7701_lcd_init_cmd_t),
|
||||
.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_st7701(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,
|
||||
@@ -294,7 +336,7 @@ private:
|
||||
esp_lcd_touch_config_t tp_cfg = {
|
||||
.x_max = DISPLAY_WIDTH,
|
||||
.y_max = DISPLAY_HEIGHT,
|
||||
.rst_gpio_num = GPIO_NUM_23,
|
||||
.rst_gpio_num = GPIO_NUM_NC,
|
||||
.int_gpio_num = GPIO_NUM_NC,
|
||||
.levels = {
|
||||
.reset = 0,
|
||||
@@ -307,8 +349,17 @@ private:
|
||||
},
|
||||
};
|
||||
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();
|
||||
if (ESP_OK == i2c_device_probe(ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS)) {
|
||||
esp_lcd_panel_io_i2c_config_t tp_io_config = {
|
||||
.dev_addr = ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS,
|
||||
.control_phase_bytes = 1,
|
||||
.dc_bit_offset = 0,
|
||||
.lcd_cmd_bits = 16,
|
||||
.flags =
|
||||
{
|
||||
.disable_control_phase = 1,
|
||||
}
|
||||
};
|
||||
if (ESP_OK == i2c_device_probe(ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS)) {
|
||||
ESP_LOGI(TAG, "Touch panel found at address 0x%02X", ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS);
|
||||
} else if (ESP_OK == i2c_device_probe(ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS_BACKUP)) {
|
||||
ESP_LOGI(TAG, "Touch panel found at address 0x%02X", ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS_BACKUP);
|
||||
|
||||
@@ -1,5 +1,56 @@
|
||||
#ifdef CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_4B
|
||||
// Leave it blank
|
||||
#elif CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_4_3
|
||||
static const st7701_lcd_init_cmd_t vendor_specific_init_default[] = {
|
||||
{0xFF, (uint8_t[]){0x77, 0x01, 0x00, 0x00, 0x13}, 5, 0},
|
||||
{0xEF, (uint8_t[]){0x08}, 1, 0},
|
||||
{0xFF, (uint8_t[]){0x77, 0x01, 0x00, 0x00, 0x10}, 5, 0},
|
||||
{0xC0, (uint8_t[]){0x63, 0x00}, 2, 0},
|
||||
{0xC1, (uint8_t[]){0x0D, 0x02}, 2, 0},
|
||||
{0xC2, (uint8_t[]){0x17, 0x08}, 2, 0},
|
||||
{0xCC, (uint8_t[]){0x10}, 1, 0},
|
||||
{0xB0, (uint8_t[]){0x40, 0xC9, 0x94, 0x0E, 0x10, 0x05, 0x0B, 0x09, 0x08, 0x26, 0x04, 0x52, 0x10, 0x69, 0x6B, 0x69}, 16, 0},
|
||||
|
||||
{0xB1, (uint8_t[]){0x40, 0xD2, 0x98, 0x0C, 0x92, 0x07, 0x09, 0x08, 0x07, 0x25, 0x02, 0x0E, 0x0C, 0x6E, 0x78, 0x55}, 16, 0},
|
||||
|
||||
{0xFF, (uint8_t[]){0x77, 0x01, 0x00, 0x00, 0x11}, 5, 0},
|
||||
{0xB0, (uint8_t[]){0x5D}, 1, 0},
|
||||
{0xB1, (uint8_t[]){0x4E}, 1, 0},
|
||||
{0xB2, (uint8_t[]){0x87}, 1, 0},
|
||||
{0xB3, (uint8_t[]){0x80}, 1, 0},
|
||||
{0xB5, (uint8_t[]){0x4E}, 1, 0},
|
||||
{0xB7, (uint8_t[]){0x85}, 1, 0},
|
||||
{0xB8, (uint8_t[]){0x21}, 1, 0},
|
||||
{0xB9, (uint8_t[]){0x10, 0x1F}, 2, 0},
|
||||
{0xBB, (uint8_t[]){0x03}, 1, 0},
|
||||
{0xBC, (uint8_t[]){0x00}, 1, 0},
|
||||
|
||||
{0xC1, (uint8_t[]){0x78}, 1, 0},
|
||||
{0xC2, (uint8_t[]){0x78}, 1, 0},
|
||||
{0xD0, (uint8_t[]){0x88}, 1, 0},
|
||||
{0xE0, (uint8_t[]){0x00, 0x3A, 0x02}, 3, 0},
|
||||
{0xE1, (uint8_t[]){0x04, 0xA0, 0x00, 0xA0, 0x05, 0xA0, 0x00, 0xA0, 0x00, 0x40, 0x40}, 11, 0},
|
||||
|
||||
{0xE2, (uint8_t[]){0x30, 0x00, 0x40, 0x40, 0x32, 0xA0, 0x00, 0xA0, 0x00, 0xA0, 0x00, 0xA0, 0x00}, 13, 0},
|
||||
|
||||
{0xE3, (uint8_t[]){0x00, 0x00, 0x33, 0x33}, 4, 0},
|
||||
{0xE4, (uint8_t[]){0x44, 0x44}, 2, 0},
|
||||
{0xE5, (uint8_t[]){0x09, 0x2E, 0xA0, 0xA0, 0x0B, 0x30, 0xA0, 0xA0, 0x05, 0x2A, 0xA0, 0xA0, 0x07, 0x2C, 0xA0, 0xA0}, 16, 0},
|
||||
|
||||
{0xE6, (uint8_t[]){0x00, 0x00, 0x33, 0x33}, 4, 0},
|
||||
{0xE7, (uint8_t[]){0x44, 0x44}, 2, 0},
|
||||
{0xE8, (uint8_t[]){0x08, 0x2D, 0xA0, 0xA0, 0x0A, 0x2F, 0xA0, 0xA0, 0x04, 0x29, 0xA0, 0xA0, 0x06, 0x2B, 0xA0, 0xA0}, 16, 0},
|
||||
|
||||
{0xEB, (uint8_t[]){0x00, 0x00, 0x4E, 0x4E, 0x00, 0x00, 0x00}, 7, 0},
|
||||
{0xEC, (uint8_t[]){0x08, 0x01}, 2, 0},
|
||||
|
||||
{0xED, (uint8_t[]){0xB0, 0x2B, 0x98, 0xA4, 0x56, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0x65, 0x4A, 0x89, 0xB2, 0x0B}, 16, 0},
|
||||
|
||||
{0xEF, (uint8_t[]){0x08, 0x08, 0x08, 0x45, 0x3F, 0x54}, 6, 0},
|
||||
{0xFF, (uint8_t[]){0x77, 0x01, 0x00, 0x00, 0x00}, 5, 0},
|
||||
{0x11, (uint8_t[]){0x00}, 0, 120},
|
||||
{0x29, (uint8_t[]){0x00}, 0, 0},
|
||||
};
|
||||
#elif CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_7B
|
||||
// Leave it blank
|
||||
#elif CONFIG_BOARD_TYPE_WAVESHARE_ESP32_P4_WIFI6_TOUCH_LCD_3_4C
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
新增 微雪 开发板: ESP32-S3-CAM-XXXX
|
||||
产品链接:
|
||||
https://www.waveshare.net/shop/ESP32-S3-CAM-OV5640.htm
|
||||
https://www.waveshare.net/shop/ESP32-S3-CAM-OV3660.htm
|
||||
https://www.waveshare.net/shop/ESP32-S3-CAM-GC2145.htm
|
||||
https://www.waveshare.net/shop/ESP32-S3-CAM-GC0308.htm
|
||||
@@ -0,0 +1,115 @@
|
||||
#ifndef _BOARD_CONFIG_H_
|
||||
#define _BOARD_CONFIG_H_
|
||||
|
||||
#include <driver/gpio.h>
|
||||
#include <driver/spi_master.h>
|
||||
|
||||
#define AUDIO_INPUT_SAMPLE_RATE 24000
|
||||
#define AUDIO_OUTPUT_SAMPLE_RATE 24000
|
||||
|
||||
#define BOOT_BUTTON_GPIO GPIO_NUM_0
|
||||
|
||||
#define AUDIO_I2S_GPIO_MCLK GPIO_NUM_10
|
||||
#define AUDIO_I2S_GPIO_BCLK GPIO_NUM_11
|
||||
#define AUDIO_I2S_GPIO_WS GPIO_NUM_12
|
||||
#define AUDIO_I2S_GPIO_DIN GPIO_NUM_13
|
||||
#define AUDIO_I2S_GPIO_DOUT GPIO_NUM_14
|
||||
#define AUDIO_CODEC_PA_PIN GPIO_NUM_NC
|
||||
#define AUDIO_INPUT_REFERENCE true
|
||||
#define AUDIO_CODEC_ES8311_ADDR ES8311_CODEC_DEFAULT_ADDR
|
||||
#define AUDIO_CODEC_ES7210_ADDR ES7210_CODEC_DEFAULT_ADDR
|
||||
|
||||
#define I2C_SCL_IO GPIO_NUM_7
|
||||
#define I2C_SDA_IO GPIO_NUM_8
|
||||
|
||||
#define BSP_IO_EXPANDER_I2C_ADDRESS CUSTOM_IO_EXPANDER_I2C_CH32V003_ADDRESS
|
||||
|
||||
#define DISPLAY_SDA_PIN I2C_SDA_IO
|
||||
#define DISPLAY_SCL_PIN I2C_SCL_IO
|
||||
|
||||
#define DISPLAY_MISO_PIN GPIO_NUM_2
|
||||
#define DISPLAY_MOSI_PIN GPIO_NUM_1
|
||||
#define DISPLAY_SCLK_PIN GPIO_NUM_5
|
||||
#define DISPLAY_CS_PIN GPIO_NUM_6
|
||||
#define DISPLAY_DC_PIN GPIO_NUM_3
|
||||
#define DISPLAY_RESET_PIN GPIO_NUM_NC
|
||||
#define DISPLAY_BACKLIGHT_PIN GPIO_NUM_NC
|
||||
#define DISPLAY_SPI_SCLK_HZ (40 * 1000 * 1000)
|
||||
|
||||
|
||||
/* Camera pins */
|
||||
#define CAMERA_PIN_PWDN GPIO_NUM_NC
|
||||
#define CAMERA_PIN_RESET GPIO_NUM_NC
|
||||
#define CAMERA_PIN_XCLK GPIO_NUM_38
|
||||
#define CAMERA_PIN_SIOD GPIO_NUM_NC
|
||||
#define CAMERA_PIN_SIOC GPIO_NUM_NC
|
||||
|
||||
#define CAMERA_PIN_D7 GPIO_NUM_21
|
||||
#define CAMERA_PIN_D6 GPIO_NUM_39
|
||||
#define CAMERA_PIN_D5 GPIO_NUM_40
|
||||
#define CAMERA_PIN_D4 GPIO_NUM_42
|
||||
#define CAMERA_PIN_D3 GPIO_NUM_46
|
||||
#define CAMERA_PIN_D2 GPIO_NUM_48
|
||||
#define CAMERA_PIN_D1 GPIO_NUM_47
|
||||
#define CAMERA_PIN_D0 GPIO_NUM_45
|
||||
#define CAMERA_PIN_VSYNC GPIO_NUM_17
|
||||
#define CAMERA_PIN_HREF GPIO_NUM_18
|
||||
#define CAMERA_PIN_PCLK GPIO_NUM_41
|
||||
|
||||
#define XCLK_FREQ_HZ 20000000
|
||||
|
||||
|
||||
|
||||
#ifdef CONFIG_BSP_LCD_SIZE_2INCH
|
||||
#define DISPLAY_WIDTH 240
|
||||
#define DISPLAY_HEIGHT 320
|
||||
|
||||
#define DISPLAY_SWAP_XY false
|
||||
#define DISPLAY_MIRROR_X false
|
||||
#define DISPLAY_MIRROR_Y false
|
||||
#define DISPLAY_INVERT_COLOR true
|
||||
#define BACKLIGHT_INVERT false
|
||||
#define DISPLAY_OFFSET_X 0
|
||||
#define DISPLAY_OFFSET_Y 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BSP_LCD_SIZE_2_8INCH
|
||||
#define DISPLAY_WIDTH 240
|
||||
#define DISPLAY_HEIGHT 320
|
||||
|
||||
#define DISPLAY_SWAP_XY false
|
||||
#define DISPLAY_MIRROR_X false
|
||||
#define DISPLAY_MIRROR_Y false
|
||||
#define DISPLAY_INVERT_COLOR true
|
||||
#define BACKLIGHT_INVERT false
|
||||
#define DISPLAY_OFFSET_X 0
|
||||
#define DISPLAY_OFFSET_Y 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BSP_LCD_SIZE_3_5INCH
|
||||
#define DISPLAY_WIDTH 320
|
||||
#define DISPLAY_HEIGHT 480
|
||||
|
||||
#define DISPLAY_SWAP_XY false
|
||||
#define DISPLAY_MIRROR_X true
|
||||
#define DISPLAY_MIRROR_Y false
|
||||
#define DISPLAY_INVERT_COLOR true
|
||||
#define BACKLIGHT_INVERT false
|
||||
#define DISPLAY_OFFSET_X 0
|
||||
#define DISPLAY_OFFSET_Y 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BSP_LCD_SIZE_1_83INCH
|
||||
#define DISPLAY_WIDTH 240
|
||||
#define DISPLAY_HEIGHT 284
|
||||
|
||||
#define DISPLAY_SWAP_XY false
|
||||
#define DISPLAY_MIRROR_X false
|
||||
#define DISPLAY_MIRROR_Y false
|
||||
#define DISPLAY_INVERT_COLOR true
|
||||
#define BACKLIGHT_INVERT false
|
||||
#define DISPLAY_OFFSET_X 0
|
||||
#define DISPLAY_OFFSET_Y 0
|
||||
#endif
|
||||
|
||||
#endif // _BOARD_CONFIG_H_
|
||||
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"manufacturer": "waveshare",
|
||||
"target": "esp32s3",
|
||||
"builds": [
|
||||
{
|
||||
"name": "esp32-s3-cam-2",
|
||||
"sdkconfig_append": [
|
||||
"CONFIG_BOARD_TYPE_WAVESHARE_ESP32_S3_CAM_XXXX=y",
|
||||
"CONFIG_USE_DEVICE_AEC=y",
|
||||
"CONFIG_BSP_LCD_SIZE_2INCH=y"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "esp32-s3-cam-2.8",
|
||||
"sdkconfig_append": [
|
||||
"CONFIG_BOARD_TYPE_WAVESHARE_ESP32_S3_CAM_XXXX=y",
|
||||
"CONFIG_USE_DEVICE_AEC=y",
|
||||
"CONFIG_BSP_LCD_SIZE_2_8INCH=y"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "esp32-s3-cam-3.5",
|
||||
"sdkconfig_append": [
|
||||
"CONFIG_BOARD_TYPE_WAVESHARE_ESP32_S3_CAM_XXXX=y",
|
||||
"CONFIG_USE_DEVICE_AEC=y",
|
||||
"CONFIG_BSP_LCD_SIZE_3_5INCH=y"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "esp32-s3-cam-1.83",
|
||||
"sdkconfig_append": [
|
||||
"CONFIG_BOARD_TYPE_WAVESHARE_ESP32_S3_CAM_XXXX=y",
|
||||
"CONFIG_USE_DEVICE_AEC=y",
|
||||
"CONFIG_BSP_LCD_SIZE_1_83INCH=y"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,282 @@
|
||||
#include "wifi_board.h"
|
||||
#include "codecs/box_audio_codec.h"
|
||||
#include "display/lcd_display.h"
|
||||
#include "system_reset.h"
|
||||
#include "application.h"
|
||||
#include "button.h"
|
||||
#include "config.h"
|
||||
|
||||
#include <esp_log.h>
|
||||
#include "i2c_device.h"
|
||||
#include <driver/i2c_master.h>
|
||||
#include <driver/ledc.h>
|
||||
#include <wifi_station.h>
|
||||
#include <esp_lcd_panel_io.h>
|
||||
#include <esp_lcd_panel_ops.h>
|
||||
#include <esp_timer.h>
|
||||
#include "esp32_camera.h"
|
||||
|
||||
#include "esp_lcd_panel_vendor.h"
|
||||
#include "custom_io_expander_ch32v003.h"
|
||||
#include "esp_lcd_st7796.h"
|
||||
#include "esp_ota_ops.h"
|
||||
|
||||
#define TAG "waveshare_s3_cam_xxxx"
|
||||
|
||||
#define LCD_OPCODE_WRITE_CMD (0x02ULL)
|
||||
#define LCD_OPCODE_READ_CMD (0x0BULL)
|
||||
#define LCD_OPCODE_WRITE_COLOR (0x32ULL)
|
||||
|
||||
void switch_to_main(void)
|
||||
{
|
||||
const esp_partition_t *factory_part =
|
||||
esp_partition_find_first(ESP_PARTITION_TYPE_APP,
|
||||
ESP_PARTITION_SUBTYPE_APP_FACTORY,
|
||||
NULL);
|
||||
if (!factory_part) {
|
||||
ESP_LOGE("APP_SWITCH", "未找到 factory 分区");
|
||||
return;
|
||||
}
|
||||
|
||||
esp_err_t err = esp_ota_set_boot_partition(factory_part);
|
||||
if (err == ESP_OK) {
|
||||
ESP_LOGI("APP_SWITCH", "已设置 factory 为启动分区,重启回到主程序");
|
||||
esp_restart();
|
||||
} else {
|
||||
ESP_LOGE("APP_SWITCH", "设置启动分区失败: %s", esp_err_to_name(err));
|
||||
}
|
||||
}
|
||||
|
||||
class CustomBacklight : public Backlight {
|
||||
public:
|
||||
CustomBacklight(esp_io_expander_handle_t io_handle)
|
||||
: Backlight(), io_handle_(io_handle) {}
|
||||
|
||||
protected:
|
||||
esp_io_expander_handle_t io_handle_;
|
||||
|
||||
virtual void SetBrightnessImpl(uint8_t brightness) override {
|
||||
if (brightness > 100) brightness = 100;
|
||||
int flipped_brightness = 100 - brightness;
|
||||
|
||||
custom_io_expander_set_pwm(io_handle_, flipped_brightness * 255 / 100);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class CustomBoard : public WifiBoard {
|
||||
private:
|
||||
Button boot_button_;
|
||||
i2c_master_bus_handle_t i2c_bus_;
|
||||
LcdDisplay* display_;
|
||||
Esp32Camera* camera_;
|
||||
esp_io_expander_handle_t io_expander = NULL;
|
||||
CustomBacklight *backlight_;
|
||||
|
||||
void InitializeI2c() {
|
||||
// Initialize I2C peripheral
|
||||
i2c_master_bus_config_t i2c_bus_cfg = {
|
||||
.i2c_port = (i2c_port_t)1,
|
||||
.sda_io_num = I2C_SDA_IO,
|
||||
.scl_io_num = I2C_SCL_IO,
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
};
|
||||
ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_cfg, &i2c_bus_));
|
||||
}
|
||||
|
||||
void Initialize_Expander(void)
|
||||
{
|
||||
|
||||
custom_io_expander_new_i2c_ch32v003(i2c_bus_, BSP_IO_EXPANDER_I2C_ADDRESS, &io_expander);
|
||||
esp_io_expander_set_dir(io_expander, IO_EXPANDER_PIN_NUM_0 | IO_EXPANDER_PIN_NUM_1 | IO_EXPANDER_PIN_NUM_4 | IO_EXPANDER_PIN_NUM_6, IO_EXPANDER_OUTPUT);
|
||||
|
||||
esp_io_expander_set_level(io_expander, IO_EXPANDER_PIN_NUM_0 | IO_EXPANDER_PIN_NUM_1 , 1);
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
esp_io_expander_set_level(io_expander, IO_EXPANDER_PIN_NUM_0 | IO_EXPANDER_PIN_NUM_1 , 0);
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
esp_io_expander_set_level(io_expander, IO_EXPANDER_PIN_NUM_0 | IO_EXPANDER_PIN_NUM_1 , 1);
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
|
||||
esp_io_expander_set_level(io_expander, IO_EXPANDER_PIN_NUM_4 | IO_EXPANDER_PIN_NUM_6 , 1);
|
||||
|
||||
//custom_io_expander_set_pwm(io_expander,100);
|
||||
}
|
||||
|
||||
void InitializeSpi() {
|
||||
spi_bus_config_t buscfg = {};
|
||||
buscfg.mosi_io_num = DISPLAY_MOSI_PIN;
|
||||
buscfg.miso_io_num = GPIO_NUM_NC;
|
||||
buscfg.sclk_io_num = DISPLAY_SCLK_PIN;
|
||||
buscfg.quadwp_io_num = GPIO_NUM_NC;
|
||||
buscfg.quadhd_io_num = GPIO_NUM_NC;
|
||||
buscfg.max_transfer_sz = DISPLAY_WIDTH * DISPLAY_HEIGHT * sizeof(uint16_t);
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(SPI2_HOST, &buscfg, SPI_DMA_CH_AUTO));
|
||||
}
|
||||
|
||||
void InitializeSt7789Display() {
|
||||
esp_lcd_panel_io_handle_t panel_io = nullptr;
|
||||
esp_lcd_panel_handle_t panel = nullptr;
|
||||
// 液晶屏控制IO初始化
|
||||
ESP_LOGD(TAG, "Install panel IO");
|
||||
esp_lcd_panel_io_spi_config_t io_config = {};
|
||||
io_config.cs_gpio_num = DISPLAY_CS_PIN;
|
||||
io_config.dc_gpio_num = DISPLAY_DC_PIN;
|
||||
io_config.spi_mode = 0;
|
||||
io_config.pclk_hz = DISPLAY_SPI_SCLK_HZ;
|
||||
io_config.trans_queue_depth = 10;
|
||||
io_config.lcd_cmd_bits = 8;
|
||||
io_config.lcd_param_bits = 8;
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi(SPI2_HOST, &io_config, &panel_io));
|
||||
|
||||
// 初始化液晶屏驱动芯片ST7789
|
||||
ESP_LOGD(TAG, "Install LCD driver");
|
||||
esp_lcd_panel_dev_config_t panel_config = {};
|
||||
panel_config.reset_gpio_num = GPIO_NUM_NC;
|
||||
panel_config.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB;
|
||||
panel_config.bits_per_pixel = 16;
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_st7789(panel_io, &panel_config, &panel));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_reset(panel));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_init(panel));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_swap_xy(panel, DISPLAY_SWAP_XY));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_mirror(panel, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_invert_color(panel, DISPLAY_INVERT_COLOR));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel,true));
|
||||
display_ = new SpiLcdDisplay(panel_io, panel,
|
||||
DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY);
|
||||
backlight_ = new CustomBacklight(io_expander);
|
||||
backlight_->RestoreBrightness();
|
||||
}
|
||||
|
||||
void InitializeSt7796Display() {
|
||||
esp_lcd_panel_io_handle_t panel_io = nullptr;
|
||||
esp_lcd_panel_handle_t panel = nullptr;
|
||||
// 液晶屏控制IO初始化
|
||||
ESP_LOGD(TAG, "Install panel IO");
|
||||
esp_lcd_panel_io_spi_config_t io_config = {};
|
||||
io_config.cs_gpio_num = DISPLAY_CS_PIN;
|
||||
io_config.dc_gpio_num = DISPLAY_DC_PIN;
|
||||
io_config.spi_mode = 0;
|
||||
io_config.pclk_hz = DISPLAY_SPI_SCLK_HZ;
|
||||
io_config.trans_queue_depth = 10;
|
||||
io_config.lcd_cmd_bits = 8;
|
||||
io_config.lcd_param_bits = 8;
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi(SPI2_HOST, &io_config, &panel_io));
|
||||
|
||||
// 初始化液晶屏驱动芯片ST7789
|
||||
ESP_LOGD(TAG, "Install LCD driver");
|
||||
esp_lcd_panel_dev_config_t panel_config = {};
|
||||
panel_config.reset_gpio_num = GPIO_NUM_NC;
|
||||
panel_config.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_BGR;
|
||||
panel_config.bits_per_pixel = 16;
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_st7796(panel_io, &panel_config, &panel));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_reset(panel));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_init(panel));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_swap_xy(panel, DISPLAY_SWAP_XY));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_mirror(panel, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_invert_color(panel, DISPLAY_INVERT_COLOR));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel,true));
|
||||
display_ = new SpiLcdDisplay(panel_io, panel,
|
||||
DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY);
|
||||
backlight_ = new CustomBacklight(io_expander);
|
||||
backlight_->RestoreBrightness();
|
||||
}
|
||||
|
||||
void InitializeButtons() {
|
||||
boot_button_.OnClick([this]() {
|
||||
auto& app = Application::GetInstance();
|
||||
if (app.GetDeviceState() == kDeviceStateStarting) {
|
||||
EnterWifiConfigMode();
|
||||
return;
|
||||
}
|
||||
app.ToggleChatState();
|
||||
});
|
||||
boot_button_.OnLongPress([this]() {
|
||||
auto& app = Application::GetInstance();
|
||||
switch_to_main();
|
||||
});
|
||||
|
||||
#if CONFIG_USE_DEVICE_AEC
|
||||
boot_button_.OnDoubleClick([this]() {
|
||||
auto& app = Application::GetInstance();
|
||||
if (app.GetDeviceState() == kDeviceStateIdle) {
|
||||
app.SetAecMode(app.GetAecMode() == kAecOff ? kAecOnDeviceSide : kAecOff);
|
||||
}
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void InitializeCamera() {
|
||||
camera_config_t camera_config = {
|
||||
.pin_pwdn = CAMERA_PIN_PWDN,
|
||||
.pin_reset = CAMERA_PIN_RESET,
|
||||
.pin_xclk = CAMERA_PIN_XCLK,
|
||||
.pin_sccb_sda = -1, // Use initialized I2C
|
||||
.pin_sccb_scl = -1,
|
||||
.pin_d7 = CAMERA_PIN_D7,
|
||||
.pin_d6 = CAMERA_PIN_D6,
|
||||
.pin_d5 = CAMERA_PIN_D5,
|
||||
.pin_d4 = CAMERA_PIN_D4,
|
||||
.pin_d3 = CAMERA_PIN_D3,
|
||||
.pin_d2 = CAMERA_PIN_D2,
|
||||
.pin_d1 = CAMERA_PIN_D1,
|
||||
.pin_d0 = CAMERA_PIN_D0,
|
||||
.pin_vsync = CAMERA_PIN_VSYNC,
|
||||
.pin_href = CAMERA_PIN_HREF,
|
||||
.pin_pclk = CAMERA_PIN_PCLK,
|
||||
|
||||
.xclk_freq_hz = XCLK_FREQ_HZ,
|
||||
.ledc_timer = LEDC_TIMER_0,
|
||||
.ledc_channel = LEDC_CHANNEL_0,
|
||||
|
||||
.pixel_format = PIXFORMAT_RGB565,
|
||||
.frame_size = FRAMESIZE_QVGA,
|
||||
.jpeg_quality = 12,
|
||||
.fb_count = 2,
|
||||
.fb_location = CAMERA_FB_IN_PSRAM,
|
||||
.grab_mode = CAMERA_GRAB_WHEN_EMPTY,
|
||||
.sccb_i2c_port = (i2c_port_t)1,
|
||||
};
|
||||
|
||||
camera_ = new Esp32Camera(camera_config);
|
||||
if (camera_ != nullptr) {
|
||||
camera_->SetVFlip(true);
|
||||
}
|
||||
}
|
||||
public:
|
||||
CustomBoard() :
|
||||
boot_button_(BOOT_BUTTON_GPIO) {
|
||||
InitializeI2c();
|
||||
Initialize_Expander();
|
||||
InitializeSpi();
|
||||
InitializeButtons();
|
||||
#ifdef CONFIG_BSP_LCD_SIZE_2INCH
|
||||
InitializeSt7789Display();
|
||||
#elif CONFIG_BSP_LCD_SIZE_2_8INCH
|
||||
InitializeSt7789Display();
|
||||
#elif CONFIG_BSP_LCD_SIZE_1_83INCH
|
||||
InitializeSt7789Display();
|
||||
#elif CONFIG_BSP_LCD_SIZE_3_5INCH
|
||||
InitializeSt7796Display();
|
||||
#endif
|
||||
|
||||
InitializeCamera();
|
||||
|
||||
}
|
||||
|
||||
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_;
|
||||
}
|
||||
};
|
||||
|
||||
DECLARE_BOARD(CustomBoard);
|
||||
@@ -0,0 +1,60 @@
|
||||
# 产品链接
|
||||
|
||||
[微雪电子 ESP32-S3-LCD-0.85](https://www.waveshare.net/shop/ESP32-S3-LCD-0.85.htm)
|
||||
|
||||
# 编译配置命令
|
||||
|
||||
**克隆工程**
|
||||
|
||||
```bash
|
||||
git clone https://github.com/78/xiaozhi-esp32.git
|
||||
```
|
||||
|
||||
**进入工程**
|
||||
|
||||
```bash
|
||||
cd xiaozhi-esp32
|
||||
```
|
||||
|
||||
**配置编译目标为 ESP32C6**
|
||||
|
||||
```bash
|
||||
idf.py set-target esp32S3
|
||||
```
|
||||
|
||||
**打开 menuconfig**
|
||||
|
||||
```bash
|
||||
idf.py menuconfig
|
||||
```
|
||||
|
||||
**选择板子**
|
||||
|
||||
```bash
|
||||
Xiaozhi Assistant -> Board Type -> Waveshare ESP32-S3-LCD-0.85
|
||||
```
|
||||
|
||||
**修改 flash 大小:**
|
||||
|
||||
```
|
||||
Serial flasher config -> Flash size -> 8 MB
|
||||
```
|
||||
|
||||
**修改分区表:**
|
||||
|
||||
```
|
||||
Partition Table -> Custom partition CSV file -> partitions/v2/8m.csv
|
||||
```
|
||||
|
||||
**编译**
|
||||
|
||||
```ba
|
||||
idf.py build
|
||||
```
|
||||
|
||||
**下载并打开串口终端**
|
||||
|
||||
```bash
|
||||
idf.py build flash monitor
|
||||
```
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
#ifndef _BOARD_CONFIG_H_
|
||||
#define _BOARD_CONFIG_H_
|
||||
|
||||
#include <driver/gpio.h>
|
||||
#include <driver/spi_master.h>
|
||||
|
||||
#define AUDIO_INPUT_SAMPLE_RATE 24000
|
||||
#define AUDIO_OUTPUT_SAMPLE_RATE 24000
|
||||
|
||||
#define AUDIO_I2S_GPIO_MCLK GPIO_NUM_8
|
||||
#define AUDIO_I2S_GPIO_WS GPIO_NUM_10
|
||||
#define AUDIO_I2S_GPIO_BCLK GPIO_NUM_9
|
||||
#define AUDIO_I2S_GPIO_DIN GPIO_NUM_11
|
||||
#define AUDIO_I2S_GPIO_DOUT GPIO_NUM_12
|
||||
|
||||
#define AUDIO_CODEC_PA_PIN GPIO_NUM_7
|
||||
#define AUDIO_CODEC_I2C_SDA_PIN GPIO_NUM_42
|
||||
#define AUDIO_CODEC_I2C_SCL_PIN GPIO_NUM_41
|
||||
#define AUDIO_CODEC_ES8311_ADDR ES8311_CODEC_DEFAULT_ADDR
|
||||
#define AUDIO_CODEC_ES7210_ADDR ES7210_CODEC_DEFAULT_ADDR
|
||||
|
||||
#define BUILTIN_LED_GPIO GPIO_NUM_48
|
||||
#define PWR_BUTTON_GPIO GPIO_NUM_5
|
||||
#define VOLUME_UP_BUTTON_GPIO GPIO_NUM_4
|
||||
#define VOLUME_DOWN_BUTTON_GPIO GPIO_NUM_0
|
||||
|
||||
#define DISPLAY_SPI_MODE 3
|
||||
#define DISPLAY_CS_PIN GPIO_NUM_21
|
||||
#define DISPLAY_MOSI_PIN GPIO_NUM_39
|
||||
#define DISPLAY_MISO_PIN GPIO_NUM_NC
|
||||
#define DISPLAY_CLK_PIN GPIO_NUM_38
|
||||
#define DISPLAY_DC_PIN GPIO_NUM_45
|
||||
#define DISPLAY_RST_PIN GPIO_NUM_40
|
||||
|
||||
#define TOOUCH_INT_PIN GPIO_NUM_48
|
||||
#define TOOUCH_RST_PIN GPIO_NUM_47
|
||||
|
||||
#define BATTERY_EN_PIN GPIO_NUM_2
|
||||
#define BATTERY_ADC_PIN GPIO_NUM_1
|
||||
#define BATTERY_CHARGING_PIN GPIO_NUM_3
|
||||
|
||||
#define DISPLAY_WIDTH 128
|
||||
#define DISPLAY_HEIGHT 128
|
||||
#define DISPLAY_MIRROR_X true
|
||||
#define DISPLAY_MIRROR_Y true
|
||||
#define DISPLAY_SWAP_XY false
|
||||
#define DISPLAY_RGB_ORDER LCD_RGB_ELEMENT_ORDER_BGR
|
||||
#define DISPLAY_INVERT_COLOR true
|
||||
|
||||
#define DISPLAY_OFFSET_X 2
|
||||
#define DISPLAY_OFFSET_Y 1
|
||||
|
||||
#define DISPLAY_BACKLIGHT_PIN GPIO_NUM_46
|
||||
#define DISPLAY_BACKLIGHT_OUTPUT_INVERT false
|
||||
|
||||
#endif // _BOARD_CONFIG_H_
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"manufacturer": "waveshare",
|
||||
"target": "esp32s3",
|
||||
"builds": [
|
||||
{
|
||||
"name": "esp32-s3-lcd-0.85",
|
||||
"sdkconfig_append": [
|
||||
"CONFIG_USE_DEVICE_AEC=y",
|
||||
"CONFIG_USE_WECHAT_MESSAGE_STYLE=n",
|
||||
"CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y",
|
||||
"CONFIG_PARTITION_TABLE_CUSTOM_FILENAME=\"partitions/v2/8m.csv\""
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,311 @@
|
||||
#include "wifi_board.h"
|
||||
#include "codecs/box_audio_codec.h"
|
||||
#include "display/lcd_display.h"
|
||||
#include "system_reset.h"
|
||||
#include "application.h"
|
||||
#include "button.h"
|
||||
#include "config.h"
|
||||
#include "mcp_server.h"
|
||||
#include <esp_log.h>
|
||||
#include "i2c_device.h"
|
||||
#include <driver/i2c_master.h>
|
||||
#include <driver/ledc.h>
|
||||
#include <wifi_station.h>
|
||||
#include <esp_lcd_panel_vendor.h>
|
||||
#include <esp_lcd_panel_io.h>
|
||||
#include <esp_lcd_panel_ops.h>
|
||||
#include <esp_timer.h>
|
||||
#include "power_save_timer.h"
|
||||
#include "assets/lang_config.h"
|
||||
#include <esp_lvgl_port.h>
|
||||
#include "driver/gpio.h"
|
||||
#include "iot_button.h"
|
||||
#include "power_manager.h"
|
||||
#include "led/circular_strip.h"
|
||||
#include "led_strip_control.h"
|
||||
|
||||
#define TAG "waveshare_lcd_0_85"
|
||||
|
||||
|
||||
class CustomButton: public Button{
|
||||
public:
|
||||
void OnPressDownDel(void) {
|
||||
if (button_handle_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
on_press_down_ = NULL;
|
||||
iot_button_unregister_cb(button_handle_, BUTTON_PRESS_DOWN, nullptr);
|
||||
}
|
||||
void OnPressUpDel(void) {
|
||||
if (button_handle_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
on_press_up_ = NULL;
|
||||
iot_button_unregister_cb(button_handle_, BUTTON_PRESS_UP, nullptr);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class CustomBoard : public WifiBoard {
|
||||
private:
|
||||
CustomButton pwr_button_;
|
||||
CustomButton volume_up_button_;
|
||||
CustomButton volume_down_button_;
|
||||
i2c_master_bus_handle_t i2c_bus_;
|
||||
CircularStrip* led_strip_;
|
||||
LcdDisplay* display_;
|
||||
PowerManager* power_manager_ = nullptr;
|
||||
PowerSaveTimer* power_save_timer_ = nullptr;
|
||||
|
||||
void InitializePowerManager() {
|
||||
power_manager_ = new PowerManager(BATTERY_CHARGING_PIN, BATTERY_ADC_PIN, BATTERY_EN_PIN);
|
||||
power_manager_->PowerON();
|
||||
}
|
||||
|
||||
void InitializePowerSaveTimer() {
|
||||
power_save_timer_ = new PowerSaveTimer(-1, 60, 300);
|
||||
power_save_timer_->OnEnterSleepMode([this]() {
|
||||
ESP_LOGI(TAG, "Enabling sleep mode");
|
||||
auto display = GetDisplay();
|
||||
display->SetChatMessage("system", "");
|
||||
display->SetEmotion("sleepy");
|
||||
GetBacklight()->SetBrightness(20);
|
||||
});
|
||||
power_save_timer_->OnExitSleepMode([this]() {
|
||||
auto display = GetDisplay();
|
||||
display->SetChatMessage("system", "");
|
||||
display->SetEmotion("neutral");
|
||||
GetBacklight()->RestoreBrightness();
|
||||
});
|
||||
power_save_timer_->OnShutdownRequest([this]() {
|
||||
power_manager_->PowerOff();
|
||||
});
|
||||
power_save_timer_->SetEnabled(true);
|
||||
}
|
||||
|
||||
void InitializeI2c() {
|
||||
// Initialize I2C peripheral
|
||||
i2c_master_bus_config_t i2c_bus_cfg = {
|
||||
.i2c_port = (i2c_port_t)0,
|
||||
.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_));
|
||||
}
|
||||
|
||||
void InitializeSpi() {
|
||||
ESP_LOGI(TAG, "Initialize QSPI bus");
|
||||
spi_bus_config_t buscfg = {};
|
||||
buscfg.mosi_io_num = DISPLAY_MOSI_PIN;
|
||||
buscfg.miso_io_num = DISPLAY_MISO_PIN;
|
||||
buscfg.sclk_io_num = DISPLAY_CLK_PIN;
|
||||
buscfg.quadwp_io_num = GPIO_NUM_NC;
|
||||
buscfg.quadhd_io_num = GPIO_NUM_NC;
|
||||
buscfg.max_transfer_sz = DISPLAY_WIDTH * DISPLAY_HEIGHT * sizeof(uint16_t);
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(SPI3_HOST, &buscfg, SPI_DMA_CH_AUTO));
|
||||
}
|
||||
|
||||
void InitializeLed() {
|
||||
led_strip_ = new CircularStrip(BUILTIN_LED_GPIO, 8);
|
||||
new LedStripControl(led_strip_);
|
||||
}
|
||||
|
||||
void InitializeLcdDisplay() {
|
||||
esp_lcd_panel_io_handle_t panel_io = nullptr;
|
||||
esp_lcd_panel_handle_t panel = nullptr;
|
||||
// 液晶屏控制IO初始化
|
||||
ESP_LOGI(TAG, "Install panel IO");
|
||||
esp_lcd_panel_io_spi_config_t io_config = {};
|
||||
io_config.cs_gpio_num = DISPLAY_CS_PIN;
|
||||
io_config.dc_gpio_num = DISPLAY_DC_PIN;
|
||||
io_config.spi_mode = DISPLAY_SPI_MODE;
|
||||
io_config.pclk_hz = 40 * 1000 * 1000;
|
||||
io_config.trans_queue_depth = 10;
|
||||
io_config.lcd_cmd_bits = 8;
|
||||
io_config.lcd_param_bits = 8;
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi(SPI3_HOST, &io_config, &panel_io));
|
||||
|
||||
|
||||
// 初始化液晶屏驱动芯片
|
||||
ESP_LOGI(TAG, "Install LCD driver");
|
||||
esp_lcd_panel_dev_config_t panel_config = {};
|
||||
panel_config.reset_gpio_num = DISPLAY_RST_PIN;
|
||||
panel_config.rgb_ele_order = DISPLAY_RGB_ORDER;
|
||||
panel_config.bits_per_pixel = 16;
|
||||
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_st7789(panel_io, &panel_config, &panel));
|
||||
|
||||
|
||||
esp_lcd_panel_reset(panel);
|
||||
|
||||
esp_lcd_panel_init(panel);
|
||||
esp_lcd_panel_invert_color(panel, DISPLAY_INVERT_COLOR);
|
||||
esp_lcd_panel_swap_xy(panel, DISPLAY_SWAP_XY);
|
||||
esp_lcd_panel_mirror(panel, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y);
|
||||
|
||||
|
||||
display_ = new SpiLcdDisplay(panel_io, panel,
|
||||
DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY);
|
||||
}
|
||||
|
||||
void InitializeButtons() {
|
||||
|
||||
pwr_button_.OnPressUp([this]() {
|
||||
pwr_button_.OnClick([this]() {
|
||||
auto& app = Application::GetInstance();
|
||||
app.ToggleChatState();
|
||||
});
|
||||
pwr_button_.OnLongPress([this]() {
|
||||
printf("Power button long press\n");
|
||||
if (power_manager_ != nullptr){
|
||||
power_manager_->PowerOff();
|
||||
}
|
||||
});
|
||||
|
||||
pwr_button_.OnDoubleClick([this]() {
|
||||
static uint8_t brightness_last = 0;
|
||||
auto backlight = Board::GetInstance().GetBacklight();
|
||||
if (backlight->brightness() == 0) {
|
||||
brightness_last = 0;
|
||||
if (brightness_last == 0) {
|
||||
backlight->SetBrightness(50, true);
|
||||
} else {
|
||||
backlight->SetBrightness(brightness_last, true);
|
||||
}
|
||||
} else {
|
||||
brightness_last = backlight->brightness();
|
||||
backlight->SetBrightness(0);
|
||||
}
|
||||
});
|
||||
pwr_button_.OnMultipleClick([this]() {
|
||||
EnterWifiConfigMode();
|
||||
}, 3);
|
||||
pwr_button_.OnPressUpDel();
|
||||
});
|
||||
|
||||
volume_up_button_.OnClick([this]() {
|
||||
auto codec = Board::GetInstance().GetAudioCodec();
|
||||
auto volume = codec->output_volume() + 10;
|
||||
if (volume > 100) {
|
||||
volume = 100;
|
||||
}
|
||||
codec->SetOutputVolume(volume);
|
||||
GetDisplay()->ShowNotification(Lang::Strings::VOLUME + std::to_string(volume/10));
|
||||
});
|
||||
|
||||
volume_up_button_.OnLongPress([this]() {
|
||||
Board::GetInstance().GetAudioCodec()->SetOutputVolume(100);
|
||||
GetDisplay()->ShowNotification(Lang::Strings::MAX_VOLUME);
|
||||
});
|
||||
|
||||
volume_down_button_.OnClick([this]() {
|
||||
auto codec = Board::GetInstance().GetAudioCodec();
|
||||
auto volume = codec->output_volume() - 10;
|
||||
if (volume < 0) {
|
||||
volume = 0;
|
||||
}
|
||||
codec->SetOutputVolume(volume);
|
||||
GetDisplay()->ShowNotification(Lang::Strings::VOLUME + std::to_string(volume/10));
|
||||
});
|
||||
|
||||
volume_down_button_.OnLongPress([this]() {
|
||||
Board::GetInstance().GetAudioCodec()->SetOutputVolume(0);
|
||||
GetDisplay()->ShowNotification(Lang::Strings::MUTED);
|
||||
});
|
||||
#if CONFIG_USE_DEVICE_AEC
|
||||
volume_down_button_.OnDoubleClick([this]() {
|
||||
auto& app = Application::GetInstance();
|
||||
if (app.GetDeviceState() == kDeviceStateIdle) {
|
||||
app.SetAecMode(app.GetAecMode() == kAecOff ? kAecOnDeviceSide : kAecOff);
|
||||
}
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
// 初始化工具
|
||||
void InitializeTools() {
|
||||
auto &mcp_server = McpServer::GetInstance();
|
||||
mcp_server.AddTool("self.system.reconfigure_wifi",
|
||||
"Reboot the device and enter WiFi configuration mode.\n"
|
||||
"**CAUTION** You must ask the user to confirm this action.",
|
||||
PropertyList(), [this](const PropertyList& properties) {
|
||||
EnterWifiConfigMode();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
public:
|
||||
CustomBoard() :
|
||||
pwr_button_(PWR_BUTTON_GPIO),
|
||||
volume_up_button_(VOLUME_UP_BUTTON_GPIO),
|
||||
volume_down_button_(VOLUME_DOWN_BUTTON_GPIO) {
|
||||
InitializePowerManager();
|
||||
InitializePowerSaveTimer();
|
||||
InitializeI2c();
|
||||
InitializeSpi();
|
||||
InitializeLcdDisplay();
|
||||
InitializeButtons();
|
||||
InitializeLed();
|
||||
InitializeTools();
|
||||
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,
|
||||
true);
|
||||
return &audio_codec;
|
||||
}
|
||||
|
||||
virtual Led* GetLed() override {
|
||||
return led_strip_;
|
||||
}
|
||||
|
||||
virtual Display* GetDisplay() override {
|
||||
return display_;
|
||||
}
|
||||
|
||||
virtual Backlight* GetBacklight() override {
|
||||
static PwmBacklight backlight(DISPLAY_BACKLIGHT_PIN, DISPLAY_BACKLIGHT_OUTPUT_INVERT);
|
||||
return &backlight;
|
||||
}
|
||||
|
||||
virtual bool GetBatteryLevel(int &level, bool& charging, bool& discharging) override {
|
||||
static bool last_discharging = false;
|
||||
charging = power_manager_->IsCharging();
|
||||
discharging = power_manager_->IsDischarging();
|
||||
if (discharging != last_discharging) {
|
||||
power_save_timer_->SetEnabled(discharging);
|
||||
last_discharging = discharging;
|
||||
}
|
||||
|
||||
level = power_manager_->GetBatteryLevel();
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void SetPowerSaveLevel(PowerSaveLevel level) override {
|
||||
if (level != PowerSaveLevel::LOW_POWER) {
|
||||
power_save_timer_->WakeUp();
|
||||
}
|
||||
WifiBoard::SetPowerSaveLevel(level);
|
||||
}
|
||||
};
|
||||
|
||||
DECLARE_BOARD(CustomBoard);
|
||||
@@ -0,0 +1,130 @@
|
||||
#include "led_strip_control.h"
|
||||
#include "settings.h"
|
||||
#include "mcp_server.h"
|
||||
#include <esp_log.h>
|
||||
|
||||
#define TAG "LedStripControl"
|
||||
|
||||
|
||||
int LedStripControl::LevelToBrightness(int level) const {
|
||||
if (level < 0) level = 0;
|
||||
if (level > 8) level = 8;
|
||||
return (1 << level) - 1; // 2^n - 1
|
||||
}
|
||||
|
||||
StripColor LedStripControl::RGBToColor(int red, int green, int blue) {
|
||||
if (red < 0) red = 0;
|
||||
if (red > 255) red = 255;
|
||||
if (green < 0) green = 0;
|
||||
if (green > 255) green = 255;
|
||||
if (blue < 0) blue = 0;
|
||||
if (blue > 255) blue = 255;
|
||||
return {static_cast<uint8_t>(red), static_cast<uint8_t>(green), static_cast<uint8_t>(blue)};
|
||||
}
|
||||
|
||||
LedStripControl::LedStripControl(CircularStrip* led_strip)
|
||||
: led_strip_(led_strip) {
|
||||
// 从设置中读取亮度等级
|
||||
Settings settings("led_strip");
|
||||
brightness_level_ = settings.GetInt("brightness", 4); // 默认等级4
|
||||
led_strip_->SetBrightness(LevelToBrightness(brightness_level_), 4);
|
||||
|
||||
auto& mcp_server = McpServer::GetInstance();
|
||||
mcp_server.AddTool("self.led_strip.get_brightness",
|
||||
"Get the brightness of the led strip (0-8)",
|
||||
PropertyList(), [this](const PropertyList& properties) -> ReturnValue {
|
||||
return brightness_level_;
|
||||
});
|
||||
|
||||
mcp_server.AddTool("self.led_strip.set_brightness",
|
||||
"Set the brightness of the led strip (0-8)",
|
||||
PropertyList({
|
||||
Property("level", kPropertyTypeInteger, 0, 8)
|
||||
}), [this](const PropertyList& properties) -> ReturnValue {
|
||||
int level = properties["level"].value<int>();
|
||||
ESP_LOGI(TAG, "Set LedStrip brightness level to %d", level);
|
||||
brightness_level_ = level;
|
||||
led_strip_->SetBrightness(LevelToBrightness(brightness_level_), 4);
|
||||
|
||||
// 保存设置
|
||||
Settings settings("led_strip", true);
|
||||
settings.SetInt("brightness", brightness_level_);
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
mcp_server.AddTool("self.led_strip.set_single_color",
|
||||
"Set the color of a single led.",
|
||||
PropertyList({
|
||||
Property("index", kPropertyTypeInteger, 0, 7),
|
||||
Property("red", kPropertyTypeInteger, 0, 255),
|
||||
Property("green", kPropertyTypeInteger, 0, 255),
|
||||
Property("blue", kPropertyTypeInteger, 0, 255)
|
||||
}), [this](const PropertyList& properties) -> ReturnValue {
|
||||
int index = properties["index"].value<int>();
|
||||
int red = properties["red"].value<int>();
|
||||
int green = properties["green"].value<int>();
|
||||
int blue = properties["blue"].value<int>();
|
||||
ESP_LOGI(TAG, "Set led strip single color %d to %d, %d, %d",
|
||||
index, red, green, blue);
|
||||
led_strip_->SetSingleColor(index, RGBToColor(green, red, blue));
|
||||
return true;
|
||||
});
|
||||
|
||||
mcp_server.AddTool("self.led_strip.set_all_color",
|
||||
"Set the color of all leds.",
|
||||
PropertyList({
|
||||
Property("red", kPropertyTypeInteger, 0, 255),
|
||||
Property("green", kPropertyTypeInteger, 0, 255),
|
||||
Property("blue", kPropertyTypeInteger, 0, 255)
|
||||
}), [this](const PropertyList& properties) -> ReturnValue {
|
||||
int red = properties["red"].value<int>();
|
||||
int green = properties["green"].value<int>();
|
||||
int blue = properties["blue"].value<int>();
|
||||
ESP_LOGI(TAG, "Set led strip all color to %d, %d, %d",
|
||||
red, green, blue);
|
||||
led_strip_->SetAllColor(RGBToColor(green, red, blue));
|
||||
return true;
|
||||
});
|
||||
|
||||
mcp_server.AddTool("self.led_strip.blink",
|
||||
"Blink the led strip. (闪烁)",
|
||||
PropertyList({
|
||||
Property("red", kPropertyTypeInteger, 0, 255),
|
||||
Property("green", kPropertyTypeInteger, 0, 255),
|
||||
Property("blue", kPropertyTypeInteger, 0, 255),
|
||||
Property("interval", kPropertyTypeInteger, 0, 1000)
|
||||
}), [this](const PropertyList& properties) -> ReturnValue {
|
||||
int red = properties["red"].value<int>();
|
||||
int green = properties["green"].value<int>();
|
||||
int blue = properties["blue"].value<int>();
|
||||
int interval = properties["interval"].value<int>();
|
||||
ESP_LOGI(TAG, "Blink led strip with color %d, %d, %d, interval %dms",
|
||||
red, green, blue, interval);
|
||||
led_strip_->Blink(RGBToColor(green, red, blue), interval);
|
||||
return true;
|
||||
});
|
||||
|
||||
mcp_server.AddTool("self.led_strip.scroll",
|
||||
"Scroll the led strip. (跑马灯)",
|
||||
PropertyList({
|
||||
Property("red", kPropertyTypeInteger, 0, 255),
|
||||
Property("green", kPropertyTypeInteger, 0, 255),
|
||||
Property("blue", kPropertyTypeInteger, 0, 255),
|
||||
Property("length", kPropertyTypeInteger, 1, 7),
|
||||
Property("interval", kPropertyTypeInteger, 0, 1000)
|
||||
}), [this](const PropertyList& properties) -> ReturnValue {
|
||||
int red = properties["red"].value<int>();
|
||||
int green = properties["green"].value<int>();
|
||||
int blue = properties["blue"].value<int>();
|
||||
int interval = properties["interval"].value<int>();
|
||||
int length = properties["length"].value<int>();
|
||||
ESP_LOGI(TAG, "Scroll led strip with color %d, %d, %d, length %d, interval %dms",
|
||||
red, green, blue, length, interval);
|
||||
StripColor low = RGBToColor(4, 4, 4);
|
||||
StripColor high = RGBToColor(green, red, blue);
|
||||
led_strip_->Scroll(low, high, length, interval);
|
||||
return true;
|
||||
});
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#ifndef LED_STRIP_CONTROL_H
|
||||
#define LED_STRIP_CONTROL_H
|
||||
|
||||
#include "led/circular_strip.h"
|
||||
|
||||
class LedStripControl {
|
||||
private:
|
||||
CircularStrip* led_strip_;
|
||||
int brightness_level_; // 亮度等级 (0-8)
|
||||
|
||||
int LevelToBrightness(int level) const; // 将等级转换为实际亮度值
|
||||
StripColor RGBToColor(int red, int green, int blue);
|
||||
|
||||
public:
|
||||
explicit LedStripControl(CircularStrip* led_strip);
|
||||
};
|
||||
|
||||
#endif // LED_STRIP_CONTROL_H
|
||||
@@ -0,0 +1,212 @@
|
||||
#pragma once
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include <esp_log.h>
|
||||
|
||||
#include <esp_timer.h>
|
||||
#include <driver/gpio.h>
|
||||
#include "esp_adc/adc_oneshot.h"
|
||||
#include "esp_adc/adc_cali.h"
|
||||
#include "esp_adc/adc_cali_scheme.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
class PowerManager
|
||||
{
|
||||
private:
|
||||
gpio_num_t charging_pin_ = GPIO_NUM_NC;
|
||||
gpio_num_t bat_adc_pin_ = GPIO_NUM_NC;
|
||||
gpio_num_t bat_power_pin_ = GPIO_NUM_NC;
|
||||
adc_oneshot_unit_handle_t adc_handle_ = NULL;
|
||||
adc_cali_handle_t adc_cali_handle_ = NULL;
|
||||
adc_channel_t adc_channel_;
|
||||
bool do_calibration = false;
|
||||
bool adc_calibration_init(adc_unit_t unit, adc_channel_t channel, adc_atten_t atten, adc_cali_handle_t *out_handle)
|
||||
{
|
||||
adc_cali_handle_t handle = NULL;
|
||||
esp_err_t ret = ESP_FAIL;
|
||||
bool calibrated = false;
|
||||
|
||||
if (!calibrated)
|
||||
{
|
||||
ESP_LOGI("power_manager", "calibration scheme version is %s", "Curve Fitting");
|
||||
adc_cali_curve_fitting_config_t cali_config = {
|
||||
.unit_id = unit,
|
||||
.chan = channel,
|
||||
.atten = atten,
|
||||
.bitwidth = ADC_BITWIDTH_DEFAULT,
|
||||
};
|
||||
ret = adc_cali_create_scheme_curve_fitting(&cali_config, &handle);
|
||||
if (ret == ESP_OK)
|
||||
{
|
||||
calibrated = true;
|
||||
}
|
||||
}
|
||||
|
||||
*out_handle = handle;
|
||||
if (ret == ESP_OK)
|
||||
{
|
||||
ESP_LOGI("power_manager", "Calibration Success");
|
||||
}
|
||||
else if (ret == ESP_ERR_NOT_SUPPORTED || !calibrated)
|
||||
{
|
||||
ESP_LOGW("power_manager", "eFuse not burnt, skip software calibration");
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGE("power_manager", "Invalid arg or no memory");
|
||||
}
|
||||
return calibrated;
|
||||
}
|
||||
|
||||
public:
|
||||
PowerManager(gpio_num_t charging_pin, gpio_num_t bat_adc_pin, gpio_num_t bat_power_pin) : charging_pin_(charging_pin),
|
||||
bat_adc_pin_(bat_adc_pin),
|
||||
bat_power_pin_(bat_power_pin)
|
||||
{
|
||||
// 初始化充电引脚
|
||||
if (charging_pin_ != GPIO_NUM_NC)
|
||||
{
|
||||
gpio_config_t io_conf = {};
|
||||
io_conf.intr_type = GPIO_INTR_DISABLE;
|
||||
io_conf.mode = GPIO_MODE_INPUT;
|
||||
io_conf.pin_bit_mask = 1ULL << charging_pin_;
|
||||
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||
io_conf.pull_up_en = GPIO_PULLUP_ENABLE;
|
||||
gpio_config(&io_conf);
|
||||
}
|
||||
// 初始化电池使能引脚
|
||||
if (bat_power_pin_ != GPIO_NUM_NC)
|
||||
{
|
||||
gpio_config_t io_conf = {};
|
||||
io_conf.intr_type = GPIO_INTR_DISABLE;
|
||||
io_conf.mode = GPIO_MODE_OUTPUT;
|
||||
io_conf.pin_bit_mask = 1ULL << bat_power_pin_;
|
||||
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||
io_conf.pull_up_en = GPIO_PULLUP_DISABLE;
|
||||
gpio_config(&io_conf);
|
||||
}
|
||||
|
||||
// 初始化adc
|
||||
if (bat_adc_pin_ != GPIO_NUM_NC)
|
||||
{
|
||||
adc_oneshot_unit_init_cfg_t init_config = {};
|
||||
init_config.ulp_mode = ADC_ULP_MODE_DISABLE;
|
||||
if (bat_adc_pin_ >= GPIO_NUM_1 && bat_adc_pin_ <= GPIO_NUM_10)
|
||||
{
|
||||
init_config.unit_id = ADC_UNIT_1;
|
||||
adc_channel_ = (adc_channel_t)((int)bat_adc_pin_ - 1);
|
||||
}
|
||||
else if (bat_adc_pin_ >= GPIO_NUM_11 && bat_adc_pin_ <= GPIO_NUM_20)
|
||||
{
|
||||
init_config.unit_id = ADC_UNIT_2;
|
||||
adc_channel_ = (adc_channel_t)((int)bat_adc_pin_ - 11);
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
ESP_ERROR_CHECK(adc_oneshot_new_unit(&init_config, &adc_handle_));
|
||||
adc_oneshot_chan_cfg_t config = {};
|
||||
config.bitwidth = ADC_BITWIDTH_DEFAULT;
|
||||
config.atten = ADC_ATTEN_DB_12;
|
||||
ESP_ERROR_CHECK(adc_oneshot_config_channel(adc_handle_, adc_channel_, &config));
|
||||
do_calibration = adc_calibration_init(init_config.unit_id, adc_channel_, config.atten, &adc_cali_handle_);
|
||||
}
|
||||
}
|
||||
|
||||
~PowerManager()
|
||||
{
|
||||
if (adc_handle_)
|
||||
{
|
||||
ESP_ERROR_CHECK(adc_oneshot_del_unit(adc_handle_));
|
||||
}
|
||||
// if (adc_cali_handle_)
|
||||
// {
|
||||
// ESP_ERROR_CHECK(adc_cali_delete_scheme_line_fitting(adc_cali_handle_));
|
||||
// }
|
||||
}
|
||||
|
||||
int GetBatteryLevel(void)
|
||||
{
|
||||
|
||||
int adc_raw = 0;
|
||||
int voltage_int = 0;
|
||||
const float voltage_float_threshold = 0.1f;
|
||||
float voltage_float = 0.0f;
|
||||
static float last_voltage_float = 0.0f;
|
||||
|
||||
static int last_battery_level = 0;
|
||||
|
||||
if (adc_handle_ != nullptr)
|
||||
{
|
||||
ESP_ERROR_CHECK(adc_oneshot_read(adc_handle_, adc_channel_, &adc_raw));
|
||||
if (do_calibration)
|
||||
{
|
||||
ESP_ERROR_CHECK(adc_cali_raw_to_voltage(adc_cali_handle_, adc_raw, &voltage_int));
|
||||
voltage_float = (voltage_int / 1000.0f) * 3.0;
|
||||
|
||||
if (fabs(voltage_float - last_voltage_float) >= voltage_float_threshold)
|
||||
{
|
||||
last_voltage_float = voltage_float;
|
||||
if (voltage_float < 3.52) {
|
||||
last_battery_level = 1;
|
||||
} else if (voltage_float < 3.64) {
|
||||
last_battery_level = 20;
|
||||
} else if (voltage_float < 3.76) {
|
||||
last_battery_level = 40;
|
||||
} else if (voltage_float < 3.88) {
|
||||
last_battery_level = 60;
|
||||
} else if (voltage_float < 4.0) {
|
||||
last_battery_level = 80;
|
||||
} else {
|
||||
last_battery_level = 100;
|
||||
}
|
||||
}
|
||||
return last_battery_level;
|
||||
}
|
||||
}
|
||||
return 100;
|
||||
}
|
||||
|
||||
bool IsCharging(void)
|
||||
{
|
||||
if (charging_pin_ != GPIO_NUM_NC)
|
||||
{
|
||||
return gpio_get_level(charging_pin_) == 0 ? true : false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsDischarging(void)
|
||||
{
|
||||
if (charging_pin_ != GPIO_NUM_NC)
|
||||
{
|
||||
return gpio_get_level(charging_pin_) == 1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IsChargingDone(void)
|
||||
{
|
||||
if (GetBatteryLevel() == 100)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void PowerOff(void)
|
||||
{
|
||||
if (bat_power_pin_ != GPIO_NUM_NC)
|
||||
{
|
||||
gpio_set_level(bat_power_pin_, 0);
|
||||
}
|
||||
}
|
||||
void PowerON(void)
|
||||
{
|
||||
if (bat_power_pin_ != GPIO_NUM_NC)
|
||||
{
|
||||
gpio_set_level(bat_power_pin_, 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -265,7 +265,16 @@ private:
|
||||
},
|
||||
};
|
||||
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_FT5x06_CONFIG();
|
||||
esp_lcd_panel_io_i2c_config_t tp_io_config = {
|
||||
.dev_addr = ESP_LCD_TOUCH_IO_I2C_FT5x06_ADDRESS,
|
||||
.control_phase_bytes = 1,
|
||||
.dc_bit_offset = 0,
|
||||
.lcd_cmd_bits = 8,
|
||||
.flags =
|
||||
{
|
||||
.disable_control_phase = 1,
|
||||
}
|
||||
};
|
||||
tp_io_config.scl_speed_hz = 400 * 1000;
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_i2c(codec_i2c_bus_, &tp_io_config, &tp_io_handle));
|
||||
ESP_LOGI(TAG, "Initialize touch controller");
|
||||
|
||||
@@ -267,7 +267,16 @@ private:
|
||||
},
|
||||
};
|
||||
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_FT5x06_CONFIG();
|
||||
esp_lcd_panel_io_i2c_config_t tp_io_config = {
|
||||
.dev_addr = ESP_LCD_TOUCH_IO_I2C_FT5x06_ADDRESS,
|
||||
.control_phase_bytes = 1,
|
||||
.dc_bit_offset = 0,
|
||||
.lcd_cmd_bits = 8,
|
||||
.flags =
|
||||
{
|
||||
.disable_control_phase = 1,
|
||||
}
|
||||
};
|
||||
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");
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
# 产品链接
|
||||
|
||||
[微雪电子 ESP32-S3-Touch-LCD-1.54](https://www.waveshare.net/shop/ESP32-S3-Touch-LCD-1.54.htm)
|
||||
[微雪电子 ESP32-S3-LCD-1.54](https://www.waveshare.net/shop/ESP32-S3-LCD-1.54.htm)
|
||||
|
||||
# 编译配置命令
|
||||
|
||||
**克隆工程**
|
||||
|
||||
```bash
|
||||
git clone https://github.com/78/xiaozhi-esp32.git
|
||||
```
|
||||
|
||||
**进入工程**
|
||||
|
||||
```bash
|
||||
cd xiaozhi-esp32
|
||||
```
|
||||
|
||||
**配置编译目标为 ESP32S3**
|
||||
|
||||
```bash
|
||||
idf.py set-target esp32s3
|
||||
```
|
||||
|
||||
**打开 menuconfig**
|
||||
|
||||
```bash
|
||||
idf.py menuconfig
|
||||
```
|
||||
|
||||
**选择板子**
|
||||
|
||||
```bash
|
||||
Xiaozhi Assistant -> Board Type -> Waveshare ESP32-S3-Touch-LCD-1.54
|
||||
```
|
||||
|
||||
**编译**
|
||||
|
||||
```ba
|
||||
idf.py build
|
||||
```
|
||||
|
||||
**下载并打开串口终端**
|
||||
|
||||
```bash
|
||||
idf.py build flash monitor
|
||||
```
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
#ifndef _BOARD_CONFIG_H_
|
||||
#define _BOARD_CONFIG_H_
|
||||
|
||||
#include <driver/gpio.h>
|
||||
#include <driver/spi_master.h>
|
||||
|
||||
#define AUDIO_INPUT_SAMPLE_RATE 24000
|
||||
#define AUDIO_OUTPUT_SAMPLE_RATE 24000
|
||||
|
||||
#define AUDIO_I2S_GPIO_MCLK GPIO_NUM_8
|
||||
#define AUDIO_I2S_GPIO_WS GPIO_NUM_10
|
||||
#define AUDIO_I2S_GPIO_BCLK GPIO_NUM_9
|
||||
#define AUDIO_I2S_GPIO_DIN GPIO_NUM_11
|
||||
#define AUDIO_I2S_GPIO_DOUT GPIO_NUM_12
|
||||
|
||||
#define AUDIO_CODEC_PA_PIN GPIO_NUM_7
|
||||
#define AUDIO_CODEC_I2C_SDA_PIN GPIO_NUM_42
|
||||
#define AUDIO_CODEC_I2C_SCL_PIN GPIO_NUM_41
|
||||
#define AUDIO_CODEC_ES8311_ADDR ES8311_CODEC_DEFAULT_ADDR
|
||||
#define AUDIO_CODEC_ES7210_ADDR ES7210_CODEC_DEFAULT_ADDR
|
||||
|
||||
#define BUILTIN_LED_GPIO GPIO_NUM_NC
|
||||
#define PWR_BUTTON_GPIO GPIO_NUM_5
|
||||
#define VOLUME_UP_BUTTON_GPIO GPIO_NUM_4
|
||||
#define VOLUME_DOWN_BUTTON_GPIO GPIO_NUM_0
|
||||
|
||||
#define DISPLAY_SPI_MODE 3
|
||||
#define DISPLAY_CS_PIN GPIO_NUM_21
|
||||
#define DISPLAY_MOSI_PIN GPIO_NUM_39
|
||||
#define DISPLAY_MISO_PIN GPIO_NUM_NC
|
||||
#define DISPLAY_CLK_PIN GPIO_NUM_38
|
||||
#define DISPLAY_DC_PIN GPIO_NUM_45
|
||||
#define DISPLAY_RST_PIN GPIO_NUM_40
|
||||
|
||||
#define TOOUCH_INT_PIN GPIO_NUM_48
|
||||
#define TOOUCH_RST_PIN GPIO_NUM_47
|
||||
|
||||
#define BATTERY_EN_PIN GPIO_NUM_2
|
||||
#define BATTERY_ADC_PIN GPIO_NUM_1
|
||||
#define BATTERY_CHARGING_PIN GPIO_NUM_3
|
||||
|
||||
#define DISPLAY_WIDTH 240
|
||||
#define DISPLAY_HEIGHT 240
|
||||
#define DISPLAY_MIRROR_X false
|
||||
#define DISPLAY_MIRROR_Y false
|
||||
#define DISPLAY_SWAP_XY false
|
||||
#define DISPLAY_RGB_ORDER LCD_RGB_ELEMENT_ORDER_RGB
|
||||
#define DISPLAY_INVERT_COLOR true
|
||||
|
||||
#define DISPLAY_OFFSET_X 0
|
||||
#define DISPLAY_OFFSET_Y 0
|
||||
|
||||
#define DISPLAY_BACKLIGHT_PIN GPIO_NUM_46
|
||||
#define DISPLAY_BACKLIGHT_OUTPUT_INVERT false
|
||||
|
||||
#endif // _BOARD_CONFIG_H_
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"manufacturer": "waveshare",
|
||||
"target": "esp32s3",
|
||||
"builds": [
|
||||
{
|
||||
"name": "esp32-s3-touch-lcd-1.54",
|
||||
"sdkconfig_append": [
|
||||
"CONFIG_USE_WECHAT_MESSAGE_STYLE=n",
|
||||
"CONFIG_USE_DEVICE_AEC=y"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,355 @@
|
||||
#include "wifi_board.h"
|
||||
#include "codecs/box_audio_codec.h"
|
||||
#include "display/lcd_display.h"
|
||||
#include "system_reset.h"
|
||||
#include "application.h"
|
||||
#include "button.h"
|
||||
#include "config.h"
|
||||
#include "mcp_server.h"
|
||||
|
||||
#include <esp_log.h>
|
||||
#include "i2c_device.h"
|
||||
#include <driver/i2c_master.h>
|
||||
#include <wifi_station.h>
|
||||
#include <esp_lcd_panel_vendor.h>
|
||||
#include <esp_lcd_panel_io.h>
|
||||
#include <esp_lcd_panel_ops.h>
|
||||
|
||||
#include <esp_timer.h>
|
||||
|
||||
#include "power_save_timer.h"
|
||||
#include "assets/lang_config.h"
|
||||
|
||||
#include <esp_lcd_touch_cst816s.h>
|
||||
#include <esp_lvgl_port.h>
|
||||
#include "driver/gpio.h"
|
||||
|
||||
#include "iot_button.h"
|
||||
|
||||
#include "power_manager.h"
|
||||
#include "esp_ota_ops.h"
|
||||
|
||||
#define TAG "waveshare_esp32_s3_touch_lcd_1_54"
|
||||
|
||||
class CustomButton: public Button{
|
||||
public:
|
||||
void OnPressDownDel(void) {
|
||||
if (button_handle_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
on_press_down_ = NULL;
|
||||
iot_button_unregister_cb(button_handle_, BUTTON_PRESS_DOWN, nullptr);
|
||||
}
|
||||
void OnPressUpDel(void) {
|
||||
if (button_handle_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
on_press_up_ = NULL;
|
||||
iot_button_unregister_cb(button_handle_, BUTTON_PRESS_UP, nullptr);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
class CustomBoard : public WifiBoard {
|
||||
private:
|
||||
CustomButton pwr_button_;
|
||||
CustomButton volume_up_button_;
|
||||
CustomButton volume_down_button_;
|
||||
i2c_master_bus_handle_t i2c_bus_;
|
||||
LcdDisplay* display_;
|
||||
PowerManager* power_manager_ = nullptr;
|
||||
PowerSaveTimer* power_save_timer_ = nullptr;
|
||||
|
||||
void InitializePowerManager() {
|
||||
power_manager_ = new PowerManager(BATTERY_CHARGING_PIN, BATTERY_ADC_PIN, BATTERY_EN_PIN);
|
||||
power_manager_->PowerON();
|
||||
}
|
||||
|
||||
void InitializePowerSaveTimer() {
|
||||
power_save_timer_ = new PowerSaveTimer(-1, 60, 300);
|
||||
power_save_timer_->OnEnterSleepMode([this]() {
|
||||
auto display = GetDisplay();
|
||||
display->SetChatMessage("system", "");
|
||||
display->SetEmotion("sleepy");
|
||||
GetBacklight()->SetBrightness(20);
|
||||
});
|
||||
power_save_timer_->OnExitSleepMode([this]() {
|
||||
auto display = GetDisplay();
|
||||
display->SetChatMessage("system", "");
|
||||
display->SetEmotion("neutral");
|
||||
GetBacklight()->RestoreBrightness();
|
||||
});
|
||||
power_save_timer_->OnShutdownRequest([this]() {
|
||||
power_manager_->PowerOff();
|
||||
});
|
||||
power_save_timer_->SetEnabled(true);
|
||||
}
|
||||
|
||||
void InitializeI2c() {
|
||||
// Initialize I2C peripheral
|
||||
i2c_master_bus_config_t i2c_bus_cfg = {
|
||||
.i2c_port = (i2c_port_t)0,
|
||||
.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_));
|
||||
}
|
||||
|
||||
void InitializeSpi() {
|
||||
ESP_LOGI(TAG, "Initialize QSPI bus");
|
||||
spi_bus_config_t buscfg = {};
|
||||
buscfg.mosi_io_num = DISPLAY_MOSI_PIN;
|
||||
buscfg.miso_io_num = DISPLAY_MISO_PIN;
|
||||
buscfg.sclk_io_num = DISPLAY_CLK_PIN;
|
||||
buscfg.quadwp_io_num = GPIO_NUM_NC;
|
||||
buscfg.quadhd_io_num = GPIO_NUM_NC;
|
||||
buscfg.max_transfer_sz = DISPLAY_WIDTH * DISPLAY_HEIGHT * sizeof(uint16_t);
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(SPI3_HOST, &buscfg, SPI_DMA_CH_AUTO));
|
||||
}
|
||||
|
||||
void InitializeTouch()
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
esp_lcd_touch_handle_t touch_handle;
|
||||
|
||||
esp_lcd_panel_io_handle_t tp_io_handle = NULL;
|
||||
|
||||
esp_lcd_panel_io_i2c_config_t tp_io_config = {
|
||||
.dev_addr = ESP_LCD_TOUCH_IO_I2C_CST816S_ADDRESS,
|
||||
.on_color_trans_done = 0,
|
||||
.user_ctx = 0,
|
||||
.control_phase_bytes = 1,
|
||||
.dc_bit_offset = 0,
|
||||
.lcd_cmd_bits = 8,
|
||||
.lcd_param_bits = 0,
|
||||
.flags =
|
||||
{
|
||||
.dc_low_on_data = 0,
|
||||
.disable_control_phase = 1,
|
||||
},
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_i2c(i2c_bus_, &tp_io_config, &tp_io_handle));
|
||||
|
||||
esp_lcd_touch_config_t tp_cfg = {
|
||||
.x_max = DISPLAY_WIDTH,
|
||||
.y_max = DISPLAY_HEIGHT,
|
||||
.rst_gpio_num = TOOUCH_RST_PIN,
|
||||
.int_gpio_num = TOOUCH_INT_PIN,
|
||||
.flags = {
|
||||
.swap_xy = 0,
|
||||
.mirror_x = 0,
|
||||
.mirror_y = 0,
|
||||
},
|
||||
};
|
||||
ESP_LOGI(TAG, "Initialize touch controller CST816");
|
||||
ret = esp_lcd_touch_new_i2c_cst816s(tp_io_handle, &tp_cfg, &touch_handle);
|
||||
if (ret == ESP_OK)
|
||||
{
|
||||
const lvgl_port_touch_cfg_t touch_cfg = {
|
||||
.disp = lv_display_get_default(),
|
||||
.handle = touch_handle,
|
||||
};
|
||||
lvgl_port_add_touch(&touch_cfg);
|
||||
ESP_LOGI(TAG, "Touch panel initialized successfully");
|
||||
}
|
||||
}
|
||||
|
||||
void InitializeLcdDisplay() {
|
||||
esp_lcd_panel_io_handle_t panel_io = nullptr;
|
||||
esp_lcd_panel_handle_t panel = nullptr;
|
||||
// 液晶屏控制IO初始化
|
||||
ESP_LOGI(TAG, "Install panel IO");
|
||||
esp_lcd_panel_io_spi_config_t io_config = {};
|
||||
io_config.cs_gpio_num = DISPLAY_CS_PIN;
|
||||
io_config.dc_gpio_num = DISPLAY_DC_PIN;
|
||||
io_config.spi_mode = DISPLAY_SPI_MODE;
|
||||
io_config.pclk_hz = 40 * 1000 * 1000;
|
||||
io_config.trans_queue_depth = 10;
|
||||
io_config.lcd_cmd_bits = 8;
|
||||
io_config.lcd_param_bits = 8;
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi(SPI3_HOST, &io_config, &panel_io));
|
||||
|
||||
|
||||
// 初始化液晶屏驱动芯片
|
||||
ESP_LOGI(TAG, "Install LCD driver");
|
||||
esp_lcd_panel_dev_config_t panel_config = {};
|
||||
panel_config.reset_gpio_num = DISPLAY_RST_PIN;
|
||||
panel_config.rgb_ele_order = DISPLAY_RGB_ORDER;
|
||||
panel_config.bits_per_pixel = 16;
|
||||
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_st7789(panel_io, &panel_config, &panel));
|
||||
|
||||
|
||||
esp_lcd_panel_reset(panel);
|
||||
|
||||
esp_lcd_panel_init(panel);
|
||||
esp_lcd_panel_invert_color(panel, DISPLAY_INVERT_COLOR);
|
||||
esp_lcd_panel_swap_xy(panel, DISPLAY_SWAP_XY);
|
||||
esp_lcd_panel_mirror(panel, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y);
|
||||
|
||||
|
||||
display_ = new SpiLcdDisplay(panel_io, panel,
|
||||
DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY
|
||||
);
|
||||
}
|
||||
|
||||
void InitializeButtons() {
|
||||
|
||||
pwr_button_.OnPressUp([this]() {
|
||||
pwr_button_.OnClick([this]() {
|
||||
auto& app = Application::GetInstance();
|
||||
app.ToggleChatState();
|
||||
});
|
||||
pwr_button_.OnLongPress([this]() {
|
||||
printf("Power button long press\n");
|
||||
// gpio_set_level(BATTERY_EN_PIN, 0);
|
||||
if (power_manager_ != nullptr){
|
||||
power_manager_->PowerOff();
|
||||
}
|
||||
});
|
||||
|
||||
pwr_button_.OnDoubleClick([this]() {
|
||||
static uint8_t brightness_last = 0;
|
||||
auto backlight = Board::GetInstance().GetBacklight();
|
||||
if (backlight->brightness() == 0) {
|
||||
brightness_last = 0;
|
||||
if (brightness_last == 0) {
|
||||
backlight->SetBrightness(50, true);
|
||||
} else {
|
||||
backlight->SetBrightness(brightness_last, true);
|
||||
}
|
||||
} else {
|
||||
brightness_last = backlight->brightness();
|
||||
backlight->SetBrightness(0);
|
||||
}
|
||||
});
|
||||
pwr_button_.OnMultipleClick([this]() {
|
||||
EnterWifiConfigMode();
|
||||
}, 3);
|
||||
pwr_button_.OnPressUpDel();
|
||||
});
|
||||
|
||||
volume_up_button_.OnClick([this]() {
|
||||
auto codec = Board::GetInstance().GetAudioCodec();
|
||||
auto volume = codec->output_volume() + 10;
|
||||
if (volume > 100) {
|
||||
volume = 100;
|
||||
}
|
||||
codec->SetOutputVolume(volume);
|
||||
GetDisplay()->ShowNotification(Lang::Strings::VOLUME + std::to_string(volume/10));
|
||||
});
|
||||
|
||||
volume_up_button_.OnLongPress([this]() {
|
||||
Board::GetInstance().GetAudioCodec()->SetOutputVolume(100);
|
||||
GetDisplay()->ShowNotification(Lang::Strings::MAX_VOLUME);
|
||||
});
|
||||
|
||||
volume_down_button_.OnClick([this]() {
|
||||
auto codec = Board::GetInstance().GetAudioCodec();
|
||||
auto volume = codec->output_volume() - 10;
|
||||
if (volume < 0) {
|
||||
volume = 0;
|
||||
}
|
||||
codec->SetOutputVolume(volume);
|
||||
GetDisplay()->ShowNotification(Lang::Strings::VOLUME + std::to_string(volume/10));
|
||||
});
|
||||
|
||||
volume_down_button_.OnLongPress([this]() {
|
||||
Board::GetInstance().GetAudioCodec()->SetOutputVolume(0);
|
||||
GetDisplay()->ShowNotification(Lang::Strings::MUTED);
|
||||
});
|
||||
|
||||
#if CONFIG_USE_DEVICE_AEC
|
||||
volume_down_button_.OnDoubleClick([this]() {
|
||||
auto& app = Application::GetInstance();
|
||||
if (app.GetDeviceState() == kDeviceStateIdle) {
|
||||
app.SetAecMode(app.GetAecMode() == kAecOff ? kAecOnDeviceSide : kAecOff);
|
||||
}
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
// 初始化工具
|
||||
void InitializeTools() {
|
||||
auto &mcp_server = McpServer::GetInstance();
|
||||
mcp_server.AddTool("self.system.reconfigure_wifi",
|
||||
"Reboot the device and enter WiFi configuration mode.\n"
|
||||
"**CAUTION** You must ask the user to confirm this action.",
|
||||
PropertyList(), [this](const PropertyList& properties) {
|
||||
EnterWifiConfigMode();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
public:
|
||||
CustomBoard() :
|
||||
pwr_button_(PWR_BUTTON_GPIO),
|
||||
volume_up_button_(VOLUME_UP_BUTTON_GPIO),
|
||||
volume_down_button_(VOLUME_DOWN_BUTTON_GPIO) {
|
||||
InitializePowerManager();
|
||||
InitializePowerSaveTimer();
|
||||
InitializeI2c();
|
||||
InitializeSpi();
|
||||
InitializeLcdDisplay();
|
||||
InitializeTouch();
|
||||
InitializeButtons();
|
||||
InitializeTools();
|
||||
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,
|
||||
true);
|
||||
return &audio_codec;
|
||||
}
|
||||
|
||||
virtual Display* GetDisplay() override {
|
||||
return display_;
|
||||
}
|
||||
|
||||
virtual Backlight* GetBacklight() override {
|
||||
static PwmBacklight backlight(DISPLAY_BACKLIGHT_PIN, DISPLAY_BACKLIGHT_OUTPUT_INVERT);
|
||||
return &backlight;
|
||||
}
|
||||
|
||||
virtual bool GetBatteryLevel(int &level, bool& charging, bool& discharging) override {
|
||||
static bool last_discharging = false;
|
||||
charging = power_manager_->IsCharging();
|
||||
discharging = power_manager_->IsDischarging();
|
||||
if (discharging != last_discharging) {
|
||||
power_save_timer_->SetEnabled(discharging);
|
||||
last_discharging = discharging;
|
||||
}
|
||||
|
||||
level = power_manager_->GetBatteryLevel();
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void SetPowerSaveLevel(PowerSaveLevel level) override {
|
||||
if (level != PowerSaveLevel::LOW_POWER) {
|
||||
power_save_timer_->WakeUp();
|
||||
}
|
||||
WifiBoard::SetPowerSaveLevel(level);
|
||||
}
|
||||
};
|
||||
|
||||
DECLARE_BOARD(CustomBoard);
|
||||
@@ -0,0 +1,212 @@
|
||||
#pragma once
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include <esp_log.h>
|
||||
|
||||
#include <esp_timer.h>
|
||||
#include <driver/gpio.h>
|
||||
#include "esp_adc/adc_oneshot.h"
|
||||
#include "esp_adc/adc_cali.h"
|
||||
#include "esp_adc/adc_cali_scheme.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
class PowerManager
|
||||
{
|
||||
private:
|
||||
gpio_num_t charging_pin_ = GPIO_NUM_NC;
|
||||
gpio_num_t bat_adc_pin_ = GPIO_NUM_NC;
|
||||
gpio_num_t bat_power_pin_ = GPIO_NUM_NC;
|
||||
adc_oneshot_unit_handle_t adc_handle_ = NULL;
|
||||
adc_cali_handle_t adc_cali_handle_ = NULL;
|
||||
adc_channel_t adc_channel_;
|
||||
bool do_calibration = false;
|
||||
bool adc_calibration_init(adc_unit_t unit, adc_channel_t channel, adc_atten_t atten, adc_cali_handle_t *out_handle)
|
||||
{
|
||||
adc_cali_handle_t handle = NULL;
|
||||
esp_err_t ret = ESP_FAIL;
|
||||
bool calibrated = false;
|
||||
|
||||
if (!calibrated)
|
||||
{
|
||||
ESP_LOGI("power_manager", "calibration scheme version is %s", "Curve Fitting");
|
||||
adc_cali_curve_fitting_config_t cali_config = {
|
||||
.unit_id = unit,
|
||||
.chan = channel,
|
||||
.atten = atten,
|
||||
.bitwidth = ADC_BITWIDTH_DEFAULT,
|
||||
};
|
||||
ret = adc_cali_create_scheme_curve_fitting(&cali_config, &handle);
|
||||
if (ret == ESP_OK)
|
||||
{
|
||||
calibrated = true;
|
||||
}
|
||||
}
|
||||
|
||||
*out_handle = handle;
|
||||
if (ret == ESP_OK)
|
||||
{
|
||||
ESP_LOGI("power_manager", "Calibration Success");
|
||||
}
|
||||
else if (ret == ESP_ERR_NOT_SUPPORTED || !calibrated)
|
||||
{
|
||||
ESP_LOGW("power_manager", "eFuse not burnt, skip software calibration");
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGE("power_manager", "Invalid arg or no memory");
|
||||
}
|
||||
return calibrated;
|
||||
}
|
||||
|
||||
public:
|
||||
PowerManager(gpio_num_t charging_pin, gpio_num_t bat_adc_pin, gpio_num_t bat_power_pin) : charging_pin_(charging_pin),
|
||||
bat_adc_pin_(bat_adc_pin),
|
||||
bat_power_pin_(bat_power_pin)
|
||||
{
|
||||
// 初始化充电引脚
|
||||
if (charging_pin_ != GPIO_NUM_NC)
|
||||
{
|
||||
gpio_config_t io_conf = {};
|
||||
io_conf.intr_type = GPIO_INTR_DISABLE;
|
||||
io_conf.mode = GPIO_MODE_INPUT;
|
||||
io_conf.pin_bit_mask = 1ULL << charging_pin_;
|
||||
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||
io_conf.pull_up_en = GPIO_PULLUP_ENABLE;
|
||||
gpio_config(&io_conf);
|
||||
}
|
||||
// 初始化电池使能引脚
|
||||
if (bat_power_pin_ != GPIO_NUM_NC)
|
||||
{
|
||||
gpio_config_t io_conf = {};
|
||||
io_conf.intr_type = GPIO_INTR_DISABLE;
|
||||
io_conf.mode = GPIO_MODE_OUTPUT;
|
||||
io_conf.pin_bit_mask = 1ULL << bat_power_pin_;
|
||||
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||
io_conf.pull_up_en = GPIO_PULLUP_DISABLE;
|
||||
gpio_config(&io_conf);
|
||||
}
|
||||
|
||||
// 初始化adc
|
||||
if (bat_adc_pin_ != GPIO_NUM_NC)
|
||||
{
|
||||
adc_oneshot_unit_init_cfg_t init_config = {};
|
||||
init_config.ulp_mode = ADC_ULP_MODE_DISABLE;
|
||||
if (bat_adc_pin_ >= GPIO_NUM_1 && bat_adc_pin_ <= GPIO_NUM_10)
|
||||
{
|
||||
init_config.unit_id = ADC_UNIT_1;
|
||||
adc_channel_ = (adc_channel_t)((int)bat_adc_pin_ - 1);
|
||||
}
|
||||
else if (bat_adc_pin_ >= GPIO_NUM_11 && bat_adc_pin_ <= GPIO_NUM_20)
|
||||
{
|
||||
init_config.unit_id = ADC_UNIT_2;
|
||||
adc_channel_ = (adc_channel_t)((int)bat_adc_pin_ - 11);
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
ESP_ERROR_CHECK(adc_oneshot_new_unit(&init_config, &adc_handle_));
|
||||
adc_oneshot_chan_cfg_t config = {};
|
||||
config.bitwidth = ADC_BITWIDTH_DEFAULT;
|
||||
config.atten = ADC_ATTEN_DB_12;
|
||||
ESP_ERROR_CHECK(adc_oneshot_config_channel(adc_handle_, adc_channel_, &config));
|
||||
do_calibration = adc_calibration_init(init_config.unit_id, adc_channel_, config.atten, &adc_cali_handle_);
|
||||
}
|
||||
}
|
||||
|
||||
~PowerManager()
|
||||
{
|
||||
if (adc_handle_)
|
||||
{
|
||||
ESP_ERROR_CHECK(adc_oneshot_del_unit(adc_handle_));
|
||||
}
|
||||
// if (adc_cali_handle_)
|
||||
// {
|
||||
// ESP_ERROR_CHECK(adc_cali_delete_scheme_line_fitting(adc_cali_handle_));
|
||||
// }
|
||||
}
|
||||
|
||||
int GetBatteryLevel(void)
|
||||
{
|
||||
|
||||
int adc_raw = 0;
|
||||
int voltage_int = 0;
|
||||
const float voltage_float_threshold = 0.1f;
|
||||
float voltage_float = 0.0f;
|
||||
static float last_voltage_float = 0.0f;
|
||||
|
||||
static int last_battery_level = 0;
|
||||
|
||||
if (adc_handle_ != nullptr)
|
||||
{
|
||||
ESP_ERROR_CHECK(adc_oneshot_read(adc_handle_, adc_channel_, &adc_raw));
|
||||
if (do_calibration)
|
||||
{
|
||||
ESP_ERROR_CHECK(adc_cali_raw_to_voltage(adc_cali_handle_, adc_raw, &voltage_int));
|
||||
voltage_float = (voltage_int / 1000.0f) * 3.0;
|
||||
|
||||
if (fabs(voltage_float - last_voltage_float) >= voltage_float_threshold)
|
||||
{
|
||||
last_voltage_float = voltage_float;
|
||||
if (voltage_float < 3.52) {
|
||||
last_battery_level = 1;
|
||||
} else if (voltage_float < 3.64) {
|
||||
last_battery_level = 20;
|
||||
} else if (voltage_float < 3.76) {
|
||||
last_battery_level = 40;
|
||||
} else if (voltage_float < 3.88) {
|
||||
last_battery_level = 60;
|
||||
} else if (voltage_float < 4.0) {
|
||||
last_battery_level = 80;
|
||||
} else {
|
||||
last_battery_level = 100;
|
||||
}
|
||||
}
|
||||
return last_battery_level;
|
||||
}
|
||||
}
|
||||
return 100;
|
||||
}
|
||||
|
||||
bool IsCharging(void)
|
||||
{
|
||||
if (charging_pin_ != GPIO_NUM_NC)
|
||||
{
|
||||
return gpio_get_level(charging_pin_) == 0 ? true : false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsDischarging(void)
|
||||
{
|
||||
if (charging_pin_ != GPIO_NUM_NC)
|
||||
{
|
||||
return gpio_get_level(charging_pin_) == 1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IsChargingDone(void)
|
||||
{
|
||||
if (GetBatteryLevel() == 100)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void PowerOff(void)
|
||||
{
|
||||
if (bat_power_pin_ != GPIO_NUM_NC)
|
||||
{
|
||||
gpio_set_level(bat_power_pin_, 0);
|
||||
}
|
||||
}
|
||||
void PowerON(void)
|
||||
{
|
||||
if (bat_power_pin_ != GPIO_NUM_NC)
|
||||
{
|
||||
gpio_set_level(bat_power_pin_, 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -172,7 +172,20 @@ private:
|
||||
},
|
||||
};
|
||||
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_CST816S_CONFIG();
|
||||
esp_lcd_panel_io_i2c_config_t tp_io_config = {
|
||||
.dev_addr = ESP_LCD_TOUCH_IO_I2C_CST816S_ADDRESS,
|
||||
.on_color_trans_done = 0,
|
||||
.user_ctx = 0,
|
||||
.control_phase_bytes = 1,
|
||||
.dc_bit_offset = 0,
|
||||
.lcd_cmd_bits = 8,
|
||||
.lcd_param_bits = 0,
|
||||
.flags =
|
||||
{
|
||||
.dc_low_on_data = 0,
|
||||
.disable_control_phase = 1,
|
||||
},
|
||||
};
|
||||
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");
|
||||
|
||||
@@ -232,7 +232,16 @@ private:
|
||||
},
|
||||
};
|
||||
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_FT5x06_CONFIG();
|
||||
esp_lcd_panel_io_i2c_config_t tp_io_config = {
|
||||
.dev_addr = ESP_LCD_TOUCH_IO_I2C_FT5x06_ADDRESS,
|
||||
.control_phase_bytes = 1,
|
||||
.dc_bit_offset = 0,
|
||||
.lcd_cmd_bits = 8,
|
||||
.flags =
|
||||
{
|
||||
.disable_control_phase = 1,
|
||||
}
|
||||
};
|
||||
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");
|
||||
|
||||
@@ -168,7 +168,16 @@ private:
|
||||
},
|
||||
};
|
||||
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();
|
||||
esp_lcd_panel_io_i2c_config_t tp_io_config = {
|
||||
.dev_addr = ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS,
|
||||
.control_phase_bytes = 1,
|
||||
.dc_bit_offset = 0,
|
||||
.lcd_cmd_bits = 16,
|
||||
.flags =
|
||||
{
|
||||
.disable_control_phase = 1,
|
||||
}
|
||||
};
|
||||
tp_io_config.scl_speed_hz = 400 * 1000;
|
||||
|
||||
esp_lcd_new_panel_io_i2c(i2c_bus_, &tp_io_config, &tp_io_handle);
|
||||
|
||||
@@ -276,7 +276,16 @@ private:
|
||||
},
|
||||
};
|
||||
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();
|
||||
esp_lcd_panel_io_i2c_config_t tp_io_config = {
|
||||
.dev_addr = ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS,
|
||||
.control_phase_bytes = 1,
|
||||
.dc_bit_offset = 0,
|
||||
.lcd_cmd_bits = 16,
|
||||
.flags =
|
||||
{
|
||||
.disable_control_phase = 1,
|
||||
}
|
||||
};
|
||||
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");
|
||||
|
||||
@@ -190,7 +190,16 @@ private:
|
||||
},
|
||||
};
|
||||
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_FT5x06_CONFIG();
|
||||
esp_lcd_panel_io_i2c_config_t tp_io_config = {
|
||||
.dev_addr = ESP_LCD_TOUCH_IO_I2C_FT5x06_ADDRESS,
|
||||
.control_phase_bytes = 1,
|
||||
.dc_bit_offset = 0,
|
||||
.lcd_cmd_bits = 8,
|
||||
.flags =
|
||||
{
|
||||
.disable_control_phase = 1,
|
||||
}
|
||||
};
|
||||
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");
|
||||
|
||||
@@ -152,7 +152,16 @@ private:
|
||||
},
|
||||
};
|
||||
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();
|
||||
esp_lcd_panel_io_i2c_config_t tp_io_config = {
|
||||
.dev_addr = ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS,
|
||||
.control_phase_bytes = 1,
|
||||
.dc_bit_offset = 0,
|
||||
.lcd_cmd_bits = 16,
|
||||
.flags =
|
||||
{
|
||||
.disable_control_phase = 1,
|
||||
}
|
||||
};
|
||||
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");
|
||||
|
||||
+10
-12
@@ -1075,18 +1075,6 @@ void LcdDisplay::SetEmotion(const char* emotion) {
|
||||
if (!setup_ui_called_) {
|
||||
ESP_LOGW(TAG, "SetEmotion('%s') called before SetupUI() - emotion will not be displayed!", emotion);
|
||||
}
|
||||
// Stop any running GIF animation
|
||||
if (gif_controller_) {
|
||||
DisplayLockGuard lock(this);
|
||||
gif_controller_->Stop();
|
||||
// Hide image before destroying GIF controller to prevent LVGL from
|
||||
// accessing freed image data during rendering between lock scopes
|
||||
if (emoji_image_) {
|
||||
lv_obj_add_flag(emoji_image_, LV_OBJ_FLAG_HIDDEN);
|
||||
}
|
||||
gif_controller_.reset();
|
||||
}
|
||||
|
||||
if (emoji_image_ == nullptr) {
|
||||
if (setup_ui_called_) {
|
||||
ESP_LOGW(TAG, "SetEmotion('%s') failed: emoji_image_ is nullptr (SetupUI() was called but emoji image not created)", emotion);
|
||||
@@ -1100,6 +1088,10 @@ void LcdDisplay::SetEmotion(const char* emotion) {
|
||||
const char* utf8 = font_awesome_get_utf8(emotion);
|
||||
if (utf8 != nullptr && emoji_label_ != nullptr) {
|
||||
DisplayLockGuard lock(this);
|
||||
if (gif_controller_) {
|
||||
gif_controller_->Stop();
|
||||
gif_controller_.reset();
|
||||
}
|
||||
lv_label_set_text(emoji_label_, utf8);
|
||||
lv_obj_add_flag(emoji_image_, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_remove_flag(emoji_label_, LV_OBJ_FLAG_HIDDEN);
|
||||
@@ -1108,6 +1100,12 @@ void LcdDisplay::SetEmotion(const char* emotion) {
|
||||
}
|
||||
|
||||
DisplayLockGuard lock(this);
|
||||
// Stop any running GIF animation in the same lock scope as setting new image
|
||||
// to prevent LVGL from accessing freed image data between operations
|
||||
if (gif_controller_) {
|
||||
gif_controller_->Stop();
|
||||
gif_controller_.reset();
|
||||
}
|
||||
if (image->IsGif()) {
|
||||
// Create new GIF controller
|
||||
gif_controller_ = std::make_unique<LvglGif>(image->image_dsc());
|
||||
|
||||
+11
-12
@@ -20,22 +20,22 @@ dependencies:
|
||||
waveshare/custom_io_expander_ch32v003: ^1.0.0
|
||||
espressif/esp_lcd_panel_io_additions: ^1.0.1
|
||||
78/esp_lcd_nv3023: ~1.0.0
|
||||
78/esp-wifi-connect: ~3.1.1
|
||||
78/esp-wifi-connect: ~3.1.2
|
||||
espressif/esp_audio_effects: ~1.2.1
|
||||
espressif/esp_audio_codec: ~2.4.1
|
||||
78/esp-ml307: ~3.6.4
|
||||
78/esp-ml307: ~3.6.5
|
||||
78/uart-eth-modem:
|
||||
version: ~0.3.3
|
||||
version: ~0.3.4
|
||||
rules:
|
||||
- if: target not in [esp32]
|
||||
78/xiaozhi-fonts: ~1.6.0
|
||||
espressif/led_strip: ~3.0.2
|
||||
espressif/esp_codec_dev: ~1.5.4
|
||||
espressif/esp_codec_dev: ~1.5.6
|
||||
espressif/esp-sr: ~2.3.0
|
||||
espressif/button: ~4.1.5
|
||||
espressif/knob: ^1.0.0
|
||||
espressif/esp32-camera:
|
||||
version: ^2.1.4
|
||||
version: ^2.1.5
|
||||
rules:
|
||||
- if: target in [esp32s3]
|
||||
espressif/esp_video:
|
||||
@@ -47,23 +47,22 @@ dependencies:
|
||||
version: ^1.0.1
|
||||
rules:
|
||||
- if: target not in [esp32]
|
||||
espressif/esp_lcd_touch_ft5x06: ~1.0.7
|
||||
espressif/esp_lcd_touch_ft5x06: ~1
|
||||
espressif/esp_lcd_touch_gt911: ^1
|
||||
espressif/esp_lcd_touch_gt1151: ^1
|
||||
waveshare/esp_lcd_touch_cst9217: ^1.0.3
|
||||
espressif/esp_lcd_touch_cst816s: ^1.0.6
|
||||
lvgl/lvgl: ~9.4.0
|
||||
esp_lvgl_port: ~2.7.0
|
||||
espressif/esp_lcd_touch_cst816s: ^1
|
||||
lvgl/lvgl: ~9.5.0
|
||||
esp_lvgl_port: ~2.7.2
|
||||
espressif/esp_io_expander_tca95xx_16bit: ^2.0.0
|
||||
espressif2022/image_player: ^1.1.1
|
||||
espressif2022/esp_emote_expression: ^0.1.0
|
||||
espressif/adc_mic: ^0.2.1
|
||||
espressif/esp_mmap_assets: '>=1.2'
|
||||
espressif/esp_mmap_assets: ^1.3.2
|
||||
txp666/otto-emoji-gif-component:
|
||||
version: ^1.1.1
|
||||
rules:
|
||||
- if: target in [esp32s3]
|
||||
espressif/adc_battery_estimation: ^0.2.0
|
||||
espressif/adc_battery_estimation: ^0.2.1
|
||||
espressif/esp_new_jpeg: ^0.6.1
|
||||
|
||||
# SenseCAP Watcher Board
|
||||
|
||||
@@ -12,8 +12,10 @@
|
||||
|
||||
|
||||
SingleLed::SingleLed(gpio_num_t gpio) {
|
||||
// If the gpio is not connected, you should use NoLed class
|
||||
assert(gpio != GPIO_NUM_NC);
|
||||
if (gpio == GPIO_NUM_NC) {
|
||||
ESP_LOGW(TAG, "SingleLed initialized with GPIO_NUM_NC, LED will not function");
|
||||
return;
|
||||
}
|
||||
|
||||
led_strip_config_t strip_config = {};
|
||||
strip_config.strip_gpio_num = gpio;
|
||||
@@ -41,7 +43,9 @@ SingleLed::SingleLed(gpio_num_t gpio) {
|
||||
}
|
||||
|
||||
SingleLed::~SingleLed() {
|
||||
esp_timer_stop(blink_timer_);
|
||||
if (blink_timer_ != nullptr) {
|
||||
esp_timer_stop(blink_timer_);
|
||||
}
|
||||
if (led_strip_ != nullptr) {
|
||||
led_strip_del(led_strip_);
|
||||
}
|
||||
|
||||
@@ -147,7 +147,7 @@ bool WebsocketProtocol::OpenAudioChannel() {
|
||||
}
|
||||
} else {
|
||||
// Parse JSON data
|
||||
auto root = cJSON_Parse(data);
|
||||
auto root = cJSON_ParseWithLength(data, len);
|
||||
auto type = cJSON_GetObjectItem(root, "type");
|
||||
if (cJSON_IsString(type)) {
|
||||
if (strcmp(type->valuestring, "hello") == 0) {
|
||||
@@ -158,7 +158,7 @@ bool WebsocketProtocol::OpenAudioChannel() {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Missing message type, data: %s", data);
|
||||
ESP_LOGE(TAG, "Missing message type, data: %s", std::string(data, len).c_str());
|
||||
}
|
||||
cJSON_Delete(root);
|
||||
}
|
||||
|
||||
@@ -3,5 +3,5 @@
|
||||
nvs, data, nvs, 0x9000, 0x4000,
|
||||
otadata, data, ota, 0xd000, 0x2000,
|
||||
phy_init, data, phy, 0xf000, 0x1000,
|
||||
factory, app, factory, 0x10000, 0x2CE000,
|
||||
assets, data, spiffs, 0x2DE000, 0x122000,
|
||||
factory, app, factory, 0x10000, 0x2F0000,
|
||||
assets, data, spiffs, 0x300000, 0x100000,
|
||||
|
+110
-13
@@ -3,6 +3,7 @@ import os
|
||||
import json
|
||||
import zipfile
|
||||
import argparse
|
||||
import re
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
@@ -139,26 +140,113 @@ def _collect_variants(config_filename: str = "config.json") -> list[dict[str, st
|
||||
|
||||
|
||||
|
||||
def _find_board_config(board_type: str) -> Optional[str]:
|
||||
"""Find the corresponding CONFIG_BOARD_TYPE_xxx for the given board_type
|
||||
|
||||
Search backwards from 'set(BOARD_TYPE "xxx")' to find the nearest if(CONFIG_BOARD_TYPE_).
|
||||
"""
|
||||
def _find_board_config_candidates(board_type: str) -> list[str]:
|
||||
"""Find all CONFIG_BOARD_TYPE_xxx candidates for the given board_type."""
|
||||
board_leaf = board_type.split("/")[-1]
|
||||
pattern = f'set(BOARD_TYPE "{board_leaf}")'
|
||||
|
||||
|
||||
cmake_file = Path("main/CMakeLists.txt")
|
||||
lines = cmake_file.read_text(encoding="utf-8").splitlines()
|
||||
|
||||
candidates: list[str] = []
|
||||
|
||||
for idx, line in enumerate(lines):
|
||||
if pattern in line:
|
||||
# Found the BOARD_TYPE line, search backwards for the config
|
||||
# Found the BOARD_TYPE line, search backwards for the nearest config guard
|
||||
for back_idx in range(idx - 1, -1, -1):
|
||||
back_line = lines[back_idx]
|
||||
if "if(CONFIG_BOARD_TYPE_" in back_line:
|
||||
return back_line.strip().split("if(")[1].split(")")[0]
|
||||
candidates.append(back_line.strip().split("if(")[1].split(")")[0])
|
||||
break
|
||||
return candidates
|
||||
|
||||
|
||||
def _extract_board_config_from_sdkconfig_append(sdkconfig_append: list[str]) -> Optional[str]:
|
||||
"""Extract explicit CONFIG_BOARD_TYPE_xxx=y from sdkconfig_append, if present."""
|
||||
pattern = re.compile(r"^(CONFIG_BOARD_TYPE_[A-Z0-9_]+)=y$")
|
||||
matches = []
|
||||
for item in sdkconfig_append:
|
||||
m = pattern.match(item.strip())
|
||||
if m:
|
||||
matches.append(m.group(1))
|
||||
if not matches:
|
||||
return None
|
||||
uniq = list(dict.fromkeys(matches))
|
||||
if len(uniq) > 1:
|
||||
raise ValueError(f"Multiple board type configs found in sdkconfig_append: {uniq}")
|
||||
return uniq[0]
|
||||
|
||||
|
||||
def _symbol_supports_target(symbol: str, target: str) -> bool:
|
||||
"""Check whether Kconfig symbol depends on given target (e.g. esp32c5)."""
|
||||
kconfig_file = Path("main/Kconfig.projbuild")
|
||||
if not kconfig_file.exists():
|
||||
return False
|
||||
|
||||
target_flag = f"IDF_TARGET_{target.upper()}"
|
||||
lines = kconfig_file.read_text(encoding="utf-8").splitlines()
|
||||
|
||||
in_symbol = False
|
||||
for line in lines:
|
||||
stripped = line.strip()
|
||||
if stripped.startswith("config "):
|
||||
curr_symbol = stripped.split("config ", 1)[1].strip()
|
||||
in_symbol = curr_symbol == symbol
|
||||
continue
|
||||
if in_symbol and stripped.startswith(("config ", "choice ", "endchoice", "menu ", "endmenu")):
|
||||
break
|
||||
return None
|
||||
if in_symbol and "depends on" in stripped and target_flag in stripped:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def _resolve_board_config(board_type: str, target: str, sdkconfig_append: list[str]) -> str:
|
||||
"""Resolve CONFIG_BOARD_TYPE_xxx for current board build."""
|
||||
explicit = _extract_board_config_from_sdkconfig_append(sdkconfig_append)
|
||||
if explicit:
|
||||
return explicit
|
||||
|
||||
candidates = _find_board_config_candidates(board_type)
|
||||
if not candidates:
|
||||
raise ValueError(f"Cannot find board config symbol for {board_type}")
|
||||
if len(candidates) == 1:
|
||||
return candidates[0]
|
||||
|
||||
by_target = [c for c in candidates if _symbol_supports_target(c, target)]
|
||||
if len(by_target) == 1:
|
||||
return by_target[0]
|
||||
if len(by_target) > 1:
|
||||
selected = by_target[0]
|
||||
print(
|
||||
f"[WARN] Ambiguous board config for {board_type} (target={target}), "
|
||||
f"target-matched candidates={by_target}, selecting first: {selected}",
|
||||
file=sys.stderr,
|
||||
)
|
||||
return selected
|
||||
|
||||
target_u = target.upper()
|
||||
target_short = target_u.replace("ESP32", "")
|
||||
by_name = [
|
||||
c for c in candidates
|
||||
if target_u in c or f"_{target_short}" in c
|
||||
]
|
||||
if len(by_name) == 1:
|
||||
return by_name[0]
|
||||
if len(by_name) > 1:
|
||||
selected = by_name[0]
|
||||
print(
|
||||
f"[WARN] Ambiguous board config for {board_type} (target={target}), "
|
||||
f"name-matched candidates={by_name}, selecting first: {selected}",
|
||||
file=sys.stderr,
|
||||
)
|
||||
return selected
|
||||
|
||||
selected = candidates[0]
|
||||
print(
|
||||
f"[WARN] Ambiguous board config for {board_type} (target={target}), "
|
||||
f"candidates={candidates}, selecting first: {selected}",
|
||||
file=sys.stderr,
|
||||
)
|
||||
return selected
|
||||
|
||||
|
||||
# Kconfig "select" entries are not automatically applied when we simply append
|
||||
@@ -258,9 +346,18 @@ def release(board_type: str, config_filename: str = "config.json", *, filter_nam
|
||||
continue
|
||||
|
||||
# Process sdkconfig_append
|
||||
board_type_config = _find_board_config(board_type)
|
||||
sdkconfig_append = [f"{board_type_config}=y"]
|
||||
sdkconfig_append.extend(build.get("sdkconfig_append", []))
|
||||
build_sdkconfig_append = build.get("sdkconfig_append", [])
|
||||
explicit_board_cfg = _extract_board_config_from_sdkconfig_append(build_sdkconfig_append)
|
||||
if explicit_board_cfg:
|
||||
print(
|
||||
f"[INFO] Board config explicitly set in config.json: {explicit_board_cfg}, "
|
||||
"skip auto-select.",
|
||||
)
|
||||
sdkconfig_append = list(build_sdkconfig_append)
|
||||
else:
|
||||
board_type_config = _resolve_board_config(board_type, target, build_sdkconfig_append)
|
||||
sdkconfig_append = [f"{board_type_config}=y"]
|
||||
sdkconfig_append.extend(build_sdkconfig_append)
|
||||
sdkconfig_append = _apply_auto_selects(sdkconfig_append)
|
||||
|
||||
print("-" * 80)
|
||||
|
||||
Submodule
+1
Submodule xiaozhi-esp32 added at 8fde7f3c62
Reference in New Issue
Block a user