/* TCA9548A 驱动。只经 hal_i2c_*,不碰任何平台头文件。契约见 tca9548a.h。 */ #include "tca9548a.h" #include #include "hal_i2c.h" bool tca9548a_addr_ok(void) { /* 同一条主干上的其它器件。撞上任何一个都是硬件表被改坏了。 ⚠️ 0x40 / 0x20 **不在**这张表里:它们在 mux 的支路上,与主干不冲突 —— 这正是 D8 的全部意义。 */ static const uint8_t others[] = { 0x43, 0x4A, 0x4B }; if (TCA9548A_ADDR > 0x7f) { return false; } for (size_t i = 0; i < sizeof(others); i++) { if (others[i] == TCA9548A_ADDR) { return false; } } return true; } hal_err_t tca9548a_select(uint8_t addr, int ch) { if (ch < TCA9548A_CH_NONE || ch >= TCA9548A_CH_COUNT) { return HAL_ERR_ARG; } /* 一个字节,**没有寄存器指针**(文件头第 1 条)。 */ const uint8_t mask = (ch == TCA9548A_CH_NONE) ? 0u : (uint8_t)(1u << ch); return hal_i2c_write(addr, &mask, 1); } hal_err_t tca9548a_read_mask(uint8_t addr, uint8_t *mask) { if (mask == NULL) { return HAL_ERR_ARG; } return hal_i2c_read(addr, mask, 1); } hal_err_t tca9548a_probe(uint8_t addr) { hal_err_t err = tca9548a_select(addr, TCA9548A_CH_NONE); if (err != HAL_OK) { return err; } uint8_t mask = 0xFF; err = tca9548a_read_mask(addr, &mask); if (err != HAL_OK) { return err; } /* 刚被写成全关的器件读回来必须是 0。不是的话要么这地址上蹲着别的东西, 要么写根本没生效 —— 后者在真板上是「所有刀片都读不到」, 而这里能在启动自检时就叫出来。 */ return (mask == 0) ? HAL_OK : HAL_ERR_BUS; } int tca9548a_mask_to_ch(uint8_t mask) { if (mask == 0) { return TCA9548A_CH_NONE; } if ((mask & (uint8_t)(mask - 1u)) != 0) { return -2; /* 多于一位:见文件头第 2 条 */ } for (int ch = 0; ch < TCA9548A_CH_COUNT; ch++) { if (mask == (uint8_t)(1u << ch)) { return ch; } } return -2; /* 到不了 */ }