Skip to content

Commit

Permalink
tpiu: bitfield ACPR, verify set_swo_baud_rate args and ops
Browse files Browse the repository at this point in the history
  • Loading branch information
tmplt committed Jan 10, 2022
1 parent 92552c7 commit c2d9756
Showing 1 changed file with 51 additions and 4 deletions.
55 changes: 51 additions & 4 deletions src/peripheral/tpiu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ pub struct RegisterBlock {
pub cspsr: RW<u32>,
reserved0: [u32; 2],
/// Asynchronous Clock Prescaler
pub acpr: RW<u32>,
pub acpr: RW<Acpr>,
reserved1: [u32; 55],
/// Selected Pin Control
pub sppr: RW<Sppr>,
Expand All @@ -41,6 +41,14 @@ bitfield! {
enfcont, set_enfcont: 1;
}

bitfield! {
/// TPIU ACPR Register.
#[repr(C)]
#[derive(Clone, Copy)]
pub struct Acpr(u32);
u16, swoscaler, set_swoscaler: 15, 0;
}

bitfield! {
/// TPIU Type Register.
#[repr(C)]
Expand Down Expand Up @@ -101,15 +109,54 @@ pub struct SWOSupports {
pub min_queue_size: u8,
}

/// Possible errors on [`TPIU::set_swo_baud_rate`].
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
pub enum ACPRError {
/// The reference clock frequency divided by the requested baud rate
/// did not yield an integer.
NonInteger,
/// Required prescaler value is too large. Largest supported
/// prescaler value is [`u16::MAX`].
TooLarge,
}

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.
/// clock rate. Returns `true` if a prescaler was correctly
/// calculated and applied, `false` otherwise.
///
/// See C1.10.4 "Asynchronous Clock Prescaler Register, TPIU_ACPR".
#[inline]
pub fn set_swo_baud_rate(&mut self, ref_clk_rate: u32, baud_rate: u32) {
pub fn set_swo_baud_rate(
&mut self,
ref_clk_rate: u32,
baud_rate: u32,
) -> Result<(), ACPRError> {
use ACPRError as Error;

if ref_clk_rate % baud_rate != 0 {
return Err(Error::NonInteger);
}

use core::convert::TryInto;
let prescaler: u16 = match { ((ref_clk_rate / baud_rate) - 1).try_into() } {
Ok(ps) => ps,
Err(_) => return Err(Error::TooLarge),
};

unsafe {
self.acpr.write((ref_clk_rate / baud_rate) - 1);
self.acpr.modify(|mut r| {
r.set_swoscaler(prescaler);
r
});
}

if self.acpr.read().swoscaler() != prescaler {
return Err(Error::TooLarge);
}

Ok(())
}

/// The used protocol for the trace output. Return `None` if an
Expand Down

0 comments on commit c2d9756

Please sign in to comment.