nrf/qdec: make available on all chips, use Instance trait, switch to new interrupt binding.
This commit is contained in:
		
							parent
							
								
									f8f1d3bcf0
								
							
						
					
					
						commit
						c66b28e759
					
				| @ -140,6 +140,8 @@ impl_twim!(TWI0, TWIM0, TWIM0_TWIS0_TWI0); | ||||
| 
 | ||||
| impl_twis!(TWI0, TWIS0, TWIM0_TWIS0_TWI0); | ||||
| 
 | ||||
| impl_qdec!(QDEC, QDEC, QDEC); | ||||
| 
 | ||||
| impl_timer!(TIMER0, TIMER0, TIMER0); | ||||
| impl_timer!(TIMER1, TIMER1, TIMER1); | ||||
| impl_timer!(TIMER2, TIMER2, TIMER2); | ||||
|  | ||||
| @ -150,6 +150,8 @@ impl_pwm!(PWM0, PWM0, PWM0); | ||||
| 
 | ||||
| impl_pdm!(PDM, PDM, PDM); | ||||
| 
 | ||||
| impl_qdec!(QDEC, QDEC, QDEC); | ||||
| 
 | ||||
| impl_timer!(TIMER0, TIMER0, TIMER0); | ||||
| impl_timer!(TIMER1, TIMER1, TIMER1); | ||||
| impl_timer!(TIMER2, TIMER2, TIMER2); | ||||
|  | ||||
| @ -152,6 +152,8 @@ impl_pwm!(PWM0, PWM0, PWM0); | ||||
| 
 | ||||
| impl_pdm!(PDM, PDM, PDM); | ||||
| 
 | ||||
| impl_qdec!(QDEC, QDEC, QDEC); | ||||
| 
 | ||||
| impl_timer!(TIMER0, TIMER0, TIMER0); | ||||
| impl_timer!(TIMER1, TIMER1, TIMER1); | ||||
| impl_timer!(TIMER2, TIMER2, TIMER2); | ||||
|  | ||||
| @ -153,6 +153,8 @@ impl_timer!(TIMER1, TIMER1, TIMER1); | ||||
| impl_timer!(TIMER2, TIMER2, TIMER2); | ||||
| impl_timer!(TIMER3, TIMER3, TIMER3, extended); | ||||
| 
 | ||||
| impl_qdec!(QDEC, QDEC, QDEC); | ||||
| 
 | ||||
| impl_pin!(P0_00, 0, 0); | ||||
| impl_pin!(P0_01, 0, 1); | ||||
| impl_pin!(P0_02, 0, 2); | ||||
|  | ||||
| @ -173,6 +173,8 @@ impl_pwm!(PWM2, PWM2, PWM2); | ||||
| 
 | ||||
| impl_pdm!(PDM, PDM, PDM); | ||||
| 
 | ||||
| impl_qdec!(QDEC, QDEC, QDEC); | ||||
| 
 | ||||
| impl_timer!(TIMER0, TIMER0, TIMER0); | ||||
| impl_timer!(TIMER1, TIMER1, TIMER1); | ||||
| impl_timer!(TIMER2, TIMER2, TIMER2); | ||||
|  | ||||
| @ -199,6 +199,8 @@ impl_pwm!(PWM3, PWM3, PWM3); | ||||
| 
 | ||||
| impl_pdm!(PDM, PDM, PDM); | ||||
| 
 | ||||
| impl_qdec!(QDEC, QDEC, QDEC); | ||||
| 
 | ||||
| impl_timer!(TIMER0, TIMER0, TIMER0); | ||||
| impl_timer!(TIMER1, TIMER1, TIMER1); | ||||
| impl_timer!(TIMER2, TIMER2, TIMER2); | ||||
|  | ||||
| @ -210,6 +210,8 @@ impl_qspi!(QSPI, QSPI, QSPI); | ||||
| 
 | ||||
| impl_pdm!(PDM, PDM, PDM); | ||||
| 
 | ||||
| impl_qdec!(QDEC, QDEC, QDEC); | ||||
| 
 | ||||
| impl_pin!(P0_00, 0, 0); | ||||
| impl_pin!(P0_01, 0, 1); | ||||
| impl_pin!(P0_02, 0, 2); | ||||
|  | ||||
| @ -37,7 +37,7 @@ pub mod pac { | ||||
|         pdm0_ns as pdm, | ||||
|         power_ns as power, | ||||
|         pwm0_ns as pwm0, | ||||
|         qdec0_ns as qdec0, | ||||
|         qdec0_ns as qdec, | ||||
|         qspi_ns as qspi, | ||||
|         regulators_ns as regulators, | ||||
|         reset_ns as reset, | ||||
| @ -256,6 +256,10 @@ embassy_hal_common::peripherals! { | ||||
|     // PDM
 | ||||
|     PDM0, | ||||
| 
 | ||||
|     // QDEC
 | ||||
|     QDEC0, | ||||
|     QDEC1, | ||||
| 
 | ||||
|     // GPIOTE
 | ||||
|     GPIOTE_CH0, | ||||
|     GPIOTE_CH1, | ||||
| @ -403,6 +407,9 @@ impl_qspi!(QSPI, QSPI, QSPI); | ||||
| 
 | ||||
| impl_pdm!(PDM0, PDM0, PDM0); | ||||
| 
 | ||||
| impl_qdec!(QDEC0, QDEC0, QDEC0); | ||||
| impl_qdec!(QDEC1, QDEC1, QDEC1); | ||||
| 
 | ||||
| impl_pin!(P0_00, 0, 0); | ||||
| impl_pin!(P0_01, 0, 1); | ||||
| #[cfg(feature = "nfc-pins-as-gpio")] | ||||
|  | ||||
| @ -57,7 +57,7 @@ pub mod pdm; | ||||
| pub mod ppi; | ||||
| #[cfg(not(any(feature = "nrf52805", feature = "nrf52820", feature = "_nrf5340-net")))] | ||||
| pub mod pwm; | ||||
| #[cfg(not(any(feature = "nrf51", feature = "_nrf9160", feature = "_nrf5340")))] | ||||
| #[cfg(not(any(feature = "nrf51", feature = "_nrf9160", feature = "_nrf5340-net")))] | ||||
| pub mod qdec; | ||||
| #[cfg(any(feature = "nrf52840", feature = "_nrf5340-app"))] | ||||
| pub mod qspi; | ||||
|  | ||||
| @ -1,20 +1,22 @@ | ||||
| //! Quadrature decoder (QDEC) driver.
 | ||||
| 
 | ||||
| #![macro_use] | ||||
| 
 | ||||
| use core::future::poll_fn; | ||||
| use core::marker::PhantomData; | ||||
| use core::task::Poll; | ||||
| 
 | ||||
| use embassy_cortex_m::interrupt::Interrupt; | ||||
| use embassy_hal_common::{into_ref, PeripheralRef}; | ||||
| use embassy_sync::waitqueue::AtomicWaker; | ||||
| 
 | ||||
| use crate::gpio::sealed::Pin as _; | ||||
| use crate::gpio::{AnyPin, Pin as GpioPin}; | ||||
| use crate::interrupt::InterruptExt; | ||||
| use crate::peripherals::QDEC; | ||||
| use crate::{interrupt, pac, Peripheral}; | ||||
| use crate::{interrupt, Peripheral}; | ||||
| 
 | ||||
| /// Quadrature decoder driver.
 | ||||
| pub struct Qdec<'d> { | ||||
|     _p: PeripheralRef<'d, QDEC>, | ||||
| pub struct Qdec<'d, T: Instance> { | ||||
|     _p: PeripheralRef<'d, T>, | ||||
| } | ||||
| 
 | ||||
| /// QDEC config
 | ||||
| @ -44,44 +46,52 @@ impl Default for Config { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static WAKER: AtomicWaker = AtomicWaker::new(); | ||||
| /// Interrupt handler.
 | ||||
| pub struct InterruptHandler<T: Instance> { | ||||
|     _phantom: PhantomData<T>, | ||||
| } | ||||
| 
 | ||||
| impl<'d> Qdec<'d> { | ||||
| impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { | ||||
|     unsafe fn on_interrupt() { | ||||
|         T::regs().intenclr.write(|w| w.reportrdy().clear()); | ||||
|         T::state().waker.wake(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<'d, T: Instance> Qdec<'d, T> { | ||||
|     /// Create a new QDEC.
 | ||||
|     pub fn new( | ||||
|         qdec: impl Peripheral<P = QDEC> + 'd, | ||||
|         irq: impl Peripheral<P = interrupt::QDEC> + 'd, | ||||
|         qdec: impl Peripheral<P = T> + 'd, | ||||
|         _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | ||||
|         a: impl Peripheral<P = impl GpioPin> + 'd, | ||||
|         b: impl Peripheral<P = impl GpioPin> + 'd, | ||||
|         config: Config, | ||||
|     ) -> Self { | ||||
|         into_ref!(a, b); | ||||
|         Self::new_inner(qdec, irq, a.map_into(), b.map_into(), None, config) | ||||
|         into_ref!(qdec, a, b); | ||||
|         Self::new_inner(qdec, a.map_into(), b.map_into(), None, config) | ||||
|     } | ||||
| 
 | ||||
|     /// Create a new QDEC, with a pin for LED output.
 | ||||
|     pub fn new_with_led( | ||||
|         qdec: impl Peripheral<P = QDEC> + 'd, | ||||
|         irq: impl Peripheral<P = interrupt::QDEC> + 'd, | ||||
|         qdec: impl Peripheral<P = T> + 'd, | ||||
|         _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | ||||
|         a: impl Peripheral<P = impl GpioPin> + 'd, | ||||
|         b: impl Peripheral<P = impl GpioPin> + 'd, | ||||
|         led: impl Peripheral<P = impl GpioPin> + 'd, | ||||
|         config: Config, | ||||
|     ) -> Self { | ||||
|         into_ref!(a, b, led); | ||||
|         Self::new_inner(qdec, irq, a.map_into(), b.map_into(), Some(led.map_into()), config) | ||||
|         into_ref!(qdec, a, b, led); | ||||
|         Self::new_inner(qdec, a.map_into(), b.map_into(), Some(led.map_into()), config) | ||||
|     } | ||||
| 
 | ||||
|     fn new_inner( | ||||
|         p: impl Peripheral<P = QDEC> + 'd, | ||||
|         irq: impl Peripheral<P = interrupt::QDEC> + 'd, | ||||
|         p: PeripheralRef<'d, T>, | ||||
|         a: PeripheralRef<'d, AnyPin>, | ||||
|         b: PeripheralRef<'d, AnyPin>, | ||||
|         led: Option<PeripheralRef<'d, AnyPin>>, | ||||
|         config: Config, | ||||
|     ) -> Self { | ||||
|         into_ref!(p, irq); | ||||
|         let r = Self::regs(); | ||||
|         let r = T::regs(); | ||||
| 
 | ||||
|         // Select pins.
 | ||||
|         a.conf().write(|w| w.input().connect().pull().pullup()); | ||||
| @ -124,20 +134,15 @@ impl<'d> Qdec<'d> { | ||||
|             SamplePeriod::_131ms => w.sampleper()._131ms(), | ||||
|         }); | ||||
| 
 | ||||
|         unsafe { T::Interrupt::steal() }.unpend(); | ||||
|         unsafe { T::Interrupt::steal() }.enable(); | ||||
| 
 | ||||
|         // Enable peripheral
 | ||||
|         r.enable.write(|w| w.enable().set_bit()); | ||||
| 
 | ||||
|         // Start sampling
 | ||||
|         unsafe { r.tasks_start.write(|w| w.bits(1)) }; | ||||
| 
 | ||||
|         irq.disable(); | ||||
|         irq.set_handler(|_| { | ||||
|             let r = Self::regs(); | ||||
|             r.intenclr.write(|w| w.reportrdy().clear()); | ||||
|             WAKER.wake(); | ||||
|         }); | ||||
|         irq.enable(); | ||||
| 
 | ||||
|         Self { _p: p } | ||||
|     } | ||||
| 
 | ||||
| @ -155,12 +160,12 @@ impl<'d> Qdec<'d> { | ||||
|     /// let delta = q.read().await;
 | ||||
|     /// ```
 | ||||
|     pub async fn read(&mut self) -> i16 { | ||||
|         let t = Self::regs(); | ||||
|         let t = T::regs(); | ||||
|         t.intenset.write(|w| w.reportrdy().set()); | ||||
|         unsafe { t.tasks_readclracc.write(|w| w.bits(1)) }; | ||||
| 
 | ||||
|         let value = poll_fn(|cx| { | ||||
|             WAKER.register(cx.waker()); | ||||
|             T::state().waker.register(cx.waker()); | ||||
|             if t.events_reportrdy.read().bits() == 0 { | ||||
|                 return Poll::Pending; | ||||
|             } else { | ||||
| @ -172,10 +177,6 @@ impl<'d> Qdec<'d> { | ||||
|         .await; | ||||
|         value | ||||
|     } | ||||
| 
 | ||||
|     fn regs() -> &'static pac::qdec::RegisterBlock { | ||||
|         unsafe { &*pac::QDEC::ptr() } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /// Sample period
 | ||||
| @ -236,3 +237,48 @@ pub enum LedPolarity { | ||||
|     /// Active low (a low output turns on the LED).
 | ||||
|     ActiveLow, | ||||
| } | ||||
| 
 | ||||
| pub(crate) mod sealed { | ||||
|     use embassy_sync::waitqueue::AtomicWaker; | ||||
| 
 | ||||
|     /// Peripheral static state
 | ||||
|     pub struct State { | ||||
|         pub waker: AtomicWaker, | ||||
|     } | ||||
| 
 | ||||
|     impl State { | ||||
|         pub const fn new() -> Self { | ||||
|             Self { | ||||
|                 waker: AtomicWaker::new(), | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub trait Instance { | ||||
|         fn regs() -> &'static crate::pac::qdec::RegisterBlock; | ||||
|         fn state() -> &'static State; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /// qdec peripheral instance.
 | ||||
| pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { | ||||
|     /// Interrupt for this peripheral.
 | ||||
|     type Interrupt: Interrupt; | ||||
| } | ||||
| 
 | ||||
| macro_rules! impl_qdec { | ||||
|     ($type:ident, $pac_type:ident, $irq:ident) => { | ||||
|         impl crate::qdec::sealed::Instance for peripherals::$type { | ||||
|             fn regs() -> &'static crate::pac::qdec::RegisterBlock { | ||||
|                 unsafe { &*pac::$pac_type::ptr() } | ||||
|             } | ||||
|             fn state() -> &'static crate::qdec::sealed::State { | ||||
|                 static STATE: crate::qdec::sealed::State = crate::qdec::sealed::State::new(); | ||||
|                 &STATE | ||||
|             } | ||||
|         } | ||||
|         impl crate::qdec::Instance for peripherals::$type { | ||||
|             type Interrupt = crate::interrupt::$irq; | ||||
|         } | ||||
|     }; | ||||
| } | ||||
|  | ||||
| @ -4,16 +4,19 @@ | ||||
| 
 | ||||
| use defmt::info; | ||||
| use embassy_executor::Spawner; | ||||
| use embassy_nrf::interrupt; | ||||
| use embassy_nrf::qdec::{self, Qdec}; | ||||
| use embassy_nrf::{bind_interrupts, peripherals}; | ||||
| use {defmt_rtt as _, panic_probe as _}; | ||||
| 
 | ||||
| bind_interrupts!(struct Irqs { | ||||
|     QDEC => qdec::InterruptHandler<peripherals::QDEC>; | ||||
| }); | ||||
| 
 | ||||
| #[embassy_executor::main] | ||||
| async fn main(_spawner: Spawner) { | ||||
|     let p = embassy_nrf::init(Default::default()); | ||||
|     let irq = interrupt::take!(QDEC); | ||||
|     let config = qdec::Config::default(); | ||||
|     let mut rotary_enc = Qdec::new(p.QDEC, irq, p.P0_31, p.P0_30, config); | ||||
|     let mut rotary_enc = Qdec::new(p.QDEC, Irqs, p.P0_31, p.P0_30, config); | ||||
| 
 | ||||
|     info!("Turn rotary encoder!"); | ||||
|     let mut value = 0; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user