Support fan PWM settings #73

Merged
sb10q merged 16 commits from esavkin/thermostat:69-fan_pwm into master 2023-03-22 17:15:49 +08:00
5 changed files with 55 additions and 8 deletions
Showing only changes of commit 30350a3651 - Show all commits

View File

@ -342,12 +342,20 @@ impl Channels {
get(&self.pwm.max_i_neg0),
(0, PwmPin::MaxV) =>
get(&self.pwm.max_v0),
(0, PwmPin::Tacho) =>
Outdated
Review

Are you sure this is the best place to put this? This channel business looks highly suspicious.

Are you sure this is the best place to put this? This channel business looks highly suspicious.
get(&self.pwm.tacho),
(0, PwmPin::Fan) =>
get(&self.pwm.fan),
(1, PwmPin::MaxIPos) =>
get(&self.pwm.max_i_pos1),
(1, PwmPin::MaxINeg) =>
get(&self.pwm.max_i_neg1),
(1, PwmPin::MaxV) =>
get(&self.pwm.max_v1),
(1, PwmPin::Tacho) =>
get(&self.pwm.tacho),
(1, PwmPin::Fan) =>
get(&self.pwm.fan),
_ =>
unreachable!(),
}
@ -381,7 +389,7 @@ impl Channels {
(self.read_tec_u_meas(channel) - ElectricPotential::new::<volt>(1.5)) * 4.0
}
fn set_pwm(&mut self, channel: usize, pin: PwmPin, duty: f64) -> f64 {
pub fn set_pwm(&mut self, channel: usize, pin: PwmPin, duty: f64) -> f64 {
fn set<P: hal::PwmPin<Duty=u16>>(pin: &mut P, duty: f64) -> f64 {
let max = pin.get_max_duty();
let value = ((duty * (max as f64)) as u16).min(max);
@ -397,12 +405,16 @@ impl Channels {
set(&mut self.pwm.max_i_neg0, duty),
(0, PwmPin::MaxV) =>
set(&mut self.pwm.max_v0, duty),
(0, PwmPin::Fan) =>
set(&mut self.pwm.fan, duty),
(1, PwmPin::MaxIPos) =>
set(&mut self.pwm.max_i_pos1, duty),
(1, PwmPin::MaxINeg) =>
set(&mut self.pwm.max_i_neg1, duty),
(1, PwmPin::MaxV) =>
set(&mut self.pwm.max_v1, duty),
(1, PwmPin::Fan) =>
set(&mut self.pwm.fan, duty),
_ =>
unreachable!(),
}
@ -481,6 +493,8 @@ impl Channels {
max_v: (self.get_max_v(channel), ElectricPotential::new::<volt>(5.0)).into(),
max_i_pos: self.get_max_i_pos(channel).into(),
max_i_neg: self.get_max_i_neg(channel).into(),
tacho: self.get_pwm(0, PwmPin::Tacho),
Outdated
Review

PWM channels cannot measure frequencies. That's not going to work.

PWM channels cannot measure frequencies. That's not going to work.
fan: self.get_pwm(0, PwmPin::Fan),
}
}
Outdated
Review

Why does tacho need to appear twice?

Why does tacho need to appear twice?

Because output is JSON array, and I didn't want to restructure it for this not so major change

Because output is JSON array, and I didn't want to restructure it for this not so major change
Outdated
Review

Can you just put it somewhere else than that array then?

Can you just put it somewhere else than that array then?
@ -578,6 +592,8 @@ pub struct PwmSummary {
max_v: PwmSummaryField<ElectricPotential>,
Outdated
Review

Noise can potentially make this >1 with maximum TEC current settings. What happens then?

Noise can potentially make this >1 with maximum TEC current settings. What happens then?

It would still run on 1.0, as there is a limiter in the PWM setter.

It would still run on 1.0, as there is a limiter in the PWM setter.
max_i_pos: PwmSummaryField<ElectricCurrent>,
Outdated
Review

You should make the slope configurable and then experiment on the hardware to find a reasonable default.

You should make the slope configurable and then experiment on the hardware to find a reasonable default.

Introduce a,b,c of quadratic equation coefficients?

Introduce a,b,c of quadratic equation coefficients?
Outdated
Review

Just a*current**2 + b should be enough...

Just ``a*current**2 + b`` should be enough...

c would add ability to make it nearly linear

`c` would add ability to make it nearly linear

Also, that may be useful for GUI, as user could choose any 3 points on the fan graph.

Also, that may be useful for GUI, as user could choose any 3 points on the fan graph.
Outdated
Review

I doubt we need a GUI for this, the hardware is fixed.

I doubt we need a GUI for this, the hardware is fixed.
max_i_neg: PwmSummaryField<ElectricCurrent>,
tacho: f64,
fan: f64,
Outdated
Review

f64 really? Now we're talking high precision fan control!

f64 really? Now we're talking high precision fan control!

I think we can go with int range from 1 to 100, since fan seems to not support values less than 0.01

I think we can go with int range from 1 to 100, since fan seems to not support values less than 0.01
}
#[derive(Serialize)]

View File

@ -199,6 +199,10 @@ impl Handler {
let current = ElectricCurrent::new::<ampere>(value);
channels.set_max_i_neg(channel, current);
}
PwmPin::Tacho => {}
PwmPin::Fan => {
channels.set_pwm(channel, PwmPin::Fan, value);
}
}
send_line(socket, b"{}");
Ok(Handler::Handled)

View File

@ -127,6 +127,8 @@ pub enum PwmPin {
MaxIPos,
MaxINeg,
MaxV,
Tacho,
Fan
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
@ -299,7 +301,18 @@ fn pwm_setup(input: &[u8]) -> IResult<&[u8], Result<(PwmPin, f64), Error>> {
)
),
result_with_pin(PwmPin::MaxV)
))
),
map(
preceded(
tag("fan"),
preceded(
whitespace,
float
)
),
result_with_pin(PwmPin::Fan)
)
)
)(input)
}

View File

@ -119,7 +119,7 @@ fn main() -> ! {
timer::setup(cp.SYST, clocks);
let (pins, mut leds, mut eeprom, eth_pins, usb) = Pins::setup(
clocks, dp.TIM1, dp.TIM3,
clocks, dp.TIM1, dp.TIM3, dp.TIM8,
dp.GPIOA, dp.GPIOB, dp.GPIOC, dp.GPIOD, dp.GPIOE, dp.GPIOF, dp.GPIOG,
dp.I2C1,
dp.SPI2, dp.SPI4, dp.SPI5,

View File

@ -23,7 +23,7 @@ use stm32f4xx_hal::{
I2C1,
OTG_FS_GLOBAL, OTG_FS_DEVICE, OTG_FS_PWRCLK,
SPI2, SPI4, SPI5,
TIM1, TIM3,
TIM1, TIM3, TIM8
},
timer::Timer,
time::U32Ext,
@ -114,7 +114,7 @@ impl Pins {
/// Setup GPIO pins and configure MCU peripherals
pub fn setup(
clocks: Clocks,
tim1: TIM1, tim3: TIM3,
tim1: TIM1, tim3: TIM3, tim8: TIM8,
gpioa: GPIOA, gpiob: GPIOB, gpioc: GPIOC, gpiod: GPIOD, gpioe: GPIOE, gpiof: GPIOF, gpiog: GPIOG,
i2c1: I2C1,
spi2: SPI2, spi4: SPI4, spi5: SPI5,
@ -135,10 +135,10 @@ impl Pins {
let pins_adc = Adc::adc1(adc1, true, Default::default());
let pwm = PwmPins::setup(
clocks, tim1, tim3,
clocks, tim1, tim3, tim8,
gpioc.pc6, gpioc.pc7,
gpioe.pe9, gpioe.pe11,
gpioe.pe13, gpioe.pe14
gpioe.pe13, gpioe.pe14, gpioc.pc8, gpioc.pc9
);
let (dac0_spi, dac0_sync) = Self::setup_dac0(
@ -283,19 +283,24 @@ pub struct PwmPins {
pub max_i_pos1: PwmChannels<TIM1, pwm::C2>,
pub max_i_neg0: PwmChannels<TIM1, pwm::C3>,
pub max_i_neg1: PwmChannels<TIM1, pwm::C4>,
pub tacho: PwmChannels<TIM8, pwm::C3>,
pub fan: PwmChannels<TIM8, pwm::C4>,
}
impl PwmPins {
fn setup<M1, M2, M3, M4, M5, M6>(
fn setup<M1, M2, M3, M4, M5, M6, M7, M8>(
clocks: Clocks,
tim1: TIM1,
tim3: TIM3,
tim8: TIM8,
max_v0: PC6<M1>,
max_v1: PC7<M2>,
max_i_pos0: PE9<M3>,
max_i_pos1: PE11<M4>,
max_i_neg0: PE13<M5>,
max_i_neg1: PE14<M6>,
tacho: PC8<M7>,
fan: PC9<M8>,
) -> PwmPins {
let freq = 20u32.khz();
@ -312,6 +317,14 @@ impl PwmPins {
init_pwm_pin(&mut max_v0);
init_pwm_pin(&mut max_v1);
let channels = (
tacho.into_alternate(),
fan.into_alternate(),
);
let (mut tacho, mut fan) = Timer::new(tim8, &clocks).pwm(channels, freq);
init_pwm_pin(&mut tacho);
Outdated
Review

No.

No.
init_pwm_pin(&mut fan);
let channels = (
max_i_pos0.into_alternate(),
max_i_pos1.into_alternate(),
@ -329,6 +342,7 @@ impl PwmPins {
max_v0, max_v1,
max_i_pos0, max_i_pos1,
max_i_neg0, max_i_neg1,
tacho, fan
}
}
}