From c676102b33ebde0414b1c61d60df8e323291e10b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 11 May 2017 14:55:00 +0800 Subject: [PATCH] handle protection, print current/voltage values --- firmware/src/board.rs | 50 ++++++++------- firmware/src/loop_anode.rs | 15 ++++- firmware/src/loop_cathode.rs | 29 +++++++-- firmware/src/main.rs | 118 ++++++++++++++++++++++++----------- firmware/src/pid.rs | 8 +-- 5 files changed, 148 insertions(+), 72 deletions(-) diff --git a/firmware/src/board.rs b/firmware/src/board.rs index ae5d256..3ca58c6 100644 --- a/firmware/src/board.rs +++ b/firmware/src/board.rs @@ -81,7 +81,7 @@ pub fn set_fbv_pwm(duty: u16) { } -#[derive(Clone, Copy)] +#[derive(Clone, Copy, PartialEq, Eq)] pub enum EmissionRange { Low, // 22K Med, // 22K//(200Ω + compensated diode) @@ -102,39 +102,41 @@ pub fn set_emission_range(range: EmissionRange) { }); } -fn reset_error() { +pub fn reset_error() { cortex_m::interrupt::free(|cs| { - let gpio_l = tm4c129x::GPIO_PORTL.borrow(cs); let gpio_q = tm4c129x::GPIO_PORTQ.borrow(cs); gpio_q.data.modify(|r, w| w.data().bits(r.data().bits() & !ERR_RESN)); - while gpio_l.data.read().bits() as u8 & ERR_LATCHN == 0 {} gpio_q.data.modify(|r, w| w.data().bits(r.data().bits() | ERR_RESN)); }); } -pub fn process_errors() { +pub fn error_latched() -> bool { cortex_m::interrupt::free(|cs| { let gpio_l = tm4c129x::GPIO_PORTL.borrow(cs); - let errors_n = gpio_l.data.read().bits() as u8; - if errors_n & FV_ERRN == 0 { - hprintln!("Filament overvolt"); - } - if errors_n & FBV_ERRN == 0 { - hprintln!("Filament bias overvolt"); - } - if errors_n & FBI_ERRN == 0 { - hprintln!("Filament bias overcurrent"); - } - if errors_n & AV_ERRN == 0 { - hprintln!("Anode overvolt"); - } - if errors_n & AI_ERRN == 0 { - hprintln!("Anode overcurrent"); - } - if errors_n & ERR_LATCHN == 0 { - hprintln!("Protection latched"); - } + gpio_l.data.read().bits() as u8 & ERR_LATCHN == 0 + }) +} + +pub fn process_errors() { + let errors_n = cortex_m::interrupt::free(|cs| { + let gpio_l = tm4c129x::GPIO_PORTL.borrow(cs); + gpio_l.data.read().bits() as u8 }); + if errors_n & FV_ERRN == 0 { + println!("Filament overvolt"); + } + if errors_n & FBV_ERRN == 0 { + println!("Filament bias overvolt"); + } + if errors_n & FBI_ERRN == 0 { + println!("Filament bias overcurrent"); + } + if errors_n & AV_ERRN == 0 { + println!("Anode overvolt"); + } + if errors_n & AI_ERRN == 0 { + println!("Anode overcurrent"); + } } pub fn init() { diff --git a/firmware/src/loop_anode.rs b/firmware/src/loop_anode.rs index fa8ce41..b5a5781 100644 --- a/firmware/src/loop_anode.rs +++ b/firmware/src/loop_anode.rs @@ -30,10 +30,21 @@ impl Controller { } pub fn set_target(&mut self, volts: f32) { - self.pid.set_target(volts*board::AV_ADC_GAIN) + self.pid.target = volts*board::AV_ADC_GAIN; } - pub fn ready(&mut self) -> bool { + pub fn ready(&self) -> bool { self.pid.is_within(1.0*board::AV_ADC_GAIN) } + + pub fn reset(&mut self) { + self.pid.reset(); + } + + pub fn debug_print(&self) { + println!("anode ready: {}", self.ready()); + if self.pid.last_input.is_some() { + println!("voltage: {}V", self.pid.last_input.unwrap()/board::AV_ADC_GAIN); + } + } } diff --git a/firmware/src/loop_cathode.rs b/firmware/src/loop_cathode.rs index 4ac083d..7f98104 100644 --- a/firmware/src/loop_cathode.rs +++ b/firmware/src/loop_cathode.rs @@ -55,7 +55,7 @@ impl Controller { fbi_r225 + (fbi_voltage - fd_voltage)/board::FBI_R223 }, board::EmissionRange::High => { - let fd_voltage = 0.8; + let fd_voltage = 0.9; fbi_r225 + (fbi_voltage - fd_voltage)/board::FBI_R224 } }; @@ -92,9 +92,10 @@ impl Controller { } pub fn emission_ready(&self) -> bool { + let tolerance = if self.fbi_range == board::EmissionRange::High { 0.20 } else { 0.02 }; match self.last_fbi { None => false, - Some(last_fbi) => (self.fbi_target - last_fbi).abs()/self.fbi_target < 0.02 + Some(last_fbi) => (self.fbi_target - last_fbi).abs()/self.fbi_target < tolerance } } @@ -106,9 +107,27 @@ impl Controller { } pub fn ready(&self) -> bool { - hprintln!("emission current: {}mA", 1000.0*self.last_fbi.unwrap()); - hprintln!("filament voltage: {}V", self.last_fv.unwrap()); - hprintln!("bias voltage: {}V", self.last_fbv.unwrap()); self.emission_ready() & self.bias_ready() } + + pub fn reset(&mut self) { + self.pid.reset(); + self.fbi_buffer_count = 0; + self.last_fbi = None; + self.last_fv = None; + self.last_fbv = None; + } + + pub fn debug_print(&self) { + println!("cathode ready: {}", self.ready()); + if self.last_fbi.is_some() { + println!("emission: {}mA", 1000.0*self.last_fbi.unwrap()); + } + if self.last_fv.is_some() { + println!("fil voltage: {}V", self.last_fv.unwrap()); + } + if self.last_fbv.is_some() { + println!("bias voltage: {}V", self.last_fbv.unwrap()); + } + } } diff --git a/firmware/src/main.rs b/firmware/src/main.rs index e781493..cabcba9 100644 --- a/firmware/src/main.rs +++ b/firmware/src/main.rs @@ -1,24 +1,44 @@ #![feature(used, const_fn, core_float)] #![no_std] -#[macro_use] extern crate cortex_m; extern crate cortex_m_rt; extern crate tm4c129x; use core::cell::{Cell, RefCell}; use core::fmt; -use cortex_m::ctxt::Local; use cortex_m::exception::Handlers as ExceptionHandlers; use cortex_m::interrupt::Mutex; use tm4c129x::interrupt::Interrupt; use tm4c129x::interrupt::Handlers as InterruptHandlers; +#[macro_export] +macro_rules! print { + ($($arg:tt)*) => ({ + use core::fmt::Write; + write!($crate::UART0, $($arg)*).unwrap() + }) +} + +#[macro_export] +macro_rules! println { + ($fmt:expr) => (print!(concat!($fmt, "\n"))); + ($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*)); +} + +#[macro_use] mod board; mod pid; mod loop_anode; mod loop_cathode; +static TIME: Mutex> = Mutex::new(Cell::new(0)); + +fn get_time() -> u64 { + cortex_m::interrupt::free(|cs| { + TIME.borrow(cs).get() + }) +} static LOOP_ANODE: Mutex> = Mutex::new(RefCell::new( loop_anode::Controller::new())); @@ -42,21 +62,6 @@ impl fmt::Write for UART0 { } } -#[macro_export] -macro_rules! print { - ($($arg:tt)*) => ({ - use core::fmt::Write; - write!($crate::UART0, $($arg)*).unwrap() - }) -} - -#[macro_export] -macro_rules! println { - ($fmt:expr) => (print!(concat!($fmt, "\n"))); - ($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*)); -} - - fn main() { board::init(); @@ -70,7 +75,7 @@ fn main() { let mut loop_anode = LOOP_ANODE.borrow(cs).borrow_mut(); let mut loop_cathode = LOOP_CATHODE.borrow(cs).borrow_mut(); - let anode_cathode = 60.0; + let anode_cathode = 20.0; let cathode_bias = 12.0; loop_anode.set_target(anode_cathode+cathode_bias); loop_cathode.set_emission_target(anode_cathode/10000.0); @@ -78,18 +83,65 @@ fn main() { board::set_fv_pwm(10); }); - println!("ready"); + println!(r#" + _ _ + (_) | | + _ ___ _ __ _ __ __ _| | + | |/ _ \| '_ \| '_ \ / _` | |/ / + | | (_) | | | | |_) | (_| | < + |_|\___/|_| |_| .__/ \__,_|_|\_\ + | | + |_| +Ready."#); + let mut next_blink = 0; + let mut next_info = 0; + let mut led_state = true; + let mut latch_reset_time = None; loop { board::process_errors(); + + let time = get_time(); + + if time > next_blink { + led_state = !led_state; + next_blink = time + 100; + board::set_led(1, led_state); + } + + if time > next_info { + // FIXME: done in ISR now because of FPU snafu + /*cortex_m::interrupt::free(|cs| { + LOOP_CATHODE.borrow(cs).borrow().debug_print(); + });*/ + next_info = next_info + 300; + } + + if board::error_latched() { + match latch_reset_time { + None => { + println!("Protection latched"); + latch_reset_time = Some(time + 1000); + } + Some(t) => if time > t { + latch_reset_time = None; + cortex_m::interrupt::free(|cs| { + board::reset_error(); + // reset PID loops as they have accumulated large errors + // while the protection was active, which would cause + // unnecessary overshoots. + LOOP_ANODE.borrow(cs).borrow_mut().reset(); + LOOP_CATHODE.borrow(cs).borrow_mut().reset(); + }); + println!("Protection reset"); + } + } + } } } use tm4c129x::interrupt::ADC0SS0; -extern fn adc0_ss0(ctxt: ADC0SS0) { - static ELAPSED: Local, ADC0SS0> = Local::new(Cell::new(0)); - let elapsed = ELAPSED.borrow(&ctxt); - +extern fn adc0_ss0(_ctxt: ADC0SS0) { cortex_m::interrupt::free(|cs| { let adc0 = tm4c129x::ADC0.borrow(cs); if adc0.ostat.read().ov0().bit() { @@ -97,7 +149,7 @@ extern fn adc0_ss0(ctxt: ADC0SS0) { } adc0.isc.write(|w| w.in0().bit(true)); - let _ic_sample = adc0.ssfifo0.read().data().bits(); + let ic_sample = adc0.ssfifo0.read().data().bits(); let fbi_sample = adc0.ssfifo0.read().data().bits(); let fv_sample = adc0.ssfifo0.read().data().bits(); let fd_sample = adc0.ssfifo0.read().data().bits(); @@ -109,17 +161,13 @@ extern fn adc0_ss0(ctxt: ADC0SS0) { loop_anode.adc_input(av_sample); loop_cathode.adc_input(fbi_sample, fd_sample, fv_sample, fbv_sample); - elapsed.set(elapsed.get() + 1); - if elapsed.get() % 100 == 0 { - board::set_led(1, true); - board::set_led(2, false); - } - if elapsed.get() % 100 == 50 { - board::set_led(1, false); - board::set_led(2, true); - } - if elapsed.get() == 1000 { - loop_cathode.ready(); + let time = TIME.borrow(cs); + time.set(time.get() + 1); + + if time.get() % 300 == 0 { + loop_anode.debug_print(); + loop_cathode.debug_print(); + println!("{}", ic_sample); } }); } diff --git a/firmware/src/pid.rs b/firmware/src/pid.rs index af46758..91dbb54 100644 --- a/firmware/src/pid.rs +++ b/firmware/src/pid.rs @@ -13,9 +13,9 @@ pub struct Parameters { pub struct Controller { parameters: Parameters, - target: f32, + pub target: f32, integral: f32, - last_input: Option + pub last_input: Option } impl Controller { @@ -58,10 +58,6 @@ impl Controller { output } - pub fn set_target(&mut self, target: f32) { - self.target = target - } - #[allow(dead_code)] pub fn is_within(&self, tolerance: f32) -> bool { match self.last_input {