1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
// Licensed under the Apache License, Version 2.0 or the MIT License.
// SPDX-License-Identifier: Apache-2.0 OR MIT
// Copyright Tock Contributors 2022.
//! Temperature sensor driver, nRF5X-family
//!
//! Generates a simple temperature measurement without sampling
//!
//! Authors
//! -------------------
//! * Niklas Adolfsson <niklasadolfsson1@gmail.com>
//! * Fredrik Nilsson <frednils@student.chalmers.se>
//! * Date: March 03, 2017
use kernel::utilities::cells::OptionalCell;
use kernel::utilities::registers::interfaces::{Readable, Writeable};
use kernel::utilities::registers::{register_bitfields, ReadOnly, ReadWrite, WriteOnly};
use kernel::utilities::StaticRef;
use kernel::ErrorCode;
const TEMP_BASE: StaticRef<TempRegisters> =
unsafe { StaticRef::new(0x4000C000 as *const TempRegisters) };
#[repr(C)]
struct TempRegisters {
/// Start temperature measurement
/// Address: 0x000 - 0x004
pub task_start: WriteOnly<u32, Task::Register>,
/// Stop temperature measurement
/// Address: 0x004 - 0x008
pub task_stop: WriteOnly<u32, Task::Register>,
/// Reserved
pub _reserved1: [u32; 62],
/// Temperature measurement complete, data ready
/// Address: 0x100 - 0x104
pub event_datardy: ReadWrite<u32, Event::Register>,
/// Reserved
// Note, `inten` register on nRF51 is ignored because it's not supported by nRF52
// And intenset and intenclr provide the same functionality
pub _reserved2: [u32; 128],
/// Enable interrupt
/// Address: 0x304 - 0x308
pub intenset: ReadWrite<u32, Intenset::Register>,
/// Disable interrupt
/// Address: 0x308 - 0x30c
pub intenclr: ReadWrite<u32, Intenclr::Register>,
/// Reserved
pub _reserved3: [u32; 127],
/// Temperature in °C (0.25° steps)
/// Address: 0x508 - 0x50c
pub temp: ReadOnly<u32, Temperature::Register>,
/// Reserved
pub _reserved4: [u32; 5],
/// Slope of piece wise linear function (nRF52 only)
/// Address 0x520 - 0x534
#[cfg(feature = "nrf52")]
pub a: [ReadWrite<u32, A::Register>; 6],
pub _reserved5: [u32; 2],
/// y-intercept of 5th piece wise linear function (nRF52 only)
/// Address: 0x540 - 0x554
#[cfg(feature = "nrf52")]
pub b: [ReadWrite<u32, B::Register>; 6],
pub _reserved6: [u32; 2],
/// End point of 1st piece wise linear function (nRF52 only)
/// Address: 0x560 - 0x570
#[cfg(feature = "nrf52")]
pub t: [ReadWrite<u32, B::Register>; 5],
}
register_bitfields! [u32,
/// Start task
Task [
ENABLE OFFSET(0) NUMBITS(1)
],
/// Read event
Event [
READY OFFSET(0) NUMBITS(1)
],
/// Enabled interrupt
Intenset [
DATARDY OFFSET(0) NUMBITS(1)
],
/// Disable interrupt
Intenclr [
DATARDY OFFSET(0) NUMBITS(1)
],
/// Temperature in °C (0.25° steps)
Temperature [
TEMP OFFSET(0) NUMBITS(32)
],
/// Slope of piece wise linear function
A [
SLOPE OFFSET(0) NUMBITS(12)
],
/// y-intercept of wise linear function
B [
INTERCEPT OFFSET(0) NUMBITS(14)
],
/// End point of wise linear function
T [
PIECE OFFSET(0) NUMBITS(8)
]
];
pub struct Temp<'a> {
registers: StaticRef<TempRegisters>,
client: OptionalCell<&'a dyn kernel::hil::sensors::TemperatureClient>,
}
impl<'a> Temp<'a> {
pub const fn new() -> Temp<'a> {
Temp {
registers: TEMP_BASE,
client: OptionalCell::empty(),
}
}
/// Temperature interrupt handler
pub fn handle_interrupt(&self) {
// disable interrupts
self.disable_interrupts();
// get temperature
// Result of temperature measurement in °C, 2's complement format, 0.25 °C steps
let temp = (self.registers.temp.get() as i32 * 100) / 4;
// stop measurement
self.registers.task_stop.write(Task::ENABLE::SET);
// disable interrupts
self.disable_interrupts();
// trigger callback with temperature
self.client.map(|client| client.callback(Ok(temp)));
}
fn enable_interrupts(&self) {
self.registers.intenset.write(Intenset::DATARDY::SET);
}
fn disable_interrupts(&self) {
self.registers.intenclr.write(Intenclr::DATARDY::SET);
}
}
impl<'a> kernel::hil::sensors::TemperatureDriver<'a> for Temp<'a> {
fn read_temperature(&self) -> Result<(), ErrorCode> {
self.enable_interrupts();
self.registers.event_datardy.write(Event::READY::CLEAR);
self.registers.task_start.write(Task::ENABLE::SET);
Ok(())
}
fn set_client(&self, client: &'a dyn kernel::hil::sensors::TemperatureClient) {
self.client.set(client);
}
}