add PWM abstraction for TEC control
This commit is contained in:
parent
8d01ca8d20
commit
a82ffadb35
@ -4,6 +4,7 @@ use tm4c129x;
|
|||||||
pub mod gpio;
|
pub mod gpio;
|
||||||
pub mod softspi;
|
pub mod softspi;
|
||||||
pub mod systick;
|
pub mod systick;
|
||||||
|
pub mod pwm;
|
||||||
|
|
||||||
|
|
||||||
const UART_DIV: u32 = (((/*sysclk*/120_000_000 * 8) / /*baud*/115200) + 1) / 2;
|
const UART_DIV: u32 = (((/*sysclk*/120_000_000 * 8) / /*baud*/115200) + 1) / 2;
|
||||||
@ -130,66 +131,10 @@ pub fn init() {
|
|||||||
}
|
}
|
||||||
while !timers_ready(sysctl) {}
|
while !timers_ready(sysctl) {}
|
||||||
|
|
||||||
// Manual: 13.4.5 PWM Mode
|
|
||||||
macro_rules! setup_timer_pwm {
|
|
||||||
($T: tt) => (
|
|
||||||
let timer = unsafe { &*tm4c129x::$T::ptr() };
|
|
||||||
timer.cfg.write(|w| unsafe { w.bits(4) });
|
|
||||||
timer.tamr.modify(|_, w| unsafe {
|
|
||||||
w
|
|
||||||
.taams().bit(true)
|
|
||||||
.tacmr().bit(false)
|
|
||||||
.tamr().bits(2)
|
|
||||||
});
|
|
||||||
timer.tbmr.modify(|_, w| unsafe {
|
|
||||||
w
|
|
||||||
.tbams().bit(true)
|
|
||||||
.tbcmr().bit(false)
|
|
||||||
.tbmr().bits(2)
|
|
||||||
});
|
|
||||||
timer.ctl.modify(|_, w| {
|
|
||||||
w
|
|
||||||
.tapwml().bit(false)
|
|
||||||
.tbpwml().bit(false)
|
|
||||||
});
|
|
||||||
// no prescaler
|
|
||||||
// no interrupts
|
|
||||||
timer.tailr.write(|w| unsafe { w.bits(0xFFFF) });
|
|
||||||
timer.tbilr.write(|w| unsafe { w.bits(0xFFFF) });
|
|
||||||
timer.tamatchr.write(|w| unsafe { w.bits(0x8000) });
|
|
||||||
timer.tbmatchr.write(|w| unsafe { w.bits(0x8000) });
|
|
||||||
timer.ctl.modify(|_, w| {
|
|
||||||
w
|
|
||||||
.taen().bit(true)
|
|
||||||
.tben().bit(true)
|
|
||||||
});
|
|
||||||
)
|
|
||||||
}
|
|
||||||
setup_timer_pwm!(TIMER2);
|
|
||||||
setup_timer_pwm!(TIMER3);
|
|
||||||
setup_timer_pwm!(TIMER4);
|
|
||||||
setup_timer_pwm!(TIMER5);
|
|
||||||
|
|
||||||
systick::init(cs);
|
systick::init(cs);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_timer_pwm(matchr: u32, ilr: u32) {
|
|
||||||
macro_rules! set_timer_pwm {
|
|
||||||
($T: tt) => (
|
|
||||||
let timer = unsafe { &*tm4c129x::$T::ptr() };
|
|
||||||
timer.tamatchr.write(|w| unsafe { w.bits(matchr) });
|
|
||||||
timer.tbmatchr.write(|w| unsafe { w.bits(matchr) });
|
|
||||||
timer.tailr.write(|w| unsafe { w.bits(ilr) });
|
|
||||||
timer.tbilr.write(|w| unsafe { w.bits(ilr) });
|
|
||||||
)
|
|
||||||
}
|
|
||||||
set_timer_pwm!(TIMER2);
|
|
||||||
set_timer_pwm!(TIMER3);
|
|
||||||
set_timer_pwm!(TIMER4);
|
|
||||||
set_timer_pwm!(TIMER5);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_mac_address() -> [u8; 6] {
|
pub fn get_mac_address() -> [u8; 6] {
|
||||||
let (userreg0, userreg1) = cortex_m::interrupt::free(|_cs| {
|
let (userreg0, userreg1) = cortex_m::interrupt::free(|_cs| {
|
||||||
let flashctl = unsafe { &*tm4c129x::FLASH_CTRL::ptr() };
|
let flashctl = unsafe { &*tm4c129x::FLASH_CTRL::ptr() };
|
||||||
|
125
firmware/src/board/pwm.rs
Normal file
125
firmware/src/board/pwm.rs
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
use tm4c129x::{
|
||||||
|
TIMER2, TIMER3, TIMER4, TIMER5,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct T2CCP0;
|
||||||
|
pub struct T2CCP1;
|
||||||
|
pub struct T3CCP0;
|
||||||
|
pub struct T3CCP1;
|
||||||
|
pub struct T4CCP0;
|
||||||
|
pub struct T4CCP1;
|
||||||
|
pub struct T5CCP0;
|
||||||
|
pub struct T5CCP1;
|
||||||
|
|
||||||
|
pub trait PwmPeripheral {
|
||||||
|
type ChannelA: PwmChannel;
|
||||||
|
type ChannelB: PwmChannel;
|
||||||
|
fn split_16bit_ab() -> (Self::ChannelA, Self::ChannelB);
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! pwm_peripheral {
|
||||||
|
($TIMER: ty, $A: tt, $B: tt) => {
|
||||||
|
impl PwmPeripheral for $TIMER {
|
||||||
|
type ChannelA = $A;
|
||||||
|
type ChannelB = $B;
|
||||||
|
fn split_16bit_ab() -> (Self::ChannelA, Self::ChannelB) {
|
||||||
|
let regs = unsafe { &*Self::ptr() };
|
||||||
|
regs.cfg.write(|w| unsafe { w.bits(4) });
|
||||||
|
|
||||||
|
let mut a = $A;
|
||||||
|
a.configure();
|
||||||
|
let mut b = $B;
|
||||||
|
b.configure();
|
||||||
|
(a, b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pwm_peripheral!(TIMER2, T2CCP0, T2CCP1);
|
||||||
|
pwm_peripheral!(TIMER3, T3CCP0, T3CCP1);
|
||||||
|
pwm_peripheral!(TIMER4, T4CCP0, T4CCP1);
|
||||||
|
pwm_peripheral!(TIMER5, T5CCP0, T5CCP1);
|
||||||
|
|
||||||
|
|
||||||
|
pub trait PwmChannel {
|
||||||
|
fn configure(&mut self);
|
||||||
|
fn set(&mut self, width: u16, total: u16);
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! pwm_channel_a {
|
||||||
|
($CHANNEL: ty, $TIMER: tt) => {
|
||||||
|
impl PwmChannel for $CHANNEL {
|
||||||
|
fn configure(&mut self) {
|
||||||
|
let timer = unsafe { &*tm4c129x::$TIMER::ptr() };
|
||||||
|
timer.tamr.modify(|_, w| unsafe {
|
||||||
|
w
|
||||||
|
.taams().bit(true)
|
||||||
|
.tacmr().bit(false)
|
||||||
|
.tamr().bits(2)
|
||||||
|
});
|
||||||
|
timer.ctl.modify(|_, w| {
|
||||||
|
w
|
||||||
|
.tapwml().bit(false)
|
||||||
|
});
|
||||||
|
// no prescaler
|
||||||
|
// no interrupts
|
||||||
|
timer.tailr.write(|w| unsafe { w.bits(0xFFFF) });
|
||||||
|
timer.tamatchr.write(|w| unsafe { w.bits(0x0) });
|
||||||
|
timer.ctl.modify(|_, w| {
|
||||||
|
w
|
||||||
|
.taen().bit(true)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set(&mut self, width: u16, total: u16) {
|
||||||
|
let timer = unsafe { &*tm4c129x::$TIMER::ptr() };
|
||||||
|
timer.tamatchr.write(|w| unsafe { w.bits(width.into()) });
|
||||||
|
timer.tailr.write(|w| unsafe { w.bits(total.into()) });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! pwm_channel_b {
|
||||||
|
($CHANNEL: ty, $TIMER: tt) => {
|
||||||
|
impl PwmChannel for $CHANNEL {
|
||||||
|
fn configure(&mut self) {
|
||||||
|
let timer = unsafe { &*tm4c129x::$TIMER::ptr() };
|
||||||
|
timer.tbmr.modify(|_, w| unsafe {
|
||||||
|
w
|
||||||
|
.tbams().bit(true)
|
||||||
|
.tbcmr().bit(false)
|
||||||
|
.tbmr().bits(2)
|
||||||
|
});
|
||||||
|
timer.ctl.modify(|_, w| {
|
||||||
|
w
|
||||||
|
.tbpwml().bit(false)
|
||||||
|
});
|
||||||
|
// no prescaler
|
||||||
|
// no interrupts
|
||||||
|
timer.tbilr.write(|w| unsafe { w.bits(0xFFFF) });
|
||||||
|
timer.tbmatchr.write(|w| unsafe { w.bits(0x0) });
|
||||||
|
timer.ctl.modify(|_, w| {
|
||||||
|
w
|
||||||
|
.tben().bit(true)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set(&mut self, width: u16, total: u16) {
|
||||||
|
let timer = unsafe { &*tm4c129x::$TIMER::ptr() };
|
||||||
|
timer.tbmatchr.write(|w| unsafe { w.bits(width.into()) });
|
||||||
|
timer.tbilr.write(|w| unsafe { w.bits(total.into()) });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pwm_channel_a!(T2CCP0, TIMER2);
|
||||||
|
pwm_channel_b!(T2CCP1, TIMER2);
|
||||||
|
pwm_channel_a!(T3CCP0, TIMER3);
|
||||||
|
pwm_channel_b!(T3CCP1, TIMER3);
|
||||||
|
pwm_channel_a!(T4CCP0, TIMER4);
|
||||||
|
pwm_channel_b!(T4CCP1, TIMER4);
|
||||||
|
pwm_channel_a!(T5CCP0, TIMER5);
|
||||||
|
pwm_channel_b!(T5CCP1, TIMER5);
|
@ -84,8 +84,8 @@ pub enum PidParameter {
|
|||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum PwmMode {
|
pub enum PwmMode {
|
||||||
Manual {
|
Manual {
|
||||||
width: u32,
|
width: u16,
|
||||||
total: u32,
|
total: u16,
|
||||||
},
|
},
|
||||||
Pid,
|
Pid,
|
||||||
}
|
}
|
||||||
@ -123,7 +123,7 @@ fn whitespace(input: &[u8]) -> IResult<&[u8], ()> {
|
|||||||
fold_many1(char(' '), (), |(), _| ())(input)
|
fold_many1(char(' '), (), |(), _| ())(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unsigned(input: &[u8]) -> IResult<&[u8], Result<u32, Error>> {
|
fn unsigned(input: &[u8]) -> IResult<&[u8], Result<u16, Error>> {
|
||||||
take_while1(is_digit)(input)
|
take_while1(is_digit)(input)
|
||||||
.map(|(input, digits)| {
|
.map(|(input, digits)| {
|
||||||
let result = lexical::parse(digits)
|
let result = lexical::parse(digits)
|
||||||
|
@ -35,7 +35,11 @@ pub fn panic_fmt(info: &core::panic::PanicInfo) -> ! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mod board;
|
mod board;
|
||||||
use self::board::{gpio::Gpio, systick::get_time};
|
use self::board::{
|
||||||
|
gpio::Gpio,
|
||||||
|
systick::get_time,
|
||||||
|
pwm::*,
|
||||||
|
};
|
||||||
mod ethmac;
|
mod ethmac;
|
||||||
mod command_parser;
|
mod command_parser;
|
||||||
use command_parser::{Command, ShowCommand, PwmMode};
|
use command_parser::{Command, ShowCommand, PwmMode};
|
||||||
@ -43,6 +47,8 @@ mod session;
|
|||||||
use self::session::{Session, SessionOutput};
|
use self::session::{Session, SessionOutput};
|
||||||
mod ad7172;
|
mod ad7172;
|
||||||
mod pid;
|
mod pid;
|
||||||
|
mod tec;
|
||||||
|
use tec::TEC;
|
||||||
|
|
||||||
pub struct UART0;
|
pub struct UART0;
|
||||||
|
|
||||||
@ -77,6 +83,29 @@ macro_rules! create_socket {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn init_pwm_tec() -> (
|
||||||
|
TEC<T2CCP0, T2CCP1, T3CCP0, T3CCP1>,
|
||||||
|
TEC<T4CCP0, T4CCP1, T5CCP0, T5CCP1>
|
||||||
|
) {
|
||||||
|
let (t2ccp0, t2ccp1) = tm4c129x::TIMER2::split_16bit_ab();
|
||||||
|
let (t3ccp0, t3ccp1) = tm4c129x::TIMER3::split_16bit_ab();
|
||||||
|
let (t4ccp0, t4ccp1) = tm4c129x::TIMER4::split_16bit_ab();
|
||||||
|
let (t5ccp0, t5ccp1) = tm4c129x::TIMER5::split_16bit_ab();
|
||||||
|
let tec0 = TEC {
|
||||||
|
max_i_pos: t2ccp0,
|
||||||
|
max_i_neg: t2ccp1,
|
||||||
|
i_set: t3ccp0,
|
||||||
|
max_v: t3ccp1,
|
||||||
|
};
|
||||||
|
let tec1 = TEC {
|
||||||
|
max_i_pos: t4ccp0,
|
||||||
|
max_i_neg: t4ccp1,
|
||||||
|
i_set: t5ccp0,
|
||||||
|
max_v: t5ccp1,
|
||||||
|
};
|
||||||
|
(tec0, tec1)
|
||||||
|
}
|
||||||
|
|
||||||
const DEFAULT_PID_PARAMETERS: pid::Parameters = pid::Parameters {
|
const DEFAULT_PID_PARAMETERS: pid::Parameters = pid::Parameters {
|
||||||
kp: 1.0,
|
kp: 1.0,
|
||||||
ki: 1.0,
|
ki: 1.0,
|
||||||
@ -104,6 +133,7 @@ fn main() -> ! {
|
|||||||
let mut stdout = hio::hstdout().unwrap();
|
let mut stdout = hio::hstdout().unwrap();
|
||||||
writeln!(stdout, "ionpak boot").unwrap();
|
writeln!(stdout, "ionpak boot").unwrap();
|
||||||
board::init();
|
board::init();
|
||||||
|
let (mut tec0, mut tec1) = init_pwm_tec();
|
||||||
writeln!(stdout, "board initialized").unwrap();
|
writeln!(stdout, "board initialized").unwrap();
|
||||||
|
|
||||||
println!(r#"
|
println!(r#"
|
||||||
@ -235,9 +265,11 @@ fn main() -> ! {
|
|||||||
let state = &mut states[usize::from(channel)];
|
let state = &mut states[usize::from(channel)];
|
||||||
|
|
||||||
if state.pid_enabled {
|
if state.pid_enabled {
|
||||||
let width = state.pid.update(data as f32) as u32;
|
let width = state.pid.update(data as f32) as u16;
|
||||||
if channel == 0 { // TODO
|
match channel {
|
||||||
board::set_timer_pwm(width as u32, 0xffff);
|
0 => tec0.i_set.set(width, 0xffff),
|
||||||
|
1 => tec1.i_set.set(width, 0xffff),
|
||||||
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -328,13 +360,15 @@ fn main() -> ! {
|
|||||||
}
|
}
|
||||||
Command::Pwm { channel, mode: PwmMode::Manual { width, total }} => {
|
Command::Pwm { channel, mode: PwmMode::Manual { width, total }} => {
|
||||||
states[channel].pid_enabled = false;
|
states[channel].pid_enabled = false;
|
||||||
board::set_timer_pwm(width, total);
|
match channel {
|
||||||
if channel == 0 { // TODO
|
0 => tec0.i_set.set(width, total),
|
||||||
let _ = writeln!(
|
1 => tec1.i_set.set(width, total),
|
||||||
socket, "channel {}: PWM duty cycle manually set to {}/{}",
|
_ => unreachable!(),
|
||||||
channel, width, total
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
let _ = writeln!(
|
||||||
|
socket, "channel {}: PWM duty cycle manually set to {}/{}",
|
||||||
|
channel, width, total
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Command::Pwm { channel, mode: PwmMode::Pid } => {
|
Command::Pwm { channel, mode: PwmMode::Pid } => {
|
||||||
states[channel].pid_enabled = true;
|
states[channel].pid_enabled = true;
|
||||||
|
9
firmware/src/tec.rs
Normal file
9
firmware/src/tec.rs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
use crate::board::pwm::PwmChannel;
|
||||||
|
|
||||||
|
/// Thermo-Electric Cooling device controlled through PWM
|
||||||
|
pub struct TEC<MaxIPos: PwmChannel, MaxINeg: PwmChannel, ISet: PwmChannel, MaxV: PwmChannel> {
|
||||||
|
pub max_i_pos: MaxIPos,
|
||||||
|
pub max_i_neg: MaxINeg,
|
||||||
|
pub i_set: ISet,
|
||||||
|
pub max_v: MaxV,
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user