diff options
Diffstat (limited to 'src/peripheral/tpiu.rs')
-rw-r--r-- | src/peripheral/tpiu.rs | 135 |
1 files changed, 132 insertions, 3 deletions
diff --git a/src/peripheral/tpiu.rs b/src/peripheral/tpiu.rs index 11cb79e..3ff5f55 100644 --- a/src/peripheral/tpiu.rs +++ b/src/peripheral/tpiu.rs @@ -4,6 +4,9 @@ use volatile_register::{RO, RW, WO}; +use crate::peripheral::TPIU; +use bitfield::bitfield; + /// Register block #[repr(C)] pub struct RegisterBlock { @@ -16,10 +19,10 @@ pub struct RegisterBlock { pub acpr: RW<u32>, reserved1: [u32; 55], /// Selected Pin Control - pub sppr: RW<u32>, + pub sppr: RW<Sppr>, reserved2: [u32; 132], /// Formatter and Flush Control - pub ffcr: RW<u32>, + pub ffcr: RW<Ffcr>, reserved3: [u32; 810], /// Lock Access pub lar: WO<u32>, @@ -27,5 +30,131 @@ pub struct RegisterBlock { pub lsr: RO<u32>, reserved4: [u32; 4], /// TPIU Type - pub _type: RO<u32>, + pub _type: RO<Type>, +} + +bitfield! { + /// Formatter and flush control register. + #[repr(C)] + #[derive(Clone, Copy)] + pub struct Ffcr(u32); + enfcont, set_enfcont: 1; +} + +bitfield! { + /// TPIU Type Register. + #[repr(C)] + #[derive(Clone, Copy)] + pub struct Type(u32); + u8, fifosz, _: 8, 6; + ptinvalid, _: 9; + mancvalid, _: 10; + nrzvalid, _: 11; +} + +bitfield! { + /// Selected pin protocol register. + #[repr(C)] + #[derive(Clone, Copy)] + pub struct Sppr(u32); + u8, txmode, set_txmode: 1, 0; +} + +/// The available protocols for the trace output. +#[repr(u8)] +#[derive(Debug, Eq, PartialEq, Copy, Clone)] +pub enum TraceProtocol { + /// Parallel trace port mode + Parallel = 0b00, + /// Asynchronous SWO, using Manchester encoding + AsyncSWOManchester = 0b01, + /// Asynchronous SWO, using NRZ encoding + AsyncSWONRZ = 0b10, +} +impl core::convert::TryFrom<u8> for TraceProtocol { + type Error = (); + + /// Tries to convert from a `TXMODE` field value. Fails if the set mode is + /// unknown (and thus unpredictable). + #[inline] + fn try_from(value: u8) -> Result<Self, Self::Error> { + match value { + x if x == Self::Parallel as u8 => Ok(Self::Parallel), + x if x == Self::AsyncSWOManchester as u8 => Ok(Self::AsyncSWOManchester), + x if x == Self::AsyncSWONRZ as u8 => Ok(Self::AsyncSWONRZ), + _ => Err(()), // unknown and unpredictable mode + } + } +} + +/// The SWO options supported by the TPIU. +#[derive(Debug, Eq, PartialEq, Copy, Clone)] +pub struct SWOSupports { + /// Whether UART/NRZ encoding is supported for SWO. + nrz_encoding: bool, + /// Whether Manchester encoding is supported for SWO. + manchester_encoding: bool, + /// Whether parallel trace port operation is supported. + parallel_operation: bool, + /// The minimum implemented FIFO queue size of the TPIU for trace data. + min_queue_size: u8, +} + +impl TPIU { + /// Sets the prescaler value for a wanted baud rate of the Serial + /// Wire Output (SWO) in relation to a given asynchronous refernce + /// clock rate. + #[inline] + pub fn set_swo_baud_rate(&mut self, ref_clk_rate: u32, baud_rate: u32) { + unsafe { + self.acpr.write((ref_clk_rate / baud_rate) - 1); + } + } + + /// The used protocol for the trace output. Return `None` if an + /// unknown (and thus unpredicable mode) is configured by means + /// other than + /// [`trace_output_protocol`](Self::set_trace_output_protocol). + #[inline] + pub fn trace_output_protocol(&self) -> Option<TraceProtocol> { + use core::convert::TryInto; + self.sppr.read().txmode().try_into().ok() + } + + /// Sets the used protocol for the trace output. + #[inline] + pub fn set_trace_output_protocol(&mut self, proto: TraceProtocol) { + unsafe { + self.sppr.modify(|mut r| { + r.set_txmode(proto as u8); + r + }); + } + } + + /// Whether to enable the formatter. If disabled, only ITM and DWT + /// trace sources are passed through. Data from the ETM is + /// discarded. + #[inline] + pub fn enable_continuous_formatting(&mut self, bit: bool) { + unsafe { + self.ffcr.modify(|mut r| { + r.set_enfcont(bit); + r + }); + } + } + + /// Reads the supported trace output modes and the minimum size of + /// the TPIU FIFO queue for trace data. + #[inline] + pub fn swo_supports() -> SWOSupports { + let _type = unsafe { (*Self::ptr())._type.read() }; + SWOSupports { + nrz_encoding: _type.nrzvalid(), + manchester_encoding: _type.mancvalid(), + parallel_operation: !_type.ptinvalid(), + min_queue_size: _type.fifosz(), + } + } } |