probe_rs/architecture/arm/swo/mod.rs
1//! SWO tracing related functions.
2
3use std::time::Duration;
4
5use crate::architecture::arm::communication_interface::ArmDebugInterface;
6
7use super::ArmError;
8
9/// The protocol the SWO pin should use for data transmission.
10#[derive(Debug, Copy, Clone)]
11pub enum SwoMode {
12 /// UART
13 Uart,
14 /// Manchester
15 Manchester,
16}
17
18/// The config for the SWO pin.
19#[derive(Debug, Copy, Clone)]
20pub struct SwoConfig {
21 /// SWO mode: either UART or Manchester.
22 mode: SwoMode,
23
24 /// Baud rate of SWO, in Hz.
25 ///
26 /// This value is used to configure what baud rate the target
27 /// generates and to configure what baud rate the probe receives,
28 /// so must be a baud rate supported by both target and probe.
29 baud: u32,
30
31 /// Clock input to TPIU in Hz. This is often the system clock (HCLK/SYSCLK etc).
32 tpiu_clk: u32,
33
34 /// Whether to enable TPIU formatting.
35 /// This is required to use ETM over SWO, but otherwise
36 /// adds overhead if only DWT/ITM data is used.
37 tpiu_continuous_formatting: bool,
38}
39
40impl SwoConfig {
41 /// Create a new SwoConfig using the specified TPIU clock in Hz.
42 ///
43 /// By default the UART mode is used at 1MBd and
44 /// TPIU continuous formatting is disabled (DWT/ITM only).
45 pub fn new(tpiu_clk: u32) -> Self {
46 SwoConfig {
47 mode: SwoMode::Uart,
48 baud: 1_000_000,
49 tpiu_clk,
50 tpiu_continuous_formatting: false,
51 }
52 }
53
54 /// Set the baud rate in Hz.
55 pub fn set_baud(mut self, baud: u32) -> Self {
56 self.baud = baud;
57 self
58 }
59
60 /// Set the mode in this SwoConfig.
61 pub fn set_mode(mut self, mode: SwoMode) -> Self {
62 self.mode = mode;
63 self
64 }
65
66 /// Set the mode to UART
67 pub fn set_mode_uart(mut self) -> Self {
68 self.mode = SwoMode::Uart;
69 self
70 }
71
72 /// Set the mode to Manchester
73 pub fn set_mode_manchester(mut self) -> Self {
74 self.mode = SwoMode::Manchester;
75 self
76 }
77
78 /// Set the TPIU continuous formatting setting.
79 pub fn set_continuous_formatting(mut self, enabled: bool) -> Self {
80 self.tpiu_continuous_formatting = enabled;
81 self
82 }
83
84 /// The SWO mode.
85 pub fn mode(&self) -> SwoMode {
86 self.mode
87 }
88
89 /// Baud rate of SWO, in Hz.
90 ///
91 /// This value is used to configure what baud rate the target generates
92 /// and to configure what baud rate the probe receives,
93 /// so must be a baud rate supported by both target and probe.
94 pub fn baud(&self) -> u32 {
95 self.baud
96 }
97
98 /// Clock input to TPIU in Hz. This is often the system clock (HCLK/SYSCLK etc).
99 pub fn tpiu_clk(&self) -> u32 {
100 self.tpiu_clk
101 }
102
103 /// Whether to enable TPIU formatting. This is required to use ETM over
104 /// SWO, but otherwise adds overhead if only DWT/ITM data is used.
105 pub fn tpiu_continuous_formatting(&self) -> bool {
106 self.tpiu_continuous_formatting
107 }
108}
109
110/// An interface to operate SWO to be implemented on drivers that support SWO.
111pub trait SwoAccess {
112 /// Configure a SwoAccess interface for reading SWO data.
113 fn enable_swo(&mut self, config: &SwoConfig) -> Result<(), ArmError>;
114
115 /// Disable SWO reading on this SwoAccess interface.
116 fn disable_swo(&mut self) -> Result<(), ArmError>;
117
118 /// Read any available SWO data without waiting.
119 ///
120 /// Returns a `Vec<u8>` of received SWO bytes since the last `read_swo()` call.
121 /// If no data was available, returns an empty Vec.
122 fn read_swo(&mut self) -> Result<Vec<u8>, ArmError> {
123 self.read_swo_timeout(Duration::from_millis(10))
124 }
125
126 /// Read SWO data for up to `timeout` duration.
127 ///
128 /// If no data is received before the timeout, returns an empty Vec.
129 /// May return earlier than `timeout` if the receive buffer fills up.
130 fn read_swo_timeout(&mut self, timeout: Duration) -> Result<Vec<u8>, ArmError>;
131
132 /// Request an estimated best time to wait between polls of `read_swo`.
133 ///
134 /// A probe can implement this if it can work out a sensible time to
135 /// wait between polls, for example using the probe's internal buffer
136 /// size and SWO baud rate, or a 0s duration if reads can block for
137 /// new data.
138 ///
139 /// The default implementation computes an estimated interval based on the buffer
140 /// size, mode, and baud rate.
141 fn swo_poll_interval_hint(&mut self, config: &SwoConfig) -> Option<Duration> {
142 match self.swo_buffer_size() {
143 Some(size) => poll_interval_from_buf_size(config, size),
144 None => None,
145 }
146 }
147
148 /// Request the probe SWO buffer size, if known.
149 fn swo_buffer_size(&mut self) -> Option<usize> {
150 None
151 }
152}
153
154/// Helper function to compute a poll interval from a SwoConfig and SWO buffer size.
155pub(crate) fn poll_interval_from_buf_size(config: &SwoConfig, buf_size: usize) -> Option<Duration> {
156 let time_to_full_ms = match config.mode() {
157 // In UART, the output data is at the baud rate with 10 clocks per byte.
158 SwoMode::Uart => (1000 * buf_size as u32) / (config.baud() / 10),
159
160 // In Manchester, the output data is at half the baud rate with
161 // between 8.25 and 10 clocks per byte, so use a conservative 8 clocks/byte.
162 SwoMode::Manchester => (500 * buf_size as u32) / (config.baud() / 8),
163 };
164
165 // Poll frequently enough to catch the buffer at 1/4 full
166 Some(Duration::from_millis(time_to_full_ms as u64 / 4))
167}
168
169/// A reader interface to pull SWO data from the underlying driver.
170pub struct SwoReader<'a> {
171 interface: &'a mut dyn ArmDebugInterface,
172 buf: Vec<u8>,
173}
174
175impl<'a> SwoReader<'a> {
176 pub(crate) fn new(interface: &'a mut dyn ArmDebugInterface) -> Self {
177 Self {
178 interface,
179 buf: Vec::new(),
180 }
181 }
182}
183
184impl std::io::Read for SwoReader<'_> {
185 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
186 use std::{cmp, io::Error, mem};
187
188 // Always buffer: this pulls data as quickly as possible from
189 // the target to clear it's embedded trace buffer, minimizing
190 // the chance of an overflow event during which packets are
191 // lost.
192 self.buf
193 .append(&mut self.interface.read_swo().map_err(Error::other)?);
194
195 let swo = {
196 let next_buf = self.buf.split_off(cmp::min(self.buf.len(), buf.len()));
197 mem::replace(&mut self.buf, next_buf)
198 };
199
200 buf[..swo.len()].copy_from_slice(&swo);
201 Ok(swo.len())
202 }
203}