--- a/firmware/main/board_pins.h +++ b/firmware/main/board_pins.h @@ -22,8 +22,11 @@ #define BOARD_PIN_I2C_SDA 14 /* 模组脚 22 —— 6×INA226 + 2×DAC + PCA9555(+ 载板 LM75) */ #define BOARD_PIN_I2C_SCL 15 /* 模组脚 8 */ -#define BOARD_PIN_FAN_TACH 16 /* 模组脚 9 → R731/R732 分压 */ -#define BOARD_PIN_FAN_PWM 18 /* 模组脚 11 → R733 */ +/* KiCad FAN-R2: common power enable, inverted open-drain PWM, two receivers. */ +#define BOARD_PIN_FAN_EN 5 /* Module pin 5 -> R742/Q8; active high */ +#define BOARD_PIN_FAN_TACH_IN 16 /* Module pin 9 -> Q9; intake */ +#define BOARD_PIN_FAN_TACH_OUT 4 /* Module pin 4 -> Q10; exhaust */ +#define BOARD_PIN_FAN_PWM 18 /* Module pin 11 -> R733/Q6; GPIO duty = 1 - fan duty */ #define BOARD_PIN_UP_VBUS_DET 47 /* 模组脚 24 → J24.25,上游 VBUS 有没有插 */ #define BOARD_PIN_NTC1 1 /* 模组脚 39,ADC1_CH0 —— 必须是 IO1~IO10 */ #define BOARD_PIN_NTC2 2 /* 模组脚 38,ADC1_CH1 */ --- a/firmware/main/rail_cfg.c +++ b/firmware/main/rail_cfg.c @@ -107,7 +107,7 @@ static bool pins_ok(const rail_cfg_t *t) { /* 全板用掉的每一个脚。顺序无所谓,这里只查「都能用」和「不重复」。 */ - int used[2 * PHONERAIL_RAIL_COUNT + 14]; + int used[2 * PHONERAIL_RAIL_COUNT + 16]; size_t n = 0; for (int rail = 1; rail <= PHONERAIL_RAIL_COUNT; rail++) { @@ -116,7 +116,9 @@ } used[n++] = BOARD_PIN_I2C_SDA; used[n++] = BOARD_PIN_I2C_SCL; - used[n++] = BOARD_PIN_FAN_TACH; + used[n++] = BOARD_PIN_FAN_EN; + used[n++] = BOARD_PIN_FAN_TACH_IN; + used[n++] = BOARD_PIN_FAN_TACH_OUT; used[n++] = BOARD_PIN_FAN_PWM; used[n++] = BOARD_PIN_UP_VBUS_DET; used[n++] = BOARD_PIN_NTC1; --- a/firmware/test/test_rail_cfg.c +++ b/firmware/test/test_rail_cfg.c @@ -136,6 +136,20 @@ TEST_ASSERT_EQUAL_HEX32(RAIL_SELFTEST_PINS, rail_selftest_table(t)); } +static void test_each_fan_pin_collision_is_caught(void) +{ + const int fan_pins[] = { + BOARD_PIN_FAN_EN, BOARD_PIN_FAN_PWM, + BOARD_PIN_FAN_TACH_IN, BOARD_PIN_FAN_TACH_OUT, + }; + rail_cfg_t t[N]; + for (unsigned i = 0; i < sizeof(fan_pins) / sizeof(fan_pins[0]); i++) { + copy_real_table(t); + t[0].efuse_en = fan_pins[i]; + TEST_ASSERT_EQUAL_HEX32(RAIL_SELFTEST_PINS, rail_selftest_table(t)); + } +} + /* 两样一起坏,两位一起报 —— 别在第一个错上就 return。 */ static void test_two_kinds_of_breakage_report_two_bits(void) { @@ -378,7 +392,8 @@ static const int strapping[] = BOARD_PINS_STRAPPING; static const int reserved[] = BOARD_PINS_RESERVED; static const int others[] = { - BOARD_PIN_I2C_SDA, BOARD_PIN_I2C_SCL, BOARD_PIN_FAN_TACH, BOARD_PIN_FAN_PWM, + BOARD_PIN_I2C_SDA, BOARD_PIN_I2C_SCL, BOARD_PIN_FAN_TACH_IN, BOARD_PIN_FAN_PWM, + BOARD_PIN_FAN_EN, BOARD_PIN_FAN_TACH_OUT, BOARD_PIN_NTC1, BOARD_PIN_NTC2, BOARD_PIN_USB_DM, BOARD_PIN_USB_DP, BOARD_PIN_UP_VBUS_DET, SR595_PIN_SER, SR595_PIN_SRCLK, SR595_PIN_RCLK, SR595_PIN_OE_N, PCA9555_PIN_INT_N, @@ -583,6 +598,7 @@ RUN_TEST(test_a_faithful_copy_of_the_real_table_passes); RUN_TEST(test_a_cell_that_drifted_from_the_driver_is_caught); RUN_TEST(test_every_kind_of_bad_pin_is_caught); + RUN_TEST(test_each_fan_pin_collision_is_caught); RUN_TEST(test_two_kinds_of_breakage_report_two_bits); RUN_TEST(test_no_two_rails_share_anything); RUN_TEST(test_shift_chain_bits_avoid_hub_reset_and_the_unused_pins);