文件
zhou yang和Claude Opus 5.5 b8ad69681f 固件:R2 迁移 R-0 ~ R-6(底板 + 5 片同构刀片)
2026-09-16 完成、当时未提交,这里补提交(原样,不含 09-27 上板的修改)。

- 器件层 / 拓扑层整体从 R1 换到 R2:TCA9548A 分通道、五路同址 INA226 0x40 + 输入侧 0x43、
  刀片 PCA9555(VBUS_EN 挪到 P0.4)、CH224A 只读驱动、风扇闭环 t_thermal
- 新增 i2cbus(mux 原子事务)、slot(刀片 I/O 门面)、host/qtest.sh
- 74HC595 链退役(代码与测试保留)
- 判据阈值与时间常量未动;19 个 ctest 全绿,idf.py build 通过

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-27 10:26:24 +08:00

76 行
2.1 KiB
C

/* TCA9548A 驱动。只经 hal_i2c_*,不碰任何平台头文件。契约见 tca9548a.h。 */
#include "tca9548a.h"
#include <stddef.h>
#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; /* 到不了 */
}