Skip to content

Commit c2d9756

Browse files
committed
tpiu: bitfield ACPR, verify set_swo_baud_rate args and ops
Closes #388.
1 parent 92552c7 commit c2d9756

File tree

1 file changed

+51
-4
lines changed

1 file changed

+51
-4
lines changed

src/peripheral/tpiu.rs

+51-4
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ pub struct RegisterBlock {
1616
pub cspsr: RW<u32>,
1717
reserved0: [u32; 2],
1818
/// Asynchronous Clock Prescaler
19-
pub acpr: RW<u32>,
19+
pub acpr: RW<Acpr>,
2020
reserved1: [u32; 55],
2121
/// Selected Pin Control
2222
pub sppr: RW<Sppr>,
@@ -41,6 +41,14 @@ bitfield! {
4141
enfcont, set_enfcont: 1;
4242
}
4343

44+
bitfield! {
45+
/// TPIU ACPR Register.
46+
#[repr(C)]
47+
#[derive(Clone, Copy)]
48+
pub struct Acpr(u32);
49+
u16, swoscaler, set_swoscaler: 15, 0;
50+
}
51+
4452
bitfield! {
4553
/// TPIU Type Register.
4654
#[repr(C)]
@@ -101,15 +109,54 @@ pub struct SWOSupports {
101109
pub min_queue_size: u8,
102110
}
103111

112+
/// Possible errors on [`TPIU::set_swo_baud_rate`].
113+
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
114+
pub enum ACPRError {
115+
/// The reference clock frequency divided by the requested baud rate
116+
/// did not yield an integer.
117+
NonInteger,
118+
/// Required prescaler value is too large. Largest supported
119+
/// prescaler value is [`u16::MAX`].
120+
TooLarge,
121+
}
122+
104123
impl TPIU {
105124
/// Sets the prescaler value for a wanted baud rate of the Serial
106125
/// Wire Output (SWO) in relation to a given asynchronous refernce
107-
/// clock rate.
126+
/// clock rate. Returns `true` if a prescaler was correctly
127+
/// calculated and applied, `false` otherwise.
128+
///
129+
/// See C1.10.4 "Asynchronous Clock Prescaler Register, TPIU_ACPR".
108130
#[inline]
109-
pub fn set_swo_baud_rate(&mut self, ref_clk_rate: u32, baud_rate: u32) {
131+
pub fn set_swo_baud_rate(
132+
&mut self,
133+
ref_clk_rate: u32,
134+
baud_rate: u32,
135+
) -> Result<(), ACPRError> {
136+
use ACPRError as Error;
137+
138+
if ref_clk_rate % baud_rate != 0 {
139+
return Err(Error::NonInteger);
140+
}
141+
142+
use core::convert::TryInto;
143+
let prescaler: u16 = match { ((ref_clk_rate / baud_rate) - 1).try_into() } {
144+
Ok(ps) => ps,
145+
Err(_) => return Err(Error::TooLarge),
146+
};
147+
110148
unsafe {
111-
self.acpr.write((ref_clk_rate / baud_rate) - 1);
149+
self.acpr.modify(|mut r| {
150+
r.set_swoscaler(prescaler);
151+
r
152+
});
153+
}
154+
155+
if self.acpr.read().swoscaler() != prescaler {
156+
return Err(Error::TooLarge);
112157
}
158+
159+
Ok(())
113160
}
114161

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

0 commit comments

Comments
 (0)