Compare commits

..

5 Commits

6 changed files with 70 additions and 14 deletions

View File

@ -70,6 +70,8 @@ The scope of this setting is per TCP session.
| `pid <0/1> integral_max <value>` | Set integral upper bound | | `pid <0/1> integral_max <value>` | Set integral upper bound |
| `s-h` | Show Steinhart-Hart equation parameters | | `s-h` | Show Steinhart-Hart equation parameters |
| `s-h <0/1> <t/b/r0> <value>` | Set Steinhart-Hart parameter for a channel | | `s-h <0/1> <t/b/r0> <value>` | Set Steinhart-Hart parameter for a channel |
| `postfilter` | Show postfilter settings |
| `postfilter <0/1> off` | Disable postfilter |
| `postfilter <0/1> rate <rate>` | Set postfilter output data rate | | `postfilter <0/1> rate <rate>` | Set postfilter output data rate |
| `load` | Restore configuration from EEPROM | | `load` | Restore configuration from EEPROM |
| `save` | Save configuration to EEPROM | | `save` | Save configuration to EEPROM |

View File

@ -1,5 +1,6 @@
use core::fmt; use core::fmt;
use num_traits::float::Float; use num_traits::float::Float;
use serde::{Serialize, Deserialize};
use stm32f4xx_hal::{ use stm32f4xx_hal::{
time::MegaHertz, time::MegaHertz,
spi, spi,
@ -144,7 +145,7 @@ impl fmt::Display for RefSource {
} }
} }
#[derive(Clone, Copy)] #[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
#[repr(u8)] #[repr(u8)]
pub enum PostFilter { pub enum PostFilter {
/// 27 SPS, 47 dB rejection, 36.7 ms settling /// 27 SPS, 47 dB rejection, 36.7 ms settling

View File

@ -52,6 +52,7 @@ impl Channels {
for channel in 0..CHANNELS { for channel in 0..CHANNELS {
channels.channel_state(channel).vref = channels.read_vref(channel); channels.channel_state(channel).vref = channels.read_vref(channel);
channels.calibrate_dac_value(channel); channels.calibrate_dac_value(channel);
channels.set_i(channel, ElectricCurrent::new::<ampere>(0.0));
} }
channels channels
} }
@ -252,7 +253,7 @@ impl Channels {
/// Calibrate the I_SET DAC using the DAC_FB ADC pin. /// Calibrate the I_SET DAC using the DAC_FB ADC pin.
/// ///
/// These loops perform a width-first search for the DAC setting /// These loops perform a breadth-first search for the DAC setting
/// that will produce a `target_voltage`. /// that will produce a `target_voltage`.
pub fn calibrate_dac_value(&mut self, channel: usize) { pub fn calibrate_dac_value(&mut self, channel: usize) {
let target_voltage = ElectricPotential::new::<volt>(2.5); let target_voltage = ElectricPotential::new::<volt>(2.5);

View File

@ -164,7 +164,7 @@ pub enum Command {
}, },
PostFilter { PostFilter {
channel: usize, channel: usize,
rate: f32, rate: Option<f32>,
}, },
} }
@ -392,15 +392,23 @@ fn postfilter(input: &[u8]) -> IResult<&[u8], Result<Command, Error>> {
|input| { |input| {
let (input, channel) = channel(input)?; let (input, channel) = channel(input)?;
let (input, _) = whitespace(input)?; let (input, _) = whitespace(input)?;
let (input, _) = tag("rate")(input)?; alt((
let (input, _) = whitespace(input)?; value(Ok(Command::PostFilter {
let (input, rate) = float(input)?;
let result = rate
.map(|rate| Command::PostFilter {
channel, channel,
rate: rate as f32, rate: None,
}); }), tag("off")),
Ok((input, result)) move |input| {
let (input, _) = tag("rate")(input)?;
let (input, _) = whitespace(input)?;
let (input, rate) = float(input)?;
let result = rate
.map(|rate| Command::PostFilter {
channel,
rate: Some(rate as f32),
});
Ok((input, result))
}
))(input)
} }
), ),
value(Ok(Command::Show(ShowCommand::PostFilter)), end) value(Ok(Command::Show(ShowCommand::PostFilter)), end)
@ -570,12 +578,27 @@ mod test {
})); }));
} }
#[test]
fn parse_postfilter() {
let command = Command::parse(b"postfilter");
assert_eq!(command, Ok(Command::Show(ShowCommand::PostFilter)));
}
#[test]
fn parse_postfilter_off() {
let command = Command::parse(b"postfilter 1 off");
assert_eq!(command, Ok(Command::PostFilter {
channel: 1,
rate: None,
}));
}
#[test] #[test]
fn parse_postfilter_rate() { fn parse_postfilter_rate() {
let command = Command::parse(b"postfilter 0 rate 21"); let command = Command::parse(b"postfilter 0 rate 21");
assert_eq!(command, Ok(Command::PostFilter { assert_eq!(command, Ok(Command::PostFilter {
channel: 0, channel: 0,
rate: 21.0, rate: Some(21.0),
})); }));
} }

View File

@ -9,6 +9,7 @@ use uom::si::{
thermodynamic_temperature::degree_celsius, thermodynamic_temperature::degree_celsius,
}; };
use crate::{ use crate::{
ad7172::PostFilter,
channels::{CHANNELS, Channels}, channels::{CHANNELS, Channels},
command_parser::CenterPoint, command_parser::CenterPoint,
EEPROM_SIZE, EEPROM_PAGE_SIZE, EEPROM_SIZE, EEPROM_PAGE_SIZE,
@ -94,11 +95,18 @@ pub struct ChannelConfig {
pid_target: f32, pid_target: f32,
sh: SteinhartHartConfig, sh: SteinhartHartConfig,
pwm: PwmLimits, pwm: PwmLimits,
/// uses variant `PostFilter::Invalid` instead of `None` to save space
adc_postfilter: PostFilter,
} }
impl ChannelConfig { impl ChannelConfig {
pub fn new(channels: &mut Channels, channel: usize) -> Self { pub fn new(channels: &mut Channels, channel: usize) -> Self {
let pwm = PwmLimits::new(channels, channel); let pwm = PwmLimits::new(channels, channel);
let adc_postfilter = channels.adc.get_postfilter(channel as u8)
.unwrap()
.unwrap_or(PostFilter::Invalid);
let state = channels.channel_state(channel); let state = channels.channel_state(channel);
ChannelConfig { ChannelConfig {
center: state.center.clone(), center: state.center.clone(),
@ -106,6 +114,7 @@ impl ChannelConfig {
pid_target: state.pid.target as f32, pid_target: state.pid.target as f32,
sh: (&state.sh).into(), sh: (&state.sh).into(),
pwm, pwm,
adc_postfilter,
} }
} }
@ -115,7 +124,14 @@ impl ChannelConfig {
state.pid.parameters = self.pid.clone(); state.pid.parameters = self.pid.clone();
state.pid.target = self.pid_target.into(); state.pid.target = self.pid_target.into();
state.sh = (&self.sh).into(); state.sh = (&self.sh).into();
self.pwm.apply(channels, channel); self.pwm.apply(channels, channel);
let adc_postfilter = match self.adc_postfilter {
PostFilter::Invalid => None,
adc_postfilter => Some(adc_postfilter),
};
let _ = channels.adc.set_postfilter(channel as u8, adc_postfilter);
} }
} }
@ -188,6 +204,7 @@ mod test {
max_i_pos: 2.1, max_i_pos: 2.1,
max_i_neg: 2.25, max_i_neg: 2.25,
}, },
adc_postfilter: PostFilter::F21SPS,
}; };
let config = Config { let config = Config {
channels: [ channels: [
@ -213,6 +230,7 @@ mod test {
max_i_pos: 2.1, max_i_pos: 2.1,
max_i_neg: 2.25, max_i_neg: 2.25,
}, },
adc_postfilter: PostFilter::F21SPS,
}; };
let config = Config { let config = Config {
channels: [ channels: [

View File

@ -308,7 +308,7 @@ fn main() -> ! {
} }
None => { None => {
let _ = writeln!( let _ = writeln!(
socket, "channel {}: no postfilter", socket, "channel {}: postfilter disabled",
channel channel
); );
} }
@ -421,7 +421,14 @@ fn main() -> ! {
} }
let _ = writeln!(socket, "Steinhart-Hart equation parameter updated"); let _ = writeln!(socket, "Steinhart-Hart equation parameter updated");
} }
Command::PostFilter { channel, rate } => { Command::PostFilter { channel, rate: None } => {
channels.adc.set_postfilter(channel as u8, None).unwrap();
let _ = writeln!(
socket, "channel {}: postfilter disabled",
channel
);
}
Command::PostFilter { channel, rate: Some(rate) } => {
let filter = ad7172::PostFilter::closest(rate); let filter = ad7172::PostFilter::closest(rate);
match filter { match filter {
Some(filter) => { Some(filter) => {
@ -459,6 +466,10 @@ fn main() -> ! {
} }
} }
Command::Reset => { Command::Reset => {
for i in 0..CHANNELS {
channels.power_down(i);
}
SCB::sys_reset(); SCB::sys_reset();
} }
} }