Support fan PWM settings #73
|
@ -342,12 +342,20 @@ impl Channels {
|
||||||
get(&self.pwm.max_i_neg0),
|
get(&self.pwm.max_i_neg0),
|
||||||
(0, PwmPin::MaxV) =>
|
(0, PwmPin::MaxV) =>
|
||||||
get(&self.pwm.max_v0),
|
get(&self.pwm.max_v0),
|
||||||
|
(0, PwmPin::Tacho) =>
|
||||||
|
|||||||
|
get(&self.pwm.tacho),
|
||||||
|
(0, PwmPin::Fan) =>
|
||||||
|
get(&self.pwm.fan),
|
||||||
(1, PwmPin::MaxIPos) =>
|
(1, PwmPin::MaxIPos) =>
|
||||||
get(&self.pwm.max_i_pos1),
|
get(&self.pwm.max_i_pos1),
|
||||||
(1, PwmPin::MaxINeg) =>
|
(1, PwmPin::MaxINeg) =>
|
||||||
get(&self.pwm.max_i_neg1),
|
get(&self.pwm.max_i_neg1),
|
||||||
(1, PwmPin::MaxV) =>
|
(1, PwmPin::MaxV) =>
|
||||||
get(&self.pwm.max_v1),
|
get(&self.pwm.max_v1),
|
||||||
|
(1, PwmPin::Tacho) =>
|
||||||
|
get(&self.pwm.tacho),
|
||||||
|
(1, PwmPin::Fan) =>
|
||||||
|
get(&self.pwm.fan),
|
||||||
_ =>
|
_ =>
|
||||||
unreachable!(),
|
unreachable!(),
|
||||||
}
|
}
|
||||||
|
@ -381,7 +389,7 @@ impl Channels {
|
||||||
(self.read_tec_u_meas(channel) - ElectricPotential::new::<volt>(1.5)) * 4.0
|
(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 {
|
fn set<P: hal::PwmPin<Duty=u16>>(pin: &mut P, duty: f64) -> f64 {
|
||||||
let max = pin.get_max_duty();
|
let max = pin.get_max_duty();
|
||||||
let value = ((duty * (max as f64)) as u16).min(max);
|
let value = ((duty * (max as f64)) as u16).min(max);
|
||||||
|
@ -397,12 +405,16 @@ impl Channels {
|
||||||
set(&mut self.pwm.max_i_neg0, duty),
|
set(&mut self.pwm.max_i_neg0, duty),
|
||||||
(0, PwmPin::MaxV) =>
|
(0, PwmPin::MaxV) =>
|
||||||
set(&mut self.pwm.max_v0, duty),
|
set(&mut self.pwm.max_v0, duty),
|
||||||
|
(0, PwmPin::Fan) =>
|
||||||
|
set(&mut self.pwm.fan, duty),
|
||||||
(1, PwmPin::MaxIPos) =>
|
(1, PwmPin::MaxIPos) =>
|
||||||
set(&mut self.pwm.max_i_pos1, duty),
|
set(&mut self.pwm.max_i_pos1, duty),
|
||||||
(1, PwmPin::MaxINeg) =>
|
(1, PwmPin::MaxINeg) =>
|
||||||
set(&mut self.pwm.max_i_neg1, duty),
|
set(&mut self.pwm.max_i_neg1, duty),
|
||||||
(1, PwmPin::MaxV) =>
|
(1, PwmPin::MaxV) =>
|
||||||
set(&mut self.pwm.max_v1, duty),
|
set(&mut self.pwm.max_v1, duty),
|
||||||
|
(1, PwmPin::Fan) =>
|
||||||
|
set(&mut self.pwm.fan, duty),
|
||||||
_ =>
|
_ =>
|
||||||
unreachable!(),
|
unreachable!(),
|
||||||
}
|
}
|
||||||
|
@ -481,6 +493,8 @@ impl Channels {
|
||||||
max_v: (self.get_max_v(channel), ElectricPotential::new::<volt>(5.0)).into(),
|
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_pos: self.get_max_i_pos(channel).into(),
|
||||||
max_i_neg: self.get_max_i_neg(channel).into(),
|
max_i_neg: self.get_max_i_neg(channel).into(),
|
||||||
|
tacho: self.get_pwm(0, PwmPin::Tacho),
|
||||||
sb10q
commented
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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sb10q
commented
Why does tacho need to appear twice? Why does tacho need to appear twice?
esavkin
commented
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
sb10q
commented
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>,
|
max_v: PwmSummaryField<ElectricPotential>,
|
||||||
sb10q
commented
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?
esavkin
commented
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>,
|
max_i_pos: PwmSummaryField<ElectricCurrent>,
|
||||||
sb10q
commented
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.
esavkin
commented
Introduce a,b,c of quadratic equation coefficients? Introduce a,b,c of quadratic equation coefficients?
sb10q
commented
Just Just ``a*current**2 + b`` should be enough...
esavkin
commented
`c` would add ability to make it nearly linear
esavkin
commented
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.
sb10q
commented
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>,
|
max_i_neg: PwmSummaryField<ElectricCurrent>,
|
||||||
|
tacho: f64,
|
||||||
|
fan: f64,
|
||||||
sb10q
commented
f64 really? Now we're talking high precision fan control! f64 really? Now we're talking high precision fan control!
esavkin
commented
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)]
|
#[derive(Serialize)]
|
||||||
|
|
|
@ -199,6 +199,10 @@ impl Handler {
|
||||||
let current = ElectricCurrent::new::<ampere>(value);
|
let current = ElectricCurrent::new::<ampere>(value);
|
||||||
channels.set_max_i_neg(channel, current);
|
channels.set_max_i_neg(channel, current);
|
||||||
}
|
}
|
||||||
|
PwmPin::Tacho => {}
|
||||||
|
PwmPin::Fan => {
|
||||||
|
channels.set_pwm(channel, PwmPin::Fan, value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
send_line(socket, b"{}");
|
send_line(socket, b"{}");
|
||||||
Ok(Handler::Handled)
|
Ok(Handler::Handled)
|
||||||
|
|
|
@ -127,6 +127,8 @@ pub enum PwmPin {
|
||||||
MaxIPos,
|
MaxIPos,
|
||||||
MaxINeg,
|
MaxINeg,
|
||||||
MaxV,
|
MaxV,
|
||||||
|
Tacho,
|
||||||
|
Fan
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[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)
|
result_with_pin(PwmPin::MaxV)
|
||||||
))
|
),
|
||||||
|
map(
|
||||||
|
preceded(
|
||||||
|
tag("fan"),
|
||||||
|
preceded(
|
||||||
|
whitespace,
|
||||||
|
float
|
||||||
|
)
|
||||||
|
),
|
||||||
|
result_with_pin(PwmPin::Fan)
|
||||||
|
)
|
||||||
|
)
|
||||||
)(input)
|
)(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -119,7 +119,7 @@ fn main() -> ! {
|
||||||
timer::setup(cp.SYST, clocks);
|
timer::setup(cp.SYST, clocks);
|
||||||
|
|
||||||
let (pins, mut leds, mut eeprom, eth_pins, usb) = Pins::setup(
|
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.GPIOA, dp.GPIOB, dp.GPIOC, dp.GPIOD, dp.GPIOE, dp.GPIOF, dp.GPIOG,
|
||||||
dp.I2C1,
|
dp.I2C1,
|
||||||
dp.SPI2, dp.SPI4, dp.SPI5,
|
dp.SPI2, dp.SPI4, dp.SPI5,
|
||||||
|
|
24
src/pins.rs
|
@ -23,7 +23,7 @@ use stm32f4xx_hal::{
|
||||||
I2C1,
|
I2C1,
|
||||||
OTG_FS_GLOBAL, OTG_FS_DEVICE, OTG_FS_PWRCLK,
|
OTG_FS_GLOBAL, OTG_FS_DEVICE, OTG_FS_PWRCLK,
|
||||||
SPI2, SPI4, SPI5,
|
SPI2, SPI4, SPI5,
|
||||||
TIM1, TIM3,
|
TIM1, TIM3, TIM8
|
||||||
},
|
},
|
||||||
timer::Timer,
|
timer::Timer,
|
||||||
time::U32Ext,
|
time::U32Ext,
|
||||||
|
@ -114,7 +114,7 @@ impl Pins {
|
||||||
/// Setup GPIO pins and configure MCU peripherals
|
/// Setup GPIO pins and configure MCU peripherals
|
||||||
pub fn setup(
|
pub fn setup(
|
||||||
clocks: Clocks,
|
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,
|
gpioa: GPIOA, gpiob: GPIOB, gpioc: GPIOC, gpiod: GPIOD, gpioe: GPIOE, gpiof: GPIOF, gpiog: GPIOG,
|
||||||
i2c1: I2C1,
|
i2c1: I2C1,
|
||||||
spi2: SPI2, spi4: SPI4, spi5: SPI5,
|
spi2: SPI2, spi4: SPI4, spi5: SPI5,
|
||||||
|
@ -135,10 +135,10 @@ impl Pins {
|
||||||
let pins_adc = Adc::adc1(adc1, true, Default::default());
|
let pins_adc = Adc::adc1(adc1, true, Default::default());
|
||||||
|
|
||||||
let pwm = PwmPins::setup(
|
let pwm = PwmPins::setup(
|
||||||
clocks, tim1, tim3,
|
clocks, tim1, tim3, tim8,
|
||||||
gpioc.pc6, gpioc.pc7,
|
gpioc.pc6, gpioc.pc7,
|
||||||
gpioe.pe9, gpioe.pe11,
|
gpioe.pe9, gpioe.pe11,
|
||||||
gpioe.pe13, gpioe.pe14
|
gpioe.pe13, gpioe.pe14, gpioc.pc8, gpioc.pc9
|
||||||
);
|
);
|
||||||
|
|
||||||
let (dac0_spi, dac0_sync) = Self::setup_dac0(
|
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_pos1: PwmChannels<TIM1, pwm::C2>,
|
||||||
pub max_i_neg0: PwmChannels<TIM1, pwm::C3>,
|
pub max_i_neg0: PwmChannels<TIM1, pwm::C3>,
|
||||||
pub max_i_neg1: PwmChannels<TIM1, pwm::C4>,
|
pub max_i_neg1: PwmChannels<TIM1, pwm::C4>,
|
||||||
|
pub tacho: PwmChannels<TIM8, pwm::C3>,
|
||||||
|
pub fan: PwmChannels<TIM8, pwm::C4>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PwmPins {
|
impl PwmPins {
|
||||||
fn setup<M1, M2, M3, M4, M5, M6>(
|
fn setup<M1, M2, M3, M4, M5, M6, M7, M8>(
|
||||||
clocks: Clocks,
|
clocks: Clocks,
|
||||||
tim1: TIM1,
|
tim1: TIM1,
|
||||||
tim3: TIM3,
|
tim3: TIM3,
|
||||||
|
tim8: TIM8,
|
||||||
max_v0: PC6<M1>,
|
max_v0: PC6<M1>,
|
||||||
max_v1: PC7<M2>,
|
max_v1: PC7<M2>,
|
||||||
max_i_pos0: PE9<M3>,
|
max_i_pos0: PE9<M3>,
|
||||||
max_i_pos1: PE11<M4>,
|
max_i_pos1: PE11<M4>,
|
||||||
max_i_neg0: PE13<M5>,
|
max_i_neg0: PE13<M5>,
|
||||||
max_i_neg1: PE14<M6>,
|
max_i_neg1: PE14<M6>,
|
||||||
|
tacho: PC8<M7>,
|
||||||
|
fan: PC9<M8>,
|
||||||
) -> PwmPins {
|
) -> PwmPins {
|
||||||
let freq = 20u32.khz();
|
let freq = 20u32.khz();
|
||||||
|
|
||||||
|
@ -312,6 +317,14 @@ impl PwmPins {
|
||||||
init_pwm_pin(&mut max_v0);
|
init_pwm_pin(&mut max_v0);
|
||||||
init_pwm_pin(&mut max_v1);
|
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);
|
||||||
sb10q
commented
No. No.
|
|||||||
|
init_pwm_pin(&mut fan);
|
||||||
|
|
||||||
let channels = (
|
let channels = (
|
||||||
max_i_pos0.into_alternate(),
|
max_i_pos0.into_alternate(),
|
||||||
max_i_pos1.into_alternate(),
|
max_i_pos1.into_alternate(),
|
||||||
|
@ -329,6 +342,7 @@ impl PwmPins {
|
||||||
max_v0, max_v1,
|
max_v0, max_v1,
|
||||||
max_i_pos0, max_i_pos1,
|
max_i_pos0, max_i_pos1,
|
||||||
max_i_neg0, max_i_neg1,
|
max_i_neg0, max_i_neg1,
|
||||||
|
tacho, fan
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Are you sure this is the best place to put this? This channel business looks highly suspicious.