summaryrefslogtreecommitdiff
path: root/test/fan.c
diff options
context:
space:
mode:
authorRichard Yeh <rcy@google.com>2022-11-28 02:02:16 +0000
committerChromeos LUCI <chromeos-scoped@luci-project-accounts.iam.gserviceaccount.com>2022-12-13 07:14:15 +0000
commit62c3a651befeb8d9b3ad03994b23b579d92c20d8 (patch)
treebfb65fa429c7a78fadfa5c968fc84dd351d703e2 /test/fan.c
parent802a90e2e991129c0d9ff2b4b1d8f6bd36f0a492 (diff)
downloadchrome-ec-62c3a651befeb8d9b3ad03994b23b579d92c20d8.tar.gz
fan: Rewrite and test the most common custom fan_percent_to_rpm.
temp_ratio_to_rpm_hysteresis uses a sorted fan_table containing a mapping of temp_ratio (percent, 0-100) to fan rpm. This clarifies the relationship of temperature to fan speed, while reducing the number of static variables. The existing temp_ratio expressing the percentage of cooling needed (temperature from temp_fan_off to temp_fan_max) suggests the possibility that a proportional-integral-derivative (PID) feedback controller might have been considered; but the default implementation is purely linear (mapping to fan speed from min to max) and this stepwise one just enables hysteresis --- different speeds when the board is warming up than when cooling down. The hysteresis attempts to avoid oscillations in temperature and fan speed. This refactoring is in preparation for reusing this implementation for {ambassador, genesis, moonbuggy, scout}. {kalista, berknip, chronicler, dewatt, endeavour, ezkinil, fizz} define CONFIG_FAN_RPM_CUSTOM and use this or nearly this implementation of a fan_percent_to_rpm with hysteresis. {chronicler} also performs boxcar smoothing of the input. {osiris}, which has two fans, and {jinlon, redrix, and other boards with multiple sensors}, use a similar but not exactly the same implementation, and would need additional abstraction. See: https://source.chromium.org/search?q=f:ec%2Fb%20fan_step%20-f:board.c BRANCH=refactor-fan-percent-to-rpm BUG=b:252966838,b:191187610,chromium:1383859 TEST=make -j run-fan && make -j buildall && make -j runhosttests Signed-off-by: Richard Yeh <rcy@google.com> Change-Id: I50ad4d78ac1145f92573a417646c1f57b8945463 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/4021951 Reviewed-by: Jeremy Bettis <jbettis@chromium.org> Reviewed-by: Daisuke Nojiri <dnojiri@chromium.org> Code-Coverage: Zoss <zoss-cl-coverage@prod.google.com> Reviewed-by: Abe Levkoy <alevkoy@chromium.org>
Diffstat (limited to 'test/fan.c')
-rw-r--r--test/fan.c112
1 files changed, 112 insertions, 0 deletions
diff --git a/test/fan.c b/test/fan.c
index 76c3208cc6..48a019382b 100644
--- a/test/fan.c
+++ b/test/fan.c
@@ -104,9 +104,121 @@ static int test_fan(void)
return EC_SUCCESS;
}
+/* Provide a test driver to make test easier to read. */
+int temp_to_rpm(int temperature_c)
+{
+ const int temp_fan_off = C_TO_K(35);
+ const int temp_fan_max = C_TO_K(55);
+ const struct fan_step_1_1 fan_table[] = {
+ { .decreasing_temp_ratio_threshold = TEMP_TO_RATIO(35),
+ .increasing_temp_ratio_threshold = TEMP_TO_RATIO(41),
+ .rpm = 2500 },
+ { .decreasing_temp_ratio_threshold = TEMP_TO_RATIO(37),
+ .increasing_temp_ratio_threshold = TEMP_TO_RATIO(43),
+ .rpm = 3200 },
+ { .decreasing_temp_ratio_threshold = TEMP_TO_RATIO(42),
+ .increasing_temp_ratio_threshold = TEMP_TO_RATIO(45),
+ .rpm = 3500 },
+ { .decreasing_temp_ratio_threshold = TEMP_TO_RATIO(44),
+ .increasing_temp_ratio_threshold = TEMP_TO_RATIO(47),
+ .rpm = 3900 },
+ { .decreasing_temp_ratio_threshold = TEMP_TO_RATIO(46),
+ .increasing_temp_ratio_threshold = TEMP_TO_RATIO(49),
+ .rpm = 4500 },
+ { .decreasing_temp_ratio_threshold = TEMP_TO_RATIO(48),
+ .increasing_temp_ratio_threshold = TEMP_TO_RATIO(52),
+ .rpm = 5100 },
+ { .decreasing_temp_ratio_threshold = TEMP_TO_RATIO(51),
+ .increasing_temp_ratio_threshold = TEMP_TO_RATIO(55),
+ .rpm = 5400 },
+ };
+ const int num_fan_levels = ARRAY_SIZE(fan_table);
+ int temp_ratio = TEMP_TO_RATIO(temperature_c);
+
+ int rpm = temp_ratio_to_rpm_hysteresis(fan_table, num_fan_levels, 0,
+ temp_ratio, NULL);
+
+ fan_set_rpm_target(FAN_CH(0), rpm);
+ return rpm;
+}
+
+static int test_temp_ratio_to_rpm_hysteresis(void)
+{
+ const int ZERO = 0;
+ /* set initial value to be different so that a log message appears */
+ fan_set_rpm_target(FAN_CH(0), 5400);
+ /* initial turn-on behavior, ramp up. @ represents fan speed; + temp */
+ TEST_ASSERT(temp_to_rpm(30) == ZERO); /* @+. . 40 . 50 .60 */
+ TEST_ASSERT(temp_to_rpm(30) == ZERO); /* @+. . . . . . */
+ TEST_ASSERT(temp_to_rpm(35) == ZERO); /* @ + . . . . */
+ TEST_ASSERT(temp_to_rpm(37) == ZERO); /* @ . + . . . . */
+ TEST_ASSERT(temp_to_rpm(39) == ZERO); /* @ . +. . . . */
+ TEST_ASSERT(temp_to_rpm(40) == ZERO); /* @ . + . . . */
+ TEST_ASSERT(temp_to_rpm(41) == 2500); /* @. .+ . . . */
+ TEST_ASSERT(temp_to_rpm(36) == 2500); /* @.+ . . . . */
+ TEST_ASSERT(temp_to_rpm(42) == 2500); /* @. . + . . . */
+ TEST_ASSERT(temp_to_rpm(43) == 3200); /* @ . + . . . */
+ TEST_ASSERT(temp_to_rpm(38) == 3200); /* @ + . . . . */
+ TEST_ASSERT(temp_to_rpm(44) == 3200); /* @ . +. . . */
+ TEST_ASSERT(temp_to_rpm(45) == 3500); /* .@ . + . . */
+ TEST_ASSERT(temp_to_rpm(43) == 3500); /* .@ . + . . . */
+ TEST_ASSERT(temp_to_rpm(46) == 3500); /* .@ . .+ . . */
+ TEST_ASSERT(temp_to_rpm(47) == 3900); /* . @ . . + . . */
+ TEST_ASSERT(temp_to_rpm(45) == 3900); /* . @ . + . . */
+ TEST_ASSERT(temp_to_rpm(48) == 3900); /* . @ . . + . . */
+ TEST_ASSERT(temp_to_rpm(49) == 4500); /* . @ . . +. . */
+ TEST_ASSERT(temp_to_rpm(47) == 4500); /* . @ . . + . . */
+ TEST_ASSERT(temp_to_rpm(51) == 4500); /* . @ . . .+ . */
+ TEST_ASSERT(temp_to_rpm(52) == 5100); /* . @. . . + . */
+ TEST_ASSERT(temp_to_rpm(49) == 5100); /* . @. . +. . */
+ TEST_ASSERT(temp_to_rpm(54) == 5100); /* . @. . . +. */
+ TEST_ASSERT(temp_to_rpm(55) == 5400); /* . @ . . + */
+ TEST_ASSERT(temp_to_rpm(52) == 5400); /* . @ . . + . */
+ TEST_ASSERT(temp_to_rpm(60) == 5400); /* . @ . 50 ..+ */
+ /* cool-down */
+ TEST_ASSERT(temp_to_rpm(55) == 5400); /* . @ . . + */
+ TEST_ASSERT(temp_to_rpm(52) == 5400); /* . @ . . + . */
+ TEST_ASSERT(temp_to_rpm(51) == 5100); /* . @. . .+ . */
+ TEST_ASSERT(temp_to_rpm(54) == 5100); /* . @. . . +. */
+ TEST_ASSERT(temp_to_rpm(49) == 5100); /* . @. . +. . */
+ TEST_ASSERT(temp_to_rpm(48) == 4500); /* . @ . . + . . */
+ TEST_ASSERT(temp_to_rpm(51) == 4500); /* . @ . . .+ . */
+ TEST_ASSERT(temp_to_rpm(47) == 4500); /* . @ . . + . . */
+ TEST_ASSERT(temp_to_rpm(46) == 3900); /* . @ . .+ . . */
+ TEST_ASSERT(temp_to_rpm(48) == 3900); /* . @ . . + . . */
+ TEST_ASSERT(temp_to_rpm(45) == 3900); /* . @ . + . . */
+ TEST_ASSERT(temp_to_rpm(44) == 3500); /* .@ . +. . . */
+ TEST_ASSERT(temp_to_rpm(46) == 3500); /* .@ . .+ . . */
+ TEST_ASSERT(temp_to_rpm(43) == 3500); /* .@ . + . . . */
+ TEST_ASSERT(temp_to_rpm(42) == 3200); /* @ . + . . . */
+ TEST_ASSERT(temp_to_rpm(44) == 3200); /* @ . +. . . */
+ TEST_ASSERT(temp_to_rpm(38) == 3200); /* @ + . . . . */
+ TEST_ASSERT(temp_to_rpm(37) == 2500); /* @. + . . . . */
+ TEST_ASSERT(temp_to_rpm(42) == 2500); /* @. . + . . . */
+ TEST_ASSERT(temp_to_rpm(36) == 2500); /* @.+ . . . . */
+ TEST_ASSERT(temp_to_rpm(35) == ZERO); /* @ + 40 . 50 . */
+ /* warm up again */
+ TEST_ASSERT(temp_to_rpm(38) == ZERO); /* @ . + . . . . */
+ /* jumping */
+ TEST_ASSERT(temp_to_rpm(46) == 3500); /* .@ . .+ . . */
+ TEST_ASSERT(temp_to_rpm(36) == 2500); /* @.+ . . . . */
+ TEST_ASSERT(temp_to_rpm(35) == ZERO); /* @ + . . . . */
+ TEST_ASSERT(temp_to_rpm(37) == ZERO); /* @ . + . . . . */
+ TEST_ASSERT(temp_to_rpm(46) == 3500); /* .@ . .+ . . */
+ TEST_ASSERT(temp_to_rpm(54) == 5100); /* . @. . . +. */
+ TEST_ASSERT(temp_to_rpm(55) == 5400); /* . @ . . + */
+ TEST_ASSERT(temp_to_rpm(60) == 5400); /* . @ . . ..+ */
+ TEST_ASSERT(temp_to_rpm(53) == 5400); /* . @ . . + . */
+ TEST_ASSERT(temp_to_rpm(46) == 3900); /* . @ . .+ . . */
+ TEST_ASSERT(temp_to_rpm(30) == ZERO); /* @+. . 40 . 50 . */
+
+ return EC_SUCCESS;
+}
+
void run_test(int argc, const char **argv)
{
RUN_TEST(test_fan);
+ RUN_TEST(test_temp_ratio_to_rpm_hysteresis);
test_print_result();
}