Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ITM: exhaustively check feature support during configure; improve standard correctness, documentation #383

Open
wants to merge 18 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
Also fixes `VectActive::from` to take a `u16` and subtract `16` for
`VectActive::Interrupt`s to match `SBC::vect_active()` (#373).
- DWT: add `configure` API for address, cycle count comparison (#342, #367).
- ITM: add `configure` API (#342).
- ITM: add `configure` API; `lock`, `unlock`, `busy`, `locked` functions (#342, #383).
- TPIU: add API for *Formatter and Flush Control* (FFCR) and *Selected Pin Control* (SPPR) registers (#342).
- Add `std` and `serde` crate features for improved host-side ITM decode functionality when working with the downstream `itm`, `cargo-rtic-scope` crates (#363, #366).

Expand Down
172 changes: 159 additions & 13 deletions src/peripheral/itm.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
//! Instrumentation Trace Macrocell
//!
//! The documentation in this module contains references to ARM specifications, namely:
//! - coresight: [*ARM CoreSight Architecture Specification*, Version 3.0](https://developer.arm.com/documentation/ihi0029/latest).
//!
//! *NOTE* Not available on Armv6-M and Armv8-M Baseline.

use core::cell::UnsafeCell;
Expand Down Expand Up @@ -31,7 +34,7 @@ pub struct RegisterBlock {
/// Lock Access
pub lar: WO<u32>,
/// Lock Status
pub lsr: RO<u32>,
pub lsr: RO<Lsr>,
}

bitfield! {
Expand All @@ -50,6 +53,15 @@ bitfield! {
busy, _: 23;
}

bitfield! {
/// Software Lock Status Register
#[repr(C)]
#[derive(Copy, Clone)]
pub struct Lsr(u32);
sli, _: 0;
slk, _: 1;
}

/// Stimulus Port
pub struct Stim {
register: UnsafeCell<u32>,
Expand Down Expand Up @@ -174,42 +186,176 @@ pub struct ITMSettings {
pub timestamp_clk_src: TimestampClkSrc,
}

/// Possible errors on [ITM::configure].
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
pub enum ITMConfigurationError {
tmplt marked this conversation as resolved.
Show resolved Hide resolved
/// Global timestamp generation is not supported on this target.
/// Request [`GlobalTimestampOptions::Disabled`] instead.
///
/// [`ITM_TCR`](struct@Tcr) register remains unchanged on this error.
GTS,
/// The requested timestamp clock source is not supported on this target.
///
/// *NOTE*: `GTSFREQ` in [`ITM_TCR`](struct@Tcr) field has
/// potentially been changed on this error.
TimestampClkSrc,
/// The target does not implement the local timestamp prescaler.
/// Request [`LocalTimestampOptions::Disabled`] or
/// [`LocalTimestampOptions::Disabled`] instead.
///
/// *NOTE*: `GTSFREQ` and `SWOENA` in [`ITM_TCR`](struct@Tcr) fields
/// have potentially changed on this error.
TSPrescale,
}

impl ITM {
/// Removes the software lock on the ITM.
/// Removes the software lock on the [`ITM`]. Must be called before
tmplt marked this conversation as resolved.
Show resolved Hide resolved
/// any mutating [`ITM`] functions if a software lock mechanism is
/// implemented. See [`has_software_lock`].
///
/// See (coresight, B2.3.10).
#[inline]
pub fn unlock(&mut self) {
// NOTE(unsafe) atomic write to a stateless, write-only register
unsafe { self.lar.write(0xC5AC_CE55) }
}

/// Configures the ITM with the passed [ITMSettings].
/// Adds the software lock on the [`ITM`]. Should be called after any other mutating [`ITM`] functions.
tmplt marked this conversation as resolved.
Show resolved Hide resolved
///
/// See (coresight, B2.3.10).
#[inline]
pub fn lock(&mut self) {
// NOTE(unsafe) atomic write to a stateless, write-only register
unsafe { self.lar.write(0) }
}

/// Checks whether the target implements the software lock
/// mechanism. If `true`, [`unlock`] must be called before any other
/// mutating [`ITM`] functions.
///
/// See (coresight, B2.3.10).
#[inline]
pub fn has_software_lock(&self) -> bool {
self.lsr.read().sli()
}
tmplt marked this conversation as resolved.
Show resolved Hide resolved

/// Checks whether the peripheral is locked.
///
/// See (coresight, B2.3.10).
#[inline]
pub fn locked(&self) -> bool {
self.lsr.read().slk()
}

/// Indicates whether the [`ITM`] is currently processing events.
/// Returns `true` if [`ITM`] events are present and are being drained.
#[inline]
pub fn configure(&mut self, settings: ITMSettings) {
pub fn busy(&self) -> bool {
self.tcr.read().busy()
}

/// Configures the [`ITM`] with the passed [`ITMSettings`]. Returns `true`
/// if the configuration was successfully applied.
tmplt marked this conversation as resolved.
Show resolved Hide resolved
#[allow(clippy::missing_inline_in_public_items)]
pub fn configure(&mut self, settings: ITMSettings) -> Result<(), ITMConfigurationError> {
use ITMConfigurationError as Error;

// The ITM must be unlocked before we apply any changes.
if self.has_software_lock() && self.locked() {
self.unlock();
while self.locked() {}
}

// The ITM must then be disabled before altering certain fields
// in order to avoid trace stream corruption.
//
// NOTE: this is only required before modifying the TraceBusID
// field, but better be on the safe side for now.
unsafe {
self.tcr.modify(|mut r| {
r.set_itmena(false);
r
});
while self.busy() {}
}

unsafe {
self.tcr.modify(|mut r| {
r.set_itmena(settings.enable);
r.set_tsena(settings.local_timestamps != LocalTimestampOptions::Disabled);
r.set_txena(settings.forward_dwt);
r.set_tsprescale(match settings.local_timestamps {
LocalTimestampOptions::Disabled | LocalTimestampOptions::Enabled => 0b00,
LocalTimestampOptions::EnabledDiv4 => 0b10,
LocalTimestampOptions::EnabledDiv16 => 0b10,
LocalTimestampOptions::EnabledDiv64 => 0b11,
});
r.set_gtsfreq(match settings.global_timestamps {
GlobalTimestampOptions::Disabled => 0b00,
GlobalTimestampOptions::Every128Cycles => 0b01,
GlobalTimestampOptions::Every8192Cycles => 0b10,
GlobalTimestampOptions::EveryPacket => 0b11,
});

r
});
}
// GTSFREQ is potentially RAZ/WI
if settings.global_timestamps != GlobalTimestampOptions::Disabled
&& self.tcr.read().gtsfreq() == 0
{
return Err(Error::GTS);
tmplt marked this conversation as resolved.
Show resolved Hide resolved
}

unsafe {
self.tcr.modify(|mut r| {
r.set_swoena(match settings.timestamp_clk_src {
TimestampClkSrc::SystemClock => false,
TimestampClkSrc::AsyncTPIU => true,
});

r
});
}
// SWOENA is potentially either RAZ or RAO
if !{
match settings.timestamp_clk_src {
TimestampClkSrc::SystemClock => !self.tcr.read().swoena(),
TimestampClkSrc::AsyncTPIU => self.tcr.read().swoena(),
}
} {
return Err(Error::TimestampClkSrc);
}

unsafe {
self.tcr.modify(|mut r| {
r.set_tsprescale(match settings.local_timestamps {
LocalTimestampOptions::Disabled | LocalTimestampOptions::Enabled => 0b00,
LocalTimestampOptions::EnabledDiv4 => 0b10,
LocalTimestampOptions::EnabledDiv16 => 0b10,
LocalTimestampOptions::EnabledDiv64 => 0b11,
});

r
})
}
// TSPrescale is potentially RAZ/WI
if settings.local_timestamps != LocalTimestampOptions::Disabled
&& settings.local_timestamps != LocalTimestampOptions::Enabled
&& self.tcr.read().tsprescale() == 0
{
return Err(Error::TSPrescale);
}

unsafe {
self.tcr.modify(|mut r| {
r.set_tsena(settings.local_timestamps != LocalTimestampOptions::Disabled);
r.set_txena(settings.forward_dwt); // forward hardware event packets from the DWT to the ITM
r.set_tracebusid(settings.bus_id.unwrap_or(0));

// must be modified after TraceBusID, see last section in
// <https://developer.arm.com/documentation/ddi0403/d/Debug-Architecture/ARMv7-M-Debug/The-Instrumentation-Trace-Macrocell/Trace-Control-Register--ITM-TCR?lang=en>
r.set_itmena(settings.enable);

r
});
}

if self.has_software_lock() {
self.lock();
}

Ok(())
}
}