pd_mon: make transconductance user-configurable

- hw change: different boards now have different gain settings in order
    to set a pd current range close to the ld being used
- transconductance and fin_gain params are added to flash with "Device"
    as key
This commit is contained in:
linuswck 2024-06-13 11:10:40 +08:00
parent d1660c6090
commit d5a620c76b
6 changed files with 109 additions and 31 deletions

View File

@ -132,6 +132,22 @@ class Device:
""" """
return await self._send_cmd(TARGET_DEVICE, "SetActiveReportMode", on) return await self._send_cmd(TARGET_DEVICE, "SetActiveReportMode", on)
async def set_pd_mon_fin_gain(self, gain):
"""
Configure the photodiode monitor transconductance
- gain: unitless
"""
print("set_pd_mon_fin_gain")
return await self._send_cmd(TARGET_DEVICE, "SetPdFinGain", gain)
async def set_pd_mon_transconductance(self, transconductance):
"""
Configure the photodiode monitor transconductance
- transconductance: 1/Ohm
"""
print("set_pd_mon_transconductance")
return await self._send_cmd(TARGET_DEVICE, "SetPdTransconductance", transconductance)
async def get_status_report(self): async def get_status_report(self):
""" """
Get status of all peripherals in a json object Get status of all peripherals in a json object
@ -541,6 +557,8 @@ class Kirdy:
self._cmd_list = { self._cmd_list = {
TARGET_DEVICE: { TARGET_DEVICE: {
"SetIPSettings": IP_SETTINGS, "SetIPSettings": IP_SETTINGS,
"SetPdFinGain": DATA_F32,
"SetPdTransconductance": DATA_F32,
"SetActiveReportMode": DATA_BOOL, "SetActiveReportMode": DATA_BOOL,
"GetStatusReport": None, "GetStatusReport": None,
"GetSettingsSummary": None, "GetSettingsSummary": None,

View File

@ -1,14 +1,13 @@
use core::marker::PhantomData; use core::marker::PhantomData;
use log::info;
use miniconf::Tree; use miniconf::Tree;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use stm32f4xx_hal::{pac::{ADC3, TIM2}, use stm32f4xx_hal::{pac::{ADC3, TIM2},
timer::CounterUs}; timer::CounterUs};
use uom::{si::{electric_current::{ampere, milliampere}, use uom::si::{electric_current::{ampere, milliampere},
f32::{ElectricCurrent, ElectricPotential, Power}, f32::{ElectricCurrent, ElectricPotential, ElectricalConductance, ElectricalResistance, Power},
power::milliwatt, power::milliwatt};
Quantity, ISQ, SI},
typenum::*};
use crate::{device::sys_timer::sleep, use crate::{device::sys_timer::sleep,
laser_diode::{ld_ctrl::{Impedance, LdCtrl}, laser_diode::{ld_ctrl::{Impedance, LdCtrl},
@ -16,11 +15,6 @@ use crate::{device::sys_timer::sleep,
ld_pwr_exc_protector::{self, LdPwrExcProtector}, ld_pwr_exc_protector::{self, LdPwrExcProtector},
pd_mon_params}}; pd_mon_params}};
// Volt / Ampere
pub type TransimpedanceUnit = Quantity<ISQ<P2, P1, N3, N2, Z0, Z0, Z0>, SI<f32>, f32>;
// Ampere / Volt
type TransconductanceUnit = Quantity<ISQ<N2, N1, P3, P2, Z0, Z0, Z0>, SI<f32>, f32>;
impl Settings { impl Settings {
pub const LD_CURRENT_MAX: ElectricCurrent = ElectricCurrent { pub const LD_CURRENT_MAX: ElectricCurrent = ElectricCurrent {
dimension: PhantomData, dimension: PhantomData,
@ -33,14 +27,7 @@ impl Settings {
value: 4.096, value: 4.096,
}; };
// Unit: A/V const LD_DRIVE_TRANSIMPEDANCE: ElectricalResistance = ElectricalResistance {
const PD_MON_TRANSCONDUCTANCE: TransconductanceUnit = TransconductanceUnit {
dimension: PhantomData,
units: PhantomData,
value: 0.001,
};
const LD_DRIVE_TRANSIMPEDANCE: TransimpedanceUnit = TransimpedanceUnit {
dimension: PhantomData, dimension: PhantomData,
units: PhantomData, units: PhantomData,
value: 10.0 / 0.75, value: 10.0 / 0.75,
@ -152,13 +139,17 @@ impl LdDrive {
} }
pub fn get_pd_i(&mut self) -> ElectricCurrent { pub fn get_pd_i(&mut self) -> ElectricCurrent {
LdPwrExcProtector::get_status().v * Settings::PD_MON_TRANSCONDUCTANCE self.settings
.pd_mon_params
.get_pd_i_from_pd_v(LdPwrExcProtector::get_status().v)
} }
pub fn get_pd_pwr(&mut self) -> Power { pub fn get_pd_pwr(&mut self) -> Power {
self.settings.pd_mon_params.get_ld_pwr_from_ld_i(
self.settings self.settings
.pd_mon_params .pd_mon_params
.get_ld_pwr_from_ld_i(LdPwrExcProtector::get_status().v * Settings::PD_MON_TRANSCONDUCTANCE) .get_pd_i_from_pd_v(LdPwrExcProtector::get_status().v),
)
} }
pub fn ld_set_i(&mut self, i: ElectricCurrent) { pub fn ld_set_i(&mut self, i: ElectricCurrent) {
@ -188,6 +179,10 @@ impl LdDrive {
LdPwrExcProtector::clear_alarm_status(); LdPwrExcProtector::clear_alarm_status();
} }
pub fn set_pd_transconductance(&mut self, transconductance: ElectricalConductance) {
self.settings.pd_mon_params.set_transconductance(transconductance)
}
pub fn set_pd_responsitivity(&mut self, responsitivity: pd_mon_params::ResponsitivityUnit) { pub fn set_pd_responsitivity(&mut self, responsitivity: pd_mon_params::ResponsitivityUnit) {
self.settings.pd_mon_params.set(responsitivity); self.settings.pd_mon_params.set(responsitivity);
} }
@ -198,13 +193,13 @@ impl LdDrive {
pub fn set_ld_power_limit(&mut self, pwr_limit: Power) { pub fn set_ld_power_limit(&mut self, pwr_limit: Power) {
LdPwrExcProtector::set_trigger_threshold_v( LdPwrExcProtector::set_trigger_threshold_v(
self.settings.pd_mon_params.get_ld_i_from_ld_pwr(pwr_limit) / Settings::PD_MON_TRANSCONDUCTANCE, self.settings.pd_mon_params.get_pd_i_from_ld_pwr(pwr_limit) / self.settings.pd_mon_params.transconductance,
); );
self.settings.ld_pwr_limit = pwr_limit; self.settings.ld_pwr_limit = pwr_limit;
} }
pub fn set_pd_i_limit(&mut self, i: ElectricCurrent) { pub fn set_pd_i_limit(&mut self, i: ElectricCurrent) {
LdPwrExcProtector::set_trigger_threshold_v(i / Settings::PD_MON_TRANSCONDUCTANCE); LdPwrExcProtector::set_trigger_threshold_v(i / self.settings.pd_mon_params.transconductance);
} }
pub fn set_default_pwr_on(&mut self, pwr_on: bool) { pub fn set_default_pwr_on(&mut self, pwr_on: bool) {

View File

@ -5,11 +5,10 @@ use stm32f4xx_hal::{gpio::{gpioa::*, gpiob::*, gpiod::*, Input, Output, PushPull
pac::SPI2, pac::SPI2,
spi::Spi}; spi::Spi};
use uom::si::{electric_current::ampere, use uom::si::{electric_current::ampere,
f32::{ElectricCurrent, ElectricPotential}, f32::{ElectricCurrent, ElectricPotential, ElectricalResistance},
ratio::ratio}; ratio::ratio};
use crate::laser_diode::{laser_diode::TransimpedanceUnit, use crate::laser_diode::max5719::{self, Dac};
max5719::{self, Dac}};
#[derive(Deserialize, Serialize, Debug, Clone, Copy)] #[derive(Deserialize, Serialize, Debug, Clone, Copy)]
pub enum Impedance { pub enum Impedance {
@ -84,7 +83,7 @@ impl LdCtrl {
pub fn set_i( pub fn set_i(
&mut self, &mut self,
current: ElectricCurrent, current: ElectricCurrent,
transimpedance: TransimpedanceUnit, transimpedance: ElectricalResistance,
dac_out_v_max: ElectricPotential, dac_out_v_max: ElectricPotential,
) -> ElectricCurrent { ) -> ElectricCurrent {
self.i_set = self.set_dac(current * transimpedance, dac_out_v_max) / transimpedance; self.i_set = self.set_dac(current * transimpedance, dac_out_v_max) / transimpedance;

View File

@ -1,9 +1,10 @@
use core::{f32::NAN, marker::PhantomData}; use core::{f32::NAN, marker::PhantomData};
use miniconf::Tree; use miniconf::Tree;
use num_traits::Zero;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use uom::{si::{electric_current::microampere, use uom::{si::{electric_current::microampere,
f32::{ElectricCurrent, Power}, f32::{ElectricCurrent, ElectricPotential, ElectricalConductance, Power},
Quantity, ISQ, SI}, Quantity, ISQ, SI},
typenum::*}; typenum::*};
@ -12,6 +13,7 @@ pub type ResponsitivityUnit = Quantity<ISQ<N2, N1, P3, P1, Z0, Z0, Z0>, SI<f32>,
#[derive(Deserialize, Serialize, Clone, Copy, Debug, PartialEq, Tree)] #[derive(Deserialize, Serialize, Clone, Copy, Debug, PartialEq, Tree)]
pub struct Parameters { pub struct Parameters {
pub transconductance: ElectricalConductance,
responsitivity: ResponsitivityUnit, responsitivity: ResponsitivityUnit,
i_dark: ElectricCurrent, i_dark: ElectricCurrent,
} }
@ -22,11 +24,15 @@ impl Parameters {
ld_power ld_power
} }
pub fn get_ld_i_from_ld_pwr(&self, pwr: Power) -> ElectricCurrent { pub fn get_pd_i_from_ld_pwr(&self, pwr: Power) -> ElectricCurrent {
let ld_i = pwr * self.responsitivity + self.i_dark; let ld_i = pwr * self.responsitivity + self.i_dark;
ld_i ld_i
} }
pub fn get_pd_i_from_pd_v(&self, v: ElectricPotential) -> ElectricCurrent {
(v * self.transconductance).max(ElectricCurrent::zero())
}
pub fn set(&mut self, responsitivity: ResponsitivityUnit) { pub fn set(&mut self, responsitivity: ResponsitivityUnit) {
self.responsitivity = responsitivity; self.responsitivity = responsitivity;
} }
@ -34,11 +40,20 @@ impl Parameters {
pub fn set_i_dark(&mut self, i_dark: ElectricCurrent) { pub fn set_i_dark(&mut self, i_dark: ElectricCurrent) {
self.i_dark = i_dark; self.i_dark = i_dark;
} }
pub fn set_transconductance(&mut self, transconductance: ElectricalConductance) {
self.transconductance = transconductance;
}
} }
impl Default for Parameters { impl Default for Parameters {
fn default() -> Self { fn default() -> Self {
Parameters { Parameters {
transconductance: ElectricalConductance {
dimension: PhantomData,
units: PhantomData,
value: 1.0 / 1000.0,
},
responsitivity: ResponsitivityUnit { responsitivity: ResponsitivityUnit {
dimension: PhantomData, dimension: PhantomData,
units: PhantomData, units: PhantomData,

View File

@ -1,9 +1,12 @@
#![cfg_attr(not(test), no_main)] #![cfg_attr(not(test), no_main)]
#![cfg_attr(not(test), no_std)] #![cfg_attr(not(test), no_std)]
use core::marker::PhantomData;
use cortex_m_rt::entry; use cortex_m_rt::entry;
use log::{debug, info}; use log::{debug, info};
use stm32f4xx_hal::pac::{CorePeripherals, Peripherals}; use stm32f4xx_hal::pac::{CorePeripherals, Peripherals};
use uom::si::f32::ElectricalConductance;
mod device; mod device;
mod laser_diode; mod laser_diode;
mod net; mod net;
@ -35,6 +38,8 @@ static mut ETH_DATA_BUFFER: [u8; 1024] = [0; 1024];
#[derive(Deserialize, Serialize, Clone, Copy, Debug)] #[derive(Deserialize, Serialize, Clone, Copy, Debug)]
pub struct DeviceSettings { pub struct DeviceSettings {
ip_settings: IpSettings, ip_settings: IpSettings,
pd_mon_fin_gain: f32,
pd_mon_transconductance: ElectricalConductance,
} }
const CONFIG_KEY: [&str; 3] = ["Device", "Laser_0", "Thermostat_0"]; const CONFIG_KEY: [&str; 3] = ["Device", "Laser_0", "Thermostat_0"];
@ -63,6 +68,12 @@ fn main() -> ! {
let mut device_settings = DeviceSettings { let mut device_settings = DeviceSettings {
ip_settings: IpSettings::default(), ip_settings: IpSettings::default(),
pd_mon_fin_gain: 1.0,
pd_mon_transconductance: ElectricalConductance {
dimension: PhantomData,
units: PhantomData,
value: 1.0 / 1000.0,
},
}; };
let mut active_report: [bool; net::net::NUM_OF_SOCKETS] = [false; net::net::NUM_OF_SOCKETS]; let mut active_report: [bool; net::net::NUM_OF_SOCKETS] = [false; net::net::NUM_OF_SOCKETS];
@ -88,6 +99,7 @@ fn main() -> ! {
match flash_store.read_value(CONFIG_KEY[0]) { match flash_store.read_value(CONFIG_KEY[0]) {
Ok(Some(config)) => { Ok(Some(config)) => {
device_settings_flash = config; device_settings_flash = config;
laser.set_pd_transconductance(config.pd_mon_fin_gain * config.pd_mon_transconductance);
debug!("Found Device Settings"); debug!("Found Device Settings");
} }
Ok(None) => { Ok(None) => {

View File

@ -6,13 +6,14 @@ use serde::{Deserialize, Serialize};
use smoltcp::iface::SocketHandle; use smoltcp::iface::SocketHandle;
use uom::si::{electric_current::{ampere, ElectricCurrent}, use uom::si::{electric_current::{ampere, ElectricCurrent},
electric_potential::{volt, ElectricPotential}, electric_potential::{volt, ElectricPotential},
electrical_conductance::{siemens, ElectricalConductance},
electrical_resistance::{ohm, ElectricalResistance}, electrical_resistance::{ohm, ElectricalResistance},
power::{watt, Power}, power::{watt, Power},
thermodynamic_temperature::{degree_celsius, ThermodynamicTemperature}}; thermodynamic_temperature::{degree_celsius, ThermodynamicTemperature}};
use crate::{device::{dfu, sys_timer}, use crate::{device::{dfu, sys_timer},
laser_diode::{laser_diode::{LdDrive, LdSettingsSummary, StatusReport as LdStatusReport}, laser_diode::{laser_diode::{LdDrive, LdSettingsSummary, StatusReport as LdStatusReport},
pd_mon_params::ResponsitivityUnit}, pd_mon_params::{self, ResponsitivityUnit}},
net::net, net::net,
thermostat::{ad7172::FilterType, thermostat::{ad7172::FilterType,
pid_state::PidSettings::*, pid_state::PidSettings::*,
@ -61,6 +62,8 @@ enum DeviceCmd {
Reserved, Reserved,
SetIPSettings, SetIPSettings,
SetActiveReportMode, SetActiveReportMode,
SetPdFinGain,
SetPdTransconductance,
GetStatusReport, GetStatusReport,
GetSettingsSummary, GetSettingsSummary,
Dfu, Dfu,
@ -311,6 +314,42 @@ pub fn execute_cmd(
); );
} }
}, },
Some(DeviceCmd::SetPdFinGain) => match cmd.json.data_f32 {
Some(val) => {
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
device_settings.pd_mon_fin_gain = val;
laser.set_pd_transconductance(
device_settings.pd_mon_fin_gain * device_settings.pd_mon_transconductance,
);
*state = State::SaveDeviceSettings;
}
None => {
send_response(
buffer,
ResponseEnum::InvalidDatatype,
Some(ERR_MSG_MISSING_DATA_F32),
socket,
);
}
},
Some(DeviceCmd::SetPdTransconductance) => match cmd.json.data_f32 {
Some(val) => {
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
device_settings.pd_mon_transconductance = ElectricalConductance::new::<siemens>(val);
laser.set_pd_transconductance(
device_settings.pd_mon_fin_gain * device_settings.pd_mon_transconductance,
);
*state = State::SaveDeviceSettings;
}
None => {
send_response(
buffer,
ResponseEnum::InvalidDatatype,
Some(ERR_MSG_MISSING_DATA_F32),
socket,
);
}
},
Some(DeviceCmd::GetStatusReport) => { Some(DeviceCmd::GetStatusReport) => {
send_status_report(buffer, laser, thermostat, socket); send_status_report(buffer, laser, thermostat, socket);
} }