use super::{
dac::{R_SENSE, VREF_TEC},
hal::{
gpio::{gpiob::*, gpioc::*, gpiod::*, gpioe::*, Alternate},
hal::PwmPin,
prelude::*,
pwm::{ActiveHigh, ComplementaryDisabled, ComplementaryImpossible, C1, C2, C3, C4},
rcc::{rec, CoreClocks},
stm32::{TIM1, TIM3, TIM4},
time::KiloHertz,
},
OutputChannelIdx,
};
pub enum Limit {
Voltage(OutputChannelIdx),
NegativeCurrent(OutputChannelIdx),
PositiveCurrent(OutputChannelIdx),
}
#[derive(Debug)]
pub enum Error {
Bounds,
}
#[allow(clippy::type_complexity)]
pub struct PwmPins {
pub voltage: (
PE9<Alternate<1>>,
PE11<Alternate<1>>,
PE13<Alternate<1>>,
PE14<Alternate<1>>,
),
pub negative_current: (
PC6<Alternate<2>>,
PB5<Alternate<2>>,
PC8<Alternate<2>>,
PC9<Alternate<2>>,
),
pub positive_current: (
PD12<Alternate<2>>,
PD13<Alternate<2>>,
PD14<Alternate<2>>,
PD15<Alternate<2>>,
),
}
type Pt0<T, S> = super::hal::pwm::Pwm<T, S, ComplementaryDisabled, ActiveHigh, ActiveHigh>;
type Pt1<T, S> = super::hal::pwm::Pwm<T, S, ComplementaryImpossible, ActiveHigh, ActiveHigh>;
#[allow(clippy::type_complexity)]
pub struct Pwm {
voltage: (Pt0<TIM1, C1>, Pt0<TIM1, C2>, Pt0<TIM1, C3>, Pt1<TIM1, C4>),
positive_current: (Pt1<TIM4, C1>, Pt1<TIM4, C2>, Pt1<TIM4, C3>, Pt1<TIM4, C4>),
negative_current: (Pt1<TIM3, C1>, Pt1<TIM3, C2>, Pt1<TIM3, C3>, Pt1<TIM3, C4>),
}
impl Pwm {
const MAX_DUTY: u32 = 10000; const V_PWM: f32 = 3.3; pub const MAX_CURRENT_LIMIT: f32 = (Pwm::V_PWM * 0.15) / (VREF_TEC * R_SENSE);
pub fn new(
clocks: &CoreClocks,
tim_rec: (rec::Tim1, rec::Tim3, rec::Tim4),
tim: (TIM1, TIM3, TIM4),
pins: PwmPins,
) -> Pwm {
const F_PWM: KiloHertz = KiloHertz::kHz(20);
let mut voltage = tim.0.pwm(pins.voltage, F_PWM.convert(), tim_rec.0, clocks);
let mut negative_current =
tim.1
.pwm(pins.negative_current, F_PWM.convert(), tim_rec.1, clocks);
let mut positive_current =
tim.2
.pwm(pins.positive_current, F_PWM.convert(), tim_rec.2, clocks);
fn init_pwm_pin<P: PwmPin<Duty = u16>>(pin: &mut P) {
pin.set_duty(0);
pin.enable();
}
init_pwm_pin(&mut voltage.0);
init_pwm_pin(&mut voltage.1);
init_pwm_pin(&mut voltage.2);
init_pwm_pin(&mut voltage.3);
init_pwm_pin(&mut negative_current.0);
init_pwm_pin(&mut negative_current.1);
init_pwm_pin(&mut negative_current.2);
init_pwm_pin(&mut negative_current.3);
init_pwm_pin(&mut positive_current.0);
init_pwm_pin(&mut positive_current.1);
init_pwm_pin(&mut positive_current.2);
init_pwm_pin(&mut positive_current.3);
Pwm {
voltage,
negative_current,
positive_current,
}
}
pub fn set_limit(&mut self, lim: Limit, val: f32) -> Result<(), Error> {
pub fn current_limit_to_duty_cycle(i: f32) -> f32 {
i * ((VREF_TEC * R_SENSE) / (Pwm::V_PWM * 0.15))
}
pub fn voltage_limit_to_duty_cycle(v: f32) -> f32 {
v * (1.0 / 4.0 / Pwm::V_PWM)
}
fn set_pwm_channel<P: PwmPin<Duty = u16>>(channel: &mut P, duty: f32) -> Result<(), Error> {
let value = (duty * Pwm::MAX_DUTY as f32) as i32;
if !(0..=Pwm::MAX_DUTY as _).contains(&value) {
return Err(Error::Bounds);
}
channel.set_duty(value as u16);
Ok(())
}
match lim {
Limit::Voltage(OutputChannelIdx::Zero) => {
set_pwm_channel(&mut self.voltage.0, voltage_limit_to_duty_cycle(val))
}
Limit::Voltage(OutputChannelIdx::One) => {
set_pwm_channel(&mut self.voltage.1, voltage_limit_to_duty_cycle(val))
}
Limit::Voltage(OutputChannelIdx::Two) => {
set_pwm_channel(&mut self.voltage.2, voltage_limit_to_duty_cycle(val))
}
Limit::Voltage(OutputChannelIdx::Three) => {
set_pwm_channel(&mut self.voltage.3, voltage_limit_to_duty_cycle(val))
}
Limit::NegativeCurrent(OutputChannelIdx::Zero) => set_pwm_channel(
&mut self.negative_current.0,
current_limit_to_duty_cycle(-val),
),
Limit::NegativeCurrent(OutputChannelIdx::One) => set_pwm_channel(
&mut self.negative_current.1,
current_limit_to_duty_cycle(-val),
),
Limit::NegativeCurrent(OutputChannelIdx::Two) => set_pwm_channel(
&mut self.negative_current.2,
current_limit_to_duty_cycle(-val),
),
Limit::NegativeCurrent(OutputChannelIdx::Three) => set_pwm_channel(
&mut self.negative_current.3,
current_limit_to_duty_cycle(-val),
),
Limit::PositiveCurrent(OutputChannelIdx::Zero) => set_pwm_channel(
&mut self.positive_current.0,
current_limit_to_duty_cycle(val),
),
Limit::PositiveCurrent(OutputChannelIdx::One) => set_pwm_channel(
&mut self.positive_current.1,
current_limit_to_duty_cycle(val),
),
Limit::PositiveCurrent(OutputChannelIdx::Two) => set_pwm_channel(
&mut self.positive_current.2,
current_limit_to_duty_cycle(val),
),
Limit::PositiveCurrent(OutputChannelIdx::Three) => set_pwm_channel(
&mut self.positive_current.3,
current_limit_to_duty_cycle(val),
),
}
}
}