Compare commits
5 Commits
ecfcce13a8
...
ec5bf1d6b6
Author | SHA1 | Date |
---|---|---|
linuswck | ec5bf1d6b6 | |
linuswck | 3737c2ed59 | |
linuswck | 4cd328d98c | |
linuswck | af95de0f16 | |
linuswck | db2f76771a |
|
@ -1,45 +1,148 @@
|
|||
from driver.kirdy_async import Kirdy
|
||||
from pprint import pp
|
||||
from driver.kirdy_async import Kirdy, FilterConfig
|
||||
import asyncio
|
||||
import signal
|
||||
|
||||
async def main():
|
||||
kirdy = Kirdy()
|
||||
await kirdy.start_session(host='192.168.1.128', port=1337, timeout=0.25)
|
||||
await kirdy.device.set_active_report_mode(False)
|
||||
"""
|
||||
Enter Device Firmware Upgrade(Dfu) mode
|
||||
Please see README.md for flash instructions.
|
||||
"""
|
||||
async def enter_dfu_mode(kirdy: Kirdy):
|
||||
print(await kirdy.device.dfu())
|
||||
await kirdy.end_session()
|
||||
exit()
|
||||
|
||||
"""
|
||||
Configure Kirdy to actively report status
|
||||
Press Ctrl + C to exit active report mode
|
||||
"""
|
||||
async def active_report(kirdy: Kirdy):
|
||||
class SignalHandler:
|
||||
def __init__(self):
|
||||
signal.signal(signal.SIGINT, self.exit_gracefully)
|
||||
signal.signal(signal.SIGTERM, self.exit_gracefully)
|
||||
def exit_gracefully(self, signum, frame):
|
||||
kirdy.stop_report_mode()
|
||||
|
||||
signal_handler = SignalHandler()
|
||||
|
||||
async for data in kirdy.report_mode():
|
||||
pp(data)
|
||||
|
||||
"""
|
||||
Configure Kirdy network and board specific transconductance settings.
|
||||
These configs are saved to flash immediately after command is processed.
|
||||
"""
|
||||
async def device_cfg(kirdy: Kirdy):
|
||||
# Kirdy rev0_3's gain and transconductance varies between boards to maximize the
|
||||
# PD current range resolution.
|
||||
await kirdy.device.set_pd_mon_fin_gain(1.0)
|
||||
await kirdy.device.set_pd_mon_transconductance(1/1000.0)
|
||||
|
||||
# Network Settings will be updated on next reboot.
|
||||
await kirdy.device.set_ip_settings(
|
||||
addr="192.168.1.128",
|
||||
port=1337,
|
||||
prefix_len=24,
|
||||
gateway="192.168.1.1"
|
||||
)
|
||||
# Hard reset Kirdy.
|
||||
await kirdy.device.hard_reset()
|
||||
await kirdy.end_session()
|
||||
exit()
|
||||
|
||||
"""
|
||||
Control and config laser diode and thermostat parameters.
|
||||
"""
|
||||
async def ld_thermostat_cfg(kirdy: Kirdy):
|
||||
# Load the laser diode and thermostat settings from flash
|
||||
await kirdy.device.restore_settings_from_flash()
|
||||
|
||||
# Power off the laser diode and thermostat and clear alarm (if any)
|
||||
await kirdy.laser.set_power_on(False)
|
||||
await kirdy.laser.clear_alarm()
|
||||
await kirdy.laser.set_i(0)
|
||||
await kirdy.laser.set_i_soft_limit(0.25)
|
||||
await kirdy.laser.set_power_on(True)
|
||||
|
||||
await kirdy.thermostat.set_power_on(False)
|
||||
await kirdy.thermostat.clear_alarm()
|
||||
|
||||
# Set the laser diode terminals not to be shorted
|
||||
await kirdy.laser.set_ld_terms_short(False)
|
||||
|
||||
# Do not power up the laser & thermostat during initial startup
|
||||
await kirdy.laser.set_default_pwr_on(False)
|
||||
await kirdy.thermostat.set_default_pwr_on(False)
|
||||
|
||||
# The laser diode output current range is bounded by this software limit setting
|
||||
await kirdy.laser.set_i(0)
|
||||
await kirdy.laser.set_i_soft_limit(30.0 / 1000)
|
||||
|
||||
# Configure the laser diode output power limit and photodiode parameters
|
||||
# Exceeding the measured power limit triggers overpower protection alarm.
|
||||
# The laser diode power will be turned off while the thermostat power remains unchanged.
|
||||
await kirdy.laser.set_ld_pwr_limit(0.0)
|
||||
await kirdy.laser.set_pd_mon_dark_current(0.0)
|
||||
await kirdy.laser.set_pd_mon_responsitivity(0.0)
|
||||
|
||||
# Configure the thermostat NTC thermistor parameters.
|
||||
await kirdy.thermostat.set_sh_r0(10.0 * 1000)
|
||||
await kirdy.thermostat.set_sh_t0(25)
|
||||
await kirdy.thermostat.set_sh_beta(3900)
|
||||
|
||||
await kirdy.thermostat.set_temperature_setpoint(25)
|
||||
await kirdy.thermostat.set_temp_mon_upper_limit(40)
|
||||
await kirdy.thermostat.set_temp_mon_lower_limit(10)
|
||||
# Configure the thermostat output limits.
|
||||
# The actual output current is limited by the hardware limit set below.
|
||||
await kirdy.thermostat.set_tec_max_cooling_i(1.0)
|
||||
await kirdy.thermostat.set_tec_max_heating_i(1.0)
|
||||
await kirdy.thermostat.set_tec_max_v(4.0)
|
||||
|
||||
# Configure the thermostat temperature monitor limit.
|
||||
# Exceeding the limit will trigger over temperature protection alarm.
|
||||
# The laser diode and thermostat power will be turned off.
|
||||
await kirdy.thermostat.set_temp_mon_upper_limit(70)
|
||||
await kirdy.thermostat.set_temp_mon_lower_limit(0)
|
||||
|
||||
# Configure the thermostat PID related parameter.
|
||||
# You can configure the PID parameter with the autotune tool.
|
||||
# Here provides an example if it is configured manually.
|
||||
await kirdy.thermostat.set_temperature_setpoint(25)
|
||||
await kirdy.thermostat.set_pid_kp(0.15668282198105507)
|
||||
await kirdy.thermostat.set_pid_ki(0.002135962407793784)
|
||||
await kirdy.thermostat.set_pid_kd(0.829254515277143)
|
||||
|
||||
await kirdy.thermostat.set_pid_output_max(1.0)
|
||||
await kirdy.thermostat.set_pid_output_min(-1.0)
|
||||
|
||||
await kirdy.thermostat.config_temp_adc_filter("Sinc5Sinc1With50hz60HzRejection", "F16SPS")
|
||||
await kirdy.thermostat.set_power_on(True)
|
||||
# Configure the thermostat ADC Filter Setting / PID Update Rate / Report Rate.
|
||||
# The ADC sampling rate determines the report and pid update rate.
|
||||
# The chosen filter and sampling rate affects the noise of the readings.
|
||||
# For details, please refer to the AD7172 datasheet.
|
||||
await kirdy.thermostat.config_temp_adc_filter(FilterConfig.Sinc5Sinc1With50hz60HzRejection.f16sps)
|
||||
|
||||
# Configure thermostat to run in PID control mode
|
||||
await kirdy.thermostat.set_pid_control_mode()
|
||||
|
||||
await kirdy.laser.set_default_pwr_on(False)
|
||||
await kirdy.thermostat.set_default_pwr_on(True)
|
||||
# When control mode is switched from PID to constant current(CC) control mode,
|
||||
# the thermostat keeps its instantaneous output current unchanged.
|
||||
# Thermostat output current should only be set if it is in CC control mode
|
||||
# or the value set will not be overwritten by PID output.
|
||||
await kirdy.thermostat.set_constant_current_control_mode()
|
||||
await kirdy.thermostat.set_tec_i_out(0.0)
|
||||
|
||||
# Save the above settings configured into the flash
|
||||
await kirdy.device.save_current_settings_to_flash()
|
||||
|
||||
async for data in kirdy.report_mode():
|
||||
print(data)
|
||||
# Power on the laser diode and thermostat
|
||||
await kirdy.laser.set_power_on(True)
|
||||
await kirdy.thermostat.set_power_on(True)
|
||||
|
||||
pp(await kirdy.device.get_settings_summary())
|
||||
pp(await kirdy.device.get_status_report())
|
||||
|
||||
async def main():
|
||||
kirdy = Kirdy()
|
||||
await kirdy.start_session(host='192.168.1.128', port=1337, timeout=0.25)
|
||||
|
||||
# await ld_thermostat_cfg(kirdy)
|
||||
# await active_report(kirdy)
|
||||
# await device_cfg(kirdy)
|
||||
await enter_dfu_mode(kirdy)
|
||||
|
||||
await kirdy.end_session()
|
||||
|
||||
|
|
|
@ -129,16 +129,11 @@ class FilterConfig:
|
|||
def _filter_type(self):
|
||||
return "Sinc3"
|
||||
|
||||
############## Rewrite
|
||||
class Sinc3WithFineODR():
|
||||
def __init__(self, rate):
|
||||
assert rate >= 1.907465 and rate <= 31250
|
||||
self.rate = float(rate)
|
||||
|
||||
# def rate(self, rate):
|
||||
# assert rate >= 1.907465 and rate <= 31250
|
||||
# return float(rate)
|
||||
|
||||
def _odr_type(self):
|
||||
return "sinc3fineodr"
|
||||
|
||||
|
@ -228,7 +223,7 @@ class Device:
|
|||
'ld_i_set': 0.0, # Laser Diode Output Current (A)
|
||||
'pd_i': 2.0000002e-06, # Internal Photodiode Monitor current (A)
|
||||
'pd_pwr': None, # Power Readings from Internal Photodiode (W). Return None if pd_mon parameter(s) are not defined.
|
||||
'term_status': 'Is50Ohm' # Is the Low Frequency Modulation Input's Impedance 50 Ohm? (Is50Ohm/Not50Ohm)
|
||||
'term_50ohm': 'Is50Ohm' # Is the Low Frequency Modulation Input's Impedance 50 Ohm? (On/Off)
|
||||
},
|
||||
'thermostat': {
|
||||
'pwr_on': False, # Tec Power is On (True/False)
|
||||
|
|
|
@ -332,7 +332,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
|||
{'name': 'LD Current Set', 'type': 'float', 'suffix': 'A', 'siPrefix': True, 'readonly': True},
|
||||
{'name': 'PD Current', 'type': 'float', 'suffix': 'A', 'siPrefix': True, 'readonly': True},
|
||||
{'name': 'PD Power', 'type': 'float', 'suffix': 'W', 'siPrefix': True, 'readonly': True},
|
||||
{'name': 'LF Mod Impedance', 'type': 'list', 'limits': ['Is50Ohm', 'Not50Ohm'], 'readonly': True}
|
||||
{'name': 'LF Mod Termination (50 Ohm)', 'type': 'list', 'limits': ['On', 'Off'], 'readonly': True}
|
||||
]},
|
||||
{'name': 'Output Config', 'expanded': True, 'type': 'group', 'children': [
|
||||
{'name': 'LD Current Set', 'type': 'float', 'value': 0, 'step': 1, 'decimals': 6, 'limits': (0, 1),
|
||||
|
@ -818,7 +818,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
|||
self.params[1].child('Readings', 'PD Power').setValue(report["pd_pwr"])
|
||||
else:
|
||||
self.params[1].child('Readings', 'PD Power').setValue(0)
|
||||
self.params[1].child('Readings', 'LF Mod Impedance').setValue(report["term_status"])
|
||||
self.params[1].child('Readings', 'LF Mod Termination (50 Ohm)').setValue(report["term_50ohm"])
|
||||
except Exception as e:
|
||||
logging.error(f"Params tree cannot be updated. Data:{report}", exc_info=True)
|
||||
|
||||
|
@ -898,7 +898,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
|||
try:
|
||||
if not (self.kirdy.connecting() or self.kirdy.connected()):
|
||||
self.status_lbl.setText("Connecting...")
|
||||
await self.kirdy.start_session(host=host, port=port, timeout=0.1)
|
||||
await self.kirdy.start_session(host=host, port=port, timeout=5.0)
|
||||
await self._on_connection_changed(True)
|
||||
else:
|
||||
await self.bail()
|
||||
|
|
|
@ -10,7 +10,7 @@ use uom::si::{electric_current::{ampere, milliampere},
|
|||
power::milliwatt};
|
||||
|
||||
use crate::{device::sys_timer::sleep,
|
||||
laser_diode::{ld_ctrl::{Impedance, LdCtrl},
|
||||
laser_diode::{ld_ctrl::{Impedance50Ohm, LdCtrl},
|
||||
ld_current_out_ctrl_timer::LdCurrentOutCtrlTimer,
|
||||
ld_pwr_exc_protector::{self, LdPwrExcProtector},
|
||||
pd_mon_params}};
|
||||
|
@ -66,7 +66,7 @@ pub struct StatusReport {
|
|||
ld_i_set: ElectricCurrent,
|
||||
pd_i: ElectricCurrent,
|
||||
pd_pwr: Power,
|
||||
term_status: Impedance,
|
||||
term_50ohm: Impedance50Ohm,
|
||||
}
|
||||
|
||||
pub struct LdDrive {
|
||||
|
@ -210,7 +210,7 @@ impl LdDrive {
|
|||
self.settings.default_pwr_on = pwr_on;
|
||||
}
|
||||
|
||||
pub fn get_term_status(&mut self) -> Impedance {
|
||||
pub fn get_term_status(&mut self) -> Impedance50Ohm {
|
||||
self.ctrl.get_lf_mod_in_impedance()
|
||||
}
|
||||
|
||||
|
@ -226,7 +226,7 @@ impl LdDrive {
|
|||
ld_i_set: ld_i_set,
|
||||
pd_i: self.get_pd_i(),
|
||||
pd_pwr: self.get_pd_pwr(),
|
||||
term_status: self.get_term_status(),
|
||||
term_50ohm: self.get_term_status(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -255,6 +255,9 @@ impl LdDrive {
|
|||
self.settings.pd_mon_params = settings.pd_mon_params;
|
||||
self.settings.ld_pwr_limit = settings.ld_pwr_limit;
|
||||
self.settings.default_pwr_on = settings.default_pwr_on;
|
||||
|
||||
self.set_ld_power_limit(settings.ld_pwr_limit);
|
||||
|
||||
if self.settings.ld_terms_short {
|
||||
self.ld_short();
|
||||
} else {
|
||||
|
|
|
@ -11,9 +11,9 @@ use uom::si::{electric_current::ampere,
|
|||
use crate::laser_diode::max5719::{self, Dac};
|
||||
|
||||
#[derive(Deserialize, Serialize, Debug, Clone, Copy)]
|
||||
pub enum Impedance {
|
||||
Is50Ohm,
|
||||
Not50Ohm,
|
||||
pub enum Impedance50Ohm {
|
||||
On,
|
||||
Off,
|
||||
}
|
||||
|
||||
pub trait ChannelPins {
|
||||
|
@ -66,11 +66,11 @@ impl LdCtrl {
|
|||
self.phy.current_source_short_pin.set_high();
|
||||
}
|
||||
|
||||
pub fn get_lf_mod_in_impedance(&mut self) -> Impedance {
|
||||
pub fn get_lf_mod_in_impedance(&mut self) -> Impedance50Ohm {
|
||||
if self.phy.termination_status_pin.is_high() {
|
||||
Impedance::Is50Ohm
|
||||
Impedance50Ohm::On
|
||||
} else {
|
||||
Impedance::Not50Ohm
|
||||
Impedance50Ohm::Off
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ use stm32f4xx_hal::{adc::{config::{self, AdcConfig},
|
|||
timer::pwm::PwmChannel};
|
||||
use uom::si::{electric_potential::millivolt, f32::ElectricPotential, ratio::ratio};
|
||||
|
||||
use crate::thermostat::ad5680;
|
||||
use crate::{device::sys_timer::sleep, thermostat::ad5680};
|
||||
|
||||
pub const PWM_FREQ_KHZ: KilohertzU32 = KilohertzU32::from_raw(20);
|
||||
|
||||
|
@ -77,6 +77,7 @@ pub struct MAX1968 {
|
|||
pub phy: MAX1968Phy<Channel0>,
|
||||
pub pins_adc: Adc<ADC1>,
|
||||
pub dma_adc: DMA_Transfer<Stream2<DMA2>, 1, Adc<ADC2>, PeripheralToMemory, &'static mut [u16; 16]>,
|
||||
pub dac_out_range: ElectricPotential,
|
||||
prev_vtec_volt: ElectricPotential,
|
||||
prev_itec_volt: ElectricPotential,
|
||||
}
|
||||
|
@ -115,7 +116,7 @@ static mut ADC2_FIRST_BUFFER: [u16; 16] = [0; 16];
|
|||
static mut ADC2_LOCAL_BUFFER: [u16; 16] = [0; 16];
|
||||
|
||||
impl MAX1968 {
|
||||
pub fn new(phy_ch0: MAX1968Phy<Channel0>, adc1: ADC1, adc2: ADC2, dma2: DMA2) -> Self {
|
||||
pub fn new(mut phy_ch0: MAX1968Phy<Channel0>, adc1: ADC1, adc2: ADC2, dma2: DMA2) -> Self {
|
||||
let adc_config = AdcConfig::default()
|
||||
.clock(config::Clock::Pclk2_div_8)
|
||||
.default_sample_time(config::SampleTime::Cycles_480);
|
||||
|
@ -222,10 +223,26 @@ impl MAX1968 {
|
|||
NVIC::unmask(interrupt::DMA2_STREAM2);
|
||||
}
|
||||
|
||||
phy_ch0.dac.set(ad5680::MAX_VALUE).unwrap();
|
||||
sleep(500);
|
||||
let mut sample = 0;
|
||||
for _ in 0..512 {
|
||||
sample += pins_adc1.convert(
|
||||
&phy_ch0.dac_feedback_pin,
|
||||
stm32f4xx_hal::adc::config::SampleTime::Cycles_480,
|
||||
) as u32;
|
||||
}
|
||||
let sample = sample / 512 as u32;
|
||||
let mv = pins_adc1.sample_to_millivolts(sample as u16);
|
||||
let dac_out_range = ElectricPotential::new::<millivolt>(mv as f32);
|
||||
phy_ch0.dac.set(0).unwrap();
|
||||
|
||||
|
||||
MAX1968 {
|
||||
phy: phy_ch0,
|
||||
pins_adc: pins_adc1,
|
||||
dma_adc: dma_adc,
|
||||
dac_out_range: dac_out_range,
|
||||
prev_vtec_volt: ElectricPotential::new::<millivolt>(0.0),
|
||||
prev_itec_volt: ElectricPotential::new::<millivolt>(0.0),
|
||||
}
|
||||
|
|
|
@ -47,11 +47,6 @@ pub struct TecSettings {
|
|||
}
|
||||
|
||||
impl TecSettings {
|
||||
pub const DAC_OUT_V_MAX: ElectricPotential = ElectricPotential {
|
||||
dimension: PhantomData,
|
||||
units: PhantomData,
|
||||
value: 3.0,
|
||||
};
|
||||
pub const TEC_VSEC_BIAS_V: ElectricPotential = ElectricPotential {
|
||||
dimension: PhantomData,
|
||||
units: PhantomData,
|
||||
|
@ -237,7 +232,8 @@ impl Thermostat {
|
|||
|
||||
pub fn set_i(&mut self, i_tec: ElectricCurrent) -> ElectricCurrent {
|
||||
let voltage = i_tec * 10.0 * R_SENSE + self.tec_settings.center_pt;
|
||||
let voltage = self.max1968.set_dac(voltage, TecSettings::DAC_OUT_V_MAX);
|
||||
let voltage = self.max1968.set_dac(voltage, self.max1968.dac_out_range);
|
||||
|
||||
self.tec_settings.i_set = (voltage - self.tec_settings.center_pt) / (10.0 * R_SENSE);
|
||||
self.tec_settings.i_set
|
||||
}
|
||||
|
@ -335,7 +331,7 @@ impl Thermostat {
|
|||
best_error = error;
|
||||
start_value = prev_value;
|
||||
|
||||
let vref = (value as f32 / ad5680::MAX_VALUE as f32) * TecSettings::DAC_OUT_V_MAX;
|
||||
let vref = (value as f32 / ad5680::MAX_VALUE as f32) * self.max1968.dac_out_range;
|
||||
self.set_center_pt(vref);
|
||||
}
|
||||
prev_value = value;
|
||||
|
|
Loading…
Reference in New Issue