diff options
| -rw-r--r-- | embassy-stm32f4/src/lib.rs | 1 | ||||
| -rw-r--r-- | embassy-stm32f4/src/qei.rs | 95 | ||||
| -rw-r--r-- | embassy-traits/Cargo.toml | 1 | ||||
| -rw-r--r-- | embassy-traits/src/lib.rs | 1 | ||||
| -rw-r--r-- | embassy-traits/src/qei.rs | 22 |
5 files changed, 120 insertions, 0 deletions
diff --git a/embassy-stm32f4/src/lib.rs b/embassy-stm32f4/src/lib.rs index aa31951d3..aa99068c2 100644 --- a/embassy-stm32f4/src/lib.rs +++ b/embassy-stm32f4/src/lib.rs | |||
| @@ -313,5 +313,6 @@ pub(crate) mod fmt; | |||
| 313 | 313 | ||
| 314 | pub mod exti; | 314 | pub mod exti; |
| 315 | pub mod interrupt; | 315 | pub mod interrupt; |
| 316 | pub mod qei; | ||
| 316 | pub mod rtc; | 317 | pub mod rtc; |
| 317 | pub mod serial; | 318 | pub mod serial; |
diff --git a/embassy-stm32f4/src/qei.rs b/embassy-stm32f4/src/qei.rs new file mode 100644 index 000000000..1d4689e19 --- /dev/null +++ b/embassy-stm32f4/src/qei.rs | |||
| @@ -0,0 +1,95 @@ | |||
| 1 | use crate::interrupt; | ||
| 2 | use core::future::Future; | ||
| 3 | use core::pin::Pin; | ||
| 4 | use embassy::interrupt::Interrupt; | ||
| 5 | use embassy::traits::qei::WaitForRotate; | ||
| 6 | use embedded_hal::Direction; | ||
| 7 | use embedded_hal::Qei as THQei; | ||
| 8 | use stm32f4xx_hal::pac::TIM2; | ||
| 9 | use stm32f4xx_hal::qei::{Pins, Qei as HalQei}; | ||
| 10 | |||
| 11 | pub struct Qei<T: Instance, PINS> { | ||
| 12 | qei: HalQei<T, PINS>, | ||
| 13 | int: T::Interrupt, | ||
| 14 | } | ||
| 15 | |||
| 16 | impl<PINS: Pins<TIM2>> Qei<TIM2, PINS> { | ||
| 17 | pub fn tim2(tim: TIM2, pins: PINS, interrupt: interrupt::TIM2) -> Self { | ||
| 18 | let qei = HalQei::tim2(tim, pins); | ||
| 19 | |||
| 20 | let tim = unsafe { | ||
| 21 | &mut *(stm32f4xx_hal::stm32::TIM2::ptr() | ||
| 22 | as *mut stm32f4xx_hal::stm32::tim2::RegisterBlock) | ||
| 23 | }; | ||
| 24 | /* | ||
| 25 | enable qei interrupt | ||
| 26 | */ | ||
| 27 | tim.dier.write(|w| w.uie().set_bit()); | ||
| 28 | |||
| 29 | Qei { | ||
| 30 | qei: qei, | ||
| 31 | int: interrupt, | ||
| 32 | } | ||
| 33 | } | ||
| 34 | } | ||
| 35 | |||
| 36 | impl<PINS: Pins<TIM2> + 'static> WaitForRotate for Qei<TIM2, PINS> { | ||
| 37 | type RotateFuture<'a> = impl Future<Output = Direction> + 'a; | ||
| 38 | |||
| 39 | fn wait_for_rotate<'a>( | ||
| 40 | self: Pin<&'a mut Self>, | ||
| 41 | count_down: u16, | ||
| 42 | count_up: u16, | ||
| 43 | ) -> Self::RotateFuture<'a> { | ||
| 44 | let s = unsafe { self.get_unchecked_mut() }; | ||
| 45 | |||
| 46 | let tim = unsafe { | ||
| 47 | &mut *(stm32f4xx_hal::stm32::TIM2::ptr() | ||
| 48 | as *mut stm32f4xx_hal::stm32::tim2::RegisterBlock) | ||
| 49 | }; | ||
| 50 | |||
| 51 | /* | ||
| 52 | the interrupt will be reached at zero or the max count | ||
| 53 | write the total range to the qei. | ||
| 54 | */ | ||
| 55 | tim.arr | ||
| 56 | .write(|w| unsafe { w.bits((count_down + count_up) as u32) }); | ||
| 57 | |||
| 58 | /* | ||
| 59 | set timer to the correct value in the range | ||
| 60 | */ | ||
| 61 | tim.cnt.write(|w| unsafe { w.bits(count_down as u32) }); | ||
| 62 | |||
| 63 | /* | ||
| 64 | clear interrupt flag | ||
| 65 | */ | ||
| 66 | tim.sr.write(|w| w.uif().clear_bit()); | ||
| 67 | |||
| 68 | async move { | ||
| 69 | embassy::util::InterruptFuture::new(&mut s.int).await; | ||
| 70 | |||
| 71 | if tim.cnt.read().bits() == 0 { | ||
| 72 | Direction::Downcounting | ||
| 73 | } else if tim.cnt.read() == count_down + count_up { | ||
| 74 | Direction::Upcounting | ||
| 75 | } else { | ||
| 76 | panic!("unexpected value") | ||
| 77 | } | ||
| 78 | } | ||
| 79 | } | ||
| 80 | } | ||
| 81 | |||
| 82 | mod sealed { | ||
| 83 | pub trait Sealed {} | ||
| 84 | } | ||
| 85 | |||
| 86 | pub trait Instance: sealed::Sealed { | ||
| 87 | type Interrupt: interrupt::Interrupt; | ||
| 88 | } | ||
| 89 | |||
| 90 | #[cfg(feature = "stm32f405")] | ||
| 91 | impl sealed::Sealed for TIM2 {} | ||
| 92 | #[cfg(feature = "stm32f405")] | ||
| 93 | impl Instance for TIM2 { | ||
| 94 | type Interrupt = interrupt::TIM2; | ||
| 95 | } | ||
diff --git a/embassy-traits/Cargo.toml b/embassy-traits/Cargo.toml index 626bf9f3a..737f91181 100644 --- a/embassy-traits/Cargo.toml +++ b/embassy-traits/Cargo.toml | |||
| @@ -9,3 +9,4 @@ std = [] | |||
| 9 | 9 | ||
| 10 | [dependencies] | 10 | [dependencies] |
| 11 | defmt = { version = "0.2.0", optional = true } | 11 | defmt = { version = "0.2.0", optional = true } |
| 12 | embedded-hal = { version = "0.2.3", features = ["unproven"] } | ||
diff --git a/embassy-traits/src/lib.rs b/embassy-traits/src/lib.rs index 10d44d9de..d8b06a091 100644 --- a/embassy-traits/src/lib.rs +++ b/embassy-traits/src/lib.rs | |||
| @@ -9,5 +9,6 @@ | |||
| 9 | pub mod delay; | 9 | pub mod delay; |
| 10 | pub mod flash; | 10 | pub mod flash; |
| 11 | pub mod gpio; | 11 | pub mod gpio; |
| 12 | pub mod qei; | ||
| 12 | pub mod i2c; | 13 | pub mod i2c; |
| 13 | pub mod uart; | 14 | pub mod uart; |
diff --git a/embassy-traits/src/qei.rs b/embassy-traits/src/qei.rs new file mode 100644 index 000000000..73581256d --- /dev/null +++ b/embassy-traits/src/qei.rs | |||
| @@ -0,0 +1,22 @@ | |||
| 1 | use core::future::Future; | ||
| 2 | use core::pin::Pin; | ||
| 3 | use embedded_hal::Direction; | ||
| 4 | |||
| 5 | // Wait for a specified number of rotations either up or down | ||
| 6 | pub trait WaitForRotate { | ||
| 7 | type RotateFuture<'a>: Future<Output = Direction> + 'a; | ||
| 8 | |||
| 9 | /// Wait for a specified number of rotations, in ticks, either up or down. | ||
| 10 | /// | ||
| 11 | /// Return Direction::Upcounting if the high bound is reached. | ||
| 12 | /// Return Direction::Downcounting if the low bound is reached. | ||
| 13 | /// | ||
| 14 | /// Number of ticks is encoder dependent. As an example, if we connect | ||
| 15 | /// the Bourns PEC11H-4120F-S0020, we have 20 ticks per full rotation. | ||
| 16 | /// Other encoders may vary. | ||
| 17 | fn wait_for_rotate<'a>( | ||
| 18 | self: Pin<&'a mut Self>, | ||
| 19 | count_down: u16, | ||
| 20 | count_up: u16, | ||
| 21 | ) -> Self::RotateFuture<'a>; | ||
| 22 | } | ||
