stm32-rs / stm32f4xx-hal

A Rust embedded-hal HAL for all MCUs in the STM32 F4 family
BSD Zero Clause License
573 stars 213 forks source link

Support more channels for PwmInput #495

Open brandonros opened 2 years ago

brandonros commented 2 years ago
#![no_main]
#![no_std]

use panic_probe as _;
use core::{cell::RefCell, ops::Deref};
use cortex_m::interrupt::{Mutex, free};
use cortex_m_rt::entry;
use stm32f4xx_hal::{
    gpio::{Alternate, PC6, PC8},
    pac::{interrupt, Interrupt, Peripherals, TIM8},
    prelude::*,
    timer::{Timer, PwmInput}
};
use rtt_target::{rprintln, rtt_init_print};

//type Pc6PwmInput = PwmInput<TIM8, PC6<Alternate<3>>>;
type Pc8PwmInput = PwmInput<TIM8, PC8<Alternate<3>>>;

//static PC6_MONITOR: Mutex<RefCell<Option<Pc6PwmInput>>> = Mutex::new(RefCell::new(None));
static PC8_MONITOR: Mutex<RefCell<Option<Pc8PwmInput>>> = Mutex::new(RefCell::new(None));

#[interrupt]
fn TIM8_CC() {
    /*free(|cs| {
        let pc6_monitor_ref = PC6_MONITOR.borrow(cs).borrow();
        if let Some(ref pc6_monitor) = pc6_monitor_ref.deref() {
            // TODO: clear interrupt?
            // throw out invalid captures
            if pc6_monitor.is_valid_capture() == false {
                return;
            }
            // read PWM input
            let duty_cycle = pc6_monitor.get_duty_cycle() / 100.0;
            rprintln!("pc6: {}", duty_cycle);
        }
    });*/
    free(|cs| {
        let pc8_monitor_ref = PC8_MONITOR.borrow(cs).borrow();
        if let Some(ref pc8_monitor) = pc8_monitor_ref.deref() {
            // TODO: clear interrupt?
            // throw out invalid captures
            if pc8_monitor.is_valid_capture() == false {
                return;
            }
            // read PWM input
            let duty_cycle = pc8_monitor.get_duty_cycle() / 100.0;
            rprintln!("pc8: {}", duty_cycle);
        }
    });   
}

#[entry]
fn main() -> ! {
    // enable console
    rtt_init_print!();
    // get peripherals + clocks
    let dp = Peripherals::take().unwrap();
    let rcc = dp.RCC.constrain();
    let clocks = rcc.cfgr.freeze();
    let gpioc = dp.GPIOC.split();
    let tim8_timer = Timer::new(dp.TIM8, &clocks);
    // setup GIPOC.PC6 as PWM input on TIM8
    /*let pc6_pin = gpioc.pc6.into_alternate();
    let pc6_frequency = 1.Hz();
    let pc6_monitor = tim8_timer.pwm_input(pc6_frequency, pc6_pin);
    free(|cs| {
        PC6_MONITOR.borrow(cs).replace(Some(pc6_monitor));
    });*/
    // setup GIPOC.PC8 as PWM input on TIM8
    let pc8_pin = gpioc.pc8.into_alternate();
    let pc8_frequency = 1.Hz();
    let pc8_monitor = tim8_timer.pwm_input(pc8_frequency, pc8_pin);
    free(|cs| {
        PC8_MONITOR.borrow(cs).replace(Some(pc8_monitor));
    });
    // enable interrupt
    unsafe {
        cortex_m::peripheral::NVIC::unmask(Interrupt::TIM8_CC);
    }
    // do not do wfi, it messes with debugger
    loop {}
}

For some reason pin PC6 works fine with TIM8, but I can't figure out how to get pin PC8 to work with TIM8 or any other timer?

brandonros commented 2 years ago
error[E0277]: the trait bound `stm32f4xx_hal::gpio::Pin<'C', 8_u8, Alternate<3_u8>>: CPin<TIM8, 0_u8>` is not satisfied
  --> src/main.rs:20:42
   |
20 | static PC8_MONITOR: Mutex<RefCell<Option<Pc8PwmInput>>> = Mutex::new(RefCell::new(None));
   |                                          ^^^^^^^^^^^ the trait `CPin<TIM8, 0_u8>` is not implemented for `stm32f4xx_hal::gpio::Pin<'C', 8_u8, Alternate<3_u8>>`
   |
   = help: the following implementations were found:
             <stm32f4xx_hal::gpio::Pin<'A', 0_u8, Alternate<1_u8, Otype>> as CPin<stm32f4xx_hal::pac::TIM2, 0_u8>>
             <stm32f4xx_hal::gpio::Pin<'A', 0_u8, Alternate<2_u8, Otype>> as CPin<stm32f4xx_hal::pac::TIM5, 0_u8>>
             <stm32f4xx_hal::gpio::Pin<'A', 10_u8, Alternate<1_u8, Otype>> as CPin<TIM1, 2_u8>>
             <stm32f4xx_hal::gpio::Pin<'A', 11_u8, Alternate<1_u8, Otype>> as CPin<TIM1, 3_u8>>
           and 63 others
   = note: required because of the requirements on the impl of `stm32f4xx_hal::timer::pwm_input::Pins<TIM8>` for `stm32f4xx_hal::gpio::Pin<'C', 8_u8, Alternate<3_u8>>`
note: required by a bound in `PwmInput`
  --> /Users/brandonros/.cargo/registry/src/github.com-1ecc6299db9ec823/stm32f4xx-hal-0.13.1/src/timer/pwm_input.rs:39:11
   |
39 |     PINS: Pins<TIM>,
   |           ^^^^^^^^^ required by this bound in `PwmInput`

I wish I could figure out how to list the "other 63 implementations found"...

brandonros commented 2 years ago

https://github.com/stm32-rs/stm32f4xx-hal/blob/master/src/timer/pwm_input.rs#L9

I think this is the offending line, based on the comment above it.

image

How do we expand pwm_input to support TIM8_CH3 instead of only TIM8_CH1?

brandonros commented 2 years ago

@burrbull wondering if you can lend a hand, trying to use PwmInput with a TIM8 channel other than 1?

brandonros commented 2 years ago
$ cargo expand timer::pins --features stm32f407
    Checking stm32f4xx-hal v0.13.1 (/Users/brandonros/Desktop/stm32f4xx-hal)
    Finished dev [unoptimized + debuginfo] target(s) in 0.43s

#[cfg(feature = "device-selected")]
mod pins {
    use crate::gpio::{self, Alternate};
    pub trait CPin<TIM, const C: u8> {}
    pub struct Ch<const C: u8>;
    pub const C1: u8 = 0;
    pub const C2: u8 = 1;
    pub const C3: u8 = 2;
    pub const C4: u8 = 3;
    impl<Otype> CPin<crate::pac::TIM1, C1> for gpio::PA8<Alternate<1, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM1, C2> for gpio::PA9<Alternate<1, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM1, C3> for gpio::PA10<Alternate<1, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM1, C4> for gpio::PA11<Alternate<1, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM5, C1> for gpio::PA0<Alternate<2, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM5, C2> for gpio::PA1<Alternate<2, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM5, C3> for gpio::PA2<Alternate<2, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM5, C4> for gpio::PA3<Alternate<2, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM9, C1> for gpio::PA2<Alternate<3, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM9, C2> for gpio::PA3<Alternate<3, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM11, C1> for gpio::PB9<Alternate<3, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM1, C1> for gpio::PE9<Alternate<1, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM1, C2> for gpio::PE11<Alternate<1, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM1, C3> for gpio::PE13<Alternate<1, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM1, C4> for gpio::PE14<Alternate<1, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM2, C1> for gpio::PA0<Alternate<1, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM2, C2> for gpio::PA1<Alternate<1, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM2, C3> for gpio::PA2<Alternate<1, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM2, C4> for gpio::PA3<Alternate<1, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM2, C2> for gpio::PB3<Alternate<1, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM2, C3> for gpio::PB10<Alternate<1, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM2, C4> for gpio::PB11<Alternate<1, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM2, C1> for gpio::PA5<Alternate<1, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM2, C1> for gpio::PA15<Alternate<1, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM3, C1> for gpio::PA6<Alternate<2, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM3, C2> for gpio::PA7<Alternate<2, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM3, C3> for gpio::PB0<Alternate<2, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM3, C4> for gpio::PB1<Alternate<2, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM3, C1> for gpio::PB4<Alternate<2, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM3, C2> for gpio::PB5<Alternate<2, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM3, C1> for gpio::PC6<Alternate<2, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM3, C2> for gpio::PC7<Alternate<2, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM3, C3> for gpio::PC8<Alternate<2, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM3, C4> for gpio::PC9<Alternate<2, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM4, C1> for gpio::PB6<Alternate<2, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM4, C2> for gpio::PB7<Alternate<2, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM4, C3> for gpio::PB8<Alternate<2, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM4, C4> for gpio::PB9<Alternate<2, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM4, C1> for gpio::PD12<Alternate<2, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM4, C2> for gpio::PD13<Alternate<2, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM4, C3> for gpio::PD14<Alternate<2, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM4, C4> for gpio::PD15<Alternate<2, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM10, C1> for gpio::PB8<Alternate<3, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM9, C1> for gpio::PE5<Alternate<3, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM9, C2> for gpio::PE6<Alternate<3, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM8, C1> for gpio::PC6<Alternate<3, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM8, C2> for gpio::PC7<Alternate<3, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM8, C3> for gpio::PC8<Alternate<3, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM8, C4> for gpio::PC9<Alternate<3, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM10, C1> for gpio::PF6<Alternate<3, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM11, C1> for gpio::PF7<Alternate<3, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM12, C1> for gpio::PB14<Alternate<9, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM12, C2> for gpio::PB15<Alternate<9, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM13, C1> for gpio::PA6<Alternate<9, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM13, C1> for gpio::PF8<Alternate<9, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM14, C1> for gpio::PA7<Alternate<9, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM14, C1> for gpio::PF9<Alternate<9, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM5, C1> for gpio::PH10<Alternate<2, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM5, C2> for gpio::PH11<Alternate<2, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM5, C3> for gpio::PH12<Alternate<2, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM5, C4> for gpio::PI0<Alternate<2, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM8, C1> for gpio::PI5<Alternate<3, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM8, C2> for gpio::PI6<Alternate<3, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM8, C3> for gpio::PI7<Alternate<3, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM8, C4> for gpio::PI2<Alternate<3, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM12, C1> for gpio::PH6<Alternate<9, Otype>> {}
    impl<Otype> CPin<crate::pac::TIM12, C2> for gpio::PH9<Alternate<9, Otype>> {}
}

Posting this here to try to make sense of what's happening myself in the meantime.

burrbull commented 2 years ago

The problem is in PwmInput implementation which supports only CH1 now. https://github.com/stm32-rs/stm32f4xx-hal/blob/7e500316a87b98202d783251201615a17329eb7b/src/timer/pwm_input.rs#L9 If you have time you could help to improve it.