forked from M-Labs/kirdy
Thermostat: Add fns to report status & settings
- Report all system status, PID Settings, NTC parameter, TEC Settings
This commit is contained in:
parent
ff3d9b790a
commit
2f7ca2a706
|
@ -7,6 +7,7 @@ use stm32f4xx_hal::pac::{CorePeripherals, Peripherals};
|
|||
mod device;
|
||||
mod laser_diode;
|
||||
mod thermostat;
|
||||
mod pid;
|
||||
|
||||
use device::{boot::bootup, log_setup, sys_timer};
|
||||
use uom::fmt::DisplayStyle::Abbreviation;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
use miniconf::Miniconf;
|
||||
use miniconf::serde::{Serialize, Deserialize};
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Miniconf)]
|
||||
pub struct Parameters {
|
||||
/// Gain coefficient for proportional term
|
||||
pub kp: f32,
|
||||
|
@ -28,8 +28,9 @@ impl Default for Parameters {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Debug, PartialEq, Miniconf)]
|
||||
pub struct Controller {
|
||||
#[miniconf(defer)]
|
||||
pub parameters: Parameters,
|
||||
pub target : f64,
|
||||
u1 : f64,
|
||||
|
@ -88,6 +89,7 @@ impl Controller {
|
|||
|
||||
#[derive(Clone, Debug, Miniconf)]
|
||||
pub struct Summary {
|
||||
#[miniconf(defer)]
|
||||
parameters: Parameters,
|
||||
target: f64,
|
||||
}
|
||||
|
|
|
@ -23,8 +23,8 @@ const VREF_SENS: f64 = 3.3 / 2.0;
|
|||
pub struct PidState {
|
||||
pub adc_data: Option<u32>,
|
||||
pub adc_calibration: ad7172::ChannelCalibration,
|
||||
pub sample_ts: Instant,
|
||||
pub sampling_interval: Duration,
|
||||
pub update_ts: Time,
|
||||
pub update_interval: Time,
|
||||
/// i_set 0A center point
|
||||
pub center_point: ElectricPotential,
|
||||
pub dac_volt: ElectricPotential,
|
||||
|
@ -45,9 +45,9 @@ impl Default for PidState {
|
|||
PidState {
|
||||
adc_data: None,
|
||||
adc_calibration: ad7172::ChannelCalibration::default(),
|
||||
sample_ts: Instant::from_secs(0),
|
||||
update_ts: Time::new::<millisecond>(0.0),
|
||||
// default: 10 Hz
|
||||
sampling_interval: Duration::from_millis(100),
|
||||
update_interval: Time::new::<millisecond>(100.0),
|
||||
center_point: ElectricPotential::new::<volt>(1.5),
|
||||
dac_volt: ElectricPotential::new::<volt>(0.0),
|
||||
pid_engaged: false,
|
||||
|
@ -69,8 +69,8 @@ impl PidState {
|
|||
} else {
|
||||
Some(adc_data)
|
||||
};
|
||||
self.sampling_interval = now - self.sample_ts;
|
||||
self.sample_ts = now;
|
||||
self.update_interval = Time::new::<millisecond>(now.millis() as f64) - self.update_ts;
|
||||
self.update_ts = Time::new::<millisecond>(now.millis() as f64);
|
||||
}
|
||||
|
||||
/// Update PID state on ADC input, calculate new DAC output
|
||||
|
@ -81,12 +81,12 @@ impl PidState {
|
|||
Some(pid_output)
|
||||
}
|
||||
|
||||
pub fn get_sample_ts(&self) -> Time {
|
||||
Time::new::<millisecond>(self.sample_ts.total_millis() as f64)
|
||||
pub fn get_update_ts(&self) -> Time {
|
||||
self.update_ts
|
||||
}
|
||||
|
||||
pub fn get_sampling_interval(&self) -> Time {
|
||||
Time::new::<millisecond>(self.sampling_interval.total_millis() as f64)
|
||||
pub fn get_update_interval(&self) -> Time {
|
||||
self.update_interval
|
||||
}
|
||||
|
||||
pub fn get_adc(&self) -> Option<ElectricPotential> {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use core::marker::PhantomData;
|
||||
use smoltcp::time::Instant;
|
||||
use crate::sys_timer;
|
||||
use crate::{sys_timer, pid::pid};
|
||||
use crate::thermostat::ad5680;
|
||||
use crate::thermostat::max1968::{MAX1968, AdcReadTarget, PwmPinsEnum};
|
||||
use crate::thermostat::ad7172;
|
||||
|
@ -11,7 +11,7 @@ use uom::si::{
|
|||
electric_current::ampere,
|
||||
electric_potential::volt,
|
||||
electrical_resistance::ohm,
|
||||
f64::{ElectricCurrent, ElectricPotential, ElectricalResistance, Time},
|
||||
f64::{ElectricCurrent, ElectricPotential, ElectricalResistance, Time, ThermodynamicTemperature},
|
||||
ratio::ratio,
|
||||
};
|
||||
use miniconf::Miniconf;
|
||||
|
@ -23,7 +23,7 @@ pub const R_SENSE: ElectricalResistance = ElectricalResistance {
|
|||
};
|
||||
|
||||
#[derive(Clone, Debug, Miniconf)]
|
||||
pub struct Settings {
|
||||
pub struct TecSettings {
|
||||
pub center_pt: ElectricPotential,
|
||||
pub max_v_set: ElectricPotential,
|
||||
pub max_i_pos_set: ElectricCurrent,
|
||||
|
@ -31,7 +31,7 @@ pub struct Settings {
|
|||
pub i_set: ElectricCurrent,
|
||||
}
|
||||
|
||||
impl Settings{
|
||||
impl TecSettings{
|
||||
// FixMe: Rev0_2 is 3.3V max while Rev0_3 is 3.0V max
|
||||
pub const DAC_OUT_V_MAX: ElectricPotential = ElectricPotential {
|
||||
dimension: PhantomData,
|
||||
|
@ -47,6 +47,11 @@ impl Settings{
|
|||
// Kirdy Design Specs:
|
||||
// MaxV = 5.0V
|
||||
// MAX Current = +- 1.0A
|
||||
const MAX_I_SET : ElectricCurrent = ElectricCurrent {
|
||||
dimension: PhantomData,
|
||||
units: PhantomData,
|
||||
value: 1.0,
|
||||
};
|
||||
const MAX_V_DUTY_TO_CURRENT_RATE: ElectricPotential = ElectricPotential {
|
||||
dimension: PhantomData,
|
||||
units: PhantomData,
|
||||
|
@ -57,7 +62,7 @@ impl Settings{
|
|||
units: PhantomData,
|
||||
value: 5.0,
|
||||
};
|
||||
const MAX_V_DUTY_MAX: f64 = Settings::MAX_V_MAX.value / Settings::MAX_V_DUTY_TO_CURRENT_RATE.value;
|
||||
const MAX_V_DUTY_MAX: f64 = TecSettings::MAX_V_MAX.value / TecSettings::MAX_V_DUTY_TO_CURRENT_RATE.value;
|
||||
const MAX_I_POS_NEG_DUTY_TO_CURRENT_RATE: ElectricCurrent = ElectricCurrent {
|
||||
dimension: PhantomData,
|
||||
units: PhantomData,
|
||||
|
@ -74,11 +79,11 @@ impl Settings{
|
|||
value: 1.0,
|
||||
};
|
||||
// .get::<ratio>() is not implemented for const
|
||||
const MAX_I_POS_DUTY_MAX: f64 = Settings::MAX_I_POS_CURRENT.value / Settings::MAX_I_POS_NEG_DUTY_TO_CURRENT_RATE.value;
|
||||
const MAX_I_NEG_DUTY_MAX: f64 = Settings::MAX_I_NEG_CURRENT.value / Settings::MAX_I_POS_NEG_DUTY_TO_CURRENT_RATE.value;
|
||||
const MAX_I_POS_DUTY_MAX: f64 = TecSettings::MAX_I_POS_CURRENT.value / TecSettings::MAX_I_POS_NEG_DUTY_TO_CURRENT_RATE.value;
|
||||
const MAX_I_NEG_DUTY_MAX: f64 = TecSettings::MAX_I_NEG_CURRENT.value / TecSettings::MAX_I_POS_NEG_DUTY_TO_CURRENT_RATE.value;
|
||||
}
|
||||
|
||||
impl Default for Settings {
|
||||
impl Default for TecSettings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
center_pt: ElectricPotential::new::<volt>(1.5),
|
||||
|
@ -93,7 +98,7 @@ impl Default for Settings {
|
|||
pub struct Thermostat {
|
||||
max1968: MAX1968,
|
||||
ad7172: ad7172::AdcPhy,
|
||||
pub tec_setting: Settings,
|
||||
pub tec_setting: TecSettings,
|
||||
pid_ctrl_ch0: PidState,
|
||||
}
|
||||
|
||||
|
@ -102,7 +107,7 @@ impl Thermostat{
|
|||
Thermostat{
|
||||
max1968: max1968,
|
||||
ad7172: ad7172,
|
||||
tec_setting: Settings::default(),
|
||||
tec_setting: TecSettings::default(),
|
||||
pid_ctrl_ch0: PidState::default(),
|
||||
}
|
||||
}
|
||||
|
@ -115,7 +120,7 @@ impl Thermostat{
|
|||
fn tec_setup(&mut self) {
|
||||
self.power_down();
|
||||
|
||||
self.tec_setting = Settings::default();
|
||||
self.tec_setting = TecSettings::default();
|
||||
|
||||
self.set_i(self.tec_setting.i_set);
|
||||
|
||||
|
@ -169,29 +174,29 @@ impl Thermostat{
|
|||
|
||||
pub fn set_i(&mut self, i_tec: ElectricCurrent) -> ElectricCurrent {
|
||||
let voltage = i_tec * 10.0 * R_SENSE + self.tec_setting.center_pt;
|
||||
let voltage = self.max1968.set_dac(voltage, Settings::DAC_OUT_V_MAX);
|
||||
let voltage = self.max1968.set_dac(voltage, TecSettings::DAC_OUT_V_MAX);
|
||||
self.tec_setting.i_set = (voltage - self.tec_setting.center_pt) / (10.0 * R_SENSE);
|
||||
self.tec_setting.i_set
|
||||
}
|
||||
|
||||
pub fn set_max_v(&mut self, max_v: ElectricPotential) -> ElectricPotential {
|
||||
let duty = (max_v / Settings::MAX_V_DUTY_TO_CURRENT_RATE).get::<ratio>();
|
||||
let duty = self.max1968.set_pwm(PwmPinsEnum::MaxV, duty, Settings::MAX_V_DUTY_MAX);
|
||||
self.tec_setting.max_v_set = duty * Settings::MAX_V_DUTY_TO_CURRENT_RATE;
|
||||
let duty = (max_v / TecSettings::MAX_V_DUTY_TO_CURRENT_RATE).get::<ratio>();
|
||||
let duty = self.max1968.set_pwm(PwmPinsEnum::MaxV, duty, TecSettings::MAX_V_DUTY_MAX);
|
||||
self.tec_setting.max_v_set = duty * TecSettings::MAX_V_DUTY_TO_CURRENT_RATE;
|
||||
self.tec_setting.max_v_set
|
||||
}
|
||||
|
||||
pub fn set_max_i_pos(&mut self, max_i_pos: ElectricCurrent) -> ElectricCurrent {
|
||||
let duty = (max_i_pos / Settings::MAX_I_POS_NEG_DUTY_TO_CURRENT_RATE).get::<ratio>();
|
||||
let duty = self.max1968.set_pwm(PwmPinsEnum::MaxPosI, duty, Settings::MAX_I_POS_DUTY_MAX);
|
||||
self.tec_setting.max_i_pos_set = duty * Settings::MAX_I_POS_NEG_DUTY_TO_CURRENT_RATE;
|
||||
let duty = (max_i_pos / TecSettings::MAX_I_POS_NEG_DUTY_TO_CURRENT_RATE).get::<ratio>();
|
||||
let duty = self.max1968.set_pwm(PwmPinsEnum::MaxPosI, duty, TecSettings::MAX_I_POS_DUTY_MAX);
|
||||
self.tec_setting.max_i_pos_set = duty * TecSettings::MAX_I_POS_NEG_DUTY_TO_CURRENT_RATE;
|
||||
self.tec_setting.max_i_pos_set
|
||||
}
|
||||
|
||||
pub fn set_max_i_neg(&mut self, max_i_neg: ElectricCurrent) -> ElectricCurrent {
|
||||
let duty = (max_i_neg / Settings::MAX_I_POS_NEG_DUTY_TO_CURRENT_RATE).get::<ratio>();
|
||||
let duty = self.max1968.set_pwm(PwmPinsEnum::MaxNegI, duty, Settings::MAX_I_NEG_DUTY_MAX);
|
||||
self.tec_setting.max_i_neg_set = duty * Settings::MAX_I_POS_NEG_DUTY_TO_CURRENT_RATE;
|
||||
let duty = (max_i_neg / TecSettings::MAX_I_POS_NEG_DUTY_TO_CURRENT_RATE).get::<ratio>();
|
||||
let duty = self.max1968.set_pwm(PwmPinsEnum::MaxNegI, duty, TecSettings::MAX_I_NEG_DUTY_MAX);
|
||||
self.tec_setting.max_i_neg_set = duty * TecSettings::MAX_I_POS_NEG_DUTY_TO_CURRENT_RATE;
|
||||
self.tec_setting.max_i_neg_set
|
||||
}
|
||||
|
||||
|
@ -211,7 +216,7 @@ impl Thermostat{
|
|||
pub fn get_tec_v(&mut self) -> ElectricPotential {
|
||||
// Fixme: Rev0_2 has Analog Input Polarity Reversed
|
||||
// Remove the -ve sign for Rev0_3
|
||||
-(self.max1968.adc_read(AdcReadTarget::VTec, 16) - Settings::TEC_VSEC_BIAS_V) * 4.0
|
||||
-(self.max1968.adc_read(AdcReadTarget::VTec, 16) - TecSettings::TEC_VSEC_BIAS_V) * 4.0
|
||||
}
|
||||
|
||||
/// Calibrates the DAC output to match vref of the MAX driver to reduce zero-current offset of the MAX driver output.
|
||||
|
@ -250,7 +255,7 @@ impl Thermostat{
|
|||
best_error = error;
|
||||
start_value = prev_value;
|
||||
|
||||
let vref = (value as f64 / ad5680::MAX_VALUE as f64) * Settings::DAC_OUT_V_MAX;
|
||||
let vref = (value as f64 / ad5680::MAX_VALUE as f64) * TecSettings::DAC_OUT_V_MAX;
|
||||
self.set_center_pt(vref);
|
||||
}
|
||||
prev_value = value;
|
||||
|
@ -266,4 +271,71 @@ impl Thermostat{
|
|||
false
|
||||
}
|
||||
|
||||
pub fn get_status_report(&mut self) -> StatusReport {
|
||||
StatusReport {
|
||||
pid_update_ts: self.pid_ctrl_ch0.get_update_ts(),
|
||||
pid_update_interval: self.pid_ctrl_ch0.get_update_interval(),
|
||||
pid_engaged: self.pid_engaged(),
|
||||
temperature: self.pid_ctrl_ch0.get_temperature(),
|
||||
i_set: self.tec_setting.i_set,
|
||||
tec_i: self.get_tec_i(),
|
||||
tec_v: self.get_tec_v(),
|
||||
tec_vref: self.get_vref(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_pid_settings(&mut self) -> pid::Controller {
|
||||
self.pid_ctrl_ch0.pid.clone()
|
||||
}
|
||||
|
||||
pub fn get_steinhart_hart(&mut self) -> steinhart_hart::Parameters {
|
||||
self.pid_ctrl_ch0.sh.clone()
|
||||
}
|
||||
|
||||
pub fn get_tec_settings(&mut self) -> TecSettingSummary {
|
||||
TecSettingSummary {
|
||||
center_point: self.tec_setting.center_pt,
|
||||
i_set: TecSettingsSummaryField { value: self.tec_setting.i_set, max: TecSettings::MAX_I_SET },
|
||||
max_v: TecSettingsSummaryField { value: self.tec_setting.max_v_set, max: TecSettings::MAX_V_MAX },
|
||||
max_i_pos: TecSettingsSummaryField { value: self.tec_setting.max_i_pos_set, max: TecSettings::MAX_I_POS_CURRENT },
|
||||
max_i_neg: TecSettingsSummaryField { value: self.tec_setting.max_i_neg_set, max: TecSettings::MAX_I_NEG_CURRENT },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Miniconf)]
|
||||
pub struct StatusReport {
|
||||
pid_update_ts: Time,
|
||||
pid_update_interval: Time,
|
||||
pid_engaged: bool,
|
||||
temperature: Option<ThermodynamicTemperature>,
|
||||
i_set: ElectricCurrent,
|
||||
tec_i: ElectricCurrent,
|
||||
tec_v: ElectricPotential,
|
||||
tec_vref: ElectricPotential,
|
||||
}
|
||||
|
||||
#[derive(Miniconf)]
|
||||
pub struct TecSettingsSummaryField<T> {
|
||||
value: T,
|
||||
max: T,
|
||||
}
|
||||
|
||||
#[derive(Miniconf)]
|
||||
pub struct TecSettingSummary {
|
||||
center_point: ElectricPotential,
|
||||
#[miniconf(defer)]
|
||||
i_set: TecSettingsSummaryField<ElectricCurrent>,
|
||||
#[miniconf(defer)]
|
||||
max_v: TecSettingsSummaryField<ElectricPotential>,
|
||||
#[miniconf(defer)]
|
||||
max_i_pos: TecSettingsSummaryField<ElectricCurrent>,
|
||||
#[miniconf(defer)]
|
||||
max_i_neg: TecSettingsSummaryField<ElectricCurrent>,
|
||||
}
|
||||
|
||||
#[derive(Miniconf)]
|
||||
pub struct SteinhartHartSummary {
|
||||
#[miniconf(defer)]
|
||||
params: steinhart_hart::Parameters,
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue