1#![doc = crate::before_snippet!()]
24use crate::{
38 pac::trace::RegisterBlock,
39 peripheral::{Peripheral, PeripheralRef},
40 system::PeripheralGuard,
41};
42
43#[derive(Debug, Clone, Copy)]
45pub enum Error {
46 NotStarted,
48}
49
50#[derive(Debug, Clone, Copy)]
52pub struct TraceResult {
53 pub valid_start_index: usize,
55 pub valid_length: usize,
57}
58
59pub struct Trace<'d, T>
61where
62 T: Instance,
63{
64 peripheral: PeripheralRef<'d, T>,
65 buffer: Option<&'d mut [u8]>,
66 _guard: PeripheralGuard,
67}
68
69impl<'d, T> Trace<'d, T>
70where
71 T: Instance,
72{
73 pub fn new(peripheral: impl Peripheral<P = T> + 'd) -> Self {
75 crate::into_ref!(peripheral);
76 let guard = PeripheralGuard::new(peripheral.peripheral());
77
78 Self {
79 peripheral,
80 buffer: None,
81 _guard: guard,
82 }
83 }
84
85 pub fn start_trace(&mut self, buffer: &'d mut [u8]) {
87 let reg_block = self.peripheral.register_block();
88
89 reg_block
90 .mem_start_addr()
91 .modify(|_, w| unsafe { w.mem_start_addr().bits(buffer.as_ptr() as *const _ as u32) });
92 reg_block.mem_end_addr().modify(|_, w| unsafe {
93 w.mem_end_addr()
94 .bits((buffer.as_ptr() as *const _ as u32) + (buffer.len() as u32))
95 });
96 reg_block
97 .mem_addr_update()
98 .write(|w| w.mem_current_addr_update().set_bit());
99
100 reg_block
102 .intr_ena()
103 .modify(|_, w| w.mem_full_intr_ena().set_bit());
104
105 reg_block
107 .trigger()
108 .write(|w| w.mem_loop().set_bit().restart_ena().set_bit());
109
110 reg_block.intr_clr().write(|w| {
111 w.fifo_overflow_intr_clr()
112 .set_bit()
113 .mem_full_intr_clr()
114 .set_bit()
115 });
116
117 self.buffer.replace(buffer);
118 reg_block.trigger().write(|w| w.on().set_bit());
119 }
120
121 pub fn stop_trace(&mut self) -> Result<TraceResult, Error> {
126 let reg_block = self.peripheral.register_block();
127
128 reg_block
129 .trigger()
130 .write(|w| w.off().set_bit().restart_ena().clear_bit());
131
132 if self.buffer.is_none() {
133 return Err(Error::NotStarted);
134 }
135
136 let buffer = self.buffer.take().unwrap();
137
138 while !reg_block.fifo_status().read().fifo_empty().bit_is_set() {}
139
140 let overflow = reg_block.intr_raw().read().mem_full_intr_raw().bit();
141 let idx = if overflow {
142 reg_block
143 .mem_current_addr()
144 .read()
145 .mem_current_addr()
146 .bits()
147 - &buffer as *const _ as u32
148 } else {
149 0
150 };
151
152 let len = if overflow {
153 buffer.len()
154 } else {
155 reg_block
156 .mem_current_addr()
157 .read()
158 .mem_current_addr()
159 .bits() as usize
160 - buffer.as_ptr() as *const _ as usize
161 - 14 };
163
164 let mut valid = false;
165 let mut fourteen_zeroes = false;
166 let mut zeroes = 0;
167 let start_index = if !valid {
168 let mut i = 0;
169 loop {
170 let b = unsafe {
171 buffer
172 .as_ptr()
173 .add((i + idx as usize) % buffer.len())
174 .read_volatile()
175 };
176
177 if !valid {
178 if b == 0 {
179 zeroes += 1;
180 } else {
181 zeroes = 0;
182 }
183
184 if zeroes >= 14 {
185 fourteen_zeroes = true;
186 }
187
188 if fourteen_zeroes && b != 0 {
189 valid = true;
190 }
191 }
192
193 if valid {
194 break i;
195 }
196
197 i += 1;
198 }
199 } else {
200 0
201 };
202
203 Ok(TraceResult {
204 valid_start_index: start_index,
205 valid_length: len,
206 })
207 }
208}
209
210#[doc(hidden)]
212pub trait Instance: crate::private::Sealed {
213 fn register_block(&self) -> &RegisterBlock;
215
216 fn peripheral(&self) -> crate::system::Peripheral;
218}
219
220impl Instance for crate::peripherals::TRACE0 {
221 fn register_block(&self) -> &RegisterBlock {
222 self.register_block()
223 }
224
225 fn peripheral(&self) -> crate::system::Peripheral {
226 crate::system::Peripheral::Trace0
227 }
228}