From 2ef4a45fa0e153cb6435c4dc52f19108ca808cc7 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Mon, 18 Oct 2021 15:24:31 +0200 Subject: [PATCH 1/5] Add support for temperature sensor peripheral * Add TEMP peripheral to all nRF52 chips * Add async HAL for reading temperature values * Add example application reading temperature values --- embassy-nrf/Cargo.toml | 1 + embassy-nrf/src/chips/nrf52805.rs | 3 ++ embassy-nrf/src/chips/nrf52810.rs | 3 ++ embassy-nrf/src/chips/nrf52811.rs | 3 ++ embassy-nrf/src/chips/nrf52820.rs | 3 ++ embassy-nrf/src/chips/nrf52832.rs | 3 ++ embassy-nrf/src/chips/nrf52833.rs | 3 ++ embassy-nrf/src/chips/nrf52840.rs | 3 ++ embassy-nrf/src/lib.rs | 2 + embassy-nrf/src/temp.rs | 84 +++++++++++++++++++++++++++++++ examples/nrf/src/bin/temp.rs | 26 ++++++++++ 11 files changed, 134 insertions(+) create mode 100644 embassy-nrf/src/temp.rs create mode 100644 examples/nrf/src/bin/temp.rs diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index 7c5f8d32b..d4d4ab8d8 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -48,6 +48,7 @@ embedded-dma = "0.1.2" futures = { version = "0.3.17", default-features = false } critical-section = "0.2.3" rand_core = "0.6.3" +fixed = "1.10.0" nrf52805-pac = { version = "0.10.1", optional = true, features = [ "rt" ] } nrf52810-pac = { version = "0.10.1", optional = true, features = [ "rt" ] } diff --git a/embassy-nrf/src/chips/nrf52805.rs b/embassy-nrf/src/chips/nrf52805.rs index db1fac2ff..317e6ed66 100644 --- a/embassy-nrf/src/chips/nrf52805.rs +++ b/embassy-nrf/src/chips/nrf52805.rs @@ -114,6 +114,9 @@ embassy_hal_common::peripherals! { P0_29, P0_30, P0_31, + + // TEMP + TEMP, } impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); diff --git a/embassy-nrf/src/chips/nrf52810.rs b/embassy-nrf/src/chips/nrf52810.rs index 06b9bfb38..b26f30cbf 100644 --- a/embassy-nrf/src/chips/nrf52810.rs +++ b/embassy-nrf/src/chips/nrf52810.rs @@ -117,6 +117,9 @@ embassy_hal_common::peripherals! { P0_29, P0_30, P0_31, + + // TEMP + TEMP, } impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); diff --git a/embassy-nrf/src/chips/nrf52811.rs b/embassy-nrf/src/chips/nrf52811.rs index 2f8d98b31..9fbe3594e 100644 --- a/embassy-nrf/src/chips/nrf52811.rs +++ b/embassy-nrf/src/chips/nrf52811.rs @@ -117,6 +117,9 @@ embassy_hal_common::peripherals! { P0_29, P0_30, P0_31, + + // TEMP + TEMP, } impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); diff --git a/embassy-nrf/src/chips/nrf52820.rs b/embassy-nrf/src/chips/nrf52820.rs index fc7a367ef..abbdba7ac 100644 --- a/embassy-nrf/src/chips/nrf52820.rs +++ b/embassy-nrf/src/chips/nrf52820.rs @@ -112,6 +112,9 @@ embassy_hal_common::peripherals! { P0_29, P0_30, P0_31, + + // TEMP + TEMP, } impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); diff --git a/embassy-nrf/src/chips/nrf52832.rs b/embassy-nrf/src/chips/nrf52832.rs index 47cf27de4..de6dd7a8c 100644 --- a/embassy-nrf/src/chips/nrf52832.rs +++ b/embassy-nrf/src/chips/nrf52832.rs @@ -124,6 +124,9 @@ embassy_hal_common::peripherals! { P0_29, P0_30, P0_31, + + // TEMP + TEMP, } impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); diff --git a/embassy-nrf/src/chips/nrf52833.rs b/embassy-nrf/src/chips/nrf52833.rs index b3d813e24..c5e1c9d33 100644 --- a/embassy-nrf/src/chips/nrf52833.rs +++ b/embassy-nrf/src/chips/nrf52833.rs @@ -144,6 +144,9 @@ embassy_hal_common::peripherals! { P1_13, P1_14, P1_15, + + // TEMP + TEMP, } impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); diff --git a/embassy-nrf/src/chips/nrf52840.rs b/embassy-nrf/src/chips/nrf52840.rs index 473036f61..76cabe6f1 100644 --- a/embassy-nrf/src/chips/nrf52840.rs +++ b/embassy-nrf/src/chips/nrf52840.rs @@ -147,6 +147,9 @@ embassy_hal_common::peripherals! { P1_13, P1_14, P1_15, + + // TEMP + TEMP, } impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 00c719a17..120df99d5 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -43,6 +43,8 @@ pub mod timer; pub mod twim; pub mod uarte; pub mod wdt; +#[cfg(not(feature = "nrf9160"))] +pub mod temp; // This mod MUST go last, so that it sees all the `impl_foo!` macros #[cfg(feature = "nrf52805")] diff --git a/embassy-nrf/src/temp.rs b/embassy-nrf/src/temp.rs new file mode 100644 index 000000000..6a334c64d --- /dev/null +++ b/embassy-nrf/src/temp.rs @@ -0,0 +1,84 @@ +//! Temperature sensor interface. + +use crate::interrupt; +use crate::pac; +use crate::peripherals::TEMP; + +use core::future::Future; +use core::marker::PhantomData; +use embassy::channel::signal::Signal; +use embassy::interrupt::InterruptExt; +use embassy::util::Unborrow; +use embassy_hal_common::{drop::OnDrop, unborrow}; +use fixed::types::I30F2; + +/// Integrated temperature sensor. +pub struct Temp<'d> { + _temp: PhantomData<&'d TEMP>, + _irq: interrupt::TEMP, +} + +static IRQ: Signal = Signal::new(); + +impl<'d> Temp<'d> { + pub fn new( + _t: impl Unborrow + 'd, + irq: impl Unborrow + 'd, + ) -> Self { + unborrow!(_t, irq); + + let t = Self::regs(); + + // Enable interrupt that signals temperature values + t.intenset.write(|w| w.datardy().set()); + irq.disable(); + irq.set_handler(|_| { + let t = Self::regs(); + t.events_datardy.reset(); + let raw = t.temp.read().bits(); + IRQ.signal(I30F2::from_bits(raw as i32)); + }); + irq.enable(); + Self { + _temp: PhantomData, + _irq: irq, + } + } + + /// Perform an asynchronous temperature measurement. The returned future + /// can be awaited to obtain the measurement. + /// + /// If the future is dropped, the measurement is cancelled. + /// + /// # Example + /// + /// ```no_run + /// let mut t = Temp::new(p.TEMP, interrupt::take!(TEMP)); + /// let v: u16 = t.read().await.to_num::(); + /// ``` + pub fn read(&mut self) -> impl Future { + // In case the future is dropped, stop the task and reset events. + let on_drop = OnDrop::new(|| { + let t = Self::regs(); + unsafe { + t.tasks_stop.write(|w| w.bits(1)); + } + t.events_datardy.reset(); + }); + + let t = Self::regs(); + // Empty signal channel and start measurement. + IRQ.reset(); + unsafe { t.tasks_start.write(|w| w.bits(1)) }; + + async move { + let value = IRQ.wait().await; + on_drop.defuse(); + value + } + } + + fn regs() -> &'static pac::temp::RegisterBlock { + unsafe { &*pac::TEMP::ptr() } + } +} diff --git a/examples/nrf/src/bin/temp.rs b/examples/nrf/src/bin/temp.rs new file mode 100644 index 000000000..04d1d58fe --- /dev/null +++ b/examples/nrf/src/bin/temp.rs @@ -0,0 +1,26 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +#[path = "../example_common.rs"] +mod example_common; +use example_common::*; + +use defmt::panic; +use embassy::{ + executor::Spawner, + time::{Duration, Timer}, +}; +use embassy_nrf::{interrupt, temp::Temp, Peripherals}; + +#[embassy::main] +async fn main(_spawner: Spawner, p: Peripherals) { + let irq = interrupt::take!(TEMP); + let mut temp = Temp::new(p.TEMP, irq); + + loop { + let value = temp.read().await; + info!("temperature: {}", value.to_num::()); + Timer::after(Duration::from_secs(1)).await; + } +} From db3b315f9450579779976c08613de984ed14206d Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Tue, 19 Oct 2021 08:37:19 +0200 Subject: [PATCH 2/5] Cargo fmt --- embassy-nrf/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 120df99d5..961a97ce9 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -39,12 +39,12 @@ pub mod rng; #[cfg(not(feature = "nrf52820"))] pub mod saadc; pub mod spim; +#[cfg(not(feature = "nrf9160"))] +pub mod temp; pub mod timer; pub mod twim; pub mod uarte; pub mod wdt; -#[cfg(not(feature = "nrf9160"))] -pub mod temp; // This mod MUST go last, so that it sees all the `impl_foo!` macros #[cfg(feature = "nrf52805")] From c777b6aae17517d59f3a905785bf98346877f0a1 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Tue, 19 Oct 2021 15:31:28 +0200 Subject: [PATCH 3/5] Use AtomicWaker instead of Signal --- embassy-nrf/src/temp.rs | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/embassy-nrf/src/temp.rs b/embassy-nrf/src/temp.rs index 6a334c64d..bd8fa75a7 100644 --- a/embassy-nrf/src/temp.rs +++ b/embassy-nrf/src/temp.rs @@ -6,11 +6,13 @@ use crate::peripherals::TEMP; use core::future::Future; use core::marker::PhantomData; -use embassy::channel::signal::Signal; +use core::task::Poll; use embassy::interrupt::InterruptExt; use embassy::util::Unborrow; +use embassy::waitqueue::AtomicWaker; use embassy_hal_common::{drop::OnDrop, unborrow}; use fixed::types::I30F2; +use futures::future::poll_fn; /// Integrated temperature sensor. pub struct Temp<'d> { @@ -18,7 +20,7 @@ pub struct Temp<'d> { _irq: interrupt::TEMP, } -static IRQ: Signal = Signal::new(); +static WAKER: AtomicWaker = AtomicWaker::new(); impl<'d> Temp<'d> { pub fn new( @@ -27,16 +29,12 @@ impl<'d> Temp<'d> { ) -> Self { unborrow!(_t, irq); - let t = Self::regs(); - // Enable interrupt that signals temperature values - t.intenset.write(|w| w.datardy().set()); irq.disable(); irq.set_handler(|_| { let t = Self::regs(); - t.events_datardy.reset(); - let raw = t.temp.read().bits(); - IRQ.signal(I30F2::from_bits(raw as i32)); + t.intenclr.write(|w| w.datardy().clear()); + WAKER.wake(); }); irq.enable(); Self { @@ -60,19 +58,26 @@ impl<'d> Temp<'d> { // In case the future is dropped, stop the task and reset events. let on_drop = OnDrop::new(|| { let t = Self::regs(); - unsafe { - t.tasks_stop.write(|w| w.bits(1)); - } + t.tasks_stop.write(|w| unsafe { w.bits(1) }); t.events_datardy.reset(); }); let t = Self::regs(); - // Empty signal channel and start measurement. - IRQ.reset(); + t.intenset.write(|w| w.datardy().set()); unsafe { t.tasks_start.write(|w| w.bits(1)) }; async move { - let value = IRQ.wait().await; + let value = poll_fn(|cx| { + WAKER.register(cx.waker()); + if t.events_datardy.read().bits() == 0 { + return Poll::Pending; + } else { + t.events_datardy.reset(); + let raw = t.temp.read().bits(); + Poll::Ready(I30F2::from_bits(raw as i32)) + } + }) + .await; on_drop.defuse(); value } From e807a9eaec0d633a0c27a8b0b53fc32c061eba06 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Tue, 19 Oct 2021 15:32:16 +0200 Subject: [PATCH 4/5] Specify unit in log output --- examples/nrf/src/bin/temp.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/nrf/src/bin/temp.rs b/examples/nrf/src/bin/temp.rs index 04d1d58fe..af9775f5a 100644 --- a/examples/nrf/src/bin/temp.rs +++ b/examples/nrf/src/bin/temp.rs @@ -20,7 +20,7 @@ async fn main(_spawner: Spawner, p: Peripherals) { loop { let value = temp.read().await; - info!("temperature: {}", value.to_num::()); + info!("temperature: {}℃", value.to_num::()); Timer::after(Duration::from_secs(1)).await; } } From 69953a78f10905330fb5d682dd5bda01f13a4e0c Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Tue, 19 Oct 2021 20:48:46 +0200 Subject: [PATCH 5/5] Use async fn instead of impl Future --- embassy-nrf/src/temp.rs | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/embassy-nrf/src/temp.rs b/embassy-nrf/src/temp.rs index bd8fa75a7..f7c6e6609 100644 --- a/embassy-nrf/src/temp.rs +++ b/embassy-nrf/src/temp.rs @@ -4,7 +4,6 @@ use crate::interrupt; use crate::pac; use crate::peripherals::TEMP; -use core::future::Future; use core::marker::PhantomData; use core::task::Poll; use embassy::interrupt::InterruptExt; @@ -54,7 +53,7 @@ impl<'d> Temp<'d> { /// let mut t = Temp::new(p.TEMP, interrupt::take!(TEMP)); /// let v: u16 = t.read().await.to_num::(); /// ``` - pub fn read(&mut self) -> impl Future { + pub async fn read(&mut self) -> I30F2 { // In case the future is dropped, stop the task and reset events. let on_drop = OnDrop::new(|| { let t = Self::regs(); @@ -66,21 +65,19 @@ impl<'d> Temp<'d> { t.intenset.write(|w| w.datardy().set()); unsafe { t.tasks_start.write(|w| w.bits(1)) }; - async move { - let value = poll_fn(|cx| { - WAKER.register(cx.waker()); - if t.events_datardy.read().bits() == 0 { - return Poll::Pending; - } else { - t.events_datardy.reset(); - let raw = t.temp.read().bits(); - Poll::Ready(I30F2::from_bits(raw as i32)) - } - }) - .await; - on_drop.defuse(); - value - } + let value = poll_fn(|cx| { + WAKER.register(cx.waker()); + if t.events_datardy.read().bits() == 0 { + return Poll::Pending; + } else { + t.events_datardy.reset(); + let raw = t.temp.read().bits(); + Poll::Ready(I30F2::from_bits(raw as i32)) + } + }) + .await; + on_drop.defuse(); + value } fn regs() -> &'static pac::temp::RegisterBlock {