forked from M-Labs/ionpak-thermostat
handle protection, print current/voltage values
This commit is contained in:
parent
1c516ca357
commit
c676102b33
|
@ -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() {
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Loading…
Reference in New Issue