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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. #include "wifi_board.h"
  2. #include "audio_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 "iot/thing_manager.h"
  9. #include <esp_log.h>
  10. #include "i2c_device.h"
  11. #include <driver/i2c.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. #define TAG "waveshare_lcd_3_5"
  22. LV_FONT_DECLARE(font_puhui_16_4);
  23. LV_FONT_DECLARE(font_awesome_16_4);
  24. class Pmic : public Axp2101 {
  25. public:
  26. Pmic(i2c_master_bus_handle_t i2c_bus, uint8_t addr) : Axp2101(i2c_bus, addr) {
  27. WriteReg(0x22, 0b110); // PWRON > OFFLEVEL as POWEROFF Source enable
  28. WriteReg(0x27, 0x10); // hold 4s to power off
  29. // Disable All DCs but DC1
  30. WriteReg(0x80, 0x01);
  31. // Disable All LDOs
  32. WriteReg(0x90, 0x00);
  33. WriteReg(0x91, 0x00);
  34. // Set DC1 to 3.3V
  35. WriteReg(0x82, (3300 - 1500) / 100);
  36. // Set ALDO1 to 3.3V
  37. WriteReg(0x92, (3300 - 500) / 100);
  38. // Enable ALDO1(MIC)
  39. WriteReg(0x90, 0x01);
  40. WriteReg(0x64, 0x02); // CV charger voltage setting to 4.1V
  41. WriteReg(0x61, 0x02); // set Main battery precharge current to 50mA
  42. WriteReg(0x62, 0x08); // set Main battery charger current to 400mA ( 0x08-200mA, 0x09-300mA, 0x0A-400mA )
  43. WriteReg(0x63, 0x01); // set Main battery term charge current to 25mA
  44. }
  45. };
  46. typedef struct {
  47. int cmd; /*<! The specific LCD command */
  48. const void *data; /*<! Buffer that holds the command specific data */
  49. size_t data_bytes; /*<! Size of `data` in memory, in bytes */
  50. unsigned int delay_ms; /*<! Delay in milliseconds after this command */
  51. } st7796_lcd_init_cmd_t;
  52. typedef struct {
  53. const st7796_lcd_init_cmd_t *init_cmds; /*!< Pointer to initialization commands array. Set to NULL if using default commands.
  54. * The array should be declared as `static const` and positioned outside the function.
  55. * Please refer to `vendor_specific_init_default` in source file.
  56. */
  57. uint16_t init_cmds_size; /*<! Number of commands in above array */
  58. } st7796_vendor_config_t;
  59. st7796_lcd_init_cmd_t st7796_lcd_init_cmds[] = {
  60. {0x11, (uint8_t []){ 0x00 }, 0, 120},
  61. // {0x36, (uint8_t []){ 0x08 }, 1, 0},
  62. {0x3A, (uint8_t []){ 0x05 }, 1, 0},
  63. {0xF0, (uint8_t []){ 0xC3 }, 1, 0},
  64. {0xF0, (uint8_t []){ 0x96 }, 1, 0},
  65. {0xB4, (uint8_t []){ 0x01 }, 1, 0},
  66. {0xB7, (uint8_t []){ 0xC6 }, 1, 0},
  67. {0xC0, (uint8_t []){ 0x80, 0x45 }, 2, 0},
  68. {0xC1, (uint8_t []){ 0x13 }, 1, 0},
  69. {0xC2, (uint8_t []){ 0xA7 }, 1, 0},
  70. {0xC5, (uint8_t []){ 0x0A }, 1, 0},
  71. {0xE8, (uint8_t []){ 0x40, 0x8A, 0x00, 0x00, 0x29, 0x19, 0xA5, 0x33}, 8, 0},
  72. {0xE0, (uint8_t []){ 0xD0, 0x08, 0x0F, 0x06, 0x06, 0x33, 0x30, 0x33, 0x47, 0x17, 0x13, 0x13, 0x2B, 0x31}, 14, 0},
  73. {0xE1, (uint8_t []){ 0xD0, 0x0A, 0x11, 0x0B, 0x09, 0x07, 0x2F, 0x33, 0x47, 0x38, 0x15, 0x16, 0x2C, 0x32},14, 0},
  74. {0xF0, (uint8_t []){ 0x3C }, 1, 0},
  75. {0xF0, (uint8_t []){ 0x69 }, 1, 120},
  76. {0x21, (uint8_t []){ 0x00 }, 0, 0},
  77. {0x29, (uint8_t []){ 0x00 }, 0, 0},
  78. };
  79. class CustomBoard : public WifiBoard {
  80. private:
  81. Button boot_button_;
  82. Pmic* pmic_ = nullptr;
  83. i2c_master_bus_handle_t i2c_bus_;
  84. esp_io_expander_handle_t io_expander = NULL;
  85. LcdDisplay* display_;
  86. PowerSaveTimer* power_save_timer_;
  87. void InitializePowerSaveTimer() {
  88. power_save_timer_ = new PowerSaveTimer(-1, 60, 300);
  89. power_save_timer_->OnEnterSleepMode([this]() {
  90. ESP_LOGI(TAG, "Enabling sleep mode");
  91. auto display = GetDisplay();
  92. display->SetChatMessage("system", "");
  93. display->SetEmotion("sleepy");
  94. GetBacklight()->SetBrightness(20);
  95. });
  96. power_save_timer_->OnExitSleepMode([this]() {
  97. auto display = GetDisplay();
  98. display->SetChatMessage("system", "");
  99. display->SetEmotion("neutral");
  100. GetBacklight()->RestoreBrightness();
  101. });
  102. power_save_timer_->OnShutdownRequest([this]() {
  103. pmic_->PowerOff();
  104. });
  105. power_save_timer_->SetEnabled(true);
  106. }
  107. void InitializeI2c() {
  108. // Initialize I2C peripheral
  109. i2c_master_bus_config_t i2c_bus_cfg = {
  110. .i2c_port = (i2c_port_t)0,
  111. .sda_io_num = AUDIO_CODEC_I2C_SDA_PIN,
  112. .scl_io_num = AUDIO_CODEC_I2C_SCL_PIN,
  113. .clk_source = I2C_CLK_SRC_DEFAULT,
  114. };
  115. ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_cfg, &i2c_bus_));
  116. }
  117. void InitializeTca9554(void)
  118. {
  119. esp_err_t ret = esp_io_expander_new_i2c_tca9554(i2c_bus_, ESP_IO_EXPANDER_I2C_TCA9554_ADDRESS_000, &io_expander);
  120. if(ret != ESP_OK)
  121. ESP_LOGE(TAG, "TCA9554 create returned error");
  122. ret = esp_io_expander_set_dir(io_expander, IO_EXPANDER_PIN_NUM_0 | IO_EXPANDER_PIN_NUM_1, IO_EXPANDER_OUTPUT);
  123. ESP_ERROR_CHECK(ret);
  124. vTaskDelay(pdMS_TO_TICKS(100));
  125. ret = esp_io_expander_set_level(io_expander, IO_EXPANDER_PIN_NUM_1, 0);
  126. ESP_ERROR_CHECK(ret);
  127. vTaskDelay(pdMS_TO_TICKS(100));
  128. ret = esp_io_expander_set_level(io_expander, IO_EXPANDER_PIN_NUM_0 | IO_EXPANDER_PIN_NUM_1, 1);
  129. ESP_ERROR_CHECK(ret);
  130. }
  131. void InitializeAxp2101() {
  132. ESP_LOGI(TAG, "Init AXP2101");
  133. pmic_ = new Pmic(i2c_bus_, 0x34);
  134. }
  135. void InitializeSpi() {
  136. ESP_LOGI(TAG, "Initialize QSPI bus");
  137. spi_bus_config_t buscfg = {};
  138. buscfg.mosi_io_num = DISPLAY_MOSI_PIN;
  139. buscfg.miso_io_num = DISPLAY_MISO_PIN;
  140. buscfg.sclk_io_num = DISPLAY_CLK_PIN;
  141. buscfg.quadwp_io_num = GPIO_NUM_NC;
  142. buscfg.quadhd_io_num = GPIO_NUM_NC;
  143. buscfg.max_transfer_sz = DISPLAY_WIDTH * DISPLAY_HEIGHT * sizeof(uint16_t);
  144. ESP_ERROR_CHECK(spi_bus_initialize(SPI3_HOST, &buscfg, SPI_DMA_CH_AUTO));
  145. }
  146. void InitializeLcdDisplay() {
  147. esp_lcd_panel_io_handle_t panel_io = nullptr;
  148. esp_lcd_panel_handle_t panel = nullptr;
  149. // 液晶屏控制IO初始化
  150. ESP_LOGI(TAG, "Install panel IO");
  151. esp_lcd_panel_io_spi_config_t io_config = {};
  152. io_config.cs_gpio_num = DISPLAY_CS_PIN;
  153. io_config.dc_gpio_num = DISPLAY_DC_PIN;
  154. io_config.spi_mode = DISPLAY_SPI_MODE;
  155. io_config.pclk_hz = 40 * 1000 * 1000;
  156. io_config.trans_queue_depth = 10;
  157. io_config.lcd_cmd_bits = 8;
  158. io_config.lcd_param_bits = 8;
  159. ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi(SPI3_HOST, &io_config, &panel_io));
  160. st7796_vendor_config_t st7796_vendor_config = {
  161. .init_cmds = st7796_lcd_init_cmds,
  162. .init_cmds_size = sizeof(st7796_lcd_init_cmds) / sizeof(st7796_lcd_init_cmd_t),
  163. };
  164. // 初始化液晶屏驱动芯片
  165. ESP_LOGI(TAG, "Install LCD driver");
  166. esp_lcd_panel_dev_config_t panel_config = {};
  167. panel_config.reset_gpio_num = DISPLAY_RST_PIN;
  168. panel_config.rgb_ele_order = DISPLAY_RGB_ORDER;
  169. panel_config.bits_per_pixel = 16;
  170. panel_config.vendor_config = &st7796_vendor_config;
  171. ESP_ERROR_CHECK(esp_lcd_new_panel_st7789(panel_io, &panel_config, &panel));
  172. esp_lcd_panel_reset(panel);
  173. esp_lcd_panel_init(panel);
  174. esp_lcd_panel_invert_color(panel, DISPLAY_INVERT_COLOR);
  175. esp_lcd_panel_swap_xy(panel, DISPLAY_SWAP_XY);
  176. esp_lcd_panel_mirror(panel, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y);
  177. display_ = new SpiLcdDisplay(panel_io, panel,
  178. DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY,
  179. {
  180. .text_font = &font_puhui_16_4,
  181. .icon_font = &font_awesome_16_4,
  182. .emoji_font = font_emoji_32_init(),
  183. });
  184. }
  185. void InitializeButtons() {
  186. boot_button_.OnClick([this]() {
  187. auto& app = Application::GetInstance();
  188. if (app.GetDeviceState() == kDeviceStateStarting && !WifiStation::GetInstance().IsConnected()) {
  189. ResetWifiConfiguration();
  190. }
  191. app.ToggleChatState();
  192. });
  193. }
  194. // 物联网初始化,添加对 AI 可见设备
  195. void InitializeIot() {
  196. auto& thing_manager = iot::ThingManager::GetInstance();
  197. thing_manager.AddThing(iot::CreateThing("Speaker"));
  198. thing_manager.AddThing(iot::CreateThing("Screen"));
  199. thing_manager.AddThing(iot::CreateThing("Battery"));
  200. thing_manager.AddThing(iot::CreateThing("BoardControl"));
  201. }
  202. public:
  203. CustomBoard() :
  204. boot_button_(BOOT_BUTTON_GPIO) {
  205. InitializePowerSaveTimer();
  206. InitializeI2c();
  207. InitializeTca9554();
  208. InitializeAxp2101();
  209. InitializeSpi();
  210. InitializeLcdDisplay();
  211. InitializeButtons();
  212. InitializeIot();
  213. GetBacklight()->RestoreBrightness();
  214. }
  215. virtual AudioCodec* GetAudioCodec() override {
  216. static Es8311AudioCodec audio_codec(i2c_bus_, I2C_NUM_0, AUDIO_INPUT_SAMPLE_RATE, AUDIO_OUTPUT_SAMPLE_RATE,
  217. AUDIO_I2S_GPIO_MCLK, AUDIO_I2S_GPIO_BCLK, AUDIO_I2S_GPIO_WS, AUDIO_I2S_GPIO_DOUT, AUDIO_I2S_GPIO_DIN,
  218. AUDIO_CODEC_PA_PIN, AUDIO_CODEC_ES8311_ADDR);
  219. return &audio_codec;
  220. }
  221. virtual Display* GetDisplay() override {
  222. return display_;
  223. }
  224. virtual Backlight* GetBacklight() override {
  225. static PwmBacklight backlight(DISPLAY_BACKLIGHT_PIN, DISPLAY_BACKLIGHT_OUTPUT_INVERT);
  226. return &backlight;
  227. }
  228. virtual bool GetBatteryLevel(int &level, bool& charging, bool& discharging) override {
  229. static bool last_discharging = false;
  230. charging = pmic_->IsCharging();
  231. discharging = pmic_->IsDischarging();
  232. if (discharging != last_discharging) {
  233. power_save_timer_->SetEnabled(discharging);
  234. last_discharging = discharging;
  235. }
  236. level = pmic_->GetBatteryLevel();
  237. return true;
  238. }
  239. virtual void SetPowerSaveMode(bool enabled) override {
  240. if (!enabled) {
  241. power_save_timer_->WakeUp();
  242. }
  243. WifiBoard::SetPowerSaveMode(enabled);
  244. }
  245. };
  246. DECLARE_BOARD(CustomBoard);