Same controller: thermistor on ADC0 averaged over 1000 free-running conversions, 50 kHz fan PWM on OC0B, 115200 Bd console with the full command set, EEPROM temperature histogram, watchdog-reset path into the boot section. The Steinhart-Hart math and the libm log are gone — the Beta equation and the cubic fan curve are consteval-evaluated into flash tables; the firmware never does floating point. Byte-identical .text in both libavr modes. Legacy stays on master. Co-Authored-By: Claude <noreply@anthropic.com>
69 lines
1.9 KiB
C++
69 lines
1.9 KiB
C++
#pragma once
|
|
|
|
#include <libavr/libavr.hpp>
|
|
|
|
// The board composition: every peripheral of the fan controller in one
|
|
// place. ATmega328P at 16 MHz — thermistor divider on ADC0 (PC0), fan on
|
|
// OC0B (PD5) at 50 kHz, console on the hardware UART.
|
|
namespace app {
|
|
|
|
using namespace avr::literals;
|
|
|
|
using dev = avr::device<{.clock = 16_MHz}>;
|
|
|
|
// Millisecond uptime from timer2 CTC (the fan owns timer0).
|
|
class uptime {
|
|
static inline volatile std::uint64_t ms = 0;
|
|
|
|
public:
|
|
using ticker = dev::timer2<{.frequency = 1_kHz, .on_compare = [] { ms = ms + 1; }}>;
|
|
|
|
static std::uint64_t millis()
|
|
{
|
|
avr::irq::atomic_guard lock;
|
|
return ms;
|
|
}
|
|
};
|
|
|
|
// 1000-sample averaging window fed by the conversion interrupt.
|
|
class sampler {
|
|
static inline volatile std::uint32_t sum = 0;
|
|
static inline volatile std::uint16_t count = 0;
|
|
static inline volatile std::uint16_t window = 0;
|
|
static inline volatile bool ready = false;
|
|
|
|
static constexpr std::uint16_t samples = 1000;
|
|
|
|
public:
|
|
using input = dev::adc<{.input = avr::adc::input_pin(0),
|
|
.trigger = avr::adc::trigger::free_running,
|
|
.on_conversion = [](std::uint16_t value) {
|
|
sum = sum + value;
|
|
count = count + 1;
|
|
if (count >= samples) {
|
|
window = static_cast<std::uint16_t>(sum / samples);
|
|
sum = 0;
|
|
count = 0;
|
|
ready = true;
|
|
}
|
|
}}>;
|
|
|
|
// The finished average (raw 10-bit), once per window.
|
|
static bool take(std::uint16_t &value)
|
|
{
|
|
avr::irq::atomic_guard lock;
|
|
if (!ready)
|
|
return false;
|
|
value = window;
|
|
ready = false;
|
|
return true;
|
|
}
|
|
};
|
|
|
|
using fan = dev::pwm<avr::pd5, {.frequency = 50_kHz}>;
|
|
|
|
using serial_t = dev::uart0<{.baud = 115200_Bd, .rx_buffer = 32, .max_baud_error = 2.5_pct}>;
|
|
inline constexpr serial_t serial{};
|
|
|
|
} // namespace app
|