|
|
|
@@ -0,0 +1,242 @@
|
|
|
|
|
/* R2 底板 I²C 扫描(临时诊断固件,不是产品固件)。
|
|
|
|
|
|
|
|
|
|
做的事:
|
|
|
|
|
1. 先以 GPIO 输入读 SDA / SCL / MUX_RST# / HUB_RST# 的空闲电平 —— 总线被拉死时 I²C 驱动只会报超时,
|
|
|
|
|
这一步能直接看出是「没上拉」还是「有器件把线拉低」;SDA 被拉低时先打 9 个 SCL 脉冲做总线恢复。
|
|
|
|
|
2. 扫主干 0x08~0x77,认得的地址打出器件名,INA226 / CH224A / TCA9548A 再读一次身份寄存器。
|
|
|
|
|
3. TCA9548A 在的话逐个打开通道 0~7,扫分支(槽 1~5 = 通道 0~4),刀片上的 INA226(0x40) 读身份、
|
|
|
|
|
PCA9555(0x20) 只读输入口 —— **一个输出寄存器都不写**。
|
|
|
|
|
4. 关掉所有通道,每 5 s 重扫一遍(插拔刀片可以直接看)。
|
|
|
|
|
|
|
|
|
|
不碰的脚:HUB_RST#(IO8,只读)—— 控制台就挂在那颗 Hub 上。MUX_RST#(IO40)读完空闲电平后推高,
|
|
|
|
|
保证 mux 不在复位里。其余 GPIO 一律保持复位态。 */
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include "freertos/FreeRTOS.h"
|
|
|
|
|
#include "freertos/task.h"
|
|
|
|
|
#include "driver/gpio.h"
|
|
|
|
|
#include "driver/i2c_master.h"
|
|
|
|
|
#include "esp_rom_sys.h"
|
|
|
|
|
|
|
|
|
|
#define PIN_SDA 41
|
|
|
|
|
#define PIN_SCL 42
|
|
|
|
|
#define PIN_MUX_RST_N 40
|
|
|
|
|
#define PIN_HUB_RST_N 8
|
|
|
|
|
#define MUX_ADDR 0x70
|
|
|
|
|
#define I2C_HZ 100000
|
|
|
|
|
#define TMO_MS 20
|
|
|
|
|
|
|
|
|
|
static i2c_master_bus_handle_t bus;
|
|
|
|
|
|
|
|
|
|
static const char *main_name(uint8_t a)
|
|
|
|
|
{
|
|
|
|
|
switch (a) {
|
|
|
|
|
case 0x70: return "TCA9548A U35 多路器";
|
|
|
|
|
case 0x43: return "INA226 U13 输入检流";
|
|
|
|
|
case 0x4A: return "DAC63204 U6";
|
|
|
|
|
case 0x4B: return "DAC63204 U7";
|
|
|
|
|
case 0x22:
|
|
|
|
|
case 0x23: return "CH224A U36 PD 取电";
|
|
|
|
|
default: return "?? 未预期";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const char *branch_name(uint8_t a)
|
|
|
|
|
{
|
|
|
|
|
switch (a) {
|
|
|
|
|
case 0x40: return "INA226 刀片检流";
|
|
|
|
|
case 0x20: return "PCA9555 刀片 IO 扩展";
|
|
|
|
|
default: return "?? 未预期";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static esp_err_t rd(uint8_t addr, uint8_t reg, uint8_t *buf, size_t n)
|
|
|
|
|
{
|
|
|
|
|
i2c_device_config_t cfg = {
|
|
|
|
|
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
|
|
|
|
|
.device_address = addr,
|
|
|
|
|
.scl_speed_hz = I2C_HZ,
|
|
|
|
|
};
|
|
|
|
|
i2c_master_dev_handle_t dev;
|
|
|
|
|
esp_err_t e = i2c_master_bus_add_device(bus, &cfg, &dev);
|
|
|
|
|
if (e != ESP_OK) {
|
|
|
|
|
return e;
|
|
|
|
|
}
|
|
|
|
|
e = i2c_master_transmit_receive(dev, ®, 1, buf, n, TMO_MS);
|
|
|
|
|
i2c_master_bus_rm_device(dev);
|
|
|
|
|
return e;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static esp_err_t mux_select(uint8_t mask)
|
|
|
|
|
{
|
|
|
|
|
i2c_device_config_t cfg = {
|
|
|
|
|
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
|
|
|
|
|
.device_address = MUX_ADDR,
|
|
|
|
|
.scl_speed_hz = I2C_HZ,
|
|
|
|
|
};
|
|
|
|
|
i2c_master_dev_handle_t dev;
|
|
|
|
|
esp_err_t e = i2c_master_bus_add_device(bus, &cfg, &dev);
|
|
|
|
|
if (e != ESP_OK) {
|
|
|
|
|
return e;
|
|
|
|
|
}
|
|
|
|
|
e = i2c_master_transmit(dev, &mask, 1, TMO_MS);
|
|
|
|
|
uint8_t back = 0xFF;
|
|
|
|
|
if (e == ESP_OK) {
|
|
|
|
|
e = i2c_master_receive(dev, &back, 1, TMO_MS);
|
|
|
|
|
if (e == ESP_OK && back != mask) {
|
|
|
|
|
printf(" ⚠ mux 回读 0x%02X ≠ 写入 0x%02X\n", back, mask);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
i2c_master_bus_rm_device(dev);
|
|
|
|
|
return e;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void pin_levels(const char *when)
|
|
|
|
|
{
|
|
|
|
|
gpio_config_t in = {
|
|
|
|
|
.pin_bit_mask = (1ULL << PIN_SDA) | (1ULL << PIN_SCL) | (1ULL << PIN_HUB_RST_N) | (1ULL << PIN_MUX_RST_N),
|
|
|
|
|
.mode = GPIO_MODE_INPUT,
|
|
|
|
|
.pull_up_en = GPIO_PULLUP_DISABLE,
|
|
|
|
|
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
|
|
|
|
};
|
|
|
|
|
gpio_config(&in);
|
|
|
|
|
printf("[%s] 空闲电平(无内部上拉):SDA=%d SCL=%d HUB_RST#=%d MUX_RST#=%d\n", when,
|
|
|
|
|
gpio_get_level(PIN_SDA), gpio_get_level(PIN_SCL), gpio_get_level(PIN_HUB_RST_N),
|
|
|
|
|
gpio_get_level(PIN_MUX_RST_N));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void bus_recover(void)
|
|
|
|
|
{
|
|
|
|
|
gpio_set_direction(PIN_SCL, GPIO_MODE_INPUT_OUTPUT_OD);
|
|
|
|
|
for (int i = 0; i < 9 && !gpio_get_level(PIN_SDA); i++) {
|
|
|
|
|
gpio_set_level(PIN_SCL, 0);
|
|
|
|
|
esp_rom_delay_us(10);
|
|
|
|
|
gpio_set_level(PIN_SCL, 1);
|
|
|
|
|
esp_rom_delay_us(10);
|
|
|
|
|
}
|
|
|
|
|
gpio_set_direction(PIN_SCL, GPIO_MODE_INPUT);
|
|
|
|
|
printf(" 总线恢复后:SDA=%d SCL=%d\n", gpio_get_level(PIN_SDA), gpio_get_level(PIN_SCL));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 扫一遍,found[] 里放主干上应答的地址(分支扫描时排除它们)。返回应答个数,-1 = 总线超时。 */
|
|
|
|
|
static int scan(uint8_t *found, int maxn, const uint8_t *skip, int nskip, bool branch)
|
|
|
|
|
{
|
|
|
|
|
int n = 0;
|
|
|
|
|
for (uint8_t a = 0x08; a <= 0x77; a++) {
|
|
|
|
|
bool sk = false;
|
|
|
|
|
for (int i = 0; i < nskip; i++) {
|
|
|
|
|
sk |= (skip[i] == a);
|
|
|
|
|
}
|
|
|
|
|
if (sk) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
esp_err_t e = i2c_master_probe(bus, a, TMO_MS);
|
|
|
|
|
if (e == ESP_OK) {
|
|
|
|
|
if (n < maxn) {
|
|
|
|
|
found[n] = a;
|
|
|
|
|
}
|
|
|
|
|
n++;
|
|
|
|
|
printf(" 0x%02X %s\n", a, branch ? branch_name(a) : main_name(a));
|
|
|
|
|
} else if (e == ESP_ERR_TIMEOUT) {
|
|
|
|
|
printf(" 0x%02X 总线超时(SCL 被拉住或无上拉)——停止本轮扫描\n", a);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return n;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void identify(uint8_t a, bool branch)
|
|
|
|
|
{
|
|
|
|
|
uint8_t b[2];
|
|
|
|
|
if (a == 0x43 || (branch && a == 0x40)) {
|
|
|
|
|
uint16_t mid = 0, did = 0;
|
|
|
|
|
if (rd(a, 0xFE, b, 2) == ESP_OK) {
|
|
|
|
|
mid = (b[0] << 8) | b[1];
|
|
|
|
|
}
|
|
|
|
|
if (rd(a, 0xFF, b, 2) == ESP_OK) {
|
|
|
|
|
did = (b[0] << 8) | b[1];
|
|
|
|
|
}
|
|
|
|
|
printf(" INA226@0x%02X 厂商 0x%04X(应 0x5449) 器件 0x%04X(应 0x2260)%s\n", a, mid, did,
|
|
|
|
|
(mid == 0x5449 && did == 0x2260) ? " ✓" : " ✗");
|
|
|
|
|
if (rd(a, 0x02, b, 2) == ESP_OK) {
|
|
|
|
|
printf(" 母线电压 %.3f V\n", ((b[0] << 8) | b[1]) * 1.25e-3);
|
|
|
|
|
}
|
|
|
|
|
} else if (!branch && (a == 0x22 || a == 0x23)) {
|
|
|
|
|
if (rd(a, 0x09, b, 1) == ESP_OK) {
|
|
|
|
|
printf(" CH224A 状态 0x09=0x%02X(bit3 PD 握手%s)\n", b[0], (b[0] & 0x08) ? "成功" : "未成功");
|
|
|
|
|
}
|
|
|
|
|
if (rd(a, 0x50, b, 1) == ESP_OK) {
|
|
|
|
|
printf(" 当前档最大电流 0x50=%u ×50mA = %.2f A\n", b[0], b[0] * 0.05);
|
|
|
|
|
}
|
|
|
|
|
} else if (branch && a == 0x20) {
|
|
|
|
|
if (rd(a, 0x00, b, 2) == ESP_OK) {
|
|
|
|
|
printf(" PCA9555 输入口 P0=0x%02X P1=0x%02X(只读,未写任何输出)\n", b[0], b[1]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void app_main(void)
|
|
|
|
|
{
|
|
|
|
|
vTaskDelay(pdMS_TO_TICKS(1500)); /* 等 USB 控制台枚举 */
|
|
|
|
|
printf("\n==== PhoneRail R2 底板 I2C 扫描 ====\n");
|
|
|
|
|
|
|
|
|
|
pin_levels("上电");
|
|
|
|
|
gpio_set_level(PIN_MUX_RST_N, 1); /* 先定电平再开输出,避免一上来输出 0 把 mux 复位 */
|
|
|
|
|
gpio_set_direction(PIN_MUX_RST_N, GPIO_MODE_INPUT_OUTPUT);
|
|
|
|
|
if (!gpio_get_level(PIN_SDA)) {
|
|
|
|
|
printf(" ⚠ SDA 被拉低,尝试 9 个 SCL 脉冲恢复\n");
|
|
|
|
|
bus_recover();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
i2c_master_bus_config_t bc = {
|
|
|
|
|
.i2c_port = 0,
|
|
|
|
|
.sda_io_num = PIN_SDA,
|
|
|
|
|
.scl_io_num = PIN_SCL,
|
|
|
|
|
.clk_source = I2C_CLK_SRC_DEFAULT,
|
|
|
|
|
.glitch_ignore_cnt = 7,
|
|
|
|
|
.flags.enable_internal_pullup = false, /* 板上 R602/R603 4.7k 上拉 */
|
|
|
|
|
};
|
|
|
|
|
ESP_ERROR_CHECK(i2c_new_master_bus(&bc, &bus));
|
|
|
|
|
|
|
|
|
|
for (int round = 1;; round++) {
|
|
|
|
|
printf("\n---- 第 %d 轮 ----\n主干(期望 0x22/23 CH224A、0x43 INA226、0x4A/4B DAC、0x70 TCA9548A):\n", round);
|
|
|
|
|
uint8_t main_found[16];
|
|
|
|
|
int nm = scan(main_found, 16, NULL, 0, false);
|
|
|
|
|
if (nm < 0) {
|
|
|
|
|
i2c_master_bus_reset(bus);
|
|
|
|
|
} else {
|
|
|
|
|
printf(" 主干共 %d 个应答\n", nm);
|
|
|
|
|
for (int i = 0; i < nm && i < 16; i++) {
|
|
|
|
|
identify(main_found[i], false);
|
|
|
|
|
}
|
|
|
|
|
bool mux = false;
|
|
|
|
|
for (int i = 0; i < nm && i < 16; i++) {
|
|
|
|
|
mux |= (main_found[i] == MUX_ADDR);
|
|
|
|
|
}
|
|
|
|
|
if (!mux) {
|
|
|
|
|
printf(" ✗ 0x70 TCA9548A 不应答 —— 刀片分支扫不了\n");
|
|
|
|
|
} else {
|
|
|
|
|
for (int ch = 0; ch < 8; ch++) {
|
|
|
|
|
if (mux_select(1u << ch) != ESP_OK) {
|
|
|
|
|
printf(" 通道 %d:选通失败\n", ch);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
printf(" 通道 %d%s:\n", ch, ch < 5 ? (const char *[]){"(槽 1)", "(槽 2)", "(槽 3)", "(槽 4)", "(槽 5)"}[ch] : "");
|
|
|
|
|
uint8_t bf[16];
|
|
|
|
|
int nb = scan(bf, 16, main_found, nm < 16 ? nm : 16, true);
|
|
|
|
|
if (nb == 0) {
|
|
|
|
|
printf(" (空)\n");
|
|
|
|
|
}
|
|
|
|
|
for (int i = 0; i < nb && i < 16; i++) {
|
|
|
|
|
identify(bf[i], true);
|
|
|
|
|
}
|
|
|
|
|
if (nb < 0) {
|
|
|
|
|
i2c_master_bus_reset(bus);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
mux_select(0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
vTaskDelay(pdMS_TO_TICKS(5000));
|
|
|
|
|
}
|
|
|
|
|
}
|