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