diff --git a/embassy-stm32f4/src/lib.rs b/embassy-stm32f4/src/lib.rs index aa31951d..aa99068c 100644 --- a/embassy-stm32f4/src/lib.rs +++ b/embassy-stm32f4/src/lib.rs @@ -313,5 +313,6 @@ pub(crate) mod fmt; pub mod exti; pub mod interrupt; +pub mod qei; pub mod rtc; pub mod serial; diff --git a/embassy-stm32f4/src/qei.rs b/embassy-stm32f4/src/qei.rs new file mode 100644 index 00000000..1d4689e1 --- /dev/null +++ b/embassy-stm32f4/src/qei.rs @@ -0,0 +1,95 @@ +use crate::interrupt; +use core::future::Future; +use core::pin::Pin; +use embassy::interrupt::Interrupt; +use embassy::traits::qei::WaitForRotate; +use embedded_hal::Direction; +use embedded_hal::Qei as THQei; +use stm32f4xx_hal::pac::TIM2; +use stm32f4xx_hal::qei::{Pins, Qei as HalQei}; + +pub struct Qei { + qei: HalQei, + int: T::Interrupt, +} + +impl> Qei { + pub fn tim2(tim: TIM2, pins: PINS, interrupt: interrupt::TIM2) -> Self { + let qei = HalQei::tim2(tim, pins); + + let tim = unsafe { + &mut *(stm32f4xx_hal::stm32::TIM2::ptr() + as *mut stm32f4xx_hal::stm32::tim2::RegisterBlock) + }; + /* + enable qei interrupt + */ + tim.dier.write(|w| w.uie().set_bit()); + + Qei { + qei: qei, + int: interrupt, + } + } +} + +impl + 'static> WaitForRotate for Qei { + type RotateFuture<'a> = impl Future + 'a; + + fn wait_for_rotate<'a>( + self: Pin<&'a mut Self>, + count_down: u16, + count_up: u16, + ) -> Self::RotateFuture<'a> { + let s = unsafe { self.get_unchecked_mut() }; + + let tim = unsafe { + &mut *(stm32f4xx_hal::stm32::TIM2::ptr() + as *mut stm32f4xx_hal::stm32::tim2::RegisterBlock) + }; + + /* + the interrupt will be reached at zero or the max count + write the total range to the qei. + */ + tim.arr + .write(|w| unsafe { w.bits((count_down + count_up) as u32) }); + + /* + set timer to the correct value in the range + */ + tim.cnt.write(|w| unsafe { w.bits(count_down as u32) }); + + /* + clear interrupt flag + */ + tim.sr.write(|w| w.uif().clear_bit()); + + async move { + embassy::util::InterruptFuture::new(&mut s.int).await; + + if tim.cnt.read().bits() == 0 { + Direction::Downcounting + } else if tim.cnt.read() == count_down + count_up { + Direction::Upcounting + } else { + panic!("unexpected value") + } + } + } +} + +mod sealed { + pub trait Sealed {} +} + +pub trait Instance: sealed::Sealed { + type Interrupt: interrupt::Interrupt; +} + +#[cfg(feature = "stm32f405")] +impl sealed::Sealed for TIM2 {} +#[cfg(feature = "stm32f405")] +impl Instance for TIM2 { + type Interrupt = interrupt::TIM2; +} diff --git a/embassy-traits/src/lib.rs b/embassy-traits/src/lib.rs index 10d44d9d..d8b06a09 100644 --- a/embassy-traits/src/lib.rs +++ b/embassy-traits/src/lib.rs @@ -9,5 +9,6 @@ pub mod delay; pub mod flash; pub mod gpio; +pub mod qei; pub mod i2c; pub mod uart; diff --git a/embassy-traits/src/qei.rs b/embassy-traits/src/qei.rs new file mode 100644 index 00000000..7e0a8961 --- /dev/null +++ b/embassy-traits/src/qei.rs @@ -0,0 +1,14 @@ +use core::future::Future; +use core::pin::Pin; +use embedded_hal::Direction; + +// Wait for a specified number of rotations either up or down +pub trait WaitForRotate { + type RotateFuture<'a>: Future + 'a; + + fn wait_for_rotate<'a>( + self: Pin<&'a mut Self>, + count_down: u16, + count_up: u16, + ) -> Self::RotateFuture<'a>; +}