Browse Source

重新配置QMI8658A和QMC6309的IIC引脚到对应硬件连接引脚,编译通过,测试后初始化成功

corvin_zhang 3 weeks ago
parent
commit
2167ae5caa

+ 4 - 2
guguji_real_robot/docs/real_robot_deployment_guide.md

@@ -38,8 +38,8 @@
 
 I2C 默认连接:
 
-- `GPIO8` -> SDA
-- `GPIO9` -> SCL
+- `GPIO10` -> SDA
+- `GPIO11` -> SCL
 - QMI8658A 默认地址 `0x6B`
 - QMC6309 默认地址 `0x7C`
 
@@ -49,6 +49,8 @@ I2C 默认连接:
 guguji_real_robot/firmware/esp32s3_espidf/main/config.h
 ```
 
+固件启动时会扫描 I2C 总线。正常情况下,串口日志里应该至少看到 QMI8658A 的 `0x6A/0x6B` 之一,以及 QMC6309 的 `0x7C`。如果两个传感器都返回同一个异常 ID,通常先检查 SDA/SCL 引脚定义和接线。
+
 ## 3. 电机准备
 
 RS00 手册说明电机默认 CAN 波特率为 1Mbps。本固件也按 1Mbps 初始化 TWAI。

+ 13 - 1
guguji_real_robot/firmware/esp32s3_espidf/README.md

@@ -23,7 +23,7 @@
 - UDP 命令端口:`7777`
 - UDP 遥测回传:发给最近一次命令来源地址
 - TWAI/CAN:1Mbps,控制 RS00 MIT 协议电机
-- I2C:读取 QMI8658A 和 QMC6309
+- I2C:`GPIO10=SDA`、`GPIO11=SCL`,读取 QMI8658A 和 QMC6309
 - GPIO42:无源蜂鸣器状态提示
 - GPIO45:WS2812 RGB LED 状态提示
 - 20ms 控制周期,200ms 命令超时停止电机
@@ -83,6 +83,18 @@ idf.py -p /dev/ttyUSB0 flash monitor
 硬件内存: Flash=16MB, PSRAM=8MB, PSRAM可用=xxxxKB
 ```
 
+传感器启动日志中应看到 I2C 扫描和初始化结果:
+
+```text
+I2C 配置: port=0 SDA=GPIO10 SCL=GPIO11 freq=100000Hz
+I2C 扫描发现设备: 0x6B
+I2C 扫描发现设备: 0x7C
+QMI8658A 初始化成功: address=0x6B who_am_i=0x05
+QMC6309 初始化成功: address=0x7C chip_id=0x90
+```
+
+如果扫描不到 `0x6A/0x6B` 或 `0x7C`,优先检查 SDA/SCL 是否接反、3.3V/GND 是否共地、I2C 是否有外部上拉电阻。
+
 ## OTA 升级
 
 第一次启用 OTA 需要通过 USB 烧录新的双分区表。以后在 WiFi 下运行:

+ 5 - 4
guguji_real_robot/firmware/esp32s3_espidf/main/config.h

@@ -30,11 +30,12 @@
 #define GUGUJI_WS2812_GPIO GPIO_NUM_45
 
 #define GUGUJI_I2C_PORT I2C_NUM_0
-#define GUGUJI_I2C_SDA_GPIO GPIO_NUM_8
-#define GUGUJI_I2C_SCL_GPIO GPIO_NUM_9
-#define GUGUJI_I2C_FREQ_HZ 400000
+#define GUGUJI_I2C_SDA_GPIO GPIO_NUM_10
+#define GUGUJI_I2C_SCL_GPIO GPIO_NUM_11
+// 机器人内部线束比开发板跳线更容易受干扰,先用 100kHz 提高上电调试稳定性。
+#define GUGUJI_I2C_FREQ_HZ 100000
 
-// QMI8658A 常见地址为 0x6A 或 0x6B;若初始化失败,先改这里
+// QMI8658A 常见地址为 0x6A 或 0x6B;启动时会自动兼容探测另一个地址
 #define GUGUJI_QMI8658A_ADDR 0x6B
 // QMC6309 数据手册给出的 7-bit 地址为 0x7C。
 #define GUGUJI_QMC6309_ADDR 0x7C

+ 168 - 46
guguji_real_robot/firmware/esp32s3_espidf/main/sensors.c

@@ -16,12 +16,16 @@ static const char *TAG = "guguji_sensors";
 #define QMI_REG_CTRL5 0x06
 #define QMI_REG_CTRL7 0x08
 #define QMI_REG_DATA_START 0x35
+#define QMI_EXPECTED_WHO_AM_I 0x05
 
 #define QMC_REG_CHIP_ID 0x00
 #define QMC_REG_DATA_START 0x01
 #define QMC_REG_STATUS 0x09
 #define QMC_REG_CTRL1 0x0A
 #define QMC_REG_CTRL2 0x0B
+#define QMC_EXPECTED_CHIP_ID 0x90
+
+#define I2C_XFER_TIMEOUT_MS 50
 
 static bool g_qmi_ok = false;
 static bool g_qmc_ok = false;
@@ -32,12 +36,12 @@ static i2c_master_dev_handle_t g_qmc_device = NULL;
 static esp_err_t i2c_write_u8(i2c_master_dev_handle_t device, uint8_t reg, uint8_t value)
 {
     uint8_t payload[2] = {reg, value};
-    return i2c_master_transmit(device, payload, sizeof(payload), 50);
+    return i2c_master_transmit(device, payload, sizeof(payload), I2C_XFER_TIMEOUT_MS);
 }
 
 static esp_err_t i2c_read(i2c_master_dev_handle_t device, uint8_t reg, uint8_t *data, size_t length)
 {
-    return i2c_master_transmit_receive(device, &reg, 1, data, length, 50);
+    return i2c_master_transmit_receive(device, &reg, 1, data, length, I2C_XFER_TIMEOUT_MS);
 }
 
 static int16_t le_i16(const uint8_t *data)
@@ -45,65 +49,183 @@ static int16_t le_i16(const uint8_t *data)
     return (int16_t)((uint16_t)data[0] | ((uint16_t)data[1] << 8));
 }
 
-esp_err_t guguji_sensors_init(void)
+static bool address_already_tried(const uint8_t *addresses, size_t current_index, uint8_t address)
 {
-    i2c_master_bus_config_t bus_config = {
-        .i2c_port = GUGUJI_I2C_PORT,
-        .sda_io_num = GUGUJI_I2C_SDA_GPIO,
-        .scl_io_num = GUGUJI_I2C_SCL_GPIO,
-        .clk_source = I2C_CLK_SRC_DEFAULT,
-        .glitch_ignore_cnt = 7,
-        .flags.enable_internal_pullup = true,
-    };
-    ESP_RETURN_ON_ERROR(i2c_new_master_bus(&bus_config, &g_i2c_bus), TAG, "创建 I2C master bus 失败");
+    for (size_t i = 0; i < current_index; ++i) {
+        if (addresses[i] == address) {
+            return true;
+        }
+    }
+    return false;
+}
 
-    i2c_device_config_t qmi_config = {
-        .dev_addr_length = I2C_ADDR_BIT_LEN_7,
-        .device_address = GUGUJI_QMI8658A_ADDR,
-        .scl_speed_hz = GUGUJI_I2C_FREQ_HZ,
-    };
-    ESP_RETURN_ON_ERROR(
-        i2c_master_bus_add_device(g_i2c_bus, &qmi_config, &g_qmi_device),
+static void log_i2c_bus_scan(void)
+{
+    int found_count = 0;
+    ESP_LOGI(
         TAG,
-        "添加 QMI8658A I2C 设备失败");
+        "I2C 配置: port=%d SDA=GPIO%d SCL=GPIO%d freq=%dHz",
+        (int)GUGUJI_I2C_PORT,
+        (int)GUGUJI_I2C_SDA_GPIO,
+        (int)GUGUJI_I2C_SCL_GPIO,
+        GUGUJI_I2C_FREQ_HZ);
 
-    i2c_device_config_t qmc_config = {
+    // QMC6309 使用 0x7C 这个较高的 7-bit 地址,所以扫描范围包含到 0x7E。
+    for (uint8_t address = 0x03; address <= 0x7E; ++address) {
+        if (i2c_master_probe(g_i2c_bus, address, 20) == ESP_OK) {
+            ESP_LOGI(TAG, "I2C 扫描发现设备: 0x%02X", address);
+            ++found_count;
+        }
+    }
+
+    if (found_count == 0) {
+        ESP_LOGW(TAG, "I2C 扫描未发现设备,请检查 SDA/SCL、3.3V、GND 和上拉电阻");
+    }
+}
+
+static esp_err_t add_i2c_device(uint8_t address, i2c_master_dev_handle_t *device)
+{
+    i2c_device_config_t config = {
         .dev_addr_length = I2C_ADDR_BIT_LEN_7,
-        .device_address = GUGUJI_QMC6309_ADDR,
+        .device_address = address,
         .scl_speed_hz = GUGUJI_I2C_FREQ_HZ,
     };
-    ESP_RETURN_ON_ERROR(
-        i2c_master_bus_add_device(g_i2c_bus, &qmc_config, &g_qmc_device),
-        TAG,
-        "添加 QMC6309 I2C 设备失败");
+    return i2c_master_bus_add_device(g_i2c_bus, &config, device);
+}
+
+static bool try_init_qmi8658a(uint8_t address)
+{
+    i2c_master_dev_handle_t device = NULL;
+    esp_err_t err = add_i2c_device(address, &device);
+    if (err != ESP_OK) {
+        ESP_LOGW(TAG, "添加 QMI8658A 候选地址 0x%02X 失败: %s", address, esp_err_to_name(err));
+        return false;
+    }
 
     uint8_t who_am_i = 0;
-    if (i2c_read(g_qmi_device, QMI_REG_WHO_AM_I, &who_am_i, 1) == ESP_OK && who_am_i == 0x05) {
-        // CTRL1: 开启地址自增并使用 little-endian,方便一次读完 AX~GZ。
-        i2c_write_u8(g_qmi_device, QMI_REG_CTRL1, 0x40);
-        // CTRL2: 加速度 ±8g,ODR 约 112Hz;CTRL3: 陀螺仪 ±512dps,ODR 约 112Hz。
-        i2c_write_u8(g_qmi_device, QMI_REG_CTRL2, 0x26);
-        i2c_write_u8(g_qmi_device, QMI_REG_CTRL3, 0x56);
+    err = i2c_read(device, QMI_REG_WHO_AM_I, &who_am_i, 1);
+    if (err != ESP_OK || who_am_i != QMI_EXPECTED_WHO_AM_I) {
+        if (err == ESP_OK) {
+            ESP_LOGW(TAG, "QMI8658A 地址 0x%02X ID 不匹配: who_am_i=0x%02X", address, who_am_i);
+        } else {
+            ESP_LOGW(TAG, "QMI8658A 地址 0x%02X 读取 ID 失败: %s", address, esp_err_to_name(err));
+        }
+        i2c_master_bus_rm_device(device);
+        return false;
+    }
+
+    // CTRL1: 开启地址自增并使用 little-endian,方便一次读完 AX~GZ。
+    err = i2c_write_u8(device, QMI_REG_CTRL1, 0x40);
+    if (err == ESP_OK) {
+        // CTRL2: 加速度 ±8g,ODR 约 112Hz。
+        err = i2c_write_u8(device, QMI_REG_CTRL2, 0x26);
+    }
+    if (err == ESP_OK) {
+        // CTRL3: 陀螺仪 ±512dps,ODR 约 112Hz。
+        err = i2c_write_u8(device, QMI_REG_CTRL3, 0x56);
+    }
+    if (err == ESP_OK) {
         // 打开加速度和陀螺仪低通滤波。
-        i2c_write_u8(g_qmi_device, QMI_REG_CTRL5, 0x11);
+        err = i2c_write_u8(device, QMI_REG_CTRL5, 0x11);
+    }
+    if (err == ESP_OK) {
         // 使能 accel + gyro。
-        i2c_write_u8(g_qmi_device, QMI_REG_CTRL7, 0x03);
-        g_qmi_ok = true;
-        ESP_LOGI(TAG, "QMI8658A 初始化成功");
-    } else {
-        ESP_LOGW(TAG, "QMI8658A 初始化失败,who_am_i=0x%02X", who_am_i);
+        err = i2c_write_u8(device, QMI_REG_CTRL7, 0x03);
+    }
+
+    if (err != ESP_OK) {
+        ESP_LOGW(TAG, "QMI8658A 地址 0x%02X 配置失败: %s", address, esp_err_to_name(err));
+        i2c_master_bus_rm_device(device);
+        return false;
+    }
+
+    g_qmi_device = device;
+    g_qmi_ok = true;
+    ESP_LOGI(TAG, "QMI8658A 初始化成功: address=0x%02X who_am_i=0x%02X", address, who_am_i);
+    return true;
+}
+
+static bool try_init_qmc6309(uint8_t address)
+{
+    i2c_master_dev_handle_t device = NULL;
+    esp_err_t err = add_i2c_device(address, &device);
+    if (err != ESP_OK) {
+        ESP_LOGW(TAG, "添加 QMC6309 候选地址 0x%02X 失败: %s", address, esp_err_to_name(err));
+        return false;
     }
 
     uint8_t chip_id = 0;
-    if (i2c_read(g_qmc_device, QMC_REG_CHIP_ID, &chip_id, 1) == ESP_OK && chip_id == 0x90) {
-        // 数据手册推荐的连续测量配置:32Gauss 量程、Set/Reset 开、OSR1/OSR2=8。
-        i2c_write_u8(g_qmc_device, QMC_REG_CTRL2, 0x00);
-        i2c_write_u8(g_qmc_device, QMC_REG_CTRL1, 0x63);
-        g_qmc_ok = true;
-        ESP_LOGI(TAG, "QMC6309 初始化成功");
-    } else {
-        ESP_LOGW(TAG, "QMC6309 初始化失败,chip_id=0x%02X", chip_id);
+    err = i2c_read(device, QMC_REG_CHIP_ID, &chip_id, 1);
+    if (err != ESP_OK || chip_id != QMC_EXPECTED_CHIP_ID) {
+        if (err == ESP_OK) {
+            ESP_LOGW(TAG, "QMC6309 地址 0x%02X ID 不匹配: chip_id=0x%02X", address, chip_id);
+        } else {
+            ESP_LOGW(TAG, "QMC6309 地址 0x%02X 读取 ID 失败: %s", address, esp_err_to_name(err));
+        }
+        i2c_master_bus_rm_device(device);
+        return false;
+    }
+
+    // 数据手册推荐的连续测量配置:32Gauss 量程、Set/Reset 开、OSR1/OSR2=8。
+    err = i2c_write_u8(device, QMC_REG_CTRL2, 0x00);
+    if (err == ESP_OK) {
+        err = i2c_write_u8(device, QMC_REG_CTRL1, 0x63);
     }
+    if (err != ESP_OK) {
+        ESP_LOGW(TAG, "QMC6309 地址 0x%02X 配置失败: %s", address, esp_err_to_name(err));
+        i2c_master_bus_rm_device(device);
+        return false;
+    }
+
+    g_qmc_device = device;
+    g_qmc_ok = true;
+    ESP_LOGI(TAG, "QMC6309 初始化成功: address=0x%02X chip_id=0x%02X", address, chip_id);
+    return true;
+}
+
+static void init_qmi8658a(void)
+{
+    const uint8_t addresses[] = {GUGUJI_QMI8658A_ADDR, 0x6A, 0x6B};
+    for (size_t i = 0; i < sizeof(addresses) / sizeof(addresses[0]); ++i) {
+        if (address_already_tried(addresses, i, addresses[i])) {
+            continue;
+        }
+        if (try_init_qmi8658a(addresses[i])) {
+            return;
+        }
+    }
+    ESP_LOGW(TAG, "QMI8658A 初始化失败,请检查地址、供电、接线和芯片型号");
+}
+
+static void init_qmc6309(void)
+{
+    const uint8_t addresses[] = {GUGUJI_QMC6309_ADDR, 0x7C, 0x3E};
+    for (size_t i = 0; i < sizeof(addresses) / sizeof(addresses[0]); ++i) {
+        if (address_already_tried(addresses, i, addresses[i])) {
+            continue;
+        }
+        if (try_init_qmc6309(addresses[i])) {
+            return;
+        }
+    }
+    ESP_LOGW(TAG, "QMC6309 初始化失败,请检查地址、供电、接线和芯片型号");
+}
+
+esp_err_t guguji_sensors_init(void)
+{
+    i2c_master_bus_config_t bus_config = {
+        .i2c_port = GUGUJI_I2C_PORT,
+        .sda_io_num = GUGUJI_I2C_SDA_GPIO,
+        .scl_io_num = GUGUJI_I2C_SCL_GPIO,
+        .clk_source = I2C_CLK_SRC_DEFAULT,
+        .glitch_ignore_cnt = 7,
+        .flags.enable_internal_pullup = true,
+    };
+    ESP_RETURN_ON_ERROR(i2c_new_master_bus(&bus_config, &g_i2c_bus), TAG, "创建 I2C master bus 失败");
+
+    log_i2c_bus_scan();
+    init_qmi8658a();
+    init_qmc6309();
 
     return ESP_OK;
 }