esp32-s3-touch-lcd-3.5.cc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  1. #include "wifi_board.h"
  2. #include "codecs/es8311_audio_codec.h"
  3. #include "display/lcd_display.h"
  4. #include "system_reset.h"
  5. #include "application.h"
  6. #include "button.h"
  7. #include "config.h"
  8. #include "mcp_server.h"
  9. #include <esp_log.h>
  10. #include "i2c_device.h"
  11. #include <driver/i2c_master.h>
  12. #include <driver/ledc.h>
  13. #include <wifi_station.h>
  14. #include <esp_lcd_panel_vendor.h>
  15. #include <esp_lcd_panel_io.h>
  16. #include <esp_lcd_panel_ops.h>
  17. #include <esp_timer.h>
  18. #include "esp_io_expander_tca9554.h"
  19. #include "axp2101.h"
  20. #include "power_save_timer.h"
  21. #include <esp_lcd_touch_ft5x06.h>
  22. #include <esp_lvgl_port.h>
  23. #include "esp32_camera.h"
  24. #define TAG "waveshare_lcd_3_5"
  25. LV_FONT_DECLARE(font_puhui_16_4);
  26. LV_FONT_DECLARE(font_awesome_16_4);
  27. class Pmic : public Axp2101 {
  28. public:
  29. Pmic(i2c_master_bus_handle_t i2c_bus, uint8_t addr) : Axp2101(i2c_bus, addr) {
  30. WriteReg(0x22, 0b110); // PWRON > OFFLEVEL as POWEROFF Source enable
  31. WriteReg(0x27, 0x10); // hold 4s to power off
  32. // Disable All DCs but DC1
  33. WriteReg(0x80, 0x01);
  34. // Disable All LDOs
  35. WriteReg(0x90, 0x00);
  36. WriteReg(0x91, 0x00);
  37. // Set DC1 to 3.3V
  38. WriteReg(0x82, (3300 - 1500) / 100);
  39. // Set ALDO1 to 3.3V
  40. WriteReg(0x92, (3300 - 500) / 100);
  41. WriteReg(0x96, (1500 - 500) / 100);
  42. WriteReg(0x97, (2800 - 500) / 100);
  43. // Enable ALDO1 BLDO1 BLDO2
  44. WriteReg(0x90, 0x31);
  45. WriteReg(0x64, 0x02); // CV charger voltage setting to 4.1V
  46. WriteReg(0x61, 0x02); // set Main battery precharge current to 50mA
  47. WriteReg(0x62, 0x08); // set Main battery charger current to 400mA ( 0x08-200mA, 0x09-300mA, 0x0A-400mA )
  48. WriteReg(0x63, 0x01); // set Main battery term charge current to 25mA
  49. }
  50. };
  51. typedef struct {
  52. int cmd; /*<! The specific LCD command */
  53. const void *data; /*<! Buffer that holds the command specific data */
  54. size_t data_bytes; /*<! Size of `data` in memory, in bytes */
  55. unsigned int delay_ms; /*<! Delay in milliseconds after this command */
  56. } st7796_lcd_init_cmd_t;
  57. typedef struct {
  58. const st7796_lcd_init_cmd_t *init_cmds; /*!< Pointer to initialization commands array. Set to NULL if using default commands.
  59. * The array should be declared as `static const` and positioned outside the function.
  60. * Please refer to `vendor_specific_init_default` in source file.
  61. */
  62. uint16_t init_cmds_size; /*<! Number of commands in above array */
  63. } st7796_vendor_config_t;
  64. st7796_lcd_init_cmd_t st7796_lcd_init_cmds[] = {
  65. {0x11, (uint8_t []){ 0x00 }, 0, 120},
  66. // {0x36, (uint8_t []){ 0x08 }, 1, 0},
  67. {0x3A, (uint8_t []){ 0x05 }, 1, 0},
  68. {0xF0, (uint8_t []){ 0xC3 }, 1, 0},
  69. {0xF0, (uint8_t []){ 0x96 }, 1, 0},
  70. {0xB4, (uint8_t []){ 0x01 }, 1, 0},
  71. {0xB7, (uint8_t []){ 0xC6 }, 1, 0},
  72. {0xC0, (uint8_t []){ 0x80, 0x45 }, 2, 0},
  73. {0xC1, (uint8_t []){ 0x13 }, 1, 0},
  74. {0xC2, (uint8_t []){ 0xA7 }, 1, 0},
  75. {0xC5, (uint8_t []){ 0x0A }, 1, 0},
  76. {0xE8, (uint8_t []){ 0x40, 0x8A, 0x00, 0x00, 0x29, 0x19, 0xA5, 0x33}, 8, 0},
  77. {0xE0, (uint8_t []){ 0xD0, 0x08, 0x0F, 0x06, 0x06, 0x33, 0x30, 0x33, 0x47, 0x17, 0x13, 0x13, 0x2B, 0x31}, 14, 0},
  78. {0xE1, (uint8_t []){ 0xD0, 0x0A, 0x11, 0x0B, 0x09, 0x07, 0x2F, 0x33, 0x47, 0x38, 0x15, 0x16, 0x2C, 0x32},14, 0},
  79. {0xF0, (uint8_t []){ 0x3C }, 1, 0},
  80. {0xF0, (uint8_t []){ 0x69 }, 1, 120},
  81. {0x21, (uint8_t []){ 0x00 }, 0, 0},
  82. {0x29, (uint8_t []){ 0x00 }, 0, 0},
  83. };
  84. class CustomBoard : public WifiBoard {
  85. private:
  86. Button boot_button_;
  87. Pmic* pmic_ = nullptr;
  88. i2c_master_bus_handle_t i2c_bus_;
  89. esp_io_expander_handle_t io_expander = NULL;
  90. LcdDisplay* display_;
  91. PowerSaveTimer* power_save_timer_;
  92. Esp32Camera* camera_;
  93. void InitializePowerSaveTimer() {
  94. power_save_timer_ = new PowerSaveTimer(-1, 60, 300);
  95. power_save_timer_->OnEnterSleepMode([this]() {
  96. ESP_LOGI(TAG, "Enabling sleep mode");
  97. auto display = GetDisplay();
  98. display->SetChatMessage("system", "");
  99. display->SetEmotion("sleepy");
  100. GetBacklight()->SetBrightness(20);
  101. });
  102. power_save_timer_->OnExitSleepMode([this]() {
  103. auto display = GetDisplay();
  104. display->SetChatMessage("system", "");
  105. display->SetEmotion("neutral");
  106. GetBacklight()->RestoreBrightness();
  107. });
  108. power_save_timer_->OnShutdownRequest([this]() {
  109. pmic_->PowerOff();
  110. });
  111. power_save_timer_->SetEnabled(true);
  112. }
  113. void InitializeI2c() {
  114. // Initialize I2C peripheral
  115. i2c_master_bus_config_t i2c_bus_cfg = {
  116. .i2c_port = (i2c_port_t)I2C_NUM_0,
  117. .sda_io_num = AUDIO_CODEC_I2C_SDA_PIN,
  118. .scl_io_num = AUDIO_CODEC_I2C_SCL_PIN,
  119. .clk_source = I2C_CLK_SRC_DEFAULT,
  120. .glitch_ignore_cnt = 7,
  121. .intr_priority = 0,
  122. .trans_queue_depth = 0,
  123. .flags = {
  124. .enable_internal_pullup = 1,
  125. },
  126. };
  127. ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_cfg, &i2c_bus_));
  128. }
  129. void InitializeTca9554(void)
  130. {
  131. esp_err_t ret = esp_io_expander_new_i2c_tca9554(i2c_bus_, ESP_IO_EXPANDER_I2C_TCA9554_ADDRESS_000, &io_expander);
  132. if(ret != ESP_OK)
  133. ESP_LOGE(TAG, "TCA9554 create returned error");
  134. ret = esp_io_expander_set_dir(io_expander, IO_EXPANDER_PIN_NUM_0 | IO_EXPANDER_PIN_NUM_1, IO_EXPANDER_OUTPUT);
  135. ESP_ERROR_CHECK(ret);
  136. vTaskDelay(pdMS_TO_TICKS(100));
  137. ret = esp_io_expander_set_level(io_expander, IO_EXPANDER_PIN_NUM_0 | IO_EXPANDER_PIN_NUM_1, 0);
  138. ESP_ERROR_CHECK(ret);
  139. vTaskDelay(pdMS_TO_TICKS(100));
  140. ret = esp_io_expander_set_level(io_expander, IO_EXPANDER_PIN_NUM_1, 1);
  141. ESP_ERROR_CHECK(ret);
  142. }
  143. void InitializeAxp2101() {
  144. ESP_LOGI(TAG, "Init AXP2101");
  145. pmic_ = new Pmic(i2c_bus_, 0x34);
  146. }
  147. void InitializeSpi() {
  148. ESP_LOGI(TAG, "Initialize QSPI bus");
  149. spi_bus_config_t buscfg = {};
  150. buscfg.mosi_io_num = DISPLAY_MOSI_PIN;
  151. buscfg.miso_io_num = DISPLAY_MISO_PIN;
  152. buscfg.sclk_io_num = DISPLAY_CLK_PIN;
  153. buscfg.quadwp_io_num = GPIO_NUM_NC;
  154. buscfg.quadhd_io_num = GPIO_NUM_NC;
  155. buscfg.max_transfer_sz = DISPLAY_WIDTH * DISPLAY_HEIGHT * sizeof(uint16_t);
  156. ESP_ERROR_CHECK(spi_bus_initialize(SPI3_HOST, &buscfg, SPI_DMA_CH_AUTO));
  157. }
  158. void InitializeCamera() {
  159. camera_config_t config = {};
  160. config.pin_pwdn = CAM_PIN_PWDN;
  161. config.pin_reset = CAM_PIN_RESET;
  162. config.pin_xclk = CAM_PIN_XCLK;
  163. config.pin_sccb_sda = CAM_PIN_SIOD;
  164. config.pin_sccb_scl = CAM_PIN_SIOC;
  165. config.sccb_i2c_port = I2C_NUM_0;
  166. config.pin_d7 = CAM_PIN_D7;
  167. config.pin_d6 = CAM_PIN_D6;
  168. config.pin_d5 = CAM_PIN_D5;
  169. config.pin_d4 = CAM_PIN_D4;
  170. config.pin_d3 = CAM_PIN_D3;
  171. config.pin_d2 = CAM_PIN_D2;
  172. config.pin_d1 = CAM_PIN_D1;
  173. config.pin_d0 = CAM_PIN_D0;
  174. config.pin_vsync = CAM_PIN_VSYNC;
  175. config.pin_href = CAM_PIN_HREF;
  176. config.pin_pclk = CAM_PIN_PCLK;
  177. /* XCLK 20MHz or 10MHz for OV2640 double FPS (Experimental) */
  178. config.xclk_freq_hz = 10000000;
  179. config.ledc_timer = LEDC_TIMER_1;
  180. config.ledc_channel = LEDC_CHANNEL_0;
  181. config.pixel_format = PIXFORMAT_RGB565; /* YUV422,GRAYSCALE,RGB565,JPEG */
  182. config.frame_size = FRAMESIZE_240X240; /* QQVGA-UXGA, For ESP32, do not use sizes above QVGA when not JPEG. The performance of the ESP32-S series has improved a lot, but JPEG mode always gives better frame rates */
  183. config.jpeg_quality = 12; /* 0-63, for OV series camera sensors, lower number means higher quality */
  184. config.fb_count = 2; /* When jpeg mode is used, if fb_count more than one, the driver will work in continuous mode */
  185. config.fb_location = CAMERA_FB_IN_PSRAM;
  186. config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
  187. esp_err_t err = esp_camera_init(&config); // 测试相机是否存在
  188. if (err != ESP_OK) {
  189. ESP_LOGE(TAG, "Camera is not plugged in or not supported, error: %s", esp_err_to_name(err));
  190. // 如果摄像头初始化失败,设置 camera_ 为 nullptr
  191. camera_ = nullptr;
  192. return;
  193. }else
  194. {
  195. esp_camera_deinit();// 释放之前的摄像头资源,为正确初始化做准备
  196. camera_ = new Esp32Camera(config);
  197. }
  198. }
  199. void InitializeTouch()
  200. {
  201. esp_lcd_touch_handle_t tp;
  202. esp_lcd_touch_config_t tp_cfg = {
  203. .x_max = DISPLAY_WIDTH,
  204. .y_max = DISPLAY_HEIGHT,
  205. .rst_gpio_num = GPIO_NUM_NC,
  206. .int_gpio_num = GPIO_NUM_NC,
  207. .levels = {
  208. .reset = 0,
  209. .interrupt = 0,
  210. },
  211. .flags = {
  212. .swap_xy = 1,
  213. .mirror_x = 1,
  214. .mirror_y = 1,
  215. },
  216. };
  217. esp_lcd_panel_io_handle_t tp_io_handle = NULL;
  218. esp_lcd_panel_io_i2c_config_t tp_io_config = ESP_LCD_TOUCH_IO_I2C_FT5x06_CONFIG();
  219. tp_io_config.scl_speed_hz = 400 * 1000;
  220. ESP_ERROR_CHECK(esp_lcd_new_panel_io_i2c(i2c_bus_, &tp_io_config, &tp_io_handle));
  221. ESP_LOGI(TAG, "Initialize touch controller");
  222. ESP_ERROR_CHECK(esp_lcd_touch_new_i2c_ft5x06(tp_io_handle, &tp_cfg, &tp));
  223. const lvgl_port_touch_cfg_t touch_cfg = {
  224. .disp = lv_display_get_default(),
  225. .handle = tp,
  226. };
  227. lvgl_port_add_touch(&touch_cfg);
  228. ESP_LOGI(TAG, "Touch panel initialized successfully");
  229. }
  230. void InitializeLcdDisplay() {
  231. esp_lcd_panel_io_handle_t panel_io = nullptr;
  232. esp_lcd_panel_handle_t panel = nullptr;
  233. // 液晶屏控制IO初始化
  234. ESP_LOGI(TAG, "Install panel IO");
  235. esp_lcd_panel_io_spi_config_t io_config = {};
  236. io_config.cs_gpio_num = DISPLAY_CS_PIN;
  237. io_config.dc_gpio_num = DISPLAY_DC_PIN;
  238. io_config.spi_mode = DISPLAY_SPI_MODE;
  239. io_config.pclk_hz = 40 * 1000 * 1000;
  240. io_config.trans_queue_depth = 10;
  241. io_config.lcd_cmd_bits = 8;
  242. io_config.lcd_param_bits = 8;
  243. ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi(SPI3_HOST, &io_config, &panel_io));
  244. st7796_vendor_config_t st7796_vendor_config = {
  245. .init_cmds = st7796_lcd_init_cmds,
  246. .init_cmds_size = sizeof(st7796_lcd_init_cmds) / sizeof(st7796_lcd_init_cmd_t),
  247. };
  248. // 初始化液晶屏驱动芯片
  249. ESP_LOGI(TAG, "Install LCD driver");
  250. esp_lcd_panel_dev_config_t panel_config = {};
  251. panel_config.reset_gpio_num = DISPLAY_RST_PIN;
  252. panel_config.rgb_ele_order = DISPLAY_RGB_ORDER;
  253. panel_config.bits_per_pixel = 16;
  254. panel_config.vendor_config = &st7796_vendor_config;
  255. ESP_ERROR_CHECK(esp_lcd_new_panel_st7789(panel_io, &panel_config, &panel));
  256. esp_lcd_panel_reset(panel);
  257. esp_lcd_panel_init(panel);
  258. esp_lcd_panel_invert_color(panel, DISPLAY_INVERT_COLOR);
  259. esp_lcd_panel_swap_xy(panel, DISPLAY_SWAP_XY);
  260. esp_lcd_panel_mirror(panel, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y);
  261. display_ = new SpiLcdDisplay(panel_io, panel,
  262. DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY,
  263. {
  264. .text_font = &font_puhui_16_4,
  265. .icon_font = &font_awesome_16_4,
  266. .emoji_font = font_emoji_32_init(),
  267. });
  268. }
  269. void InitializeButtons() {
  270. boot_button_.OnClick([this]() {
  271. auto& app = Application::GetInstance();
  272. if (app.GetDeviceState() == kDeviceStateStarting && !WifiStation::GetInstance().IsConnected()) {
  273. ResetWifiConfiguration();
  274. }
  275. app.ToggleChatState();
  276. });
  277. }
  278. // 初始化工具
  279. void InitializeTools() {
  280. auto &mcp_server = McpServer::GetInstance();
  281. mcp_server.AddTool("self.system.reconfigure_wifi",
  282. "Reboot the device and enter WiFi configuration mode.\n"
  283. "**CAUTION** You must ask the user to confirm this action.",
  284. PropertyList(), [this](const PropertyList& properties) {
  285. ResetWifiConfiguration();
  286. return true;
  287. });
  288. }
  289. public:
  290. CustomBoard() :
  291. boot_button_(BOOT_BUTTON_GPIO) {
  292. InitializePowerSaveTimer();
  293. InitializeI2c();
  294. InitializeTca9554();
  295. InitializeAxp2101();
  296. InitializeSpi();
  297. InitializeLcdDisplay();
  298. // 解决部分开机黑屏的问题
  299. if (esp_reset_reason() == ESP_RST_POWERON) {
  300. fflush(stdout);
  301. esp_restart();
  302. }
  303. InitializeTouch();
  304. InitializeButtons();
  305. InitializeCamera();
  306. InitializeTools();
  307. GetBacklight()->RestoreBrightness();
  308. }
  309. virtual AudioCodec* GetAudioCodec() override {
  310. static Es8311AudioCodec audio_codec(i2c_bus_, I2C_NUM_0, AUDIO_INPUT_SAMPLE_RATE, AUDIO_OUTPUT_SAMPLE_RATE,
  311. AUDIO_I2S_GPIO_MCLK, AUDIO_I2S_GPIO_BCLK, AUDIO_I2S_GPIO_WS, AUDIO_I2S_GPIO_DOUT, AUDIO_I2S_GPIO_DIN,
  312. AUDIO_CODEC_PA_PIN, AUDIO_CODEC_ES8311_ADDR);
  313. return &audio_codec;
  314. }
  315. virtual Display* GetDisplay() override {
  316. return display_;
  317. }
  318. virtual Backlight* GetBacklight() override {
  319. static PwmBacklight backlight(DISPLAY_BACKLIGHT_PIN, DISPLAY_BACKLIGHT_OUTPUT_INVERT);
  320. return &backlight;
  321. }
  322. virtual bool GetBatteryLevel(int &level, bool& charging, bool& discharging) override {
  323. static bool last_discharging = false;
  324. charging = pmic_->IsCharging();
  325. discharging = pmic_->IsDischarging();
  326. if (discharging != last_discharging) {
  327. power_save_timer_->SetEnabled(discharging);
  328. last_discharging = discharging;
  329. }
  330. level = pmic_->GetBatteryLevel();
  331. return true;
  332. }
  333. virtual void SetPowerSaveMode(bool enabled) override {
  334. if (!enabled) {
  335. power_save_timer_->WakeUp();
  336. }
  337. WifiBoard::SetPowerSaveMode(enabled);
  338. }
  339. virtual Camera* GetCamera() override {
  340. return camera_;
  341. }
  342. };
  343. DECLARE_BOARD(CustomBoard);