Compare commits

..

3 Commits

Author SHA1 Message Date
6b5c5340f8 README: Document swap status in report 2024-09-23 17:31:34 +08:00
37a8bde445 add swap status to the report
Signed-off-by: Egor Savkin <es@m-labs.hk>
2024-09-23 17:31:34 +08:00
f02bf414b5 Add command for flipping output polarity
Effectively switches all values related to the directionality of current
through the TEC, including current maximums. The swapped status is
stored in the flash store.

To swap current directions, use the command "pwm <ch> polarity_swapped
<bool>", where <bool> is true when TEC current direction is reversed
from the front panel markings.

This is needed for IDC cable connections, since the IDC connector and
front panel connectors have flipped polarities.
2024-09-23 17:31:34 +08:00
4 changed files with 42 additions and 26 deletions

View File

@ -256,21 +256,22 @@ Use the bare `report` command to obtain a single report. Enable
continuous reporting with `report mode on`. Reports are JSON objects
with the following keys.
| Key | Unit | Description |
| --- | :---: | --- |
| `channel` | Integer | Channel `0`, or `1` |
| `time` | Seconds | Temperature measurement time |
| `adc` | Volts | AD7172 input |
| `sens` | Ohms | Thermistor resistance derived from `adc` |
| `temperature` | Degrees Celsius | Steinhart-Hart conversion result derived from `sens` |
| `pid_engaged` | Boolean | `true` if in closed-loop mode |
| `i_set` | Amperes | TEC output current |
| `dac_value` | Volts | AD5680 output derived from `i_set` |
| `dac_feedback` | Volts | ADC measurement of the AD5680 output |
| `i_tec` | Volts | MAX1968 TEC current monitor |
| `tec_i` | Amperes | TEC output current feedback derived from `i_tec` |
| `tec_u_meas` | Volts | Measurement of the voltage across the TEC |
| `pid_output` | Amperes | PID control output |
| Key | Unit | Description |
| --- | :---: | --- |
| `channel` | Integer | Channel `0`, or `1` |
| `time` | Seconds | Temperature measurement time |
| `adc` | Volts | AD7172 input |
| `sens` | Ohms | Thermistor resistance derived from `adc` |
| `temperature` | Degrees Celsius | Steinhart-Hart conversion result derived from `sens` |
| `pid_engaged` | Boolean | `true` if in closed-loop mode |
| `current_swapped` | Boolean | `true` if TEC current direction is swapped relative to front panel |
| `i_set` | Amperes | TEC output current |
| `dac_value` | Volts | AD5680 output derived from `i_set` |
| `dac_feedback` | Volts | ADC measurement of the AD5680 output |
| `i_tec` | Volts | MAX1968 TEC current monitor |
| `tec_i` | Amperes | TEC output current feedback derived from `i_tec` |
| `tec_u_meas` | Volts | Measurement of the voltage across the TEC |
| `pid_output` | Amperes | PID control output |
Note: With Thermostat v2 and below, the voltage and current readouts `i_tec` and `tec_i` are noisy without the hardware fix shown in [this PR][https://git.m-labs.hk/M-Labs/thermostat/pulls/105].

View File

@ -157,11 +157,13 @@ impl Channels {
}
pub fn set_i(&mut self, channel: usize, i_set: ElectricCurrent) -> ElectricCurrent {
let mut i_set = i_set.min(MAX_TEC_I).max(-MAX_TEC_I);
let i_set = i_set.min(MAX_TEC_I).max(-MAX_TEC_I);
self.channel_state(channel).i_set = i_set;
if self.channel_state(channel).polarity_swapped {
i_set = -i_set;
}
let negate = if self.channel_state(channel).polarity_swapped {
-1.0
} else {
1.0
};
let vref_meas = match channel.into() {
0 => self.channel0.vref_meas,
1 => self.channel1.vref_meas,
@ -169,9 +171,9 @@ impl Channels {
};
let center_point = vref_meas;
let r_sense = ElectricalResistance::new::<ohm>(R_SENSE);
let voltage = i_set * 10.0 * r_sense + center_point;
let voltage = negate * i_set * 10.0 * r_sense + center_point;
let voltage = self.set_dac(channel, voltage);
let i_set = (voltage - center_point) / (10.0 * r_sense);
let i_set = negate * (voltage - center_point) / (10.0 * r_sense);
i_set
}
@ -477,6 +479,19 @@ impl Channels {
(duty * MAX_TEC_I_DUTY_TO_CURRENT_RATE, max)
}
pub fn swap_polarity(&mut self, channel: usize, swapped: bool) {
if self.channel_state(channel).polarity_swapped != swapped {
let i_set = self.channel_state(channel).i_set;
let max_i_pos = self.get_max_i_pos(channel).0;
let max_i_neg = self.get_max_i_neg(channel).0;
self.channel_state(channel).polarity_swapped = swapped;
self.set_i(channel, i_set);
self.set_max_i_pos(channel, max_i_pos);
self.set_max_i_neg(channel, max_i_neg);
}
}
fn report(&mut self, channel: usize) -> Report {
let i_set = self.get_i(channel);
let i_tec = self.adc_read(channel, PinsAdcReadTarget::ITec, 16);

View File

@ -182,10 +182,7 @@ impl Handler {
}
fn swap_polarity (socket: &mut TcpSocket, channels: &mut Channels, channel: usize, swapped: bool) -> Result<Handler, Error> {
channels.channel_state(channel).polarity_swapped = swapped;
let channel_state = channels.channel_state(channel);
let i_set = channel_state.i_set;
channels.set_i(channel, i_set);
channels.swap_polarity(channel, swapped);
send_line(socket, b"{}");
Ok(Handler::Handled)
}

View File

@ -20,6 +20,7 @@ pub struct ChannelConfig {
pid_target: f32,
pid_engaged: bool,
i_set: ElectricCurrent,
polarity_swapped: bool,
sh: steinhart_hart::Parameters,
pwm: PwmLimits,
/// uses variant `PostFilter::Invalid` instead of `None` to save space
@ -45,7 +46,8 @@ impl ChannelConfig {
pid: state.pid.parameters.clone(),
pid_target: state.pid.target as f32,
pid_engaged: state.pid_engaged,
i_set: i_set,
i_set,
polarity_swapped: state.polarity_swapped,
sh: state.sh.clone(),
pwm,
adc_postfilter,
@ -68,6 +70,7 @@ impl ChannelConfig {
};
let _ = channels.adc.set_postfilter(channel as u8, adc_postfilter);
let _ = channels.set_i(channel, self.i_set);
channels.swap_polarity(channel, self.polarity_swapped);
}
}