atoms3r_cam_m12_echo_base.cc 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. #include "wifi_board.h"
  2. #include "codecs/es8311_audio_codec.h"
  3. #include "application.h"
  4. #include "button.h"
  5. #include "config.h"
  6. #include "i2c_device.h"
  7. #include "assets/lang_config.h"
  8. #include <esp_log.h>
  9. #include <driver/i2c_master.h>
  10. #include <wifi_station.h>
  11. #include "esp32_camera.h"
  12. #define TAG "AtomS3R CAM/M12 + EchoBase"
  13. #define PI4IOE_ADDR 0x43
  14. #define PI4IOE_REG_CTRL 0x00
  15. #define PI4IOE_REG_IO_PP 0x07
  16. #define PI4IOE_REG_IO_DIR 0x03
  17. #define PI4IOE_REG_IO_OUT 0x05
  18. #define PI4IOE_REG_IO_PULLUP 0x0D
  19. class Pi4ioe : public I2cDevice {
  20. public:
  21. Pi4ioe(i2c_master_bus_handle_t i2c_bus, uint8_t addr) : I2cDevice(i2c_bus, addr) {
  22. WriteReg(PI4IOE_REG_IO_PP, 0x00); // Set to high-impedance
  23. WriteReg(PI4IOE_REG_IO_PULLUP, 0xFF); // Enable pull-up
  24. WriteReg(PI4IOE_REG_IO_DIR, 0x6E); // Set input=0, output=1
  25. WriteReg(PI4IOE_REG_IO_OUT, 0xFF); // Set outputs to 1
  26. }
  27. void SetSpeakerMute(bool mute) {
  28. WriteReg(PI4IOE_REG_IO_OUT, mute ? 0x00 : 0xFF);
  29. }
  30. };
  31. class AtomS3rCamM12EchoBaseBoard : public WifiBoard {
  32. private:
  33. i2c_master_bus_handle_t i2c_bus_;
  34. Pi4ioe* pi4ioe_ = nullptr;
  35. bool is_echo_base_connected_ = false;
  36. Esp32Camera* camera_;
  37. void InitializeI2c() {
  38. // Initialize I2C peripheral
  39. i2c_master_bus_config_t i2c_bus_cfg = {
  40. .i2c_port = I2C_NUM_0,
  41. .sda_io_num = AUDIO_CODEC_I2C_SDA_PIN,
  42. .scl_io_num = AUDIO_CODEC_I2C_SCL_PIN,
  43. .clk_source = I2C_CLK_SRC_DEFAULT,
  44. .glitch_ignore_cnt = 7,
  45. .intr_priority = 0,
  46. .trans_queue_depth = 0,
  47. .flags = {
  48. .enable_internal_pullup = 1,
  49. },
  50. };
  51. ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_cfg, &i2c_bus_));
  52. }
  53. void I2cDetect() {
  54. is_echo_base_connected_ = false;
  55. uint8_t echo_base_connected_flag = 0x00;
  56. uint8_t address;
  57. printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f\r\n");
  58. for (int i = 0; i < 128; i += 16) {
  59. printf("%02x: ", i);
  60. for (int j = 0; j < 16; j++) {
  61. fflush(stdout);
  62. address = i + j;
  63. esp_err_t ret = i2c_master_probe(i2c_bus_, address, pdMS_TO_TICKS(200));
  64. if (ret == ESP_OK) {
  65. printf("%02x ", address);
  66. if (address == 0x18) {
  67. echo_base_connected_flag |= 0xF0;
  68. } else if (address == 0x43) {
  69. echo_base_connected_flag |= 0x0F;
  70. }
  71. } else if (ret == ESP_ERR_TIMEOUT) {
  72. printf("UU ");
  73. } else {
  74. printf("-- ");
  75. }
  76. }
  77. printf("\r\n");
  78. }
  79. is_echo_base_connected_ = (echo_base_connected_flag == 0xFF);
  80. }
  81. void CheckEchoBaseConnection() {
  82. if (is_echo_base_connected_) {
  83. return;
  84. }
  85. while (1) {
  86. ESP_LOGE(TAG, "Atomic Echo Base is disconnected");
  87. vTaskDelay(pdMS_TO_TICKS(1000));
  88. // Rerun detection
  89. I2cDetect();
  90. if (is_echo_base_connected_) {
  91. vTaskDelay(pdMS_TO_TICKS(500));
  92. I2cDetect();
  93. if (is_echo_base_connected_) {
  94. ESP_LOGI(TAG, "Atomic Echo Base is reconnected");
  95. vTaskDelay(pdMS_TO_TICKS(200));
  96. esp_restart();
  97. }
  98. }
  99. }
  100. }
  101. void InitializePi4ioe() {
  102. ESP_LOGI(TAG, "Init PI4IOE");
  103. pi4ioe_ = new Pi4ioe(i2c_bus_, PI4IOE_ADDR);
  104. pi4ioe_->SetSpeakerMute(false);
  105. }
  106. void EnableCameraPower() {
  107. gpio_reset_pin((gpio_num_t)18);
  108. gpio_set_direction((gpio_num_t)18, GPIO_MODE_OUTPUT);
  109. gpio_set_pull_mode((gpio_num_t)18, GPIO_PULLDOWN_ONLY);
  110. ESP_LOGI(TAG, "Camera Power Enabled");
  111. vTaskDelay(pdMS_TO_TICKS(300));
  112. }
  113. void InitializeCamera() {
  114. camera_config_t config = {};
  115. config.pin_d0 = CAMERA_PIN_D0;
  116. config.pin_d1 = CAMERA_PIN_D1;
  117. config.pin_d2 = CAMERA_PIN_D2;
  118. config.pin_d3 = CAMERA_PIN_D3;
  119. config.pin_d4 = CAMERA_PIN_D4;
  120. config.pin_d5 = CAMERA_PIN_D5;
  121. config.pin_d6 = CAMERA_PIN_D6;
  122. config.pin_d7 = CAMERA_PIN_D7;
  123. config.pin_xclk = CAMERA_PIN_XCLK;
  124. config.pin_pclk = CAMERA_PIN_PCLK;
  125. config.pin_vsync = CAMERA_PIN_VSYNC;
  126. config.pin_href = CAMERA_PIN_HREF;
  127. config.pin_sccb_sda = CAMERA_PIN_SIOD;
  128. config.pin_sccb_scl = CAMERA_PIN_SIOC;
  129. config.sccb_i2c_port = 1;
  130. config.pin_pwdn = CAMERA_PIN_PWDN;
  131. config.pin_reset = CAMERA_PIN_RESET;
  132. config.xclk_freq_hz = XCLK_FREQ_HZ;
  133. config.pixel_format = PIXFORMAT_RGB565;
  134. config.frame_size = FRAMESIZE_QVGA;
  135. config.jpeg_quality = 12;
  136. config.fb_count = 1;
  137. config.fb_location = CAMERA_FB_IN_PSRAM;
  138. config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
  139. camera_ = new Esp32Camera(config);
  140. camera_->SetHMirror(false);
  141. }
  142. virtual Camera* GetCamera() override {
  143. return camera_;
  144. }
  145. public:
  146. AtomS3rCamM12EchoBaseBoard() {
  147. EnableCameraPower(); // IO18 还会控制指示灯
  148. InitializeCamera();
  149. InitializeI2c();
  150. I2cDetect();
  151. CheckEchoBaseConnection();
  152. InitializePi4ioe();
  153. }
  154. virtual AudioCodec* GetAudioCodec() override {
  155. static Es8311AudioCodec audio_codec(
  156. i2c_bus_,
  157. I2C_NUM_0,
  158. AUDIO_INPUT_SAMPLE_RATE,
  159. AUDIO_OUTPUT_SAMPLE_RATE,
  160. AUDIO_I2S_GPIO_MCLK,
  161. AUDIO_I2S_GPIO_BCLK,
  162. AUDIO_I2S_GPIO_WS,
  163. AUDIO_I2S_GPIO_DOUT,
  164. AUDIO_I2S_GPIO_DIN,
  165. AUDIO_CODEC_GPIO_PA,
  166. AUDIO_CODEC_ES8311_ADDR,
  167. false);
  168. return &audio_codec;
  169. }
  170. };
  171. DECLARE_BOARD(AtomS3rCamM12EchoBaseBoard);