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

tpiu: bitfield ACPR, verify set_swo_baud_rate args and ops #389

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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