embassy_nrf/
temp.rs

1//! Builtin temperature sensor driver.
2
3use core::future::poll_fn;
4use core::task::Poll;
5
6use embassy_hal_internal::drop::OnDrop;
7use embassy_sync::waitqueue::AtomicWaker;
8use fixed::types::I30F2;
9
10use crate::interrupt::InterruptExt;
11use crate::peripherals::TEMP;
12use crate::{interrupt, pac, Peri};
13
14/// Interrupt handler.
15pub struct InterruptHandler {
16    _private: (),
17}
18
19impl interrupt::typelevel::Handler<interrupt::typelevel::TEMP> for InterruptHandler {
20    unsafe fn on_interrupt() {
21        let r = pac::TEMP;
22        r.intenclr().write(|w| w.set_datardy(true));
23        WAKER.wake();
24    }
25}
26
27/// Builtin temperature sensor driver.
28pub struct Temp<'d> {
29    _peri: Peri<'d, TEMP>,
30}
31
32static WAKER: AtomicWaker = AtomicWaker::new();
33
34impl<'d> Temp<'d> {
35    /// Create a new temperature sensor driver.
36    pub fn new(
37        _peri: Peri<'d, TEMP>,
38        _irq: impl interrupt::typelevel::Binding<interrupt::typelevel::TEMP, InterruptHandler> + 'd,
39    ) -> Self {
40        // Enable interrupt that signals temperature values
41        interrupt::TEMP.unpend();
42        unsafe { interrupt::TEMP.enable() };
43
44        Self { _peri }
45    }
46
47    /// Perform an asynchronous temperature measurement. The returned future
48    /// can be awaited to obtain the measurement.
49    ///
50    /// If the future is dropped, the measurement is cancelled.
51    ///
52    /// # Example
53    ///
54    /// ```no_run
55    /// use embassy_nrf::{bind_interrupts, temp};
56    /// use embassy_nrf::temp::Temp;
57    ///
58    /// bind_interrupts!(struct Irqs {
59    ///     TEMP => temp::InterruptHandler;
60    /// });
61    ///
62    /// # async {
63    /// # let p: embassy_nrf::Peripherals = todo!();
64    /// let mut t = Temp::new(p.TEMP, Irqs);
65    /// let v: u16 = t.read().await.to_num::<u16>();
66    /// # };
67    /// ```
68    pub async fn read(&mut self) -> I30F2 {
69        // In case the future is dropped, stop the task and reset events.
70        let on_drop = OnDrop::new(|| {
71            let t = Self::regs();
72            t.tasks_stop().write_value(1);
73            t.events_datardy().write_value(0);
74        });
75
76        let t = Self::regs();
77        t.intenset().write(|w| w.set_datardy(true));
78        t.tasks_start().write_value(1);
79
80        let value = poll_fn(|cx| {
81            WAKER.register(cx.waker());
82            if t.events_datardy().read() == 0 {
83                Poll::Pending
84            } else {
85                t.events_datardy().write_value(0);
86                let raw = t.temp().read();
87                Poll::Ready(I30F2::from_bits(raw as i32))
88            }
89        })
90        .await;
91        on_drop.defuse();
92        value
93    }
94
95    fn regs() -> pac::temp::Temp {
96        pac::TEMP
97    }
98}