Compare commits

...

2 Commits

Author SHA1 Message Date
Astro eb9aeb160a add Channels::read_ref_adc() 2020-05-13 00:15:29 +02:00
Astro 3d1740b23b refactor into Channels::poll_adc() 2020-05-13 00:04:55 +02:00
4 changed files with 92 additions and 55 deletions

View File

@ -6,7 +6,7 @@ pub struct ChannelState {
pub adc_data: Option<u32>, pub adc_data: Option<u32>,
pub adc_time: Instant, pub adc_time: Instant,
pub dac_value: u32, pub dac_value: u32,
pub pid_enabled: bool, pub pid_engaged: bool,
pub pid: pid::Controller, pub pid: pid::Controller,
pub sh: sh::Parameters, pub sh: sh::Parameters,
} }
@ -17,7 +17,7 @@ impl Default for ChannelState {
adc_data: None, adc_data: None,
adc_time: Instant::from_secs(0), adc_time: Instant::from_secs(0),
dac_value: 0, dac_value: 0,
pid_enabled: false, pid_engaged: false,
pid: pid::Controller::new(pid::Parameters::default()), pid: pid::Controller::new(pid::Parameters::default()),
sh: sh::Parameters::default(), sh: sh::Parameters::default(),
} }
@ -26,7 +26,7 @@ impl Default for ChannelState {
impl ChannelState { impl ChannelState {
/// Update PID state on ADC input, calculate new DAC output /// Update PID state on ADC input, calculate new DAC output
pub fn update_adc(&mut self, now: Instant, adc_data: u32) { pub fn update_pid(&mut self, now: Instant, adc_data: u32) {
self.adc_data = Some(adc_data); self.adc_data = Some(adc_data);
self.adc_time = now; self.adc_time = now;

View File

@ -1,9 +1,14 @@
use stm32f4xx_hal::hal::digital::v2::OutputPin;
use smoltcp::time::Instant;
use crate::{ use crate::{
ad7172, ad7172,
channel::{Channel, Channel0, Channel1}, channel::{Channel, Channel0, Channel1},
channel_state::ChannelState,
pins, pins,
}; };
pub const CHANNELS: usize = 2;
pub struct Channels { pub struct Channels {
pub channel0: Channel<Channel0>, pub channel0: Channel<Channel0>,
pub channel1: Channel<Channel1>, pub channel1: Channel<Channel1>,
@ -27,4 +32,61 @@ impl Channels {
Channels { channel0, channel1, adc, pwm } Channels { channel0, channel1, adc, pwm }
} }
pub fn channel_state<I: Into<usize>>(&mut self, channel: I) -> &mut ChannelState {
match channel.into() {
0 => &mut self.channel0.state,
1 => &mut self.channel1.state,
_ => unreachable!(),
}
}
/// ADC input + PID processing
pub fn poll_adc(&mut self, instant: Instant) -> Option<u8> {
self.adc.data_ready().unwrap().map(|channel| {
let data = self.adc.read_data().unwrap();
let dac_value = {
let state = self.channel_state(channel);
state.update_pid(instant, data);
if state.pid_engaged {
Some(state.dac_value)
} else {
None
}
};
if let Some(dac_value) = dac_value {
// Forward PID output to i_set DAC
match channel {
0 => {
self.channel0.dac.set(dac_value).unwrap();
self.channel0.shdn.set_high().unwrap();
}
1 => {
self.channel1.dac.set(dac_value).unwrap();
self.channel1.shdn.set_high().unwrap();
}
_ =>
unreachable!(),
}
}
channel
})
}
pub fn read_ref_adc(&mut self, channel: usize) -> u16 {
match channel {
0 => self.channel0.ref_adc.convert(
&self.channel0.ref_pin,
stm32f4xx_hal::adc::config::SampleTime::Cycles_480
),
1 => self.channel1.ref_adc.convert(
&self.channel1.ref_pin,
stm32f4xx_hal::adc::config::SampleTime::Cycles_480
),
_ => unreachable!(),
}
}
} }

View File

@ -39,17 +39,16 @@ mod net;
mod server; mod server;
use server::Server; use server::Server;
mod session; mod session;
use session::{CHANNELS, Session, SessionOutput}; use session::{Session, SessionOutput};
mod command_parser; mod command_parser;
use command_parser::{Command, ShowCommand, PwmPin}; use command_parser::{Command, ShowCommand, PwmPin};
mod timer; mod timer;
mod pid; mod pid;
mod steinhart_hart; mod steinhart_hart;
mod channels; mod channels;
use channels::Channels; use channels::{CHANNELS, Channels};
mod channel; mod channel;
mod channel_state; mod channel_state;
use channel_state::ChannelState;
const HSE: MegaHertz = MegaHertz(8); const HSE: MegaHertz = MegaHertz(8);
@ -96,9 +95,6 @@ fn main() -> ! {
dp.ADC1, dp.ADC2, dp.ADC1, dp.ADC2,
); );
let mut channels = Channels::new(pins); let mut channels = Channels::new(pins);
let mut channel_states: [ChannelState; CHANNELS] = [
ChannelState::default(), ChannelState::default()
];
timer::setup(cp.SYST, clocks); timer::setup(cp.SYST, clocks);
#[cfg(not(feature = "generate-hwaddr"))] #[cfg(not(feature = "generate-hwaddr"))]
@ -114,31 +110,10 @@ fn main() -> ! {
Server::<Session>::run(iface, |server| { Server::<Session>::run(iface, |server| {
loop { loop {
let instant = Instant::from_millis(i64::from(timer::now())); let instant = Instant::from_millis(i64::from(timer::now()));
// ADC input let updated_channel = channels.poll_adc(instant);
channels.adc.data_ready().unwrap().map(|channel| { if let Some(channel) = updated_channel {
let data = channels.adc.read_data().unwrap();
let state = &mut channel_states[usize::from(channel)];
state.update_adc(instant, data);
if state.pid_enabled {
// Forward PID output to i_set DAC
match channel {
0 => {
channels.channel0.dac.set(state.dac_value).unwrap();
channels.channel0.shdn.set_high().unwrap();
}
1 => {
channels.channel1.dac.set(state.dac_value).unwrap();
channels.channel1.shdn.set_high().unwrap();
}
_ =>
unreachable!(),
}
}
server.for_each(|_, session| session.set_report_pending(channel.into())); server.for_each(|_, session| session.set_report_pending(channel.into()));
}); }
let instant = Instant::from_millis(i64::from(timer::now())); let instant = Instant::from_millis(i64::from(timer::now()));
cortex_m::interrupt::free(net::clear_pending); cortex_m::interrupt::free(net::clear_pending);
@ -165,22 +140,21 @@ fn main() -> ! {
let _ = writeln!(socket, "report={}", if session.reporting() { "on" } else { "off" }); let _ = writeln!(socket, "report={}", if session.reporting() { "on" } else { "off" });
} }
Command::Show(ShowCommand::Input) => { Command::Show(ShowCommand::Input) => {
for (channel, state) in channel_states.iter().enumerate() { for channel in 0..CHANNELS {
if let Some(adc_data) = state.adc_data { if let Some(adc_data) = channels.channel_state(channel).adc_data {
let ref_adc_data = channels.read_ref_adc(channel);
let state = channels.channel_state(channel);
let _ = writeln!( let _ = writeln!(
socket, "t={} raw{}=0x{:06X}", socket, "t={} raw{}=0x{:06X} ref_adc={}",
state.adc_time, channel, adc_data state.adc_time, channel, adc_data,
ref_adc_data
); );
} }
} }
let ref0 = channels.channel0.ref_adc.convert(
&channels.channel0.ref_pin, stm32f4xx_hal::adc::config::SampleTime::Cycles_480
);
let _ = writeln!(socket, "ref0={}", ref0);
} }
Command::Show(ShowCommand::Pid) => { Command::Show(ShowCommand::Pid) => {
for (channel, state) in channel_states.iter().enumerate() { for channel in 0..CHANNELS {
let state = channels.channel_state(channel);
let _ = writeln!(socket, "PID settings for channel {}", channel); let _ = writeln!(socket, "PID settings for channel {}", channel);
let pid = &state.pid; let pid = &state.pid;
let _ = writeln!(socket, "- target={:.4}", pid.target); let _ = writeln!(socket, "- target={:.4}", pid.target);
@ -206,11 +180,12 @@ fn main() -> ! {
} }
} }
Command::Show(ShowCommand::Pwm) => { Command::Show(ShowCommand::Pwm) => {
for (channel, state) in channel_states.iter().enumerate() { for channel in 0..CHANNELS {
let state = channels.channel_state(channel);
let _ = writeln!( let _ = writeln!(
socket, "channel {}: PID={}", socket, "channel {}: PID={}",
channel, channel,
if state.pid_enabled { "engaged" } else { "disengaged" } if state.pid_engaged { "engaged" } else { "disengaged" }
); );
let _ = writeln!(socket, "- i_set={}/{}", state.dac_value, ad5680::MAX_VALUE); let _ = writeln!(socket, "- i_set={}/{}", state.dac_value, ad5680::MAX_VALUE);
fn show_pwm_channel<S, P>(mut socket: S, name: &str, pin: &P) fn show_pwm_channel<S, P>(mut socket: S, name: &str, pin: &P)
@ -241,7 +216,8 @@ fn main() -> ! {
} }
} }
Command::Show(ShowCommand::SteinhartHart) => { Command::Show(ShowCommand::SteinhartHart) => {
for (channel, state) in channel_states.iter().enumerate() { for channel in 0..CHANNELS {
let state = channels.channel_state(channel);
let _ = writeln!( let _ = writeln!(
socket, "channel {}: Steinhart-Hart equation parameters", socket, "channel {}: Steinhart-Hart equation parameters",
channel, channel,
@ -253,7 +229,7 @@ fn main() -> ! {
} }
} }
Command::Show(ShowCommand::PostFilter) => { Command::Show(ShowCommand::PostFilter) => {
for (channel, _) in channel_states.iter().enumerate() { for channel in 0..CHANNELS {
match channels.adc.get_postfilter(channel as u8).unwrap() { match channels.adc.get_postfilter(channel as u8).unwrap() {
Some(filter) => { Some(filter) => {
let _ = writeln!( let _ = writeln!(
@ -271,12 +247,12 @@ fn main() -> ! {
} }
} }
Command::PwmPid { channel } => { Command::PwmPid { channel } => {
channel_states[channel].pid_enabled = true; channels.channel_state(channel).pid_engaged = true;
let _ = writeln!(socket, "channel {}: PID enabled to control PWM", channel let _ = writeln!(socket, "channel {}: PID enabled to control PWM", channel
); );
} }
Command::Pwm { channel, pin: PwmPin::ISet, duty } if duty <= ad5680::MAX_VALUE => { Command::Pwm { channel, pin: PwmPin::ISet, duty } if duty <= ad5680::MAX_VALUE => {
channel_states[channel].pid_enabled = false; channels.channel_state(channel).pid_engaged = false;
match channel { match channel {
0 => { 0 => {
channels.channel0.dac.set(duty).unwrap(); channels.channel0.dac.set(duty).unwrap();
@ -288,7 +264,7 @@ fn main() -> ! {
} }
_ => unreachable!(), _ => unreachable!(),
} }
channel_states[channel].dac_value = duty; channels.channel_state(channel).dac_value = duty;
let _ = writeln!( let _ = writeln!(
socket, "channel {}: PWM duty cycle manually set to {}/{}", socket, "channel {}: PWM duty cycle manually set to {}/{}",
channel, duty, ad5680::MAX_VALUE channel, duty, ad5680::MAX_VALUE
@ -335,7 +311,7 @@ fn main() -> ! {
let _ = writeln!(socket, "error: PWM duty range must fit 16 bits"); let _ = writeln!(socket, "error: PWM duty range must fit 16 bits");
} }
Command::Pid { channel, parameter, value } => { Command::Pid { channel, parameter, value } => {
let pid = &mut channel_states[channel].pid; let pid = &mut channels.channel_state(channel).pid;
use command_parser::PidParameter::*; use command_parser::PidParameter::*;
match parameter { match parameter {
Target => Target =>
@ -361,7 +337,7 @@ fn main() -> ! {
let _ = writeln!(socket, "PID parameter updated"); let _ = writeln!(socket, "PID parameter updated");
} }
Command::SteinhartHart { channel, parameter, value } => { Command::SteinhartHart { channel, parameter, value } => {
let sh = &mut channel_states[channel].sh; let sh = &mut channels.channel_state(channel).sh;
use command_parser::ShParameter::*; use command_parser::ShParameter::*;
match parameter { match parameter {
T0 => sh.t0 = value, T0 => sh.t0 = value,
@ -397,7 +373,7 @@ fn main() -> ! {
} }
} else if socket.can_send() && socket.send_capacity() - socket.send_queue() > 256 { } else if socket.can_send() && socket.send_capacity() - socket.send_queue() > 256 {
while let Some(channel) = session.is_report_pending() { while let Some(channel) = session.is_report_pending() {
let state = &mut channel_states[usize::from(channel)]; let state = &mut channels.channel_state(usize::from(channel));
let _ = writeln!( let _ = writeln!(
socket, "t={} raw{}=0x{:06X}", socket, "t={} raw{}=0x{:06X}",
state.adc_time, channel, state.adc_data.unwrap_or(0) state.adc_time, channel, state.adc_data.unwrap_or(0)

View File

@ -1,4 +1,5 @@
use super::command_parser::{Command, Error as ParserError}; use super::command_parser::{Command, Error as ParserError};
use super::channels::CHANNELS;
const MAX_LINE_LEN: usize = 64; const MAX_LINE_LEN: usize = 64;
@ -50,8 +51,6 @@ impl From<Result<Command, ParserError>> for SessionOutput {
} }
} }
pub const CHANNELS: usize = 2;
pub struct Session { pub struct Session {
reader: LineReader, reader: LineReader,
reporting: bool, reporting: bool,