diff --git a/src/device/boot.rs b/src/device/boot.rs index 24fb2dc..1d587da 100644 --- a/src/device/boot.rs +++ b/src/device/boot.rs @@ -1,5 +1,6 @@ use super::{gpio, sys_timer, usb}; use crate::laser_diode::current_sources::*; +use crate::laser_diode::pd_mon::PdMon; use crate::thermostat::max1968::{MAX1968}; use crate::thermostat::thermostat::Thermostat; use fugit::ExtU32; @@ -38,7 +39,7 @@ pub fn bootup( sys_timer::setup(core_perif.SYST, clocks); - let (_eth_pins, usb, current_source_phy, max1968_phy) = gpio::setup( + let (_eth_pins, usb, current_source_phy, pd_mon_phy, max1968_phy) = gpio::setup( clocks, perif.TIM4, perif.GPIOA, @@ -65,6 +66,9 @@ pub fn bootup( laser.setup(); laser.set_current(0.1).unwrap(); + let mut pd_mon = PdMon::new(pd_mon_phy, perif.ADC2); + + let tec_driver = MAX1968::new(max1968_phy, perif.ADC1); let mut thermostat = Thermostat::new(tec_driver); diff --git a/src/device/gpio.rs b/src/device/gpio.rs index 90380d1..e89abeb 100644 --- a/src/device/gpio.rs +++ b/src/device/gpio.rs @@ -1,4 +1,5 @@ use crate::laser_diode::current_sources::*; +use crate::laser_diode::pd_mon::PdMonPhy; use crate::thermostat::ad5680; use crate::thermostat::max1968::{Channel0, MAX1968PinSet, MAX1968Phy, PWM_FREQ_KHZ}; use fugit::RateExtU32; @@ -36,8 +37,8 @@ pub fn setup( EthernetPins, USB, CurrentSourcePhyConstruct, + PdMonPhy, MAX1968Phy, - // photo_diode_phy, // thermostat_phy ) { let gpioa = gpioa.split(); @@ -86,6 +87,10 @@ pub fn setup( current_source_short: gpioa.pa4.into_push_pull_output(), }; + let pd_mon_phy = PdMonPhy { + ch0_pin: gpioa.pa3.into_analog() + }; + let pwm_chs = ( gpiob.pb6.into_alternate(), gpiob.pb7.into_alternate(), @@ -121,5 +126,5 @@ pub fn setup( max_i_neg: max_i_neg0, }); - (eth_pins, usb, current_source_phy, max1968_phy) + (eth_pins, usb, current_source_phy, pd_mon_phy, max1968_phy) } diff --git a/src/laser_diode/current_sources.rs b/src/laser_diode/current_sources.rs index 143de88..f329050 100644 --- a/src/laser_diode/current_sources.rs +++ b/src/laser_diode/current_sources.rs @@ -1,12 +1,13 @@ use stm32f4xx_hal::{ - gpio::{gpioa::*, gpiob::*, gpiod::*, Alternate, Output, PushPull, PD9}, + gpio::{gpioa::*, gpiob::*, gpiod::*, Alternate, Output, PushPull, Analog, PD9}, hal::{blocking::spi::Write, digital::v2::OutputPin}, pac::SPI2, spi::{NoMiso, Spi, TransferModeNormal}, }; use crate::device::sys_timer::sleep; -pub trait CurrentSourcePhy { +pub trait ChannelPins { + type PdMonPin; type CurrentSourceLdoEn: OutputPin; type CurrentSourceShort: OutputPin; type Max5719Load: OutputPin; @@ -14,7 +15,7 @@ pub trait CurrentSourcePhy { type Max5719Spi: Write; } -pub struct CurrentSourcePhyConstruct { +pub struct CurrentSourcePhyConstruct { pub max5719_spi: C::Max5719Spi, pub max5719_load: C::Max5719Load, pub max5719_cs: C::Max5719Cs, @@ -24,14 +25,15 @@ pub struct CurrentSourcePhyConstruct { pub struct CurrentSourceSettings { pub output_current: f32, } -pub struct CurrentSource { +pub struct CurrentSource { pub phy: CurrentSourcePhyConstruct, pub setting: CurrentSourceSettings, } -pub struct CurrentSourcePhyCh0; +pub struct Channel0; -impl CurrentSourcePhy for CurrentSourcePhyCh0 { +impl ChannelPins for Channel0 { + type PdMonPin = PA3; type CurrentSourceLdoEn = PD9>; type CurrentSourceShort = PA4>; type Max5719Load = PB14>; @@ -40,7 +42,7 @@ impl CurrentSourcePhy for CurrentSourcePhyCh0 { Spi>, NoMiso, PB15>), TransferModeNormal>; } -impl CurrentSource { +impl CurrentSource { pub fn setup(&mut self) { let _ = self.phy.max5719_load.set_high(); let _ = self.phy.max5719_cs.set_high(); @@ -53,7 +55,7 @@ impl CurrentSource { pub fn set_current( &mut self, current: f32, - ) -> Result<(), <::Max5719Spi as Write>::Error> { + ) -> Result<(), <::Max5719Spi as Write>::Error> { let _ = self.phy.max5719_load.set_high(); let _ = self.phy.max5719_cs.set_low(); self.setting.output_current = current * 10.0 / 0.75; diff --git a/src/laser_diode/mod.rs b/src/laser_diode/mod.rs index e15efa5..c49bc5f 100644 --- a/src/laser_diode/mod.rs +++ b/src/laser_diode/mod.rs @@ -1 +1 @@ -pub mod current_sources; +pub mod current_sources; \ No newline at end of file diff --git a/src/thermostat/max1968.rs b/src/thermostat/max1968.rs index 2b527df..4581d16 100644 --- a/src/thermostat/max1968.rs +++ b/src/thermostat/max1968.rs @@ -2,7 +2,7 @@ use core::marker::PhantomData; use core::u16; use crate::thermostat::ad5680; -use crate::thermostat::thermostat::{DAC_OUT_V_MAX, TEC_VSEC_BIAS_V}; +use crate::thermostat::thermostat::Settings; use fugit::KilohertzU32; use stm32f4xx_hal::{ @@ -59,8 +59,6 @@ impl ChannelPins for Channel0 { } pub struct MAX1968Phy { - // state - pub center_pt: ElectricPotential, pub dac: ad5680::Dac, pub shdn: C::ShdnPin, pub vref_pin: C::VRefPin, @@ -86,12 +84,6 @@ pub struct MAX1968PinSet { type DacSpi = Spi>, NoMiso, PB5>), TransferModeNormal>; type DacSync = PB4>; -pub struct MaxAdcPins { - pub dac_vfb: PC0, - pub vref: PA6, - pub itec: PB1, - pub vtec: PB0, -} pub struct MAX1968 { // settings @@ -115,7 +107,6 @@ pub enum AdcReadTarget { impl MAX1968Phy { pub fn new(pins: MAX1968PinSet) -> Self { MAX1968Phy { - center_pt: ElectricPotential::new::(1.5), dac: pins.dac, shdn: pins.shdn, vref_pin: pins.vref_pin, @@ -143,27 +134,17 @@ impl MAX1968 { } } - // pub fn setup(&mut self) { - // self.power_down(); - - // let vref = self.adc_read(AdcReadTarget::VREF, 2048); - // self.set_center_point(vref); - // } - pub fn power_down(&mut self) { - let _ = self.phy.shdn.set_low(); + self.phy.shdn.set_low(); } pub fn power_up(&mut self) { - let _ = self.phy.shdn.set_high(); + self.phy.shdn.set_high(); } - pub fn set_center_point(&mut self, value: ElectricPotential) { - self.phy.center_pt = value; - } - pub fn set_dac(&mut self, voltage: ElectricPotential) -> ElectricPotential { - let value = ((voltage / ElectricPotential::new::(DAC_OUT_V_MAX)).get::() + pub fn set_dac(&mut self, voltage: ElectricPotential, dac_out_v_max: ElectricPotential) -> ElectricPotential { + let value = ((voltage / dac_out_v_max).get::() * (ad5680::MAX_VALUE as f64)) as u32; self.phy.dac.set(value).unwrap(); // TODO: Store the set-ed DAC Voltage Value @@ -216,25 +197,6 @@ impl MAX1968 { ElectricPotential::new::(mv as f64) } - pub fn get_vref(&mut self) -> ElectricPotential { - self.adc_read(AdcReadTarget::VREF, 16) - } - - pub fn get_dac_vfb(&mut self) -> ElectricPotential { - self.adc_read(AdcReadTarget:: DacVfb, 16) - } - - pub fn get_tec_i(&mut self) -> ElectricCurrent { - (self.adc_read(AdcReadTarget::ITec, 1) - self.phy.center_pt) - / ElectricalResistance::new::(0.4) - } - - pub fn get_tec_v(&mut self) -> ElectricPotential { - // Fixme: Rev0_2 has Analog Input Polarity Reversed - // Remove the -ve sign for Rev0_3 - -(self.adc_read(AdcReadTarget::VTec, 1) - TEC_VSEC_BIAS_V) * 4.0 - } - pub fn set_pwm(&mut self, pwm_pin: PwmPinsEnum, duty: f64, max_duty: f64) -> f64 { fn set>(pin: &mut P, duty: f64) -> f64 { let max = pin.get_max_duty(); diff --git a/src/thermostat/thermostat.rs b/src/thermostat/thermostat.rs index eb61f01..7026269 100644 --- a/src/thermostat/thermostat.rs +++ b/src/thermostat/thermostat.rs @@ -3,13 +3,15 @@ use crate::sys_timer; use crate::thermostat::ad5680; use crate::thermostat::max1968::{MAX1968, AdcReadTarget, PwmPinsEnum}; use log::info; +use miniconf::serde::de::value; use uom::si::{ electric_current::ampere, - electric_potential::{millivolt, volt}, + electric_potential::volt, electrical_resistance::ohm, f64::{ElectricCurrent, ElectricPotential, ElectricalResistance}, ratio::ratio, }; +use miniconf::Miniconf; pub const R_SENSE: ElectricalResistance = ElectricalResistance { dimension: PhantomData, @@ -17,72 +19,99 @@ pub const R_SENSE: ElectricalResistance = ElectricalResistance { value: 0.05, }; -// Rev 0_2: DAC Chip connects 3V3 reference voltage and thus provide 0-3.3V output range -// TODO: Rev 0_3: DAC Chip connects 3V3 reference voltage, -// which is then passed through a resistor divider to provide 0-3V output range -pub const DAC_OUT_V_MAX: f64 = 3.3; -pub const TEC_VSEC_BIAS_V: ElectricPotential = ElectricPotential { - dimension: PhantomData, - units: PhantomData, - value: 1.65, -}; +#[derive(Clone, Debug, Miniconf)] +pub struct Settings { + pub center_pt: ElectricPotential, + pub max_v_set: ElectricPotential, + pub max_i_pos_set: ElectricCurrent, + pub max_i_neg_set: ElectricCurrent, + pub i_set: ElectricCurrent, +} -// Kirdy Design Specs: -// MaxV = 5.0V -// MAX Current = +- 1.0A -const MAX_V_DUTY_TO_CURRENT_RATE: ElectricPotential = ElectricPotential { - dimension: PhantomData, - units: PhantomData, - value: 4.0 * 3.3, -}; -pub const MAX_V_MAX: ElectricPotential = ElectricPotential { - dimension: PhantomData, - units: PhantomData, - value: 5.0, -}; -const MAX_V_DUTY_MAX: f64 = MAX_V_MAX.value / MAX_V_DUTY_TO_CURRENT_RATE.value; -const MAX_I_POS_NEG_DUTY_TO_CURRENT_RATE: ElectricCurrent = ElectricCurrent { - dimension: PhantomData, - units: PhantomData, - value: 1.0 / (10.0 * R_SENSE.value / 3.3), -}; -pub const MAX_I_POS_CURRENT: ElectricCurrent = ElectricCurrent { - dimension: PhantomData, - units: PhantomData, - value: 1.0, -}; -pub const MAX_I_NEG_CURRENT: ElectricCurrent = ElectricCurrent { - dimension: PhantomData, - units: PhantomData, - value: 1.0, -}; -// .get::() is not implemented for const -const MAX_I_POS_DUTY_MAX: f64 = MAX_I_POS_CURRENT.value / MAX_I_POS_NEG_DUTY_TO_CURRENT_RATE.value; -const MAX_I_NEG_DUTY_MAX: f64 = MAX_I_NEG_CURRENT.value / MAX_I_POS_NEG_DUTY_TO_CURRENT_RATE.value; +impl Settings{ + // FixMe: Rev0_2 is 3.3V max while Rev0_3 is 3.0V max + pub const DAC_OUT_V_MAX: ElectricPotential = ElectricPotential { + dimension: PhantomData, + units: PhantomData, + value: 3.3, + }; + pub const TEC_VSEC_BIAS_V: ElectricPotential = ElectricPotential { + dimension: PhantomData, + units: PhantomData, + value: 1.65, + }; + + // Kirdy Design Specs: + // MaxV = 5.0V + // MAX Current = +- 1.0A + const MAX_V_DUTY_TO_CURRENT_RATE: ElectricPotential = ElectricPotential { + dimension: PhantomData, + units: PhantomData, + value: 4.0 * 3.3, + }; + pub const MAX_V_MAX: ElectricPotential = ElectricPotential { + dimension: PhantomData, + 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_I_POS_NEG_DUTY_TO_CURRENT_RATE: ElectricCurrent = ElectricCurrent { + dimension: PhantomData, + units: PhantomData, + value: 1.0 / (10.0 * R_SENSE.value / 3.3), + }; + pub const MAX_I_POS_CURRENT: ElectricCurrent = ElectricCurrent { + dimension: PhantomData, + units: PhantomData, + value: 1.0, + }; + pub const MAX_I_NEG_CURRENT: ElectricCurrent = ElectricCurrent { + dimension: PhantomData, + units: PhantomData, + value: 1.0, + }; + // .get::() 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; +} + +impl Default for Settings { + fn default() -> Self { + Self { + center_pt: ElectricPotential::new::(1.5), + max_v_set: ElectricPotential::new::(5.0), + max_i_pos_set: ElectricCurrent::new::(1.0), + max_i_neg_set: ElectricCurrent::new::(1.0), + i_set: ElectricCurrent::new::(0.0), + } + } +} pub struct Thermostat { max1968: MAX1968, + pub tec_setting: Settings, // TADC } impl Thermostat{ pub fn new (max1968: MAX1968) -> Self { Thermostat{ - max1968 + max1968: max1968, + tec_setting: Settings::default(), } } pub fn setup(&mut self) { - self.power_down(); + self.power_up(); + + self.tec_setting = Settings::default(); self.calibrate_dac_value(); - self.set_i(ElectricCurrent::new::(0.0)); + self.set_i(self.tec_setting.i_set); - self.set_max_v(ElectricPotential::new::(5.0)); - self.set_max_i_pos(ElectricCurrent::new::(1.0)); - self.set_max_i_neg(ElectricCurrent::new::(1.0)); - - self.max1968.power_up(); + self.set_max_v(self.tec_setting.max_v_set); + self.set_max_i_pos(self.tec_setting.max_i_pos_set); + self.set_max_i_neg(self.tec_setting.max_i_neg_set); } pub fn power_up(&mut self){ @@ -93,29 +122,56 @@ impl Thermostat{ self.max1968.power_down(); } + fn set_center_pt(&mut self, value: ElectricPotential){ + info!("set center pt: {:?}", value); + self.tec_setting.center_pt = value; + } + pub fn set_i(&mut self, i_tec: ElectricCurrent) -> ElectricCurrent { - let voltage = i_tec * 10.0 * R_SENSE + self.max1968.phy.center_pt; - let voltage = self.max1968.set_dac(voltage); - let i_tec = (voltage - self.max1968.phy.center_pt) / (10.0 * R_SENSE); - i_tec + 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); + 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 / MAX_V_DUTY_TO_CURRENT_RATE).get::(); - let duty = self.max1968.set_pwm(PwmPinsEnum::MaxV, duty, MAX_V_DUTY_MAX); - duty * MAX_V_DUTY_TO_CURRENT_RATE + let duty = (max_v / Settings::MAX_V_DUTY_TO_CURRENT_RATE).get::(); + 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; + self.tec_setting.max_v_set } pub fn set_max_i_pos(&mut self, max_i_pos: ElectricCurrent) -> ElectricCurrent { - let duty = (max_i_pos / MAX_I_POS_NEG_DUTY_TO_CURRENT_RATE).get::(); - let duty = self.max1968.set_pwm(PwmPinsEnum::MaxPosI, duty, MAX_I_POS_DUTY_MAX); - duty * MAX_I_POS_NEG_DUTY_TO_CURRENT_RATE + let duty = (max_i_pos / Settings::MAX_I_POS_NEG_DUTY_TO_CURRENT_RATE).get::(); + 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; + 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 / MAX_I_POS_NEG_DUTY_TO_CURRENT_RATE).get::(); - let duty = self.max1968.set_pwm(PwmPinsEnum::MaxNegI, duty, MAX_I_NEG_DUTY_MAX); - duty * MAX_I_POS_NEG_DUTY_TO_CURRENT_RATE + let duty = (max_i_neg / Settings::MAX_I_POS_NEG_DUTY_TO_CURRENT_RATE).get::(); + 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; + self.tec_setting.max_i_neg_set + } + + pub fn get_dac_vfb(&mut self) -> ElectricPotential { + self.max1968.adc_read(AdcReadTarget::DacVfb, 16) + } + + pub fn get_vref(&mut self) -> ElectricPotential { + self.max1968.adc_read(AdcReadTarget::VREF, 16) + } + + pub fn get_tec_i(&mut self) -> ElectricCurrent { + let vref = self.get_vref(); + (self.max1968.adc_read(AdcReadTarget::ITec, 16) - vref) / ElectricalResistance::new::(0.4) + } + + 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 } /// Calibrates the DAC output to match vref of the MAX driver to reduce zero-current offset of the MAX driver output. @@ -135,19 +191,14 @@ impl Thermostat{ /// VREF measurement can introduce significant noise at the current output, degrading the stabilily performance of the /// thermostat. pub fn calibrate_dac_value(&mut self) { - let samples = 50; - let mut target_voltage = ElectricPotential::new::(0.0); - for _ in 0..samples { - target_voltage = target_voltage + self.max1968.adc_read(AdcReadTarget::VREF, 1); - } - target_voltage = target_voltage / samples as f64; + let target_voltage = self.max1968.adc_read(AdcReadTarget::VREF, 64); let mut start_value = 1; let mut best_error = ElectricPotential::new::(100.0); for step in (0..18).rev() { info!("Step: {} Calibrating", step); let mut prev_value = start_value; for value in (start_value..=ad5680::MAX_VALUE).step_by(1 << step) { - //info!("Calibrating"); + info!("Calibrating: Value: {:?}", value); self.max1968.phy.dac.set(value).unwrap(); sys_timer::sleep(5); @@ -159,12 +210,13 @@ impl Thermostat{ best_error = error; start_value = prev_value; - let vref = (value as f64 / ad5680::MAX_VALUE as f64) * ElectricPotential::new::(DAC_OUT_V_MAX); - self.max1968.set_center_point(vref); + let vref = (value as f64 / ad5680::MAX_VALUE as f64) * Settings::DAC_OUT_V_MAX; + self.set_center_pt(vref); } prev_value = value; } } + info!("Best Error: {:?}", best_error); } } \ No newline at end of file