diff --git a/stm32-modules/include/tempdeck-gen3/tempdeck-gen3/thermal_task.hpp b/stm32-modules/include/tempdeck-gen3/tempdeck-gen3/thermal_task.hpp index 6edca3179..874b9f3bd 100644 --- a/stm32-modules/include/tempdeck-gen3/tempdeck-gen3/thermal_task.hpp +++ b/stm32-modules/include/tempdeck-gen3/tempdeck-gen3/thermal_task.hpp @@ -53,26 +53,25 @@ struct Peltier { // Provides constants & conversions for the internal ADC struct PeltierReadback { // Internal ADC max value is 12 bits = 0xFFF = 4095 - static constexpr double MAX_ADC_COUNTS = 4095; + static constexpr double MAX_ADC_COUNTS = 4096; // Internal ADC is scaled to 3.3v max static constexpr double MAX_ADC_VOLTAGE = 3.3; - // Voltage for current measurement is amplified by 50x - static constexpr double CURRENT_AMP_GAIN = 50; - // Current measurement resistor is 10 milliohms = 0.001 - static constexpr double CURRENT_AMP_RESISTOR_OHMS = 0.01; - // Milliamps per ampere - static constexpr double MILLIAMPS_PER_AMP = 1000.0; + // Amps per volt based on schematic + static constexpr double MILLIAMPS_PER_VOLT = 3773; + // Constant offset C for a y = mx + b regression + static constexpr double MILLIAMP_OFFSET = -6225; // Final conversion factor between adc and current static constexpr double MILLIAMPS_PER_COUNT = - ((MAX_ADC_VOLTAGE * MILLIAMPS_PER_AMP) / - (MAX_ADC_COUNTS * CURRENT_AMP_GAIN * CURRENT_AMP_RESISTOR_OHMS)); + ((MAX_ADC_VOLTAGE * MILLIAMPS_PER_VOLT) / MAX_ADC_COUNTS); static auto adc_to_milliamps(uint32_t adc) -> double { - return static_cast(adc) * MILLIAMPS_PER_COUNT; + return (static_cast(adc) * MILLIAMPS_PER_COUNT) + + MILLIAMP_OFFSET; } static auto milliamps_to_adc(double milliamps) -> uint32_t { - return static_cast(milliamps / MILLIAMPS_PER_COUNT); + return static_cast((milliamps - MILLIAMP_OFFSET) / + MILLIAMPS_PER_COUNT); } }; diff --git a/stm32-modules/tempdeck-gen3/firmware/thermistor/internal_adc_hardware.c b/stm32-modules/tempdeck-gen3/firmware/thermistor/internal_adc_hardware.c index c42f433a3..c1d66839a 100644 --- a/stm32-modules/tempdeck-gen3/firmware/thermistor/internal_adc_hardware.c +++ b/stm32-modules/tempdeck-gen3/firmware/thermistor/internal_adc_hardware.c @@ -169,6 +169,8 @@ static void init_adc_hardware(ADC_HandleTypeDef *handle) { ret = HAL_ADC_ConfigChannel(handle, &channel_config); configASSERT(ret == HAL_OK); } + + HAL_ADCEx_Calibration_Start(handle, ADC_SINGLE_ENDED); } static void init_dma_hardware(void) diff --git a/stm32-modules/tempdeck-gen3/tests/test_thermal_task.cpp b/stm32-modules/tempdeck-gen3/tests/test_thermal_task.cpp index 82243579a..3c3afc829 100644 --- a/stm32-modules/tempdeck-gen3/tests/test_thermal_task.cpp +++ b/stm32-modules/tempdeck-gen3/tests/test_thermal_task.cpp @@ -4,17 +4,23 @@ TEST_CASE("peltier current conversions") { GIVEN("some ADC readings") { - std::vector inputs = {0, 100, 1000}; + const auto COUNT = 4; + std::vector inputs = {0, 1000, 4095, 2048}; + std::vector expected = {-6225, -3185.23, 6222.86, 0.45}; WHEN("converting readings") { - std::vector outputs(3); + std::vector outputs(COUNT); std::transform(inputs.begin(), inputs.end(), outputs.begin(), thermal_task::PeltierReadback::adc_to_milliamps); THEN("the readings are converted correctly") { - std::vector expected = {0, 161.172, 1611.722}; - REQUIRE_THAT(outputs, Catch::Matchers::Approx(expected)); + for (auto i = 0; i < COUNT; ++i) { + DYNAMIC_SECTION("reading " << i) { + REQUIRE_THAT(outputs[i], Catch::Matchers::WithinAbs( + expected[i], 0.1)); + } + } } AND_THEN("backconverting readings") { - std::vector backconvert(3); + std::vector backconvert(COUNT); std::transform(outputs.begin(), outputs.end(), backconvert.begin(), thermal_task::PeltierReadback::milliamps_to_adc); @@ -579,6 +585,9 @@ TEST_CASE("thermal task offset constants message handling") { TEST_CASE("thermal task power debug functionality") { auto *tasks = tasks::BuildTasks(); TestThermalPolicy policy; + const double peltier_leeway = + std::abs(thermal_task::PeltierReadback::adc_to_milliamps(1) - + thermal_task::PeltierReadback::adc_to_milliamps(3)); const double peltier_current = GENERATE(200.0F, 2000.0F, 0.0F); auto current_adc = thermal_task::PeltierReadback::milliamps_to_adc(peltier_current); @@ -616,11 +625,9 @@ TEST_CASE("thermal task power debug functionality") { std::get( response_msg); REQUIRE(response.responding_to_id == power_msg.id); - // There has to be a fair amount of leeway here because the - // accuracy of the conversions isn't the best REQUIRE_THAT(response.peltier_current, Catch::Matchers::WithinAbs(peltier_current, - peltier_current * .01)); + peltier_leeway)); REQUIRE_THAT(response.peltier_pwm, Catch::Matchers::WithinAbs(0, .01)); REQUIRE_THAT(response.fan_pwm, @@ -659,11 +666,9 @@ TEST_CASE("thermal task power debug functionality") { std::get( response_msg); REQUIRE(response.responding_to_id == power_msg.id); - // There has to be a fair amount of leeway here because the - // accuracy of the conversions isn't the best REQUIRE_THAT(response.peltier_current, - Catch::Matchers::WithinAbs( - peltier_current, peltier_current * .01)); + Catch::Matchers::WithinAbs(peltier_current, + peltier_leeway)); REQUIRE_THAT( response.peltier_pwm, Catch::Matchers::WithinAbs(peltier_msg.power, .001));