handle protection, print current/voltage values

This commit is contained in:
Sebastien Bourdeauducq 2017-05-11 14:55:00 +08:00
parent 1c516ca357
commit c676102b33
5 changed files with 148 additions and 72 deletions

View File

@ -81,7 +81,7 @@ pub fn set_fbv_pwm(duty: u16) {
} }
#[derive(Clone, Copy)] #[derive(Clone, Copy, PartialEq, Eq)]
pub enum EmissionRange { pub enum EmissionRange {
Low, // 22K Low, // 22K
Med, // 22K//(200Ω + compensated diode) 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| { cortex_m::interrupt::free(|cs| {
let gpio_l = tm4c129x::GPIO_PORTL.borrow(cs);
let gpio_q = tm4c129x::GPIO_PORTQ.borrow(cs); let gpio_q = tm4c129x::GPIO_PORTQ.borrow(cs);
gpio_q.data.modify(|r, w| w.data().bits(r.data().bits() & !ERR_RESN)); 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)); 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| { cortex_m::interrupt::free(|cs| {
let gpio_l = tm4c129x::GPIO_PORTL.borrow(cs); let gpio_l = tm4c129x::GPIO_PORTL.borrow(cs);
let errors_n = gpio_l.data.read().bits() as u8; gpio_l.data.read().bits() as u8 & ERR_LATCHN == 0
if errors_n & FV_ERRN == 0 { })
hprintln!("Filament overvolt"); }
}
if errors_n & FBV_ERRN == 0 { pub fn process_errors() {
hprintln!("Filament bias overvolt"); let errors_n = cortex_m::interrupt::free(|cs| {
} let gpio_l = tm4c129x::GPIO_PORTL.borrow(cs);
if errors_n & FBI_ERRN == 0 { gpio_l.data.read().bits() as u8
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");
}
}); });
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() { pub fn init() {

View File

@ -30,10 +30,21 @@ impl Controller {
} }
pub fn set_target(&mut self, volts: f32) { 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) 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);
}
}
} }

View File

@ -55,7 +55,7 @@ impl Controller {
fbi_r225 + (fbi_voltage - fd_voltage)/board::FBI_R223 fbi_r225 + (fbi_voltage - fd_voltage)/board::FBI_R223
}, },
board::EmissionRange::High => { board::EmissionRange::High => {
let fd_voltage = 0.8; let fd_voltage = 0.9;
fbi_r225 + (fbi_voltage - fd_voltage)/board::FBI_R224 fbi_r225 + (fbi_voltage - fd_voltage)/board::FBI_R224
} }
}; };
@ -92,9 +92,10 @@ impl Controller {
} }
pub fn emission_ready(&self) -> bool { pub fn emission_ready(&self) -> bool {
let tolerance = if self.fbi_range == board::EmissionRange::High { 0.20 } else { 0.02 };
match self.last_fbi { match self.last_fbi {
None => false, 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 { 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() 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());
}
}
} }

View File

@ -1,24 +1,44 @@
#![feature(used, const_fn, core_float)] #![feature(used, const_fn, core_float)]
#![no_std] #![no_std]
#[macro_use]
extern crate cortex_m; extern crate cortex_m;
extern crate cortex_m_rt; extern crate cortex_m_rt;
extern crate tm4c129x; extern crate tm4c129x;
use core::cell::{Cell, RefCell}; use core::cell::{Cell, RefCell};
use core::fmt; use core::fmt;
use cortex_m::ctxt::Local;
use cortex_m::exception::Handlers as ExceptionHandlers; use cortex_m::exception::Handlers as ExceptionHandlers;
use cortex_m::interrupt::Mutex; use cortex_m::interrupt::Mutex;
use tm4c129x::interrupt::Interrupt; use tm4c129x::interrupt::Interrupt;
use tm4c129x::interrupt::Handlers as InterruptHandlers; 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 board;
mod pid; mod pid;
mod loop_anode; mod loop_anode;
mod loop_cathode; mod loop_cathode;
static TIME: Mutex<Cell<u64>> = Mutex::new(Cell::new(0));
fn get_time() -> u64 {
cortex_m::interrupt::free(|cs| {
TIME.borrow(cs).get()
})
}
static LOOP_ANODE: Mutex<RefCell<loop_anode::Controller>> = Mutex::new(RefCell::new( static LOOP_ANODE: Mutex<RefCell<loop_anode::Controller>> = Mutex::new(RefCell::new(
loop_anode::Controller::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() { fn main() {
board::init(); board::init();
@ -70,7 +75,7 @@ fn main() {
let mut loop_anode = LOOP_ANODE.borrow(cs).borrow_mut(); let mut loop_anode = LOOP_ANODE.borrow(cs).borrow_mut();
let mut loop_cathode = LOOP_CATHODE.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; let cathode_bias = 12.0;
loop_anode.set_target(anode_cathode+cathode_bias); loop_anode.set_target(anode_cathode+cathode_bias);
loop_cathode.set_emission_target(anode_cathode/10000.0); loop_cathode.set_emission_target(anode_cathode/10000.0);
@ -78,18 +83,65 @@ fn main() {
board::set_fv_pwm(10); 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 { loop {
board::process_errors(); 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; use tm4c129x::interrupt::ADC0SS0;
extern fn adc0_ss0(ctxt: ADC0SS0) { extern fn adc0_ss0(_ctxt: ADC0SS0) {
static ELAPSED: Local<Cell<u32>, ADC0SS0> = Local::new(Cell::new(0));
let elapsed = ELAPSED.borrow(&ctxt);
cortex_m::interrupt::free(|cs| { cortex_m::interrupt::free(|cs| {
let adc0 = tm4c129x::ADC0.borrow(cs); let adc0 = tm4c129x::ADC0.borrow(cs);
if adc0.ostat.read().ov0().bit() { if adc0.ostat.read().ov0().bit() {
@ -97,7 +149,7 @@ extern fn adc0_ss0(ctxt: ADC0SS0) {
} }
adc0.isc.write(|w| w.in0().bit(true)); 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 fbi_sample = adc0.ssfifo0.read().data().bits();
let fv_sample = adc0.ssfifo0.read().data().bits(); let fv_sample = adc0.ssfifo0.read().data().bits();
let fd_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_anode.adc_input(av_sample);
loop_cathode.adc_input(fbi_sample, fd_sample, fv_sample, fbv_sample); loop_cathode.adc_input(fbi_sample, fd_sample, fv_sample, fbv_sample);
elapsed.set(elapsed.get() + 1); let time = TIME.borrow(cs);
if elapsed.get() % 100 == 0 { time.set(time.get() + 1);
board::set_led(1, true);
board::set_led(2, false); if time.get() % 300 == 0 {
} loop_anode.debug_print();
if elapsed.get() % 100 == 50 { loop_cathode.debug_print();
board::set_led(1, false); println!("{}", ic_sample);
board::set_led(2, true);
}
if elapsed.get() == 1000 {
loop_cathode.ready();
} }
}); });
} }

View File

@ -13,9 +13,9 @@ pub struct Parameters {
pub struct Controller { pub struct Controller {
parameters: Parameters, parameters: Parameters,
target: f32, pub target: f32,
integral: f32, integral: f32,
last_input: Option<f32> pub last_input: Option<f32>
} }
impl Controller { impl Controller {
@ -58,10 +58,6 @@ impl Controller {
output output
} }
pub fn set_target(&mut self, target: f32) {
self.target = target
}
#[allow(dead_code)] #[allow(dead_code)]
pub fn is_within(&self, tolerance: f32) -> bool { pub fn is_within(&self, tolerance: f32) -> bool {
match self.last_input { match self.last_input {