build: the libavr pin advances past the audit sweep, and the numbers get names
The pin crosses libavr's phase-6 close and the guideline sweep behind it; the image is byte-identical in both modes at 8206 bytes. The port's own sweep, against the same rules. Every mutable `static inline` takes `m_` - uptime's counter, the sampler's window, the controller's five, the statistics histogram and the terminal's line state (rule 46; a private `static constexpr` is a constant rather than state and keeps its bare name). The command table is `std::to_array` and the serial config breaks one member per line (rules 36, 40). And three numbers get the name they already had somewhere: duty goes through `percent_t::of()` rather than a hand-built basis-point count, the ADC's top count is `thermistor::adc_full_scale` instead of 1023 in four places, and the two `0xffffffff` are `open_circuit` - which was already declared five lines away - and `never_written`, which replaces a comment explaining the literal (rules 5, 6, 41). Measured, not assumed: rendering `adc_full_scale` into the `show` line instead of leaving it in the message string cost 6 bytes, so the display text stays text. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2
libavr
2
libavr
Submodule libavr updated: 07a0c40235...4c7d4d6ff3
@@ -13,24 +13,24 @@ using dev = avr::device<{.clock = 16_MHz}>;
|
|||||||
|
|
||||||
// Millisecond uptime from timer2 CTC (the fan owns timer0).
|
// Millisecond uptime from timer2 CTC (the fan owns timer0).
|
||||||
class uptime {
|
class uptime {
|
||||||
static inline volatile std::uint64_t ms = 0;
|
static inline volatile std::uint64_t m_ms = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using ticker = dev::timer2<{.frequency = 1_kHz, .on_compare = [] { ms = ms + 1; }}>;
|
using ticker = dev::timer2<{.frequency = 1_kHz, .on_compare = [] { m_ms = m_ms + 1; }}>;
|
||||||
|
|
||||||
static std::uint64_t millis()
|
static std::uint64_t millis()
|
||||||
{
|
{
|
||||||
avr::irq::interrupt_guard lock;
|
avr::irq::interrupt_guard lock;
|
||||||
return ms;
|
return m_ms;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 1000-sample averaging window fed by the conversion interrupt.
|
// 1000-sample averaging window fed by the conversion interrupt.
|
||||||
class sampler {
|
class sampler {
|
||||||
static inline volatile std::uint32_t sum = 0;
|
static inline volatile std::uint32_t m_sum = 0;
|
||||||
static inline volatile std::uint16_t count = 0;
|
static inline volatile std::uint16_t m_count = 0;
|
||||||
static inline volatile std::uint16_t window = 0;
|
static inline volatile std::uint16_t m_window = 0;
|
||||||
static inline volatile bool ready = false;
|
static inline volatile bool m_ready = false;
|
||||||
|
|
||||||
static constexpr std::uint16_t samples = 1000;
|
static constexpr std::uint16_t samples = 1000;
|
||||||
|
|
||||||
@@ -38,13 +38,13 @@ class sampler {
|
|||||||
using input = dev::adc<{.trigger = avr::adc::trigger::free_running,
|
using input = dev::adc<{.trigger = avr::adc::trigger::free_running,
|
||||||
.on_conversion =
|
.on_conversion =
|
||||||
[](std::uint16_t value) {
|
[](std::uint16_t value) {
|
||||||
sum = sum + value;
|
m_sum = m_sum + value;
|
||||||
count = count + 1;
|
m_count = m_count + 1;
|
||||||
if (count >= samples) {
|
if (m_count >= samples) {
|
||||||
window = static_cast<std::uint16_t>(sum / samples);
|
m_window = static_cast<std::uint16_t>(m_sum / samples);
|
||||||
sum = 0;
|
m_sum = 0;
|
||||||
count = 0;
|
m_count = 0;
|
||||||
ready = true;
|
m_ready = true;
|
||||||
}
|
}
|
||||||
}},
|
}},
|
||||||
avr::adc::input<avr::adc::input_pin(0)>>;
|
avr::adc::input<avr::adc::input_pin(0)>>;
|
||||||
@@ -55,11 +55,11 @@ class sampler {
|
|||||||
static bool take(std::uint16_t &value)
|
static bool take(std::uint16_t &value)
|
||||||
{
|
{
|
||||||
avr::irq::interrupt_guard lock;
|
avr::irq::interrupt_guard lock;
|
||||||
if (!ready) {
|
if (!m_ready) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
value = window;
|
value = m_window;
|
||||||
ready = false;
|
m_ready = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -69,7 +69,11 @@ using fan = dev::pwm<avr::pd5, {.frequency = 50_kHz}>;
|
|||||||
// 115200 at 16 MHz lands +2.1 % off, past the receiver-tolerance table the
|
// 115200 at 16 MHz lands +2.1 % off, past the receiver-tolerance table the
|
||||||
// solver holds rates to - the rate this board has always spoken, so the
|
// solver holds rates to - the rate this board has always spoken, so the
|
||||||
// override states that it is meant.
|
// override states that it is meant.
|
||||||
using serial_t = dev::uart0<{.baud = 115200_Bd, .rx_buffer = 32, .allow_baud_error = true}>;
|
using serial_t = dev::uart0<{
|
||||||
|
.baud = 115200_Bd,
|
||||||
|
.rx_buffer = 32,
|
||||||
|
.allow_baud_error = true,
|
||||||
|
}>;
|
||||||
inline constexpr serial_t serial{};
|
inline constexpr serial_t serial{};
|
||||||
|
|
||||||
} // namespace app
|
} // namespace app
|
||||||
|
|||||||
@@ -11,16 +11,16 @@
|
|||||||
namespace app {
|
namespace app {
|
||||||
|
|
||||||
class controller {
|
class controller {
|
||||||
static inline std::uint16_t adc_average = 0;
|
static inline std::uint16_t m_adc_average = 0;
|
||||||
static inline std::int16_t temp_quarters = 0;
|
static inline std::int16_t m_temp_quarters = 0;
|
||||||
static inline std::uint8_t percent = 100;
|
static inline std::uint8_t m_percent = 100;
|
||||||
static inline bool auto_mode = true;
|
static inline bool m_auto_mode = true;
|
||||||
static inline bool have_data = false;
|
static inline bool m_have_data = false;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static void init()
|
static void init()
|
||||||
{
|
{
|
||||||
fan::set_duty(avr::percent_t{10000}); // full blast until the first reading
|
fan::set_duty(100_pct); // full blast until the first reading
|
||||||
}
|
}
|
||||||
|
|
||||||
static void poll()
|
static void poll()
|
||||||
@@ -29,50 +29,50 @@ class controller {
|
|||||||
if (!sampler::take(sample)) {
|
if (!sampler::take(sample)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
adc_average = sample;
|
m_adc_average = sample;
|
||||||
temp_quarters = thermistor::quarters(sample);
|
m_temp_quarters = thermistor::quarters(sample);
|
||||||
have_data = true;
|
m_have_data = true;
|
||||||
if (auto_mode) {
|
if (m_auto_mode) {
|
||||||
percent = curve::duty(static_cast<std::int8_t>((temp_quarters + 2) / 4));
|
m_percent = curve::duty(static_cast<std::int8_t>((m_temp_quarters + 2) / 4));
|
||||||
}
|
}
|
||||||
fan::set_duty(avr::percent_t{static_cast<std::uint16_t>(percent * 100)});
|
fan::set_duty(avr::percent_t::of(m_percent));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_manual(std::uint8_t p)
|
static void set_manual(std::uint8_t p)
|
||||||
{
|
{
|
||||||
auto_mode = false;
|
m_auto_mode = false;
|
||||||
percent = p;
|
m_percent = p;
|
||||||
fan::set_duty(avr::percent_t{static_cast<std::uint16_t>(p * 100)});
|
fan::set_duty(avr::percent_t::of(p));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_automatic()
|
static void set_automatic()
|
||||||
{
|
{
|
||||||
auto_mode = true;
|
m_auto_mode = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool automatic()
|
static bool automatic()
|
||||||
{
|
{
|
||||||
return auto_mode;
|
return m_auto_mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool data_available()
|
static bool data_available()
|
||||||
{
|
{
|
||||||
return have_data;
|
return m_have_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::int16_t temperature_quarters()
|
static std::int16_t temperature_quarters()
|
||||||
{
|
{
|
||||||
return temp_quarters;
|
return m_temp_quarters;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::uint16_t last_adc()
|
static std::uint16_t last_adc()
|
||||||
{
|
{
|
||||||
return adc_average;
|
return m_adc_average;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::uint8_t fan_percent()
|
static std::uint8_t fan_percent()
|
||||||
{
|
{
|
||||||
return percent;
|
return m_percent;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
// Temperature histogram: one uint32 bucket per C 0..99, sampled once a
|
// Temperature histogram: one uint32 bucket per C 0..99, sampled once a
|
||||||
// second, written back to EEPROM every 30 minutes (update() only touches
|
// second, written back to EEPROM every 30 minutes (update() only touches
|
||||||
// changed bytes). Erased EEPROM reads back as 0xffffffff - treated as 0.
|
// changed bytes).
|
||||||
namespace app {
|
namespace app {
|
||||||
|
|
||||||
class statistics {
|
class statistics {
|
||||||
@@ -17,11 +17,15 @@ class statistics {
|
|||||||
static constexpr std::uint32_t sample_delay_ms = 1'000;
|
static constexpr std::uint32_t sample_delay_ms = 1'000;
|
||||||
static constexpr std::uint32_t writeback_delay_ms = 1'800'000;
|
static constexpr std::uint32_t writeback_delay_ms = 1'800'000;
|
||||||
|
|
||||||
|
// What an erased cell reads back as, so a bucket nobody has written yet
|
||||||
|
// counts as no samples rather than four billion.
|
||||||
|
static constexpr std::uint32_t never_written = ~std::uint32_t{0};
|
||||||
|
|
||||||
using stored = avr::eeprom::var<std::array<std::uint32_t, range>, 0>;
|
using stored = avr::eeprom::var<std::array<std::uint32_t, range>, 0>;
|
||||||
|
|
||||||
static inline std::array<std::uint32_t, range> histogram{};
|
static inline std::array<std::uint32_t, range> m_histogram{};
|
||||||
static inline std::uint64_t last_sample = 0;
|
static inline std::uint64_t m_last_sample = 0;
|
||||||
static inline std::uint64_t last_writeback = 0;
|
static inline std::uint64_t m_last_writeback = 0;
|
||||||
|
|
||||||
static constexpr std::uint8_t clamp(std::int8_t t)
|
static constexpr std::uint8_t clamp(std::int8_t t)
|
||||||
{
|
{
|
||||||
@@ -33,9 +37,9 @@ class statistics {
|
|||||||
|
|
||||||
static void init()
|
static void init()
|
||||||
{
|
{
|
||||||
histogram = stored::read();
|
m_histogram = stored::read();
|
||||||
for (auto &bucket : histogram) {
|
for (auto &bucket : m_histogram) {
|
||||||
if (bucket == 0xffffffff) {
|
if (bucket == never_written) {
|
||||||
bucket = 0;
|
bucket = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -44,31 +48,31 @@ class statistics {
|
|||||||
static void record(std::int8_t celsius)
|
static void record(std::int8_t celsius)
|
||||||
{
|
{
|
||||||
auto now = uptime::millis();
|
auto now = uptime::millis();
|
||||||
if (now >= last_sample + sample_delay_ms) {
|
if (now >= m_last_sample + sample_delay_ms) {
|
||||||
++histogram[clamp(celsius)];
|
++m_histogram[clamp(celsius)];
|
||||||
last_sample = now;
|
m_last_sample = now;
|
||||||
}
|
}
|
||||||
if (now >= last_writeback + writeback_delay_ms) {
|
if (now >= m_last_writeback + writeback_delay_ms) {
|
||||||
save();
|
save();
|
||||||
last_writeback = now;
|
m_last_writeback = now;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void save()
|
static void save()
|
||||||
{
|
{
|
||||||
stored::update(histogram);
|
stored::update(m_histogram);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void reset()
|
static void reset()
|
||||||
{
|
{
|
||||||
histogram = {};
|
m_histogram = {};
|
||||||
stored::update(histogram);
|
stored::update(m_histogram);
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::uint8_t min_temperature()
|
static std::uint8_t min_temperature()
|
||||||
{
|
{
|
||||||
for (std::uint8_t i = 0; i < range; ++i) {
|
for (std::uint8_t i = 0; i < range; ++i) {
|
||||||
if (histogram[i]) {
|
if (m_histogram[i]) {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -78,7 +82,7 @@ class statistics {
|
|||||||
static std::uint8_t max_temperature()
|
static std::uint8_t max_temperature()
|
||||||
{
|
{
|
||||||
for (std::uint8_t i = range; i > 0; --i) {
|
for (std::uint8_t i = range; i > 0; --i) {
|
||||||
if (histogram[i - 1]) {
|
if (m_histogram[i - 1]) {
|
||||||
return i - 1;
|
return i - 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -88,7 +92,7 @@ class statistics {
|
|||||||
static std::uint64_t total_samples()
|
static std::uint64_t total_samples()
|
||||||
{
|
{
|
||||||
std::uint64_t total = 0;
|
std::uint64_t total = 0;
|
||||||
for (auto bucket : histogram) {
|
for (auto bucket : m_histogram) {
|
||||||
total += bucket;
|
total += bucket;
|
||||||
}
|
}
|
||||||
return total;
|
return total;
|
||||||
@@ -97,7 +101,7 @@ class statistics {
|
|||||||
static std::uint32_t highest_bucket()
|
static std::uint32_t highest_bucket()
|
||||||
{
|
{
|
||||||
std::uint32_t highest = 0;
|
std::uint32_t highest = 0;
|
||||||
for (auto bucket : histogram) {
|
for (auto bucket : m_histogram) {
|
||||||
if (bucket > highest) {
|
if (bucket > highest) {
|
||||||
highest = bucket;
|
highest = bucket;
|
||||||
}
|
}
|
||||||
@@ -107,7 +111,7 @@ class statistics {
|
|||||||
|
|
||||||
static std::uint32_t bucket(std::uint8_t celsius)
|
static std::uint32_t bucket(std::uint8_t celsius)
|
||||||
{
|
{
|
||||||
return histogram[clamp(static_cast<std::int8_t>(celsius))];
|
return m_histogram[clamp(static_cast<std::int8_t>(celsius))];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -22,11 +22,11 @@ class terminal {
|
|||||||
static constexpr char ctrl_c = 0x03;
|
static constexpr char ctrl_c = 0x03;
|
||||||
static constexpr char backspace = 0x08;
|
static constexpr char backspace = 0x08;
|
||||||
static constexpr char del = 0x7f;
|
static constexpr char del = 0x7f;
|
||||||
static inline std::array<char, 24> line{};
|
static inline std::array<char, 24> m_line{};
|
||||||
static inline std::uint8_t at = 0;
|
static inline std::uint8_t m_at = 0;
|
||||||
static inline bool overflowed = false;
|
static inline bool m_overflowed = false;
|
||||||
static inline bool monitoring = false;
|
static inline bool m_monitoring = false;
|
||||||
static inline std::uint64_t last_monitor = 0;
|
static inline std::uint64_t m_last_monitor = 0;
|
||||||
|
|
||||||
// Commands, in the order they are matched - which is the order the original
|
// Commands, in the order they are matched - which is the order the original
|
||||||
// firmware matched them in, and that order is load-bearing. An abbreviation
|
// firmware matched them in, and that order is load-bearing. An abbreviation
|
||||||
@@ -38,7 +38,7 @@ class terminal {
|
|||||||
bool exact; // reset only: an abbreviation must not be able to wipe data
|
bool exact; // reset only: an abbreviation must not be able to wipe data
|
||||||
};
|
};
|
||||||
|
|
||||||
static constexpr std::array<command, 13> commands{{
|
static constexpr auto commands = std::to_array<command>({
|
||||||
{"help", false},
|
{"help", false},
|
||||||
{"show", false},
|
{"show", false},
|
||||||
{"curve", false},
|
{"curve", false},
|
||||||
@@ -52,7 +52,7 @@ class terminal {
|
|||||||
{"auto", false},
|
{"auto", false},
|
||||||
{"version", false},
|
{"version", false},
|
||||||
{"save", false},
|
{"save", false},
|
||||||
}};
|
});
|
||||||
|
|
||||||
// Column the descriptions' colons line up in, counted from the start of the
|
// Column the descriptions' colons line up in, counted from the start of the
|
||||||
// name. The longest name is `bootloader` at 10, so 12 leaves it a space and
|
// name. The longest name is `bootloader` at 10, so 12 leaves it a space and
|
||||||
@@ -146,10 +146,10 @@ class terminal {
|
|||||||
static std::uint32_t resistance()
|
static std::uint32_t resistance()
|
||||||
{
|
{
|
||||||
auto adc = controller::last_adc();
|
auto adc = controller::last_adc();
|
||||||
if (adc >= 1023) {
|
if (adc >= thermistor::adc_full_scale) {
|
||||||
return 0xffffffff; // open circuit: the divider has no solution
|
return open_circuit;
|
||||||
}
|
}
|
||||||
return static_cast<std::uint32_t>(thermistor::series_resistor) * adc / (1023u - adc);
|
return static_cast<std::uint32_t>(thermistor::series_resistor) * adc / (thermistor::adc_full_scale - adc);
|
||||||
}
|
}
|
||||||
|
|
||||||
// One value per line behind a dotted label, as the original had it. A single
|
// One value per line behind a dotted label, as the original had it. A single
|
||||||
@@ -282,9 +282,9 @@ class terminal {
|
|||||||
{
|
{
|
||||||
// A line that overflowed the buffer is not a command - it is the tail of
|
// A line that overflowed the buffer is not a command - it is the tail of
|
||||||
// one. Acting on it is how a truncated `reset` becomes a surprise.
|
// one. Acting on it is how a truncated `reset` becomes a surprise.
|
||||||
if (overflowed) {
|
if (m_overflowed) {
|
||||||
serial << "input too long, ignored\r\n"_P;
|
serial << "input too long, ignored\r\n"_P;
|
||||||
overflowed = false;
|
m_overflowed = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -318,7 +318,7 @@ class terminal {
|
|||||||
print_curve();
|
print_curve();
|
||||||
return;
|
return;
|
||||||
case 3:
|
case 3:
|
||||||
monitoring = true;
|
m_monitoring = true;
|
||||||
return;
|
return;
|
||||||
case 4:
|
case 4:
|
||||||
serial << "entering bootloader\r\n"_P;
|
serial << "entering bootloader\r\n"_P;
|
||||||
@@ -398,17 +398,17 @@ class terminal {
|
|||||||
|
|
||||||
static void poll()
|
static void poll()
|
||||||
{
|
{
|
||||||
if (monitoring) {
|
if (m_monitoring) {
|
||||||
if (uptime::millis() >= last_monitor + 1000) {
|
if (uptime::millis() >= m_last_monitor + 1000) {
|
||||||
show();
|
show();
|
||||||
last_monitor = uptime::millis();
|
m_last_monitor = uptime::millis();
|
||||||
}
|
}
|
||||||
// Ctrl+C only, as the original had it. Stopping on *any* byte reads
|
// Ctrl+C only, as the original had it. Stopping on *any* byte reads
|
||||||
// well until a host sends a line ending: `monitor\r\n` then stops
|
// well until a host sends a line ending: `monitor\r\n` then stops
|
||||||
// itself on the `\n` it arrived with, one reading in.
|
// itself on the `\n` it arrived with, one reading in.
|
||||||
if (auto in = serial_t::read(); in && *in == ctrl_c) {
|
if (auto in = serial_t::read(); in && *in == ctrl_c) {
|
||||||
serial << "^C\r\n"_P;
|
serial << "^C\r\n"_P;
|
||||||
monitoring = false;
|
m_monitoring = false;
|
||||||
prompt();
|
prompt();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -419,18 +419,18 @@ class terminal {
|
|||||||
// Abandon whatever was typed and start a fresh line, which is
|
// Abandon whatever was typed and start a fresh line, which is
|
||||||
// what Ctrl+C means at every other prompt in the world.
|
// what Ctrl+C means at every other prompt in the world.
|
||||||
serial << "^C\r\n"_P;
|
serial << "^C\r\n"_P;
|
||||||
at = 0;
|
m_at = 0;
|
||||||
overflowed = false;
|
m_overflowed = false;
|
||||||
prompt();
|
prompt();
|
||||||
} else if (c == '\r' || c == '\n') {
|
} else if (c == '\r' || c == '\n') {
|
||||||
serial << "\r\n"_P;
|
serial << "\r\n"_P;
|
||||||
if (at == 0 && !overflowed) {
|
if (m_at == 0 && !m_overflowed) {
|
||||||
prompt(); // a bare Enter just reprompts, no gap needed
|
prompt(); // a bare Enter just reprompts, no gap needed
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
dispatch(std::string_view{line.data(), at});
|
dispatch(std::string_view{m_line.data(), m_at});
|
||||||
at = 0;
|
m_at = 0;
|
||||||
if (!monitoring) {
|
if (!m_monitoring) {
|
||||||
// A blank line between a command's output and the next
|
// A blank line between a command's output and the next
|
||||||
// prompt: without it the answer and the thing you type
|
// prompt: without it the answer and the thing you type
|
||||||
// next run together and a screen of them is unreadable.
|
// next run together and a screen of them is unreadable.
|
||||||
@@ -438,16 +438,16 @@ class terminal {
|
|||||||
prompt();
|
prompt();
|
||||||
}
|
}
|
||||||
} else if (c == del || c == backspace) {
|
} else if (c == del || c == backspace) {
|
||||||
if (at) {
|
if (m_at) {
|
||||||
--at;
|
--m_at;
|
||||||
serial << "\b \b"_P;
|
serial << "\b \b"_P;
|
||||||
}
|
}
|
||||||
} else if (c >= ' ') {
|
} else if (c >= ' ') {
|
||||||
if (at < line.size()) {
|
if (m_at < m_line.size()) {
|
||||||
line[at++] = c;
|
m_line[m_at++] = c;
|
||||||
serial << c; // echo
|
serial << c; // echo
|
||||||
} else {
|
} else {
|
||||||
overflowed = true; // reported when the line is submitted
|
m_overflowed = true; // reported when the line is submitted
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,10 @@
|
|||||||
// counts map to quarter- C with linear interpolation between table steps.
|
// counts map to quarter- C with linear interpolation between table steps.
|
||||||
namespace app::thermistor {
|
namespace app::thermistor {
|
||||||
|
|
||||||
|
// The converter's top count: this board reads the divider at the ADC's
|
||||||
|
// full 10 bits, so a reading and the resistance it implies both scale by it.
|
||||||
|
inline constexpr std::uint16_t adc_full_scale = (1u << 10) - 1;
|
||||||
|
|
||||||
inline constexpr double series_resistor = 9951;
|
inline constexpr double series_resistor = 9951;
|
||||||
inline constexpr double nominal_resistance = 9270;
|
inline constexpr double nominal_resistance = 9270;
|
||||||
inline constexpr double beta = 3212;
|
inline constexpr double beta = 3212;
|
||||||
@@ -20,7 +24,7 @@ namespace detail {
|
|||||||
|
|
||||||
consteval double temperature_of(double adc)
|
consteval double temperature_of(double adc)
|
||||||
{
|
{
|
||||||
double resistance = series_resistor * adc / (1023.0 - adc);
|
double resistance = series_resistor * adc / (adc_full_scale - adc);
|
||||||
// __builtin_log constant-folds on the AVR backend, so the table is
|
// __builtin_log constant-folds on the AVR backend, so the table is
|
||||||
// built at compile time with no runtime libm.
|
// built at compile time with no runtime libm.
|
||||||
double steinhart = __builtin_log(resistance / nominal_resistance) / beta + 1.0 / (nominal_temperature + 273.15);
|
double steinhart = __builtin_log(resistance / nominal_resistance) / beta + 1.0 / (nominal_temperature + 273.15);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# The board has no reset line and no programming header, so the loader-entry
|
# The board has no reset line and no programming header, so the loader-entry
|
||||||
# route in the emitted image is the only thing standing between a firmware change
|
# route in the emitted image is the only thing standing between a firmware change
|
||||||
# and an unreflashable board. It has been wrong before - see the script.
|
# and an unreflashable board.
|
||||||
find_package(Python3 COMPONENTS Interpreter)
|
find_package(Python3 COMPONENTS Interpreter)
|
||||||
if(Python3_FOUND)
|
if(Python3_FOUND)
|
||||||
add_test(NAME fantemp.reachability
|
add_test(NAME fantemp.reachability
|
||||||
|
|||||||
Reference in New Issue
Block a user