From 0d63ff5fd3ea7b13eecf01723aea0d01f62681f7 Mon Sep 17 00:00:00 2001 From: Michaela Murray Date: Tue, 15 Sep 2020 16:07:33 -0700 Subject: [PATCH 1/9] QDEC Hil and userspace driver + hardware driver for nrf52 --- boards/nordic/nrf52840dk/src/main.rs | 27 +++ capsules/README.md | 2 +- capsules/src/driver.rs | 3 +- capsules/src/lib.rs | 1 + capsules/src/qdec.rs | 108 +++++++++++ chips/nrf52/src/interrupt_service.rs | 2 + chips/nrf52/src/lib.rs | 1 + chips/nrf52/src/qdec.rs | 278 +++++++++++++++++++++++++++ chips/nrf52840/src/lib.rs | 2 +- kernel/src/hil/mod.rs | 1 + kernel/src/hil/qdec.rs | 33 ++++ 11 files changed, 455 insertions(+), 3 deletions(-) create mode 100644 capsules/src/qdec.rs create mode 100644 chips/nrf52/src/qdec.rs create mode 100644 kernel/src/hil/qdec.rs diff --git a/boards/nordic/nrf52840dk/src/main.rs b/boards/nordic/nrf52840dk/src/main.rs index 169f3d3932..318067f8f1 100644 --- a/boards/nordic/nrf52840dk/src/main.rs +++ b/boards/nordic/nrf52840dk/src/main.rs @@ -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; @@ -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; @@ -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 { @@ -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), } @@ -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 { @@ -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), }; diff --git a/capsules/README.md b/capsules/README.md index 2dfd4b270a..62d5c2ca81 100644 --- a/capsules/README.md +++ b/capsules/README.md @@ -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 diff --git a/capsules/src/driver.rs b/capsules/src/driver.rs index 256fc0e9da..26be9c9510 100644 --- a/capsules/src/driver.rs +++ b/capsules/src/driver.rs @@ -69,6 +69,7 @@ pub enum NUM { // Misc Buzzer = 0x90000, Screen = 0x90001, - Touch = 0x90002 + Touch = 0x90002, + Qdec = 0x90003 } } diff --git a/capsules/src/lib.rs b/capsules/src/lib.rs index e4423fe052..0c9efb2865 100644 --- a/capsules/src/lib.rs +++ b/capsules/src/lib.rs @@ -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; diff --git a/capsules/src/qdec.rs b/capsules/src/qdec.rs new file mode 100644 index 0000000000..20c1945f90 --- /dev/null +++ b/capsules/src/qdec.rs @@ -0,0 +1,108 @@ +//! Provides userspace access to the Qdec on a board. +//! +//! 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, +} + +#[derive(Default)] +/// This struct contains the necessary fields for an app +pub struct App { + callback: Option, + pos: u32, +} + +impl<'a> QdecInterface<'a> { + /// Create a new instance of the QdecInterface + pub fn new(driver: &'a dyn hil::qdec::QdecDriver, grant: Grant) -> Self { + Self { + driver: driver, + apps: grant, + } + } + + fn configure_callback(&self, callback: Option, 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.pos = app.pos + self.driver.get_acc(); + app.callback + .map(|mut cb| cb.schedule(app.pos 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, + 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.enabled(), + 3 => self.driver.enable_interrupts(), + 4 => ReturnCode::SuccessWithValue { + value: self.driver.get_acc() as usize, + }, + _ => ReturnCode::ENOSUPPORT, + } + } +} diff --git a/chips/nrf52/src/interrupt_service.rs b/chips/nrf52/src/interrupt_service.rs index 30767072a2..df6ccbbbb9 100644 --- a/chips/nrf52/src/interrupt_service.rs +++ b/chips/nrf52/src/interrupt_service.rs @@ -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; @@ -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 diff --git a/chips/nrf52/src/lib.rs b/chips/nrf52/src/lib.rs index c9ae441488..f6b30a7ba6 100644 --- a/chips/nrf52/src/lib.rs +++ b/chips/nrf52/src/lib.rs @@ -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; diff --git a/chips/nrf52/src/qdec.rs b/chips/nrf52/src/qdec.rs new file mode 100644 index 0000000000..0a00352990 --- /dev/null +++ b/chips/nrf52/src/qdec.rs @@ -0,0 +1,278 @@ +//! Qdec driver, nRF5x-family +//! set_client(), enable, get_ticks, +//! The nRF5x quadrature decoder +//! +#[allow(unused_imports)] +use core; +use kernel::common::cells::OptionalCell; +use kernel::common::registers::{ + register_bitfields, register_structs, ReadOnly, ReadWrite, WriteOnly, +}; +use kernel::common::StaticRef; +use kernel::ReturnCode; +use nrf5x::pinmux; +// In this section I declare a struct called QdecRegisters, which contains all the +// relevant registers as outlined in the Nordic 5x specification of the Qdec. +register_structs! { + pub QdecRegisters { + /// Start Qdec sampling + (0x000 => tasks_start: WriteOnly), + /// Stop Qdec sampling + (0x004 => tasks_stop: WriteOnly), + /// Read and clear ACC and ACCDBL + (0x008 => tasks_readclracc: WriteOnly), + /// Read and clear ACC + (0x00C => tasks_rdclracc: WriteOnly), + /// Read nad clear ACCDBL + (0x010 => tasks_rdclrdbl: WriteOnly), + ///Reserve space so tasks_rdclrdbl has access to its entire address space (?) + (0x0014 => _reserved), + /// All the events which have interrupts! + (0x100 => events_arr: [ReadWrite; 5]), + (0x0114 => _reserved2), + /// Shortcut register + (0x200 => shorts: ReadWrite), + (0x204 => _reserved3), + /// Enable interrupt + (0x304 => intenset: ReadWrite), + /// Disable Interrupt + (0x308 => intenclr: ReadWrite), + (0x30C => _reserved4), + /// Enable the quad decoder + (0x500 => enable: ReadWrite), + /// Set the LED output pin polarity + (0x504 => ledpol: WriteOnly), + /// Sampling-rate register + (0x508 => sample_per: WriteOnly), + /// Sample register (receives all samples) + (0x50C => sample: WriteOnly), + /// Reportper + (0x510 => report_per: ReadOnly), + /// Accumulating motion-sample values register + (0x514 => acc: ReadOnly), + (0x518 => acc_read: ReadOnly), + (0x51C => reserved6), + (0x520 => psel_a: ReadWrite), + (0x524 => psel_b: ReadWrite), + (0x528 => reserved5), + (0x544 => accdbl: ReadOnly), + (0x548 => accdbl_read: ReadOnly), + (0x54C => @END), + } +} + +register_bitfields![u32, + Task [ + ENABLE 0 + ], + Shorts [ + /// Write '1' to Enable shortcut on EVENTS_COMPARE\[0\] event + REPORTRDY_READCLRACC 0, + /// Write '1' to Enable shortcut on EVENTS_COMPARE\[1\] event + SAMPLERDY_STOP 1, + /// Write '1' to Enable shortcut on EVENTS_COMPARE\[2\] event + REPORTRDY_RDCLRACC 2, + /// Write '1' to Enable shortcut on EVENTS_COMPARE\[3\] event + REPORTRDY_STOP 3, + /// Write '1' to Enable shortcut on EVENTS_COMPARE\[4\] event + DBLRDY_RDCLRDBL 4, + /// Write '1' to Enable shortcut on EVENTS_COMPARE\[5\] event + DBLRDY_STOP 5, + /// Write '1' to Enable shortcut on EVENTS_COMPARE\[6\] event + SAMPLERDY_READCLRACC 6 + ], + Event [ + READY 0 + ], + PinSelect [ + Pin OFFSET(0) NUMBITS(5), + Port OFFSET(5) NUMBITS(1), + Connect OFFSET(31) NUMBITS(1) + ], + Inte [ + /// Write '1' to Enable interrupt on EVENTS_COMPARE\[0\] event + SAMPLERDY 0, + /// Write '1' to Enable interrupt on EVENTS_COMPARE\[1\] event + REPORTRDY 1, + /// Write '1' to Enable interrupt on EVENTS_COMPARE\[2\] event + ACCOF 2, + /// Write '1' to Enable interrupt on EVENTS_COMPARE\[3\] event + DBLRDY 3, + /// Write '1' to Enable interrupt on EVENTS_COMPARE\[4\] event + STOPPED 4 + ], + LedPol [ + LedPol OFFSET(0) NUMBITS(1) [ + ActiveLow = 0, + ActiveHigh = 1 + ] + ], + Sample [ + SAMPLE 1 + ], + SampPer [ + SAMPLEPER OFFSET(0) NUMBITS(4) [ + us128 = 0, + us256 = 1, + us512 = 2, + us1024 = 3, + us2048 = 4, + us4096 = 5, + us8192 = 6, + us16384 = 7, + ms32 = 8, + ms65 = 9, + ms131 = 10 + ] + ], + ReportPer [ + REPORTPER OFFSET(0) NUMBITS(4) [ + hz10 = 0, + hz40 = 1, + hz80 = 2, + hz120 = 3, + hz160 = 4, + hz200 = 5, + hz240 = 6, + hz280 = 7, + hz1 = 8 + ] + ], + Acc [ + ACC OFFSET(0) NUMBITS(32) + ], + AccDbl [ + ACCDBL OFFSET(0) NUMBITS(4) + ] +]; + +/// This defines the beginning of memory which is memory-mapped to the Qdec +/// This base is declared under the Registers Table 3 +const QDEC_BASE: StaticRef = + unsafe { StaticRef::new(0x40012000 as *const QdecRegisters) }; + +pub static mut QDEC: Qdec = Qdec::new(); + +#[derive(PartialEq, Eq)] +enum QdecState { + Start, + Stop, +} +/// Qdec type declaration: gives the Qdec instance registers and a client +pub struct Qdec { + registers: StaticRef, + client: OptionalCell<&'static dyn kernel::hil::qdec::QdecClient>, + state: QdecState, +} + +/// Qdec impl: provides the Qdec type with vital functionality including: +impl Qdec { + const fn new() -> Qdec { + let qdec = Qdec { + registers: QDEC_BASE, + client: OptionalCell::empty(), + state: QdecState::Start, + }; + qdec + } + + /// sets pins_a and pins_b to be the output pins for whatever the encoding device is + pub fn set_pins(&self, pin_a: pinmux::Pinmux, pin_b: pinmux::Pinmux) { + let regs = self.registers; + regs.psel_a.write( + PinSelect::Pin.val(pin_a.into()) + PinSelect::Port.val(0) + PinSelect::Connect.val(0), + ); + regs.psel_b.write( + PinSelect::Pin.val(pin_b.into()) + PinSelect::Port.val(0) + PinSelect::Connect.val(0), + ); + } + + pub fn set_client(&self, client: &'static dyn kernel::hil::qdec::QdecClient) { + self.client.set(client); + } + + /// When an interrupt occurs, check to see if any + /// of the interrupt register bits are set. If it + /// is, then put it in the client's bitmask + pub(crate) fn handle_interrupt(&self) { + let regs = &*self.registers; + self.client.map(|client| { + // For each of 4 possible compare events, if it's happened, + // clear it and sort its bit in val to pass in callback + for i in 0..regs.events_arr.len() { + if regs.events_arr[i].is_set(Event::READY) { + regs.events_arr[i].set(0); + match i { + 0 => { + client.sample_ready(); + } + 1 => { /*No handling for REPORTRDY*/ } + 2 => { + client.overflow(); + } + 3 => { /*No handling for DBLRDY*/ } + 4 => { + if self.state == QdecState::Stop { + self.registers.sample_per.write(SampPer::SAMPLEPER.val(5)); + self.registers.tasks_start.write(Task::ENABLE::SET); + } + } + _ => panic!("Unsupported interrupt value {}!", i), + } + } + } + }); + } + + fn enable_samplerdy_interrupts(&self) { + let regs = &*self.registers; + + regs.intenset.write(Inte::REPORTRDY::SET); /*SET REPORT READY*/ + regs.intenset.write(Inte::ACCOF::SET); /*SET ACCOF READY*/ + } + + fn enable(&self) { + let regs = &*self.registers; + regs.enable.write(Task::ENABLE::SET); + regs.tasks_start.write(Task::ENABLE::SET); + } + + fn is_enabled(&self) -> ReturnCode { + let regs = &*self.registers; + let result = if regs.enable.is_set(Task::ENABLE) { + ReturnCode::SUCCESS + } else { + ReturnCode::FAIL + }; + result + } +} + +impl kernel::hil::qdec::QdecDriver for Qdec { + fn enable_interrupts(&self) -> ReturnCode { + self.enable_samplerdy_interrupts(); + ReturnCode::SUCCESS + } + + fn enable_qdec(&self) -> ReturnCode { + if self.is_enabled() != ReturnCode::SUCCESS { + self.enable(); + } + self.is_enabled() + } + + fn enabled(&self) -> ReturnCode { + self.is_enabled() + } + + fn get_acc(&self) -> u32 { + let regs = &*self.registers; + regs.tasks_readclracc.write(Task::ENABLE::SET); + let val = regs.acc_read.read(Acc::ACC); + val + } + + fn set_client(&self, client: &'static dyn kernel::hil::qdec::QdecClient) { + self.client.set(client); + } +} diff --git a/chips/nrf52840/src/lib.rs b/chips/nrf52840/src/lib.rs index 942d0288fd..a3d6d527e0 100644 --- a/chips/nrf52840/src/lib.rs +++ b/chips/nrf52840/src/lib.rs @@ -2,7 +2,7 @@ pub use nrf52::{ acomp, adc, aes, ble_radio, clock, constants, crt1, ficr, i2c, ieee802154_radio, init, nvmc, - pinmux, ppi, pwm, rtc, spi, temperature, timer, trng, uart, uicr, usbd, + pinmux, ppi, pwm, qdec, rtc, spi, temperature, timer, trng, uart, uicr, usbd, }; pub mod chip; pub mod gpio; diff --git a/kernel/src/hil/mod.rs b/kernel/src/hil/mod.rs index 4f42afa02e..86ef06c270 100644 --- a/kernel/src/hil/mod.rs +++ b/kernel/src/hil/mod.rs @@ -16,6 +16,7 @@ pub mod led; pub mod log; pub mod nonvolatile_storage; pub mod pwm; +pub mod qdec; pub mod radio; pub mod rng; pub mod screen; diff --git a/kernel/src/hil/qdec.rs b/kernel/src/hil/qdec.rs new file mode 100644 index 0000000000..22a58a2c28 --- /dev/null +++ b/kernel/src/hil/qdec.rs @@ -0,0 +1,33 @@ +//! Interface for a Qdec compatible chip +//! +//! This trait provides a stanfard interface for chips with a +//! quadrature decoder. Note this interface is experimental and +//! may need further updates once implemented on additional chips + +use crate::returncode::ReturnCode; + +pub trait QdecDriver { + /// Sets the client which will receive interrupts + fn set_client(&self, client: &'static dyn QdecClient); + + /// Enables the SAMPLERDY interrupt + fn enable_interrupts(&self) -> ReturnCode; + + /// Enables the Qdec, returning error if Qdec does not exist + fn enable_qdec(&self) -> ReturnCode; + + /// Checks if the qdec has been enabled + fn enabled(&self) -> ReturnCode; + + /// Reads the accumulator value and resets it + /// Note accumulator means the measure of how many ticks the + /// QDEC has moved since the last time the function was called + fn get_acc(&self) -> u32; +} + +pub trait QdecClient { + /// Indicate to the client that the status of the accumulator has changed + fn sample_ready(&self); + /// Indicate to the client that an overflow has occurred + fn overflow(&self); +} From 2b2d8ba547ef3837166c2675a5ae1fa45f9e664b Mon Sep 17 00:00:00 2001 From: mmurray22 <36782608+mmurray22@users.noreply.github.com> Date: Wed, 16 Sep 2020 22:01:11 -0700 Subject: [PATCH 2/9] Update capsules/src/driver.rs Co-authored-by: Pat Pannuto --- capsules/src/driver.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/capsules/src/driver.rs b/capsules/src/driver.rs index 26be9c9510..65e228066e 100644 --- a/capsules/src/driver.rs +++ b/capsules/src/driver.rs @@ -70,6 +70,6 @@ pub enum NUM { Buzzer = 0x90000, Screen = 0x90001, Touch = 0x90002, - Qdec = 0x90003 + Qdec = 0x90003, } } From d0b5f1cfc15a663ca76a0e659fbb5c803fe23509 Mon Sep 17 00:00:00 2001 From: tock Date: Fri, 18 Sep 2020 07:18:53 +0800 Subject: [PATCH 3/9] Changes u32 type to i32 for the position --- capsules/src/qdec.rs | 2 +- chips/nrf52/src/qdec.rs | 4 ++-- kernel/src/hil/qdec.rs | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/capsules/src/qdec.rs b/capsules/src/qdec.rs index 20c1945f90..d24ae27a8c 100644 --- a/capsules/src/qdec.rs +++ b/capsules/src/qdec.rs @@ -31,7 +31,7 @@ pub struct QdecInterface<'a> { /// This struct contains the necessary fields for an app pub struct App { callback: Option, - pos: u32, + pos: i32, } impl<'a> QdecInterface<'a> { diff --git a/chips/nrf52/src/qdec.rs b/chips/nrf52/src/qdec.rs index 0a00352990..2a64bff2a7 100644 --- a/chips/nrf52/src/qdec.rs +++ b/chips/nrf52/src/qdec.rs @@ -265,11 +265,11 @@ impl kernel::hil::qdec::QdecDriver for Qdec { self.is_enabled() } - fn get_acc(&self) -> u32 { + fn get_acc(&self) -> i32 { let regs = &*self.registers; regs.tasks_readclracc.write(Task::ENABLE::SET); let val = regs.acc_read.read(Acc::ACC); - val + val as i32 } fn set_client(&self, client: &'static dyn kernel::hil::qdec::QdecClient) { diff --git a/kernel/src/hil/qdec.rs b/kernel/src/hil/qdec.rs index 22a58a2c28..46c0c1ed1a 100644 --- a/kernel/src/hil/qdec.rs +++ b/kernel/src/hil/qdec.rs @@ -13,7 +13,7 @@ pub trait QdecDriver { /// Enables the SAMPLERDY interrupt fn enable_interrupts(&self) -> ReturnCode; - /// Enables the Qdec, returning error if Qdec does not exist + /// Enables the Qdec, returning error if QDEC is not working fn enable_qdec(&self) -> ReturnCode; /// Checks if the qdec has been enabled @@ -22,7 +22,7 @@ pub trait QdecDriver { /// Reads the accumulator value and resets it /// Note accumulator means the measure of how many ticks the /// QDEC has moved since the last time the function was called - fn get_acc(&self) -> u32; + fn get_acc(&self) -> i32; } pub trait QdecClient { From 72c889f86b4180fd92ca5e0e16d13831ff6341c6 Mon Sep 17 00:00:00 2001 From: tock Date: Fri, 18 Sep 2020 07:25:30 +0800 Subject: [PATCH 4/9] Corrects name for one of the app fields --- capsules/src/qdec.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/capsules/src/qdec.rs b/capsules/src/qdec.rs index d24ae27a8c..47133cbb7f 100644 --- a/capsules/src/qdec.rs +++ b/capsules/src/qdec.rs @@ -31,7 +31,7 @@ pub struct QdecInterface<'a> { /// This struct contains the necessary fields for an app pub struct App { callback: Option, - pos: i32, + position: i32, } impl<'a> QdecInterface<'a> { From 977084f566c74a4ca1cbaa5409ae33ea5a16eab1 Mon Sep 17 00:00:00 2001 From: tock Date: Fri, 18 Sep 2020 14:20:15 +0800 Subject: [PATCH 5/9] Adds documentation to all register bitfields --- chips/nrf52/src/qdec.rs | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/chips/nrf52/src/qdec.rs b/chips/nrf52/src/qdec.rs index 2a64bff2a7..f7fa86ddac 100644 --- a/chips/nrf52/src/qdec.rs +++ b/chips/nrf52/src/qdec.rs @@ -63,6 +63,7 @@ register_structs! { register_bitfields![u32, Task [ + /// Enable ENABLE 0 ], Shorts [ @@ -82,11 +83,15 @@ register_bitfields![u32, SAMPLERDY_READCLRACC 6 ], Event [ + /// Ready to receive interrupts READY 0 ], PinSelect [ + /// Pins the QDEC is attached to Pin OFFSET(0) NUMBITS(5), + /// Port the QDEC is using Port OFFSET(5) NUMBITS(1), + /// Connects pins Connect OFFSET(31) NUMBITS(1) ], Inte [ @@ -102,46 +107,74 @@ register_bitfields![u32, STOPPED 4 ], LedPol [ + /// LED pin polarity LedPol OFFSET(0) NUMBITS(1) [ + /// Active: Low ActiveLow = 0, + /// Active: High ActiveHigh = 1 ] ], Sample [ + /// Last motion sample SAMPLE 1 ], SampPer [ + /// Sample period SAMPLEPER OFFSET(0) NUMBITS(4) [ + /// Sample every 128 microseconds us128 = 0, + /// Sample every 256 microseconds us256 = 1, + /// Sample every 512 microseconds us512 = 2, + /// Sample every 1024 microseconds us1024 = 3, + /// Sample every 2048 microseconds us2048 = 4, + /// Sample every 4096 microseconds us4096 = 5, + /// Sample every 8192 microseconds us8192 = 6, + /// Sample every 16384 microseconds us16384 = 7, + /// Sample every 32 milliseconds ms32 = 8, + /// Sample every 65 milliseconds ms65 = 9, + /// Sample every 131 milliseconds ms131 = 10 ] ], ReportPer [ + /// Captures several samples before being sent out by REPORTRDY event REPORTPER OFFSET(0) NUMBITS(4) [ + /// 10 samples/report hz10 = 0, + /// 40 samples/report hz40 = 1, + /// 80 samples/report hz80 = 2, + /// 120 samples/report hz120 = 3, + /// 160 samples/report hz160 = 4, + /// 200 samples/report hz200 = 5, + /// 240 samples/report hz240 = 6, + /// 280 samples/report hz280 = 7, + /// 1 sample/report hz1 = 8 ] ], Acc [ + /// Valid motion value samples ACC OFFSET(0) NUMBITS(32) ], AccDbl [ + /// Invalid motion value samples ACCDBL OFFSET(0) NUMBITS(4) ] ]; @@ -153,6 +186,7 @@ const QDEC_BASE: StaticRef = pub static mut QDEC: Qdec = Qdec::new(); +/// Enum defining the current QDEC state of started or stopped #[derive(PartialEq, Eq)] enum QdecState { Start, @@ -206,7 +240,11 @@ impl Qdec { 0 => { client.sample_ready(); } - 1 => { /*No handling for REPORTRDY*/ } + 1 => { /*For the time being, there will be no implementation in respone + to the firing of the REPORTRDY interrupt. It fires too frequently + in order to utilize it for position measuring. However, by that same + token, it cannot merely be marked as unimplemented since it would + crash the program.*/ } 2 => { client.overflow(); } From 4500d85f2fe2b3bac771f98b5e33681a5a88b239 Mon Sep 17 00:00:00 2001 From: tock Date: Sat, 19 Sep 2020 00:30:31 +0800 Subject: [PATCH 6/9] Adds disable functions to the QDEC HIL and Capsule --- capsules/src/qdec.rs | 6 ++++-- chips/nrf52/src/qdec.rs | 27 +++++++++++++++++++++++++++ kernel/src/hil/qdec.rs | 6 ++++++ 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/capsules/src/qdec.rs b/capsules/src/qdec.rs index 47133cbb7f..d770913679 100644 --- a/capsules/src/qdec.rs +++ b/capsules/src/qdec.rs @@ -59,9 +59,9 @@ impl<'a> hil::qdec::QdecClient for QdecInterface<'a> { fn sample_ready(&self) { for cntr in self.apps.iter() { cntr.enter(|app, _| { - app.pos = app.pos + self.driver.get_acc(); + app.position = app.position + self.driver.get_acc(); app.callback - .map(|mut cb| cb.schedule(app.pos as usize, 0, 0)); + .map(|mut cb| cb.schedule(app.position as usize, 0, 0)); }); } } @@ -102,6 +102,8 @@ impl<'a> Driver for QdecInterface<'a> { 4 => ReturnCode::SuccessWithValue { value: self.driver.get_acc() as usize, }, + 5 => self.driver.disable_qdec(), + 6 => self.driver.disabled(), _ => ReturnCode::ENOSUPPORT, } } diff --git a/chips/nrf52/src/qdec.rs b/chips/nrf52/src/qdec.rs index f7fa86ddac..2d2acb9b6f 100644 --- a/chips/nrf52/src/qdec.rs +++ b/chips/nrf52/src/qdec.rs @@ -275,6 +275,12 @@ impl Qdec { regs.tasks_start.write(Task::ENABLE::SET); } + fn disable(&self) { + let regs = &*self.registers; + regs.enable.write(Task::ENABLE::CLEAR); + regs.tasks_start.write(Task::ENABLE::CLEAR); + } + fn is_enabled(&self) -> ReturnCode { let regs = &*self.registers; let result = if regs.enable.is_set(Task::ENABLE) { @@ -284,6 +290,16 @@ impl Qdec { }; result } + + fn is_disabled(&self) -> ReturnCode { + let regs = &*self.registers; + let result = if regs.enable.is_set(Task::ENABLE) { + ReturnCode::FAIL + } else { + ReturnCode::SUCCESS + }; + result + } } impl kernel::hil::qdec::QdecDriver for Qdec { @@ -299,10 +315,21 @@ impl kernel::hil::qdec::QdecDriver for Qdec { self.is_enabled() } + fn disable_qdec(&self) -> ReturnCode { + if self.is_enabled() == ReturnCode::SUCCESS { + self.disable(); + } + self.is_disabled() + } + fn enabled(&self) -> ReturnCode { self.is_enabled() } + fn disabled(&self) -> ReturnCode { + self.is_disabled() + } + fn get_acc(&self) -> i32 { let regs = &*self.registers; regs.tasks_readclracc.write(Task::ENABLE::SET); diff --git a/kernel/src/hil/qdec.rs b/kernel/src/hil/qdec.rs index 46c0c1ed1a..1c2258bae1 100644 --- a/kernel/src/hil/qdec.rs +++ b/kernel/src/hil/qdec.rs @@ -16,9 +16,15 @@ pub trait QdecDriver { /// Enables the Qdec, returning error if QDEC is not working fn enable_qdec(&self) -> ReturnCode; + /// Disables the QDEC + fn disable_qdec(&self) -> ReturnCode; + /// Checks if the qdec has been enabled fn enabled(&self) -> ReturnCode; + /// Checks if the qdec has been disabled + fn disabled(&self) -> ReturnCode; + /// Reads the accumulator value and resets it /// Note accumulator means the measure of how many ticks the /// QDEC has moved since the last time the function was called From c838e8db21c62a82ed0262c16992a621bdaaec7c Mon Sep 17 00:00:00 2001 From: tock Date: Sat, 19 Sep 2020 00:43:03 +0800 Subject: [PATCH 7/9] Changes variable names and makes some further changes to the QDEC HIL --- capsules/src/qdec.rs | 3 +-- chips/nrf52/src/qdec.rs | 8 -------- kernel/src/hil/qdec.rs | 8 +------- 3 files changed, 2 insertions(+), 17 deletions(-) diff --git a/capsules/src/qdec.rs b/capsules/src/qdec.rs index d770913679..893b3bd26a 100644 --- a/capsules/src/qdec.rs +++ b/capsules/src/qdec.rs @@ -97,13 +97,12 @@ impl<'a> Driver for QdecInterface<'a> { match command_num { 0 => ReturnCode::SUCCESS, 1 => self.driver.enable_qdec(), - 2 => self.driver.enabled(), + 2 => self.driver.disable_qdec(), 3 => self.driver.enable_interrupts(), 4 => ReturnCode::SuccessWithValue { value: self.driver.get_acc() as usize, }, 5 => self.driver.disable_qdec(), - 6 => self.driver.disabled(), _ => ReturnCode::ENOSUPPORT, } } diff --git a/chips/nrf52/src/qdec.rs b/chips/nrf52/src/qdec.rs index 2d2acb9b6f..cdb24e2e9f 100644 --- a/chips/nrf52/src/qdec.rs +++ b/chips/nrf52/src/qdec.rs @@ -322,14 +322,6 @@ impl kernel::hil::qdec::QdecDriver for Qdec { self.is_disabled() } - fn enabled(&self) -> ReturnCode { - self.is_enabled() - } - - fn disabled(&self) -> ReturnCode { - self.is_disabled() - } - fn get_acc(&self) -> i32 { let regs = &*self.registers; regs.tasks_readclracc.write(Task::ENABLE::SET); diff --git a/kernel/src/hil/qdec.rs b/kernel/src/hil/qdec.rs index 1c2258bae1..b129d543f9 100644 --- a/kernel/src/hil/qdec.rs +++ b/kernel/src/hil/qdec.rs @@ -10,7 +10,7 @@ pub trait QdecDriver { /// Sets the client which will receive interrupts fn set_client(&self, client: &'static dyn QdecClient); - /// Enables the SAMPLERDY interrupt + /// Enables the interrupt collecting and storing samples fn enable_interrupts(&self) -> ReturnCode; /// Enables the Qdec, returning error if QDEC is not working @@ -19,12 +19,6 @@ pub trait QdecDriver { /// Disables the QDEC fn disable_qdec(&self) -> ReturnCode; - /// Checks if the qdec has been enabled - fn enabled(&self) -> ReturnCode; - - /// Checks if the qdec has been disabled - fn disabled(&self) -> ReturnCode; - /// Reads the accumulator value and resets it /// Note accumulator means the measure of how many ticks the /// QDEC has moved since the last time the function was called From f99ca7d41862af118b5b6fbcdc0c6fc96649a195 Mon Sep 17 00:00:00 2001 From: tock Date: Sat, 19 Sep 2020 00:53:31 +0800 Subject: [PATCH 8/9] Formats files --- capsules/src/qdec.rs | 5 +++-- chips/nrf52/src/qdec.rs | 11 ++++++----- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/capsules/src/qdec.rs b/capsules/src/qdec.rs index 893b3bd26a..2937d51aab 100644 --- a/capsules/src/qdec.rs +++ b/capsules/src/qdec.rs @@ -1,4 +1,6 @@ -//! Provides userspace access to the Qdec on a board. +//! 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 //! ----- @@ -102,7 +104,6 @@ impl<'a> Driver for QdecInterface<'a> { 4 => ReturnCode::SuccessWithValue { value: self.driver.get_acc() as usize, }, - 5 => self.driver.disable_qdec(), _ => ReturnCode::ENOSUPPORT, } } diff --git a/chips/nrf52/src/qdec.rs b/chips/nrf52/src/qdec.rs index cdb24e2e9f..f376114050 100644 --- a/chips/nrf52/src/qdec.rs +++ b/chips/nrf52/src/qdec.rs @@ -170,7 +170,7 @@ register_bitfields![u32, ] ], Acc [ - /// Valid motion value samples + /// Valid motion value samples ACC OFFSET(0) NUMBITS(32) ], AccDbl [ @@ -241,10 +241,11 @@ impl Qdec { client.sample_ready(); } 1 => { /*For the time being, there will be no implementation in respone - to the firing of the REPORTRDY interrupt. It fires too frequently - in order to utilize it for position measuring. However, by that same - token, it cannot merely be marked as unimplemented since it would - crash the program.*/ } + to the firing of the REPORTRDY interrupt. It fires too frequently + in order to utilize it for position measuring. However, by that same + token, it cannot merely be marked as unimplemented since it would + crash the program.*/ + } 2 => { client.overflow(); } From aadf17c77b2787babe3d8303c42c09adfe3827c5 Mon Sep 17 00:00:00 2001 From: tock Date: Tue, 22 Sep 2020 06:20:54 +0800 Subject: [PATCH 9/9] Updates DBLRDY interrupt comment --- chips/nrf52/src/qdec.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chips/nrf52/src/qdec.rs b/chips/nrf52/src/qdec.rs index f376114050..39a9b57a97 100644 --- a/chips/nrf52/src/qdec.rs +++ b/chips/nrf52/src/qdec.rs @@ -249,7 +249,7 @@ impl Qdec { 2 => { client.overflow(); } - 3 => { /*No handling for DBLRDY*/ } + 3 => { /*For the time being, there will be no handling for DBLRDY.*/ } 4 => { if self.state == QdecState::Stop { self.registers.sample_per.write(SampPer::SAMPLEPER.val(5));