Skip to content
Open
27 changes: 27 additions & 0 deletions boards/nordic/nrf52840dk/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
use capsules::virtual_alarm::VirtualMuxAlarm;
use kernel::common::dynamic_deferred_call::{DynamicDeferredCall, DynamicDeferredCallClientState};
use kernel::component::Component;
use kernel::hil::gpio::Configure;
#[allow(unused_imports)]
use kernel::{capabilities, create_capability, debug, debug_gpio, debug_verbose, static_init};
use nrf52840::gpio::Pin;
Expand Down Expand Up @@ -101,6 +102,9 @@ const SPI_MX25R6435F_CHIP_SELECT: Pin = Pin::P0_17;
const SPI_MX25R6435F_WRITE_PROTECT_PIN: Pin = Pin::P0_22;
const SPI_MX25R6435F_HOLD_PIN: Pin = Pin::P0_23;

const QDEC_PIN_A: Pin = Pin::P0_02;
const QDEC_PIN_B: Pin = Pin::P0_29;

// Constants related to the configuration of the 15.4 network stack
const SRC_MAC: u16 = 0xf00f;
const PAN_ID: u16 = 0xABCD;
Expand Down Expand Up @@ -158,6 +162,7 @@ pub struct Platform {
capsules::virtual_alarm::VirtualMuxAlarm<'static, nrf52840::rtc::Rtc<'static>>,
>,
nonvolatile_storage: &'static capsules::nonvolatile_storage_driver::NonvolatileStorage<'static>,
qdec: &'static capsules::qdec::QdecInterface<'static>,
}

impl kernel::Platform for Platform {
Expand All @@ -177,6 +182,7 @@ impl kernel::Platform for Platform {
capsules::temperature::DRIVER_NUM => f(Some(self.temp)),
capsules::analog_comparator::DRIVER_NUM => f(Some(self.analog_comparator)),
capsules::nonvolatile_storage_driver::DRIVER_NUM => f(Some(self.nonvolatile_storage)),
capsules::qdec::DRIVER_NUM => f(Some(self.qdec)),
kernel::ipc::DRIVER_NUM => f(Some(&self.ipc)),
_ => f(None),
}
Expand Down Expand Up @@ -411,6 +417,26 @@ pub unsafe fn reset_handler() {
nrf52840::acomp::Comparator
));

// qdec initialization
gpio_port[QDEC_PIN_A].make_input();
gpio_port[QDEC_PIN_B].make_input();
gpio_port[QDEC_PIN_A].set_floating_state(kernel::hil::gpio::FloatingState::PullUp);
gpio_port[QDEC_PIN_B].set_floating_state(kernel::hil::gpio::FloatingState::PullUp);

let qdec_nrf52 = &mut nrf52840::qdec::QDEC;
qdec_nrf52.set_pins(
nrf52840::pinmux::Pinmux::new(QDEC_PIN_A as u32),
nrf52840::pinmux::Pinmux::new(QDEC_PIN_B as u32),
);
let qdec = static_init!(
capsules::qdec::QdecInterface<'static>,
capsules::qdec::QdecInterface::new(
qdec_nrf52,
board_kernel.create_grant(&memory_allocation_capability)
)
);
kernel::hil::qdec::QdecDriver::set_client(&nrf52840::qdec::QDEC, qdec);

nrf52_components::NrfClockComponent::new().finalize(());

let platform = Platform {
Expand All @@ -426,6 +452,7 @@ pub unsafe fn reset_handler() {
alarm,
analog_comparator,
nonvolatile_storage,
qdec,
ipc: kernel::ipc::IPC::new(board_kernel, &memory_allocation_capability),
};

Expand Down
2 changes: 1 addition & 1 deletion capsules/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ These capsules provide a `Driver` interface for common MCU peripherals.
- **[RNG](src/rng.rs)**: Random number generation.
- **[SPI Controller](src/spi_controller.rs)**: SPI controller device (SPI master)
- **[SPI Peripheral](src/spi_peripheral.rs)**: SPI peripheral device (SPI slave)

- **[QDEC](src/qdec.rs)**: Quadrature DECoder for quadrature-encoded sensor signals

### Helpful Userspace Capsules

Expand Down
3 changes: 2 additions & 1 deletion capsules/src/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ pub enum NUM {
// Misc
Buzzer = 0x90000,
Screen = 0x90001,
Touch = 0x90002
Touch = 0x90002,
Qdec = 0x90003,
}
}
1 change: 1 addition & 0 deletions capsules/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ pub mod nrf51822_serialization;
pub mod panic_button;
pub mod pca9544a;
pub mod process_console;
pub mod qdec;
pub mod rf233;
pub mod rf233_const;
pub mod rng;
Expand Down
110 changes: 110 additions & 0 deletions capsules/src/qdec.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
//! Provides userspace access to the Quadrature Decoder (QDEC) on a board.
//! A QDEC provides buffered decoding of quadrature-encoded sensor signals.
//! It is generally used to decode mechanical and optical signals.
//!
//! Usage
//! -----
//!
//! ````
//! let qdec = static_init!(
//! capsules::qdec::Qdec<'static>,
//! capsules::qdec::QdecInterface::new(&nrf52::qdec::QDEC,
//! kernel::Grant::create())
//! );
//! kernel::hil::QdecDriver.set_client(qdec);
//! ````
//! #Interrupt Spurred Readings versus Regular Readings
//! An application can either enable interrupts to get the
//! accumulation value or manually read it whenever it wants

use crate::driver;
use kernel::hil;
use kernel::{AppId, Callback, Driver, Grant, ReturnCode};

pub const DRIVER_NUM: usize = driver::NUM::Qdec as usize;

/// This struct contains the resources necessary for the QdecInterface
pub struct QdecInterface<'a> {
driver: &'a dyn hil::qdec::QdecDriver,
apps: Grant<App>,
}

#[derive(Default)]
/// This struct contains the necessary fields for an app
pub struct App {
callback: Option<Callback>,
position: i32,
}

impl<'a> QdecInterface<'a> {
/// Create a new instance of the QdecInterface
pub fn new(driver: &'a dyn hil::qdec::QdecDriver, grant: Grant<App>) -> Self {
Self {
driver: driver,
apps: grant,
}
}

fn configure_callback(&self, callback: Option<Callback>, app_id: AppId) -> ReturnCode {
self.apps
.enter(app_id, |app, _| {
app.callback = callback;
ReturnCode::SUCCESS
})
.unwrap_or_else(|err| err.into())
}
}

impl<'a> hil::qdec::QdecClient for QdecInterface<'a> {
/// Goes through all the apps and if the app is
/// subscribed then it sends back the acc value
fn sample_ready(&self) {
for cntr in self.apps.iter() {
cntr.enter(|app, _| {
app.position = app.position + self.driver.get_acc();
app.callback
.map(|mut cb| cb.schedule(app.position as usize, 0, 0));
});
}
}

/// Goes through all the apps and if the app recently
/// had an overflow, it records the occurance
fn overflow(&self) {
/*for now, we do not handle overflows*/
}
}

impl<'a> Driver for QdecInterface<'a> {
/// Subscribes a client to (newly enabled) interrupts
fn subscribe(
&self,
subscribe_num: usize,
callback: Option<Callback>,
app_id: AppId,
) -> ReturnCode {
match subscribe_num {
0 => self.configure_callback(callback, app_id),
_ => ReturnCode::ENOSUPPORT,
}
}

/// Command switch statement for various essential processes
/// 0 is a sanity check for the switch statement
/// 1 enables the qdec
/// 2 checks that the qdec is enabled
/// 3 enables inerrupts
/// 4 gets the current displacement stored in the QDEC
fn command(&self, command_num: usize, _: usize, _: usize, _app_id: AppId) -> ReturnCode {
match command_num {
0 => ReturnCode::SUCCESS,
1 => self.driver.enable_qdec(),
2 => self.driver.disable_qdec(),
3 => self.driver.enable_interrupts(),
4 => ReturnCode::SuccessWithValue {
value: self.driver.get_acc() as usize,
},
_ => ReturnCode::ENOSUPPORT,
}
}
}
2 changes: 2 additions & 0 deletions chips/nrf52/src/interrupt_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::ble_radio;
use crate::i2c;
use crate::ieee802154_radio;
use crate::power;
use crate::qdec;
use crate::spi;
use crate::uart;
use kernel::debug;
Expand Down Expand Up @@ -123,6 +124,7 @@ impl InterruptService for Nrf52InterruptService<'_> {
}
peripheral_interrupts::SPIM2_SPIS2_SPI2 => spi::SPIM2.handle_interrupt(),
peripheral_interrupts::ADC => adc::ADC.handle_interrupt(),
peripheral_interrupts::QDEC => qdec::QDEC.handle_interrupt(),
_ => return false,
}
true
Expand Down
1 change: 1 addition & 0 deletions chips/nrf52/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ pub mod nvmc;
pub mod power;
pub mod ppi;
pub mod pwm;
pub mod qdec;
pub mod spi;
pub mod uart;
pub mod uicr;
Expand Down
Loading