diff --git a/src/device/boot.rs b/src/device/boot.rs index 7cecd00..24fb2dc 100644 --- a/src/device/boot.rs +++ b/src/device/boot.rs @@ -1,6 +1,7 @@ use super::{gpio, sys_timer, usb}; use crate::laser_diode::current_sources::*; -use crate::thermostat::max1968::MAX1968; +use crate::thermostat::max1968::{MAX1968}; +use crate::thermostat::thermostat::Thermostat; use fugit::ExtU32; use log::info; use stm32f4xx_hal::{ @@ -20,7 +21,7 @@ const WATCHDOG_PERIOD: u32 = 30000; pub fn bootup( mut core_perif: CorePeripherals, perif: Peripherals, -) -> (IndependentWatchdog, MAX1968) { +) -> (IndependentWatchdog, Thermostat) { core_perif.SCB.enable_icache(); core_perif.SCB.enable_dcache(&mut core_perif.CPUID); @@ -64,13 +65,12 @@ pub fn bootup( laser.setup(); laser.set_current(0.1).unwrap(); - let mut tec_driver = MAX1968::new(max1968_phy, perif.ADC1); + let tec_driver = MAX1968::new(max1968_phy, perif.ADC1); - tec_driver.setup(); - - tec_driver.set_i(ElectricCurrent::new::(1.0)); - - tec_driver.power_up(); + let mut thermostat = Thermostat::new(tec_driver); + thermostat.setup(); + thermostat.set_i(ElectricCurrent::new::(1.0)); + thermostat.power_up(); let mut wd = IndependentWatchdog::new(perif.IWDG); wd.start(WATCHDOG_PERIOD.millis()); @@ -78,5 +78,5 @@ pub fn bootup( info!("Kirdy setup complete"); - (wd, tec_driver) + (wd, thermostat) } diff --git a/src/thermostat/max1968.rs b/src/thermostat/max1968.rs index 92c6ccd..2b527df 100644 --- a/src/thermostat/max1968.rs +++ b/src/thermostat/max1968.rs @@ -2,6 +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 fugit::KilohertzU32; use stm32f4xx_hal::{ @@ -26,54 +27,6 @@ use uom::si::{ }; pub const PWM_FREQ_KHZ: KilohertzU32 = KilohertzU32::from_raw(20); -pub const R_SENSE: ElectricalResistance = ElectricalResistance { - dimension: PhantomData, - units: PhantomData, - 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; -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 = 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; pub trait ChannelPins { type DacSpi: Transfer; @@ -146,12 +99,7 @@ pub struct MAX1968 { pub pins_adc: Adc, } -pub struct PwmPins { - pub max_v0: PwmChannel, - pub max_i_pos0: PwmChannel, - pub max_i_neg0: PwmChannel, -} -enum PwmPinsEnum { +pub enum PwmPinsEnum { MaxV, MaxPosI, MaxNegI, @@ -164,34 +112,6 @@ pub enum AdcReadTarget { VTec, } -impl PwmPins { - fn setup(clocks: Clocks, tim4: TIM4, max_v0: PB7, max_i_pos0: PB8, max_i_neg0: PB6) -> PwmPins { - fn init_pwm_pin>(pin: &mut P) { - pin.set_duty(0); - pin.enable(); - } - - let channels = ( - max_i_neg0.into_alternate::<2>(), - max_v0.into_alternate::<2>(), - max_i_pos0.into_alternate::<2>(), - ); - - let (mut max_i_neg0, mut max_v0, mut max_i_pos0) = - tim4.pwm_hz(channels, PWM_FREQ_KHZ.convert(), &clocks).split(); - - init_pwm_pin(&mut max_v0); - init_pwm_pin(&mut max_i_neg0); - init_pwm_pin(&mut max_i_pos0); - - PwmPins { - max_v0, - max_i_pos0, - max_i_neg0, - } - } -} - impl MAX1968Phy { pub fn new(pins: MAX1968PinSet) -> Self { MAX1968Phy { @@ -223,19 +143,12 @@ impl MAX1968 { } } - pub fn setup(&mut self) { - self.power_down(); + // pub fn setup(&mut self) { + // self.power_down(); - let vref = self.adc_read(AdcReadTarget::VREF, 2048); - self.set_center_point(vref); - - // Todo: Add Calibration here - 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.set_i(ElectricCurrent::new::(0.0)); - } + // 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(); @@ -249,7 +162,7 @@ impl MAX1968 { self.phy.center_pt = value; } - fn set_dac(&mut self, voltage: ElectricPotential) -> ElectricPotential { + pub fn set_dac(&mut self, voltage: ElectricPotential) -> ElectricPotential { let value = ((voltage / ElectricPotential::new::(DAC_OUT_V_MAX)).get::() * (ad5680::MAX_VALUE as f64)) as u32; self.phy.dac.set(value).unwrap(); @@ -257,13 +170,6 @@ impl MAX1968 { voltage } - pub fn set_i(&mut self, i_tec: ElectricCurrent) -> ElectricCurrent { - let voltage = i_tec * 10.0 * R_SENSE + self.phy.center_pt; - let voltage = self.set_dac(voltage); - let i_tec = (voltage - self.phy.center_pt) / (10.0 * R_SENSE); - i_tec - } - // AN4073: ADC Reading Dispersion can be reduced through Averaging // Upon test, 16 Point Averaging = +-3 LSB Dispersion pub fn adc_read(&mut self, adc_read_target: AdcReadTarget, avg_pt: u16) -> ElectricPotential { @@ -329,7 +235,7 @@ impl MAX1968 { -(self.adc_read(AdcReadTarget::VTec, 1) - TEC_VSEC_BIAS_V) * 4.0 } - fn set_pwm(&mut self, pwm_pin: PwmPinsEnum, duty: f64, max_duty: f64) -> f64 { + 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(); let value = ((duty * (max as f64)) as u16).min(max); @@ -347,21 +253,4 @@ impl MAX1968 { } } - 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.set_pwm(PwmPinsEnum::MaxV, duty, MAX_V_DUTY_MAX); - duty * MAX_V_DUTY_TO_CURRENT_RATE - } - - 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.set_pwm(PwmPinsEnum::MaxPosI, duty, MAX_I_POS_DUTY_MAX); - duty * MAX_I_POS_NEG_DUTY_TO_CURRENT_RATE - } - - 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.set_pwm(PwmPinsEnum::MaxNegI, duty, MAX_I_NEG_DUTY_MAX); - duty * MAX_I_POS_NEG_DUTY_TO_CURRENT_RATE - } } diff --git a/src/thermostat/thermostat.rs b/src/thermostat/thermostat.rs index 91f5d70..eb61f01 100644 --- a/src/thermostat/thermostat.rs +++ b/src/thermostat/thermostat.rs @@ -1,6 +1,7 @@ +use core::marker::PhantomData; use crate::sys_timer; use crate::thermostat::ad5680; -use crate::thermostat::max1968::{MAX1968, AdcReadTarget, DAC_OUT_V_MAX}; +use crate::thermostat::max1968::{MAX1968, AdcReadTarget, PwmPinsEnum}; use log::info; use uom::si::{ electric_current::ampere, @@ -10,6 +11,55 @@ use uom::si::{ ratio::ratio, }; +pub const R_SENSE: ElectricalResistance = ElectricalResistance { + dimension: PhantomData, + units: PhantomData, + 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, +}; + +// 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; + pub struct Thermostat { max1968: MAX1968, // TADC @@ -21,8 +71,51 @@ impl Thermostat{ max1968 } } - pub fn setup(&mut self){ - self.max1968.setup(); + pub fn setup(&mut self) { + self.power_down(); + + self.calibrate_dac_value(); + + self.set_i(ElectricCurrent::new::(0.0)); + + 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(); + } + + pub fn power_up(&mut self){ + self.max1968.power_up(); + } + + pub fn power_down(&mut self){ + self.max1968.power_down(); + } + + 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 + } + + 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 + } + + 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 + } + + 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 } /// Calibrates the DAC output to match vref of the MAX driver to reduce zero-current offset of the MAX driver output. @@ -50,7 +143,6 @@ impl Thermostat{ target_voltage = target_voltage / samples as f64; let mut start_value = 1; let mut best_error = ElectricPotential::new::(100.0); - let before_cal = self.max1968.phy.center_pt; for step in (0..18).rev() { info!("Step: {} Calibrating", step); let mut prev_value = start_value; @@ -69,20 +161,10 @@ impl Thermostat{ let vref = (value as f64 / ad5680::MAX_VALUE as f64) * ElectricPotential::new::(DAC_OUT_V_MAX); self.max1968.set_center_point(vref); - } prev_value = value; } } - - loop { - info!("Before Calibration, VREF = {:?}", before_cal); - info!("After Calibration, VREF = {:?}", self.max1968.phy.center_pt); - self.max1968.set_i(ElectricCurrent::new::(0.0)); - info!("VREF Value {:?}", self.max1968.adc_read(AdcReadTarget::VREF, 64)); - info!("DAC VFB Value {:?}", self.max1968.adc_read(AdcReadTarget::DacVfb, 64)); - sys_timer::sleep(100); - } } } \ No newline at end of file