m5stack_core_s3.cc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. #include "wifi_board.h"
  2. #include "cores3_audio_codec.h"
  3. #include "display/lcd_display.h"
  4. #include "application.h"
  5. #include "config.h"
  6. #include "power_save_timer.h"
  7. #include "i2c_device.h"
  8. #include "axp2101.h"
  9. #include <esp_log.h>
  10. #include <driver/i2c_master.h>
  11. #include <wifi_station.h>
  12. #include <esp_lcd_panel_io.h>
  13. #include <esp_lcd_panel_ops.h>
  14. #include <esp_lcd_ili9341.h>
  15. #include <esp_timer.h>
  16. #include "esp32_camera.h"
  17. #define TAG "M5StackCoreS3Board"
  18. LV_FONT_DECLARE(font_puhui_20_4);
  19. LV_FONT_DECLARE(font_awesome_20_4);
  20. class Pmic : public Axp2101 {
  21. public:
  22. // Power Init
  23. Pmic(i2c_master_bus_handle_t i2c_bus, uint8_t addr) : Axp2101(i2c_bus, addr) {
  24. uint8_t data = ReadReg(0x90);
  25. data |= 0b10110100;
  26. WriteReg(0x90, data);
  27. WriteReg(0x99, (0b11110 - 5));
  28. WriteReg(0x97, (0b11110 - 2));
  29. WriteReg(0x69, 0b00110101);
  30. WriteReg(0x30, 0b111111);
  31. WriteReg(0x90, 0xBF);
  32. WriteReg(0x94, 33 - 5);
  33. WriteReg(0x95, 33 - 5);
  34. }
  35. void SetBrightness(uint8_t brightness) {
  36. brightness = ((brightness + 641) >> 5);
  37. WriteReg(0x99, brightness);
  38. }
  39. };
  40. class CustomBacklight : public Backlight {
  41. public:
  42. CustomBacklight(Pmic *pmic) : pmic_(pmic) {}
  43. void SetBrightnessImpl(uint8_t brightness) override {
  44. pmic_->SetBrightness(target_brightness_);
  45. brightness_ = target_brightness_;
  46. }
  47. private:
  48. Pmic *pmic_;
  49. };
  50. class Aw9523 : public I2cDevice {
  51. public:
  52. // Exanpd IO Init
  53. Aw9523(i2c_master_bus_handle_t i2c_bus, uint8_t addr) : I2cDevice(i2c_bus, addr) {
  54. WriteReg(0x02, 0b00000111); // P0
  55. WriteReg(0x03, 0b10001111); // P1
  56. WriteReg(0x04, 0b00011000); // CONFIG_P0
  57. WriteReg(0x05, 0b00001100); // CONFIG_P1
  58. WriteReg(0x11, 0b00010000); // GCR P0 port is Push-Pull mode.
  59. WriteReg(0x12, 0b11111111); // LEDMODE_P0
  60. WriteReg(0x13, 0b11111111); // LEDMODE_P1
  61. }
  62. void ResetAw88298() {
  63. ESP_LOGI(TAG, "Reset AW88298");
  64. WriteReg(0x02, 0b00000011);
  65. vTaskDelay(pdMS_TO_TICKS(10));
  66. WriteReg(0x02, 0b00000111);
  67. vTaskDelay(pdMS_TO_TICKS(50));
  68. }
  69. void ResetIli9342() {
  70. ESP_LOGI(TAG, "Reset IlI9342");
  71. WriteReg(0x03, 0b10000001);
  72. vTaskDelay(pdMS_TO_TICKS(20));
  73. WriteReg(0x03, 0b10000011);
  74. vTaskDelay(pdMS_TO_TICKS(10));
  75. }
  76. };
  77. class Ft6336 : public I2cDevice {
  78. public:
  79. struct TouchPoint_t {
  80. int num = 0;
  81. int x = -1;
  82. int y = -1;
  83. };
  84. Ft6336(i2c_master_bus_handle_t i2c_bus, uint8_t addr) : I2cDevice(i2c_bus, addr) {
  85. uint8_t chip_id = ReadReg(0xA3);
  86. ESP_LOGI(TAG, "Get chip ID: 0x%02X", chip_id);
  87. read_buffer_ = new uint8_t[6];
  88. }
  89. ~Ft6336() {
  90. delete[] read_buffer_;
  91. }
  92. void UpdateTouchPoint() {
  93. ReadRegs(0x02, read_buffer_, 6);
  94. tp_.num = read_buffer_[0] & 0x0F;
  95. tp_.x = ((read_buffer_[1] & 0x0F) << 8) | read_buffer_[2];
  96. tp_.y = ((read_buffer_[3] & 0x0F) << 8) | read_buffer_[4];
  97. }
  98. inline const TouchPoint_t& GetTouchPoint() {
  99. return tp_;
  100. }
  101. private:
  102. uint8_t* read_buffer_ = nullptr;
  103. TouchPoint_t tp_;
  104. };
  105. class M5StackCoreS3Board : public WifiBoard {
  106. private:
  107. i2c_master_bus_handle_t i2c_bus_;
  108. Pmic* pmic_;
  109. Aw9523* aw9523_;
  110. Ft6336* ft6336_;
  111. LcdDisplay* display_;
  112. Esp32Camera* camera_;
  113. esp_timer_handle_t touchpad_timer_;
  114. PowerSaveTimer* power_save_timer_;
  115. void InitializePowerSaveTimer() {
  116. power_save_timer_ = new PowerSaveTimer(-1, 60, 300);
  117. power_save_timer_->OnEnterSleepMode([this]() {
  118. ESP_LOGI(TAG, "Enabling sleep mode");
  119. auto display = GetDisplay();
  120. display->SetChatMessage("system", "");
  121. display->SetEmotion("sleepy");
  122. GetBacklight()->SetBrightness(10);
  123. });
  124. power_save_timer_->OnExitSleepMode([this]() {
  125. auto display = GetDisplay();
  126. display->SetChatMessage("system", "");
  127. display->SetEmotion("neutral");
  128. GetBacklight()->RestoreBrightness();
  129. });
  130. power_save_timer_->OnShutdownRequest([this]() {
  131. pmic_->PowerOff();
  132. });
  133. power_save_timer_->SetEnabled(true);
  134. }
  135. void InitializeI2c() {
  136. // Initialize I2C peripheral
  137. i2c_master_bus_config_t i2c_bus_cfg = {
  138. .i2c_port = (i2c_port_t)1,
  139. .sda_io_num = AUDIO_CODEC_I2C_SDA_PIN,
  140. .scl_io_num = AUDIO_CODEC_I2C_SCL_PIN,
  141. .clk_source = I2C_CLK_SRC_DEFAULT,
  142. .glitch_ignore_cnt = 7,
  143. .intr_priority = 0,
  144. .trans_queue_depth = 0,
  145. .flags = {
  146. .enable_internal_pullup = 1,
  147. },
  148. };
  149. ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_cfg, &i2c_bus_));
  150. }
  151. void I2cDetect() {
  152. uint8_t address;
  153. printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f\r\n");
  154. for (int i = 0; i < 128; i += 16) {
  155. printf("%02x: ", i);
  156. for (int j = 0; j < 16; j++) {
  157. fflush(stdout);
  158. address = i + j;
  159. esp_err_t ret = i2c_master_probe(i2c_bus_, address, pdMS_TO_TICKS(200));
  160. if (ret == ESP_OK) {
  161. printf("%02x ", address);
  162. } else if (ret == ESP_ERR_TIMEOUT) {
  163. printf("UU ");
  164. } else {
  165. printf("-- ");
  166. }
  167. }
  168. printf("\r\n");
  169. }
  170. }
  171. void InitializeAxp2101() {
  172. ESP_LOGI(TAG, "Init AXP2101");
  173. pmic_ = new Pmic(i2c_bus_, 0x34);
  174. }
  175. void InitializeAw9523() {
  176. ESP_LOGI(TAG, "Init AW9523");
  177. aw9523_ = new Aw9523(i2c_bus_, 0x58);
  178. vTaskDelay(pdMS_TO_TICKS(50));
  179. }
  180. void PollTouchpad() {
  181. static bool was_touched = false;
  182. static int64_t touch_start_time = 0;
  183. const int64_t TOUCH_THRESHOLD_MS = 500; // 触摸时长阈值,超过500ms视为长按
  184. ft6336_->UpdateTouchPoint();
  185. auto& touch_point = ft6336_->GetTouchPoint();
  186. // 检测触摸开始
  187. if (touch_point.num > 0 && !was_touched) {
  188. was_touched = true;
  189. touch_start_time = esp_timer_get_time() / 1000; // 转换为毫秒
  190. }
  191. // 检测触摸释放
  192. else if (touch_point.num == 0 && was_touched) {
  193. was_touched = false;
  194. int64_t touch_duration = (esp_timer_get_time() / 1000) - touch_start_time;
  195. // 只有短触才触发
  196. if (touch_duration < TOUCH_THRESHOLD_MS) {
  197. auto& app = Application::GetInstance();
  198. if (app.GetDeviceState() == kDeviceStateStarting &&
  199. !WifiStation::GetInstance().IsConnected()) {
  200. ResetWifiConfiguration();
  201. }
  202. app.ToggleChatState();
  203. }
  204. }
  205. }
  206. void InitializeFt6336TouchPad() {
  207. ESP_LOGI(TAG, "Init FT6336");
  208. ft6336_ = new Ft6336(i2c_bus_, 0x38);
  209. // 创建定时器,20ms 间隔
  210. esp_timer_create_args_t timer_args = {
  211. .callback = [](void* arg) {
  212. M5StackCoreS3Board* board = (M5StackCoreS3Board*)arg;
  213. board->PollTouchpad();
  214. },
  215. .arg = this,
  216. .dispatch_method = ESP_TIMER_TASK,
  217. .name = "touchpad_timer",
  218. .skip_unhandled_events = true,
  219. };
  220. ESP_ERROR_CHECK(esp_timer_create(&timer_args, &touchpad_timer_));
  221. ESP_ERROR_CHECK(esp_timer_start_periodic(touchpad_timer_, 20 * 1000));
  222. }
  223. void InitializeSpi() {
  224. spi_bus_config_t buscfg = {};
  225. buscfg.mosi_io_num = GPIO_NUM_37;
  226. buscfg.miso_io_num = GPIO_NUM_NC;
  227. buscfg.sclk_io_num = GPIO_NUM_36;
  228. buscfg.quadwp_io_num = GPIO_NUM_NC;
  229. buscfg.quadhd_io_num = GPIO_NUM_NC;
  230. buscfg.max_transfer_sz = DISPLAY_WIDTH * DISPLAY_HEIGHT * sizeof(uint16_t);
  231. ESP_ERROR_CHECK(spi_bus_initialize(SPI3_HOST, &buscfg, SPI_DMA_CH_AUTO));
  232. }
  233. void InitializeIli9342Display() {
  234. ESP_LOGI(TAG, "Init IlI9342");
  235. esp_lcd_panel_io_handle_t panel_io = nullptr;
  236. esp_lcd_panel_handle_t panel = nullptr;
  237. ESP_LOGD(TAG, "Install panel IO");
  238. esp_lcd_panel_io_spi_config_t io_config = {};
  239. io_config.cs_gpio_num = GPIO_NUM_3;
  240. io_config.dc_gpio_num = GPIO_NUM_35;
  241. io_config.spi_mode = 2;
  242. io_config.pclk_hz = 40 * 1000 * 1000;
  243. io_config.trans_queue_depth = 10;
  244. io_config.lcd_cmd_bits = 8;
  245. io_config.lcd_param_bits = 8;
  246. ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi(SPI3_HOST, &io_config, &panel_io));
  247. ESP_LOGD(TAG, "Install LCD driver");
  248. esp_lcd_panel_dev_config_t panel_config = {};
  249. panel_config.reset_gpio_num = GPIO_NUM_NC;
  250. panel_config.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_BGR;
  251. panel_config.bits_per_pixel = 16;
  252. ESP_ERROR_CHECK(esp_lcd_new_panel_ili9341(panel_io, &panel_config, &panel));
  253. esp_lcd_panel_reset(panel);
  254. aw9523_->ResetIli9342();
  255. esp_lcd_panel_init(panel);
  256. esp_lcd_panel_invert_color(panel, true);
  257. esp_lcd_panel_swap_xy(panel, DISPLAY_SWAP_XY);
  258. esp_lcd_panel_mirror(panel, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y);
  259. display_ = new SpiLcdDisplay(panel_io, panel,
  260. DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY,
  261. {
  262. .text_font = &font_puhui_20_4,
  263. .icon_font = &font_awesome_20_4,
  264. #if CONFIG_USE_WECHAT_MESSAGE_STYLE
  265. .emoji_font = font_emoji_32_init(),
  266. #else
  267. .emoji_font = font_emoji_64_init(),
  268. #endif
  269. });
  270. }
  271. void InitializeCamera() {
  272. // Open camera power
  273. camera_config_t config = {};
  274. config.pin_d0 = CAMERA_PIN_D0;
  275. config.pin_d1 = CAMERA_PIN_D1;
  276. config.pin_d2 = CAMERA_PIN_D2;
  277. config.pin_d3 = CAMERA_PIN_D3;
  278. config.pin_d4 = CAMERA_PIN_D4;
  279. config.pin_d5 = CAMERA_PIN_D5;
  280. config.pin_d6 = CAMERA_PIN_D6;
  281. config.pin_d7 = CAMERA_PIN_D7;
  282. config.pin_xclk = CAMERA_PIN_XCLK;
  283. config.pin_pclk = CAMERA_PIN_PCLK;
  284. config.pin_vsync = CAMERA_PIN_VSYNC;
  285. config.pin_href = CAMERA_PIN_HREF;
  286. config.pin_sccb_sda = CAMERA_PIN_SIOD;
  287. config.pin_sccb_scl = CAMERA_PIN_SIOC;
  288. config.sccb_i2c_port = 1;
  289. config.pin_pwdn = CAMERA_PIN_PWDN;
  290. config.pin_reset = CAMERA_PIN_RESET;
  291. config.xclk_freq_hz = XCLK_FREQ_HZ;
  292. config.pixel_format = PIXFORMAT_RGB565;
  293. config.frame_size = FRAMESIZE_QVGA;
  294. config.jpeg_quality = 12;
  295. config.fb_count = 1;
  296. config.fb_location = CAMERA_FB_IN_PSRAM;
  297. config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
  298. camera_ = new Esp32Camera(config);
  299. }
  300. public:
  301. M5StackCoreS3Board() {
  302. InitializePowerSaveTimer();
  303. InitializeI2c();
  304. InitializeAxp2101();
  305. InitializeAw9523();
  306. I2cDetect();
  307. InitializeSpi();
  308. InitializeIli9342Display();
  309. InitializeCamera();
  310. InitializeFt6336TouchPad();
  311. GetBacklight()->RestoreBrightness();
  312. }
  313. virtual AudioCodec* GetAudioCodec() override {
  314. static CoreS3AudioCodec audio_codec(i2c_bus_,
  315. AUDIO_INPUT_SAMPLE_RATE,
  316. AUDIO_OUTPUT_SAMPLE_RATE,
  317. AUDIO_I2S_GPIO_MCLK,
  318. AUDIO_I2S_GPIO_BCLK,
  319. AUDIO_I2S_GPIO_WS,
  320. AUDIO_I2S_GPIO_DOUT,
  321. AUDIO_I2S_GPIO_DIN,
  322. AUDIO_CODEC_AW88298_ADDR,
  323. AUDIO_CODEC_ES7210_ADDR,
  324. AUDIO_INPUT_REFERENCE);
  325. return &audio_codec;
  326. }
  327. virtual Display* GetDisplay() override {
  328. return display_;
  329. }
  330. virtual Camera* GetCamera() override {
  331. return camera_;
  332. }
  333. virtual bool GetBatteryLevel(int &level, bool& charging, bool& discharging) override {
  334. static bool last_discharging = false;
  335. charging = pmic_->IsCharging();
  336. discharging = pmic_->IsDischarging();
  337. if (discharging != last_discharging) {
  338. power_save_timer_->SetEnabled(discharging);
  339. last_discharging = discharging;
  340. }
  341. level = pmic_->GetBatteryLevel();
  342. return true;
  343. }
  344. virtual void SetPowerSaveMode(bool enabled) override {
  345. if (!enabled) {
  346. power_save_timer_->WakeUp();
  347. }
  348. WifiBoard::SetPowerSaveMode(enabled);
  349. }
  350. virtual Backlight *GetBacklight() override {
  351. static CustomBacklight backlight(pmic_);
  352. return &backlight;
  353. }
  354. };
  355. DECLARE_BOARD(M5StackCoreS3Board);