forked from M-Labs/thermostat
refactor into Channels::poll_adc()
This commit is contained in:
parent
9466961bd7
commit
3d1740b23b
@ -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;
|
||||||
|
|
||||||
|
@ -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,47 @@ 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
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
63
src/main.rs
63
src/main.rs
@ -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,7 +140,8 @@ 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 {
|
||||||
|
let state = channels.channel_state(channel);
|
||||||
if let Some(adc_data) = state.adc_data {
|
if let Some(adc_data) = state.adc_data {
|
||||||
let _ = writeln!(
|
let _ = writeln!(
|
||||||
socket, "t={} raw{}=0x{:06X}",
|
socket, "t={} raw{}=0x{:06X}",
|
||||||
@ -180,7 +156,8 @@ fn main() -> ! {
|
|||||||
let _ = writeln!(socket, "ref0={}", ref0);
|
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 +183,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 +219,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 +232,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 +250,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 +267,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 +314,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 +340,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 +376,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)
|
||||||
|
@ -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,
|
||||||
|
Loading…
Reference in New Issue
Block a user