m5stack_core_s3.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  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 "iot/thing_manager.h"
  9. #include "axp2101.h"
  10. #include <esp_log.h>
  11. #include <driver/i2c_master.h>
  12. #include <wifi_station.h>
  13. #include <esp_lcd_panel_io.h>
  14. #include <esp_lcd_panel_ops.h>
  15. #include <esp_lcd_ili9341.h>
  16. #include <esp_timer.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. esp_timer_handle_t touchpad_timer_;
  113. PowerSaveTimer* power_save_timer_;
  114. void InitializePowerSaveTimer() {
  115. power_save_timer_ = new PowerSaveTimer(-1, 60, 300);
  116. power_save_timer_->OnEnterSleepMode([this]() {
  117. ESP_LOGI(TAG, "Enabling sleep mode");
  118. auto display = GetDisplay();
  119. display->SetChatMessage("system", "");
  120. display->SetEmotion("sleepy");
  121. GetBacklight()->SetBrightness(10);
  122. });
  123. power_save_timer_->OnExitSleepMode([this]() {
  124. auto display = GetDisplay();
  125. display->SetChatMessage("system", "");
  126. display->SetEmotion("neutral");
  127. GetBacklight()->RestoreBrightness();
  128. });
  129. power_save_timer_->OnShutdownRequest([this]() {
  130. pmic_->PowerOff();
  131. });
  132. power_save_timer_->SetEnabled(true);
  133. }
  134. void InitializeI2c() {
  135. // Initialize I2C peripheral
  136. i2c_master_bus_config_t i2c_bus_cfg = {
  137. .i2c_port = (i2c_port_t)1,
  138. .sda_io_num = AUDIO_CODEC_I2C_SDA_PIN,
  139. .scl_io_num = AUDIO_CODEC_I2C_SCL_PIN,
  140. .clk_source = I2C_CLK_SRC_DEFAULT,
  141. .glitch_ignore_cnt = 7,
  142. .intr_priority = 0,
  143. .trans_queue_depth = 0,
  144. .flags = {
  145. .enable_internal_pullup = 1,
  146. },
  147. };
  148. ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_cfg, &i2c_bus_));
  149. }
  150. void I2cDetect() {
  151. uint8_t address;
  152. printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f\r\n");
  153. for (int i = 0; i < 128; i += 16) {
  154. printf("%02x: ", i);
  155. for (int j = 0; j < 16; j++) {
  156. fflush(stdout);
  157. address = i + j;
  158. esp_err_t ret = i2c_master_probe(i2c_bus_, address, pdMS_TO_TICKS(200));
  159. if (ret == ESP_OK) {
  160. printf("%02x ", address);
  161. } else if (ret == ESP_ERR_TIMEOUT) {
  162. printf("UU ");
  163. } else {
  164. printf("-- ");
  165. }
  166. }
  167. printf("\r\n");
  168. }
  169. }
  170. void InitializeAxp2101() {
  171. ESP_LOGI(TAG, "Init AXP2101");
  172. pmic_ = new Pmic(i2c_bus_, 0x34);
  173. }
  174. void InitializeAw9523() {
  175. ESP_LOGI(TAG, "Init AW9523");
  176. aw9523_ = new Aw9523(i2c_bus_, 0x58);
  177. vTaskDelay(pdMS_TO_TICKS(50));
  178. }
  179. void PollTouchpad() {
  180. static bool was_touched = false;
  181. static int64_t touch_start_time = 0;
  182. const int64_t TOUCH_THRESHOLD_MS = 500; // 触摸时长阈值,超过500ms视为长按
  183. ft6336_->UpdateTouchPoint();
  184. auto& touch_point = ft6336_->GetTouchPoint();
  185. // 检测触摸开始
  186. if (touch_point.num > 0 && !was_touched) {
  187. was_touched = true;
  188. touch_start_time = esp_timer_get_time() / 1000; // 转换为毫秒
  189. }
  190. // 检测触摸释放
  191. else if (touch_point.num == 0 && was_touched) {
  192. was_touched = false;
  193. int64_t touch_duration = (esp_timer_get_time() / 1000) - touch_start_time;
  194. // 只有短触才触发
  195. if (touch_duration < TOUCH_THRESHOLD_MS) {
  196. auto& app = Application::GetInstance();
  197. if (app.GetDeviceState() == kDeviceStateStarting &&
  198. !WifiStation::GetInstance().IsConnected()) {
  199. ResetWifiConfiguration();
  200. }
  201. app.ToggleChatState();
  202. }
  203. }
  204. }
  205. void InitializeFt6336TouchPad() {
  206. ESP_LOGI(TAG, "Init FT6336");
  207. ft6336_ = new Ft6336(i2c_bus_, 0x38);
  208. // 创建定时器,20ms 间隔
  209. esp_timer_create_args_t timer_args = {
  210. .callback = [](void* arg) {
  211. M5StackCoreS3Board* board = (M5StackCoreS3Board*)arg;
  212. board->PollTouchpad();
  213. },
  214. .arg = this,
  215. .dispatch_method = ESP_TIMER_TASK,
  216. .name = "touchpad_timer",
  217. .skip_unhandled_events = true,
  218. };
  219. ESP_ERROR_CHECK(esp_timer_create(&timer_args, &touchpad_timer_));
  220. ESP_ERROR_CHECK(esp_timer_start_periodic(touchpad_timer_, 20 * 1000));
  221. }
  222. void InitializeSpi() {
  223. spi_bus_config_t buscfg = {};
  224. buscfg.mosi_io_num = GPIO_NUM_37;
  225. buscfg.miso_io_num = GPIO_NUM_NC;
  226. buscfg.sclk_io_num = GPIO_NUM_36;
  227. buscfg.quadwp_io_num = GPIO_NUM_NC;
  228. buscfg.quadhd_io_num = GPIO_NUM_NC;
  229. buscfg.max_transfer_sz = DISPLAY_WIDTH * DISPLAY_HEIGHT * sizeof(uint16_t);
  230. ESP_ERROR_CHECK(spi_bus_initialize(SPI3_HOST, &buscfg, SPI_DMA_CH_AUTO));
  231. }
  232. void InitializeIli9342Display() {
  233. ESP_LOGI(TAG, "Init IlI9342");
  234. esp_lcd_panel_io_handle_t panel_io = nullptr;
  235. esp_lcd_panel_handle_t panel = nullptr;
  236. ESP_LOGD(TAG, "Install panel IO");
  237. esp_lcd_panel_io_spi_config_t io_config = {};
  238. io_config.cs_gpio_num = GPIO_NUM_3;
  239. io_config.dc_gpio_num = GPIO_NUM_35;
  240. io_config.spi_mode = 2;
  241. io_config.pclk_hz = 40 * 1000 * 1000;
  242. io_config.trans_queue_depth = 10;
  243. io_config.lcd_cmd_bits = 8;
  244. io_config.lcd_param_bits = 8;
  245. ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi(SPI3_HOST, &io_config, &panel_io));
  246. ESP_LOGD(TAG, "Install LCD driver");
  247. esp_lcd_panel_dev_config_t panel_config = {};
  248. panel_config.reset_gpio_num = GPIO_NUM_NC;
  249. panel_config.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_BGR;
  250. panel_config.bits_per_pixel = 16;
  251. ESP_ERROR_CHECK(esp_lcd_new_panel_ili9341(panel_io, &panel_config, &panel));
  252. esp_lcd_panel_reset(panel);
  253. aw9523_->ResetIli9342();
  254. esp_lcd_panel_init(panel);
  255. esp_lcd_panel_invert_color(panel, true);
  256. esp_lcd_panel_swap_xy(panel, DISPLAY_SWAP_XY);
  257. esp_lcd_panel_mirror(panel, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y);
  258. display_ = new SpiLcdDisplay(panel_io, panel,
  259. DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY,
  260. {
  261. .text_font = &font_puhui_20_4,
  262. .icon_font = &font_awesome_20_4,
  263. .emoji_font = font_emoji_64_init(),
  264. });
  265. }
  266. // 物联网初始化,添加对 AI 可见设备
  267. void InitializeIot() {
  268. auto& thing_manager = iot::ThingManager::GetInstance();
  269. thing_manager.AddThing(iot::CreateThing("Speaker"));
  270. thing_manager.AddThing(iot::CreateThing("Backlight"));
  271. thing_manager.AddThing(iot::CreateThing("Battery"));
  272. }
  273. public:
  274. M5StackCoreS3Board() {
  275. InitializePowerSaveTimer();
  276. InitializeI2c();
  277. InitializeAxp2101();
  278. InitializeAw9523();
  279. I2cDetect();
  280. InitializeSpi();
  281. InitializeIli9342Display();
  282. InitializeIot();
  283. InitializeFt6336TouchPad();
  284. GetBacklight()->RestoreBrightness();
  285. }
  286. virtual AudioCodec* GetAudioCodec() override {
  287. static CoreS3AudioCodec audio_codec(i2c_bus_,
  288. AUDIO_INPUT_SAMPLE_RATE,
  289. AUDIO_OUTPUT_SAMPLE_RATE,
  290. AUDIO_I2S_GPIO_MCLK,
  291. AUDIO_I2S_GPIO_BCLK,
  292. AUDIO_I2S_GPIO_WS,
  293. AUDIO_I2S_GPIO_DOUT,
  294. AUDIO_I2S_GPIO_DIN,
  295. AUDIO_CODEC_AW88298_ADDR,
  296. AUDIO_CODEC_ES7210_ADDR,
  297. AUDIO_INPUT_REFERENCE);
  298. return &audio_codec;
  299. }
  300. virtual Display* GetDisplay() override {
  301. return display_;
  302. }
  303. virtual bool GetBatteryLevel(int &level, bool& charging, bool& discharging) override {
  304. static bool last_discharging = false;
  305. charging = pmic_->IsCharging();
  306. discharging = pmic_->IsDischarging();
  307. if (discharging != last_discharging) {
  308. power_save_timer_->SetEnabled(discharging);
  309. last_discharging = discharging;
  310. }
  311. level = pmic_->GetBatteryLevel();
  312. return true;
  313. }
  314. virtual void SetPowerSaveMode(bool enabled) override {
  315. if (!enabled) {
  316. power_save_timer_->WakeUp();
  317. }
  318. WifiBoard::SetPowerSaveMode(enabled);
  319. }
  320. virtual Backlight *GetBacklight() override {
  321. static CustomBacklight backlight(pmic_);
  322. return &backlight;
  323. }
  324. };
  325. DECLARE_BOARD(M5StackCoreS3Board);