capsules_extra/
temperature_rp2040.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4
5//! SyscallDriver for RP2040 ADC MCU temperature sensor
6
7use core::cell::Cell;
8use kernel::hil::adc;
9use kernel::hil::sensors;
10use kernel::utilities::cells::OptionalCell;
11use kernel::ErrorCode;
12
13use capsules_core::driver;
14pub const DRIVER_NUM: usize = driver::NUM::Temperature as usize;
15
16#[derive(Copy, Clone, PartialEq)]
17pub enum Status {
18    Read,
19    Idle,
20}
21
22pub struct TemperatureRp2040<'a, A: adc::AdcChannel<'a>> {
23    adc: &'a A,
24    slope: f32,
25    v_27: f32,
26    temperature_client: OptionalCell<&'a dyn sensors::TemperatureClient>,
27    status: Cell<Status>,
28}
29
30impl<'a, A: adc::AdcChannel<'a>> TemperatureRp2040<'a, A> {
31    /// slope - device specific slope found in datasheet
32    /// v_27 - voltage at 27 degrees Celsius found in datasheet
33    pub fn new(adc: &'a A, slope: f32, v_27: f32) -> TemperatureRp2040<'a, A> {
34        TemperatureRp2040 {
35            adc,
36            slope,
37            v_27,
38            temperature_client: OptionalCell::empty(),
39            status: Cell::new(Status::Idle),
40        }
41    }
42}
43
44impl<'a, A: adc::AdcChannel<'a>> adc::Client for TemperatureRp2040<'a, A> {
45    fn sample_ready(&self, sample: u16) {
46        self.status.set(Status::Idle);
47        self.temperature_client.map(|client| {
48            client.callback(Ok(((27.0
49                - (((sample as f32 * 3.3 / 65535.0) - self.v_27) * 1000.0 / self.slope))
50                * 100.0) as i32));
51        });
52    }
53}
54
55impl<'a, A: adc::AdcChannel<'a>> sensors::TemperatureDriver<'a> for TemperatureRp2040<'a, A> {
56    fn set_client(&self, temperature_client: &'a dyn sensors::TemperatureClient) {
57        self.temperature_client.replace(temperature_client);
58    }
59
60    fn read_temperature(&self) -> Result<(), ErrorCode> {
61        if self.status.get() == Status::Idle {
62            self.status.set(Status::Read);
63            let _ = self.adc.sample();
64            Ok(())
65        } else {
66            Err(ErrorCode::BUSY)
67        }
68    }
69}