/* A3:INA226 驱动 + 六片地址表。 两个验收主项:①六个地址就是 0x40/41/44/45/42/43;②通道号 ≠ 地址低位。 */ #include "ina226.h" #include "sim_hal.h" #include "unity.h" void setUp(void) { sim_hal_reset(); } void tearDown(void) {} /* 挂一片假 INA226 并预置 ID,返回地址。 */ static uint8_t mount(uint8_t addr) { sim_i2c_add(addr, 2); sim_i2c_set_reg(addr, INA226_REG_MFG_ID, INA226_MFG_ID); sim_i2c_set_reg(addr, INA226_REG_DIE_ID, INA226_DIE_ID); TEST_ASSERT_EQUAL_INT(HAL_OK, hal_i2c_init(NULL)); return addr; } /* ---- 地址表 -------------------------------------------------------------- */ /* ⭐ 验收主项一:设计文档 §8.2 的六个地址,逐个钉死。 */ static void test_addr_table_is_the_one_from_8_2(void) { TEST_ASSERT_EQUAL_HEX8(0x40, ina226_rail_addr(1)); TEST_ASSERT_EQUAL_HEX8(0x41, ina226_rail_addr(2)); TEST_ASSERT_EQUAL_HEX8(0x44, ina226_rail_addr(3)); TEST_ASSERT_EQUAL_HEX8(0x45, ina226_rail_addr(4)); TEST_ASSERT_EQUAL_HEX8(0x42, ina226_rail_addr(5)); TEST_ASSERT_EQUAL_HEX8(0x43, INA226_ADDR_INPUT); static const uint8_t want[INA226_COUNT] = { 0x40, 0x41, 0x44, 0x45, 0x42, 0x43 }; TEST_ASSERT_EQUAL_HEX8_ARRAY(want, ina226_all_addr, INA226_COUNT); } /* ⭐ 验收主项二:`0x40 + ch` 这行代码一定会被写出来(需求 §10.4), 这条测试就是拦它的 —— 五路里有三路对不上,把表改成算式必红。 */ static void test_channel_index_is_not_the_address_low_bits(void) { int mismatches = 0; for (int rail = 1; rail <= INA226_RAIL_COUNT; rail++) { uint8_t naive = (uint8_t)(0x40 + (rail - 1)); if (ina226_rail_addr(rail) != naive) { mismatches++; } } TEST_ASSERT_EQUAL_INT_MESSAGE(3, mismatches, "CH3/CH4/CH5 三路必须与顺排不同"); /* 反过来也钉一遍:拿地址低位算回通道号同样会算错。 */ TEST_ASSERT_NOT_EQUAL(0x42, ina226_rail_addr(3)); /* CH3 是 0x44,不是 0x42 */ TEST_ASSERT_NOT_EQUAL(0x44, ina226_rail_addr(5)); /* CH5 是 0x42,不是 0x44 */ } static void test_addr_table_has_no_collisions(void) { TEST_ASSERT_TRUE(ina226_addr_table_ok()); /* 含与 DAC/PCA9555/LM75 的撞车检查 */ } /* ---- 认件 ---------------------------------------------------------------- */ static void test_probe_accepts_real_ina226(void) { TEST_ASSERT_EQUAL_INT(HAL_OK, ina226_probe(mount(0x40))); } /* 应答了但 ID 不对 = 贴错件或地址跳线焊错,必须和「没这个器件」区分开。 */ static void test_probe_rejects_wrong_die_id(void) { uint8_t a = mount(0x41); sim_i2c_set_reg(a, INA226_REG_DIE_ID, 0x1234); TEST_ASSERT_EQUAL_INT(HAL_ERR_BUS, ina226_probe(a)); } static void test_probe_absent_device_naks(void) { mount(0x40); TEST_ASSERT_EQUAL_INT(HAL_ERR_NAK, ina226_probe(0x44)); /* 没挂 */ sim_i2c_set_present(0x40, false); TEST_ASSERT_EQUAL_INT(HAL_ERR_NAK, ina226_probe(0x40)); /* 失联 */ } /* 需求 §12.1 步 2:六片全应答。 */ static void test_all_six_answer_scan(void) { for (int i = 0; i < INA226_COUNT; i++) { mount(ina226_all_addr[i]); } for (int i = 0; i < INA226_COUNT; i++) { TEST_ASSERT_EQUAL_INT(HAL_OK, ina226_probe(ina226_all_addr[i])); } } static void test_bus_not_initialised_propagates(void) { sim_i2c_add(0x40, 2); int32_t mv = 0; TEST_ASSERT_EQUAL_INT(HAL_ERR_STATE, ina226_read_bus_mv(0x40, &mv)); } /* ---- 初始化 -------------------------------------------------------------- */ static void test_init_writes_config_and_calibration(void) { uint8_t a = mount(0x45); TEST_ASSERT_EQUAL_INT(HAL_OK, ina226_init(a)); TEST_ASSERT_EQUAL_HEX16(INA226_CONFIG, sim_i2c_get_reg(a, INA226_REG_CONFIG)); TEST_ASSERT_EQUAL_HEX16(2048, sim_i2c_get_reg(a, INA226_REG_CALIB)); /* 两个寄存器都是「写完立刻回读校验」:4 次写(两次三字节的写 + 两次一字节的 读指针)、2 次读。最后落下的那次写就是 CAL 的读指针。 */ const sim_i2c_dev_t *d = sim_i2c_dev(a); TEST_ASSERT_EQUAL_UINT32(4, d->n_write); TEST_ASSERT_EQUAL_UINT32(2, d->n_read); TEST_ASSERT_EQUAL_UINT8(1, d->last_write_len); TEST_ASSERT_EQUAL_HEX8(INA226_REG_CALIB, d->last_write[0]); } /* CAL 掉了的现象是 Current/Power 恒读 0,不是报错 —— 所以要能查出来。 */ static void test_check_catches_lost_calibration(void) { uint8_t a = mount(0x40); TEST_ASSERT_EQUAL_INT(HAL_OK, ina226_init(a)); TEST_ASSERT_EQUAL_INT(HAL_OK, ina226_check(a)); sim_i2c_set_reg(a, INA226_REG_CALIB, 0); /* 器件掉过一次电 */ TEST_ASSERT_EQUAL_INT(HAL_ERR_BUS, ina226_check(a)); } /* ---- 换算 ---------------------------------------------------------------- */ /* 满载一路:4.010 V / 4 A / 16 W。5 mΩ + 0.5 mA LSB 下分流码与电流码同值。 */ static void test_readings_at_full_load(void) { uint8_t a = mount(0x44); sim_i2c_set_reg(a, INA226_REG_BUS_V, 3208); /* ×1.25 mV */ sim_i2c_set_reg(a, INA226_REG_SHUNT_V, 8000); /* ×2.5 µV = 20 mV */ sim_i2c_set_reg(a, INA226_REG_CURRENT, 8000); /* ×0.5 mA */ sim_i2c_set_reg(a, INA226_REG_POWER, 1280); /* ×12.5 mW */ ina226_sample_t s = { 0, 0, 0, 0 }; TEST_ASSERT_EQUAL_INT(HAL_OK, ina226_read_all(a, &s)); TEST_ASSERT_EQUAL_INT32(4010, s.bus_mv); TEST_ASSERT_EQUAL_INT32(20000, s.shunt_uv); TEST_ASSERT_EQUAL_INT32(4000000, s.current_ua); TEST_ASSERT_EQUAL_INT32(16000, s.power_mw); } /* ⭐ 反灌(SW-8):电流寄存器是**有符号**的。当成无符号会得到 +32 A 这种数, 而判据是「电流为负」,于是保护永远不触发。 */ static void test_reverse_current_is_negative(void) { uint8_t a = mount(0x42); sim_i2c_set_reg(a, INA226_REG_CURRENT, (uint16_t)(int16_t)-120); /* −60 mA */ sim_i2c_set_reg(a, INA226_REG_SHUNT_V, (uint16_t)(int16_t)-120); /* −300 µV */ int32_t ua = 0, uv = 0; TEST_ASSERT_EQUAL_INT(HAL_OK, ina226_read_current_ua(a, &ua)); TEST_ASSERT_EQUAL_INT(HAL_OK, ina226_read_shunt_uv(a, &uv)); TEST_ASSERT_EQUAL_INT32(-60000, ua); TEST_ASSERT_EQUAL_INT32(-300, uv); } /* 3.90 V 出厂默认值那一点,顺带看四舍五入。3120 × 1.25 = 3900 mV 整。 */ static void test_bus_voltage_rounding(void) { uint8_t a = mount(0x40); sim_i2c_set_reg(a, INA226_REG_BUS_V, 3120); int32_t mv = 0; TEST_ASSERT_EQUAL_INT(HAL_OK, ina226_read_bus_mv(a, &mv)); TEST_ASSERT_EQUAL_INT32(3900, mv); sim_i2c_set_reg(a, INA226_REG_BUS_V, 3121); /* 3901.25 → 3901 */ TEST_ASSERT_EQUAL_INT(HAL_OK, ina226_read_bus_mv(a, &mv)); TEST_ASSERT_EQUAL_INT32(3901, mv); } /* ⚠️ 驱动不许依赖寄存器指针自增:sim 的假器件会自增,INA226 按 datasheet 不会。 靠自增省事的写法在这里会绿,到板上四个量全读成同一个。 */ static void test_pointer_is_rewritten_before_every_read(void) { uint8_t a = mount(0x41); ina226_sample_t s = { 0, 0, 0, 0 }; sim_i2c_dev(a)->n_write = 0; sim_i2c_dev(a)->n_read = 0; TEST_ASSERT_EQUAL_INT(HAL_OK, ina226_read_all(a, &s)); TEST_ASSERT_EQUAL_UINT32(4, sim_i2c_dev(a)->n_write); TEST_ASSERT_EQUAL_UINT32(4, sim_i2c_dev(a)->n_read); } /* 巡检主路径:只读两个量(§10.3 那 8 % I²C 占用是按这个算的)。 */ static void test_read_vi_uses_two_transactions(void) { uint8_t a = mount(0x40); sim_i2c_set_reg(a, INA226_REG_BUS_V, 3120); sim_i2c_set_reg(a, INA226_REG_CURRENT, 4000); sim_i2c_dev(a)->n_read = 0; ina226_vi_t vi = { 0, 0 }; TEST_ASSERT_EQUAL_INT(HAL_OK, ina226_read_vi(a, &vi)); TEST_ASSERT_EQUAL_INT32(3900, vi.bus_mv); TEST_ASSERT_EQUAL_INT32(2000000, vi.current_ua); TEST_ASSERT_EQUAL_UINT32(2, sim_i2c_dev(a)->n_read); } /* 器件中途失联:错误必须一路传上去,不能返回一个看着正常的 0。 */ static void test_read_propagates_nak(void) { uint8_t a = mount(0x45); sim_i2c_inject_nak(a, -1); ina226_vi_t vi = { 123, 456 }; TEST_ASSERT_EQUAL_INT(HAL_ERR_NAK, ina226_read_vi(a, &vi)); } static void test_null_output_rejected(void) { mount(0x40); TEST_ASSERT_EQUAL_INT(HAL_ERR_ARG, ina226_read_vi(0x40, NULL)); TEST_ASSERT_EQUAL_INT(HAL_ERR_ARG, ina226_read_all(0x40, NULL)); TEST_ASSERT_EQUAL_INT(HAL_ERR_ARG, ina226_read_bus_mv(0x40, NULL)); } int main(void) { UNITY_BEGIN(); RUN_TEST(test_addr_table_is_the_one_from_8_2); RUN_TEST(test_channel_index_is_not_the_address_low_bits); RUN_TEST(test_addr_table_has_no_collisions); RUN_TEST(test_probe_accepts_real_ina226); RUN_TEST(test_probe_rejects_wrong_die_id); RUN_TEST(test_probe_absent_device_naks); RUN_TEST(test_all_six_answer_scan); RUN_TEST(test_bus_not_initialised_propagates); RUN_TEST(test_init_writes_config_and_calibration); RUN_TEST(test_check_catches_lost_calibration); RUN_TEST(test_readings_at_full_load); RUN_TEST(test_reverse_current_is_negative); RUN_TEST(test_bus_voltage_rounding); RUN_TEST(test_pointer_is_rewritten_before_every_read); RUN_TEST(test_read_vi_uses_two_transactions); RUN_TEST(test_read_propagates_nak); RUN_TEST(test_null_output_rejected); return UNITY_END(); }