Skip to content

Commit

Permalink
add tempmon
Browse files Browse the repository at this point in the history
  • Loading branch information
Alexander89 authored and teburd committed Jan 10, 2022
1 parent 08aa861 commit 9b85614
Show file tree
Hide file tree
Showing 2 changed files with 265 additions and 0 deletions.
8 changes: 8 additions & 0 deletions imxrt-hal/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ pub mod pit;
pub mod pwm;
pub mod spi;
pub mod srtc;
#[cfg(any(feature = "imxrt1060", feature = "imxrt1062", feature = "imxrt1064"))]
pub mod tempmon;
pub mod trng;
pub mod uart;

Expand Down Expand Up @@ -67,6 +69,8 @@ pub struct Peripherals {
pub gpt2: gpt::Unclocked,
pub dma: dma::Unclocked,
pub srtc: srtc::Unclocked,
#[cfg(any(feature = "imxrt1060", feature = "imxrt1062", feature = "imxrt1064"))]
pub tempmon: tempmon::UnInitialized,
pub trng: trng::Unclocked,
}

Expand Down Expand Up @@ -118,6 +122,8 @@ impl Peripherals {
gpt2: gpt::Unclocked::two(ral::gpt::GPT2::steal()),
dma: dma::Unclocked::new(ral::dma0::DMA0::steal(), ral::dmamux::DMAMUX::steal()),
srtc: srtc::Unclocked::new(ral::snvs::SNVS::steal()),
#[cfg(any(feature = "imxrt1060", feature = "imxrt1062", feature = "imxrt1064"))]
tempmon: tempmon::UnInitialized::new(ral::tempmon::TEMPMON::steal()),
trng: trng::Unclocked::new(ral::trng::TRNG::steal()),
}
}
Expand Down Expand Up @@ -166,6 +172,8 @@ impl Peripherals {
gpt2: gpt::Unclocked::two(ral::gpt::GPT2::take()?),
dma: dma::Unclocked::new(ral::dma0::DMA0::take()?, ral::dmamux::DMAMUX::take()?),
srtc: srtc::Unclocked::new(ral::snvs::SNVS::take()?),
#[cfg(any(feature = "imxrt1060", feature = "imxrt1062", feature = "imxrt1064"))]
tempmon: tempmon::UnInitialized::new(ral::tempmon::TEMPMON::take()?),
trng: trng::Unclocked::new(ral::trng::TRNG::take()?),
};
Some(p)
Expand Down
257 changes: 257 additions & 0 deletions imxrt-hal/src/tempmon.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,257 @@
#![cfg(any(feature = "imxrt1061", feature = "imxrt1062", feature = "imxrt1064"))]

//! Temperature Monitor (TEMPMON)
//!
//! # Example
//!
//! Manually trigger read
//!
//! ```no_run
//! use imxrt1060_hal;
//! use embedded_hal::timer::CountDown;
//!
//! let mut peripherals = imxrt1060_hal::Peripherals::take().unwrap();
//! usb_io::init();
//!
//! let (_, ipg_hz) = peripherals.ccm.pll1.set_arm_clock(
//! imxrt1060_hal::ccm::PLL1::ARM_HZ,
//! &mut peripherals.ccm.handle,
//! &mut peripherals.dcdc,
//! );
//!
//! let mut cfg = peripherals.ccm.perclk.configure(
//! &mut peripherals.ccm.handle,
//! imxrt1060_hal::ccm::perclk::PODF::DIVIDE_3,
//! imxrt1060_hal::ccm::perclk::CLKSEL::IPG(ipg_hz),
//! );
//!
//! log::debug!("init temperature monitor");
//! let mut mon = peripherals.tempmon.init();
//! t.set_alarm_values()
//! UnInitialized::new(peripherals.temp)
//! todo!()
//! ```

use crate::ral;

/// An unclocked periodic interrupt timer module
///
/// In order to activate the PIT, we must pass in the
/// configured object returned from the CCM's perclk module.
pub struct UnInitialized(ral::tempmon::Instance);

impl UnInitialized {
pub fn new(base: ral::tempmon::Instance) -> Self {
Self(base)
}

pub fn init(self) -> TempMon {
let calibration = unsafe { ral::read_reg!(ral::ocotp, OCOTP, ANA1) };

let n1_room_count = (calibration >> 20) as u16;
let t1_room_temp = 25_u16;
let n2_hot_count = ((calibration >> 8) & 0xFFF) as u16;
let t2_hot_temp = (calibration & 0xFF) as u16;

// Tmeas = T2 - (Nmeas - N2) * ((T2 – T1) / (N1 – N2))
let t_dif: f32 = (t2_hot_temp - t1_room_temp).into();
let n_dif: f32 = (n1_room_count - n2_hot_count).into();

let scaler = t_dif / n_dif;

// Tmeas = HOT_TEMP - (Nmeas - HOT_COUNT) * ((HOT_TEMP - 25.0) / (ROOM_COUNT – HOT_COUNT))

let t = TempMon {
base: self.0,
scaler,
hot_count: n2_hot_count,
hot_temp: t2_hot_temp.into(),
};
t
}

/// Initialize the temperature monitor.
///
/// The `measure_freq` determines how many RTC clocks to wait before automatically repeating a temperature
/// measurement. The pause time before remeasuring is the field value multiplied by the RTC period.
///
/// Find more details `TempMon.set_measure_frequency`
pub fn init_with_measure_freq(self, measure_freq: u16) -> TempMon {
let mut t = self.init();
t.set_measure_frequency(measure_freq);
t
}
}

/// A Temperature Monitor (TEMPMON)
pub struct TempMon {
base: ral::tempmon::Instance,
pub scaler: f32,
pub hot_count: u16,
pub hot_temp: f32,
}

impl TempMon {
pub fn convert(&self, temp_cnt: u16) -> f32 {
let n_meas: f32 = (temp_cnt - self.hot_count).into();
self.hot_temp - n_meas * self.scaler
}

#[allow(dead_code)]
fn decode(&self, temp_value: f32) -> u32 {
// let n_meas: f32 = (temp_cnt - self.hot_count).into();
// let value = self.hot_temp - n_meas * self.scaler;

// let temp_value - self.hot_temp = 0 - (temp_cnt - self.hot_count) * self.scaler;
// let ((temp_value - self.hot_temp) / self.scaler) = -temp_cnt + self.hot_count);
// let temp_cnt + ((temp_value - self.hot_temp) / self.scaler) = self.hot_count);
let v: i32 = ((temp_value - self.hot_temp) / self.scaler) as i32;
(self.hot_count as i32 - v) as u32
}

/// triggers a new measurement and waits until it's finished
///
/// If you configured automatically repeating, this will trigger additional measurement.
/// Use get_temp instate to get the last read value
pub fn measure_temp(&self) -> f32 {
ral::write_reg!(ral::tempmon, self.base, TEMPSENSE0, MEASURE_TEMP: 1);

while ral::read_reg!(ral::tempmon, self.base, TEMPSENSE0, FINISHED == 1) {}
let temp_cnt = ral::read_reg!(ral::tempmon, self.base, TEMPSENSE0, TEMP_CNT) as u16;
self.convert(temp_cnt)
}

/// Returns the last read value from the temperature sensor
pub fn get_temp(&self) -> f32 {
while ral::read_reg!(ral::tempmon, self.base, TEMPSENSE0, FINISHED == 1) {}
let temp_cnt = ral::read_reg!(ral::tempmon, self.base, TEMPSENSE0, TEMP_CNT) as u16;
self.convert(temp_cnt)
}

/// Starts the measurement process. If the measurement frequency is zero, this
/// results in a single conversion.
pub fn start(&mut self) {
ral::write_reg!(
ral::tempmon,
self.base,
TEMPSENSE0,
MEASURE_TEMP: 1
);
}

#[allow(dead_code)]
/// Stops the measurement process. This only has an effect If the measurement
/// frequency is not zero.
pub fn stop(&mut self) {
ral::write_reg!(
ral::tempmon,
self.base,
TEMPSENSE0,
MEASURE_TEMP: 0
);
}

#[allow(dead_code)]
/// This powers down the temperature sensor.
pub fn power_down(&mut self) {
ral::write_reg!(
ral::tempmon,
self.base,
TEMPSENSE0,
POWER_DOWN: 1
);
}

#[allow(dead_code)]
/// This powers up the temperature sensor.
pub fn power_up(&mut self) {
ral::write_reg!(
ral::tempmon,
self.base,
TEMPSENSE0,
POWER_DOWN: 0
);
}

#[allow(dead_code)]
/// Set the temperature that will generate a low alarm, high alarm, and panic alarm interrupt
/// when the temperature exceeded this values.
pub fn set_alarm_values(&mut self, low_alarm: f32, high_alarm: f32, panic_alarm: f32) {
let low_alarm = self.decode(low_alarm);
let high_alarm = self.decode(high_alarm);
let panic_alarm = self.decode(panic_alarm);
ral::write_reg!(ral::tempmon, self.base, TEMPSENSE0, ALARM_VALUE: high_alarm);
ral::write_reg!(
ral::tempmon,
self.base,
TEMPSENSE2,
LOW_ALARM_VALUE: low_alarm,
PANIC_ALARM_VALUE: panic_alarm
);
}

#[allow(dead_code)]
/// queries the temperature that will generate a low alarm, high alarm, and panic alarm interrupt.
///
/// returns (low_alarm_temp, high_alarm_temp, panic_alarm_temp)
pub fn alarm_values(&mut self) -> (f32, f32, f32) {
let high_alarm = ral::read_reg!(ral::tempmon, self.base, TEMPSENSE0, ALARM_VALUE);
let (low_alarm, panic_alarm) = ral::read_reg!(
ral::tempmon,
self.base,
TEMPSENSE2,
LOW_ALARM_VALUE,
PANIC_ALARM_VALUE
);
(
self.convert(low_alarm as u16),
self.convert(high_alarm as u16),
self.convert(panic_alarm as u16),
)
}

#[allow(dead_code)]
/// enables interrupts for the selected alarm
///
/// NOTE: Make sure that you implemented the TEMP_LOW_HIGH or TEMP_PANIC interrupt handler
///
/// NOTE: TEMP_LOW_HIGH is triggered for `TempSensor low` and `TempSensor high`
pub fn enable_interrupts(&mut self, low_high_alarm: bool, panic_alarm: bool) {
if low_high_alarm {
unsafe { cortex_m::peripheral::NVIC::unmask(ral::interrupt::TEMP_LOW_HIGH) };
}
if panic_alarm {
unsafe { cortex_m::peripheral::NVIC::unmask(ral::interrupt::TEMP_PANIC) };
}
}

/// disable interrupts for the selected alarm
pub fn disable_interrupts(low_high_alarm: bool, panic_alarm: bool) {
if low_high_alarm {
cortex_m::peripheral::NVIC::mask(ral::interrupt::TEMP_LOW_HIGH);
}
if panic_alarm {
cortex_m::peripheral::NVIC::mask(ral::interrupt::TEMP_PANIC);
}
}

/// This bits determines how many RTC clocks to wait before automatically repeating a temperature
/// measurement. The pause time before remeasuring is the field value multiplied by the RTC period.
///
/// | value | note |
/// | ------ | ----------------------------------------------------- |
/// | 0x0000 | Defines a single measurement with no repeat. |
/// | 0x0001 | Updates the temperature value at a RTC clock rate. |
/// | 0x0002 | Updates the temperature value at a RTC/2 clock rate. |
/// | ... | _ |
/// | 0xFFFF | Determines a two second sample period with a 32.768KHz RTC clock. Exact timings depend on the accuracy of the RTC clock.|
///
pub fn set_measure_frequency(&mut self, measure_freq: u16) {
ral::write_reg!(
ral::tempmon,
self.base,
TEMPSENSE1,
MEASURE_FREQ: measure_freq as u32
);
}
}

0 comments on commit 9b85614

Please sign in to comment.