m5stack_tab5.cc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. #include "wifi_board.h"
  2. #include "tab5_audio_codec.h"
  3. #include "display/lcd_display.h"
  4. #include "esp_lcd_ili9881c.h"
  5. #include "font_awesome_symbols.h"
  6. #include "font_emoji.h"
  7. #include "application.h"
  8. #include "button.h"
  9. #include "config.h"
  10. #include <esp_log.h>
  11. #include "esp_lcd_mipi_dsi.h"
  12. #include "esp_lcd_panel_ops.h"
  13. #include "esp_ldo_regulator.h"
  14. #include <esp_lcd_panel_vendor.h>
  15. #include <driver/i2c_master.h>
  16. #include <driver/spi_common.h>
  17. #include <wifi_station.h>
  18. #include "i2c_device.h"
  19. #include "esp_lcd_touch_gt911.h"
  20. #include <cstring>
  21. #define TAG "M5StackTab5Board"
  22. LV_FONT_DECLARE(font_puhui_30_4);
  23. LV_FONT_DECLARE(font_awesome_30_4);
  24. #define AUDIO_CODEC_ES8388_ADDR ES8388_CODEC_DEFAULT_ADDR
  25. #define LCD_MIPI_DSI_PHY_PWR_LDO_CHAN 3 // LDO_VO3 is connected to VDD_MIPI_DPHY
  26. #define LCD_MIPI_DSI_PHY_PWR_LDO_VOLTAGE_MV 2500
  27. // PI4IO registers
  28. #define PI4IO_REG_CHIP_RESET 0x01
  29. #define PI4IO_REG_IO_DIR 0x03
  30. #define PI4IO_REG_OUT_SET 0x05
  31. #define PI4IO_REG_OUT_H_IM 0x07
  32. #define PI4IO_REG_IN_DEF_STA 0x09
  33. #define PI4IO_REG_PULL_EN 0x0B
  34. #define PI4IO_REG_PULL_SEL 0x0D
  35. #define PI4IO_REG_IN_STA 0x0F
  36. #define PI4IO_REG_INT_MASK 0x11
  37. #define PI4IO_REG_IRQ_STA 0x13
  38. class Pi4ioe1 : public I2cDevice {
  39. public:
  40. Pi4ioe1(i2c_master_bus_handle_t i2c_bus, uint8_t addr) : I2cDevice(i2c_bus, addr)
  41. {
  42. WriteReg(PI4IO_REG_CHIP_RESET, 0xFF);
  43. uint8_t data = ReadReg(PI4IO_REG_CHIP_RESET);
  44. WriteReg(PI4IO_REG_IO_DIR, 0b01111111); // 0: input 1: output
  45. WriteReg(PI4IO_REG_OUT_H_IM, 0b00000000); // 使用到的引脚关闭 High-Impedance
  46. WriteReg(PI4IO_REG_PULL_SEL, 0b01111111); // pull up/down select, 0 down, 1 up
  47. WriteReg(PI4IO_REG_PULL_EN, 0b01111111); // pull up/down enable, 0 disable, 1 enable
  48. WriteReg(PI4IO_REG_IN_DEF_STA, 0b10000000); // P1, P7 默认高电平
  49. WriteReg(PI4IO_REG_INT_MASK, 0b01111111); // P7 中断使能 0 enable, 1 disable
  50. WriteReg(PI4IO_REG_OUT_SET, 0b01110110); // Output Port Register P1(SPK_EN), P2(EXT5V_EN), P4(LCD_RST), P5(TP_RST), P6(CAM)RST 输出高电平
  51. }
  52. };
  53. class Pi4ioe2 : public I2cDevice {
  54. public:
  55. Pi4ioe2(i2c_master_bus_handle_t i2c_bus, uint8_t addr) : I2cDevice(i2c_bus, addr)
  56. {
  57. WriteReg(PI4IO_REG_CHIP_RESET, 0xFF);
  58. uint8_t data = ReadReg(PI4IO_REG_CHIP_RESET);
  59. WriteReg(PI4IO_REG_IO_DIR, 0b10111001); // 0: input 1: output
  60. WriteReg(PI4IO_REG_OUT_H_IM, 0b00000110); // 使用到的引脚关闭 High-Impedance
  61. WriteReg(PI4IO_REG_PULL_SEL, 0b10111001); // pull up/down select, 0 down, 1 up
  62. WriteReg(PI4IO_REG_PULL_EN, 0b11111001); // pull up/down enable, 0 disable, 1 enable
  63. WriteReg(PI4IO_REG_IN_DEF_STA, 0b01000000); // P6 默认高电平
  64. WriteReg(PI4IO_REG_INT_MASK, 0b10111111); // P6 中断使能 0 enable, 1 disable
  65. WriteReg(PI4IO_REG_OUT_SET, 0b10001001); // Output Port Register P0(WLAN_PWR_EN), P3(USB5V_EN), P7(CHG_EN) 输出高电平
  66. }
  67. };
  68. class M5StackTab5Board : public WifiBoard {
  69. private:
  70. i2c_master_bus_handle_t i2c_bus_;
  71. Button boot_button_;
  72. LcdDisplay* display_;
  73. Pi4ioe1* pi4ioe1_;
  74. Pi4ioe2* pi4ioe2_;
  75. esp_lcd_touch_handle_t touch_ = nullptr;
  76. void InitializeI2c()
  77. {
  78. // Initialize I2C peripheral
  79. i2c_master_bus_config_t i2c_bus_cfg = {
  80. .i2c_port = (i2c_port_t)1,
  81. .sda_io_num = AUDIO_CODEC_I2C_SDA_PIN,
  82. .scl_io_num = AUDIO_CODEC_I2C_SCL_PIN,
  83. .clk_source = I2C_CLK_SRC_DEFAULT,
  84. .glitch_ignore_cnt = 7,
  85. .intr_priority = 0,
  86. .trans_queue_depth = 0,
  87. .flags = {
  88. .enable_internal_pullup = 1,
  89. },
  90. };
  91. ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_cfg, &i2c_bus_));
  92. }
  93. void I2cDetect()
  94. {
  95. uint8_t address;
  96. printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f\r\n");
  97. for (int i = 0; i < 128; i += 16) {
  98. printf("%02x: ", i);
  99. for (int j = 0; j < 16; j++) {
  100. fflush(stdout);
  101. address = i + j;
  102. esp_err_t ret = i2c_master_probe(i2c_bus_, address, pdMS_TO_TICKS(200));
  103. if (ret == ESP_OK) {
  104. printf("%02x ", address);
  105. } else if (ret == ESP_ERR_TIMEOUT) {
  106. printf("UU ");
  107. } else {
  108. printf("-- ");
  109. }
  110. }
  111. printf("\r\n");
  112. }
  113. }
  114. void InitializePi4ioe()
  115. {
  116. ESP_LOGI(TAG, "Init I/O Exapander PI4IOE");
  117. pi4ioe1_ = new Pi4ioe1(i2c_bus_, 0x43);
  118. pi4ioe2_ = new Pi4ioe2(i2c_bus_, 0x44);
  119. }
  120. void InitializeButtons()
  121. {
  122. boot_button_.OnClick([this]() {
  123. auto& app = Application::GetInstance();
  124. if (app.GetDeviceState() == kDeviceStateStarting && !WifiStation::GetInstance().IsConnected()) {
  125. // ResetWifiConfiguration();
  126. }
  127. app.ToggleChatState();
  128. });
  129. }
  130. void InitializeGt911TouchPad() {
  131. ESP_LOGI(TAG, "Init GT911");
  132. /* Initialize Touch Panel */
  133. ESP_LOGI(TAG, "Initialize touch IO (I2C)");
  134. const esp_lcd_touch_config_t tp_cfg = {
  135. .x_max = DISPLAY_WIDTH,
  136. .y_max = DISPLAY_HEIGHT,
  137. .rst_gpio_num = GPIO_NUM_NC,
  138. .int_gpio_num = TOUCH_INT_GPIO,
  139. .levels = {
  140. .reset = 0,
  141. .interrupt = 0,
  142. },
  143. .flags = {
  144. .swap_xy = 0,
  145. .mirror_x = 0,
  146. .mirror_y = 0,
  147. },
  148. };
  149. esp_lcd_panel_io_handle_t tp_io_handle = NULL;
  150. esp_lcd_panel_io_i2c_config_t tp_io_config = ESP_LCD_TOUCH_IO_I2C_GT911_CONFIG();
  151. tp_io_config.dev_addr = ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS_BACKUP; // 更改 GT911 地址
  152. tp_io_config.scl_speed_hz = 100000;
  153. esp_lcd_new_panel_io_i2c(i2c_bus_, &tp_io_config, &tp_io_handle);
  154. esp_lcd_touch_new_i2c_gt911(tp_io_handle, &tp_cfg, &touch_);
  155. // 检测不到触摸?待更换设备测试
  156. // /* read data test */
  157. // for (uint8_t i = 0; i < 50; i++) {
  158. // esp_lcd_touch_read_data(touch_);
  159. // if (touch_->data.points > 0) {
  160. // printf("\ntouch: %d, %d\n", touch_->data.coords[0].x, touch_->data.coords[0].y);
  161. // }
  162. // vTaskDelay(pdMS_TO_TICKS(100));
  163. // }
  164. }
  165. void InitializeSpi() {
  166. spi_bus_config_t buscfg = {};
  167. buscfg.mosi_io_num = GPIO_NUM_37;
  168. buscfg.miso_io_num = GPIO_NUM_NC;
  169. buscfg.sclk_io_num = GPIO_NUM_36;
  170. buscfg.quadwp_io_num = GPIO_NUM_NC;
  171. buscfg.quadhd_io_num = GPIO_NUM_NC;
  172. buscfg.max_transfer_sz = DISPLAY_WIDTH * DISPLAY_HEIGHT * sizeof(uint16_t);
  173. ESP_ERROR_CHECK(spi_bus_initialize(SPI3_HOST, &buscfg, SPI_DMA_CH_AUTO));
  174. }
  175. void InitializeIli9881cDisplay()
  176. {
  177. esp_lcd_panel_io_handle_t panel_io = nullptr;
  178. esp_lcd_panel_handle_t panel = nullptr;
  179. ESP_LOGI(TAG, "Turn on the power for MIPI DSI PHY");
  180. esp_ldo_channel_handle_t ldo_mipi_phy = NULL;
  181. esp_ldo_channel_config_t ldo_mipi_phy_config = {
  182. .chan_id = LCD_MIPI_DSI_PHY_PWR_LDO_CHAN,
  183. .voltage_mv = LCD_MIPI_DSI_PHY_PWR_LDO_VOLTAGE_MV,
  184. };
  185. ESP_ERROR_CHECK(esp_ldo_acquire_channel(&ldo_mipi_phy_config, &ldo_mipi_phy));
  186. ESP_LOGI(TAG, "Install MIPI DSI LCD control panel");
  187. esp_lcd_dsi_bus_handle_t mipi_dsi_bus;
  188. esp_lcd_dsi_bus_config_t bus_config = {
  189. .bus_id = 0,
  190. .num_data_lanes = 2,
  191. .phy_clk_src = MIPI_DSI_PHY_CLK_SRC_DEFAULT,
  192. .lane_bit_rate_mbps = 900, // 900MHz
  193. };
  194. ESP_ERROR_CHECK(esp_lcd_new_dsi_bus(&bus_config, &mipi_dsi_bus));
  195. ESP_LOGI(TAG, "Install panel IO");
  196. esp_lcd_dbi_io_config_t dbi_config = {
  197. .virtual_channel = 0,
  198. .lcd_cmd_bits = 8,
  199. .lcd_param_bits = 8,
  200. };
  201. ESP_ERROR_CHECK(esp_lcd_new_panel_io_dbi(mipi_dsi_bus, &dbi_config, &panel_io));
  202. ESP_LOGI(TAG, "Install LCD driver of ili9881c");
  203. esp_lcd_dpi_panel_config_t dpi_config = {.virtual_channel = 0,
  204. .dpi_clk_src = MIPI_DSI_DPI_CLK_SRC_DEFAULT,
  205. .dpi_clock_freq_mhz = 60,
  206. .pixel_format = LCD_COLOR_PIXEL_FORMAT_RGB565,
  207. .num_fbs = 2,
  208. .video_timing =
  209. {
  210. .h_size = DISPLAY_WIDTH,
  211. .v_size = DISPLAY_HEIGHT,
  212. .hsync_pulse_width = 40,
  213. .hsync_back_porch = 140,
  214. .hsync_front_porch = 40,
  215. .vsync_pulse_width = 4,
  216. .vsync_back_porch = 20,
  217. .vsync_front_porch = 20,
  218. },
  219. .flags = {
  220. .use_dma2d = false,
  221. }};
  222. ili9881c_vendor_config_t vendor_config = {
  223. .init_cmds = tab5_lcd_ili9881c_specific_init_code_default,
  224. .init_cmds_size = sizeof(tab5_lcd_ili9881c_specific_init_code_default) /
  225. sizeof(tab5_lcd_ili9881c_specific_init_code_default[0]),
  226. .mipi_config =
  227. {
  228. .dsi_bus = mipi_dsi_bus,
  229. .dpi_config = &dpi_config,
  230. .lane_num = 2,
  231. },
  232. };
  233. esp_lcd_panel_dev_config_t lcd_dev_config = {};
  234. lcd_dev_config.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB;
  235. lcd_dev_config.reset_gpio_num = -1;
  236. lcd_dev_config.bits_per_pixel = 16;
  237. lcd_dev_config.vendor_config = &vendor_config;
  238. ESP_ERROR_CHECK(esp_lcd_new_panel_ili9881c(panel_io, &lcd_dev_config, &panel));
  239. ESP_ERROR_CHECK(esp_lcd_panel_reset(panel));
  240. ESP_ERROR_CHECK(esp_lcd_panel_init(panel));
  241. // ESP_ERROR_CHECK(esp_lcd_panel_mirror(disp_panel, false, true));
  242. ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel, true));
  243. display_ = new MipiLcdDisplay(panel_io, panel, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_OFFSET_X,
  244. DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY,
  245. {
  246. .text_font = &font_puhui_30_4,
  247. .icon_font = &font_awesome_30_4,
  248. .emoji_font = font_emoji_64_init(),
  249. });
  250. }
  251. public:
  252. M5StackTab5Board() : boot_button_(BOOT_BUTTON_GPIO)
  253. {
  254. InitializeI2c();
  255. I2cDetect();
  256. InitializePi4ioe();
  257. InitializeGt911TouchPad();
  258. InitializeIli9881cDisplay();
  259. InitializeButtons();
  260. GetBacklight()->RestoreBrightness();
  261. }
  262. virtual AudioCodec* GetAudioCodec() override
  263. {
  264. static Tab5AudioCodec audio_codec(i2c_bus_,
  265. AUDIO_INPUT_SAMPLE_RATE,
  266. AUDIO_OUTPUT_SAMPLE_RATE,
  267. AUDIO_I2S_GPIO_MCLK,
  268. AUDIO_I2S_GPIO_BCLK,
  269. AUDIO_I2S_GPIO_WS,
  270. AUDIO_I2S_GPIO_DOUT,
  271. AUDIO_I2S_GPIO_DIN,
  272. AUDIO_CODEC_PA_PIN,
  273. AUDIO_CODEC_ES8388_ADDR,
  274. AUDIO_CODEC_ES7210_ADDR,
  275. AUDIO_INPUT_REFERENCE);
  276. return &audio_codec;
  277. }
  278. virtual Display* GetDisplay() override
  279. {
  280. return display_;
  281. }
  282. virtual Backlight* GetBacklight() override
  283. {
  284. static PwmBacklight backlight(DISPLAY_BACKLIGHT_PIN, DISPLAY_BACKLIGHT_OUTPUT_INVERT);
  285. return &backlight;
  286. }
  287. };
  288. DECLARE_BOARD(M5StackTab5Board);