//! # RISC-V Trace Encoder (TRACE) //! //! ## Overview //! The high-performance CPU supports instruction trace interface through the //! trace encoder. The trace encoder connects to HP CPU’s instruction trace //! interface, compresses the information into smaller packets, and then stores //! the packets in internal SRAM. //! //! In complex systems, understanding program execution flow is not //! straightforward. This may be due to a number of factors, for example, //! interactions with other cores, peripherals, real-time events, poor //! implementations, or some combination of all of the above. //! //! It is hard to use a debugger to monitor the program execution flow of a //! running system in real time, as this is intrusive and might affect the //! running state. But providing visibility of program execution is important. //! //! That is where instruction trace comes in, which provides trace of the //! program execution. //! //! ## Examples //! ```rust, no_run #![doc = crate::before_snippet!()] //! # use esp_hal::trace::Trace; //! let mut trace = Trace::new(peripherals.TRACE0); //! let mut buffer = [0_u8; 1024]; //! trace.start_trace(&mut buffer); //! // traced code //! //! // end traced code //! let res = trace.stop_trace().unwrap(); //! // transfer the trace result to the host and decode it there //! # } //! ``` use crate::{ peripheral::{Peripheral, PeripheralRef}, peripherals::trace::RegisterBlock, system::PeripheralClockControl, }; /// Errors returned from [Trace::stop_trace] #[derive(Debug, Clone, Copy)] pub enum Error { /// Attempted to stop a trace which had not been started yet NotStarted, } /// Returned by [Trace::stop_trace] #[derive(Debug, Clone, Copy)] pub struct TraceResult { /// Start index of the valid data pub valid_start_index: usize, /// Length of the valid data pub valid_length: usize, } /// TRACE Encoder Instance pub struct Trace<'d, T> { peripheral: PeripheralRef<'d, T>, buffer: Option<&'d mut [u8]>, } impl<'d, T> Trace<'d, T> where T: Instance, { /// Construct a new instance pub fn new(peripheral: impl Peripheral
+ 'd) -> Self {
crate::into_ref!(peripheral);
PeripheralClockControl::reset(crate::system::Peripheral::Trace0);
PeripheralClockControl::enable(crate::system::Peripheral::Trace0);
Self {
peripheral,
buffer: None,
}
}
/// Start tracing, writing data into the `buffer`
pub fn start_trace(&mut self, buffer: &'d mut [u8]) {
let reg_block = self.peripheral.register_block();
reg_block
.mem_start_addr()
.modify(|_, w| unsafe { w.mem_start_addr().bits(buffer.as_ptr() as *const _ as u32) });
reg_block.mem_end_addr().modify(|_, w| unsafe {
w.mem_end_addr()
.bits((buffer.as_ptr() as *const _ as u32) + (buffer.len() as u32))
});
reg_block
.mem_addr_update()
.write(|w| w.mem_current_addr_update().set_bit());
// won't set bit in int-raw without enabling
reg_block
.intr_ena()
.modify(|_, w| w.mem_full_intr_ena().set_bit());
// for now always use looping mode
reg_block
.trigger()
.write(|w| w.mem_loop().set_bit().restart_ena().set_bit());
reg_block.intr_clr().write(|w| {
w.fifo_overflow_intr_clr()
.set_bit()
.mem_full_intr_clr()
.set_bit()
});
self.buffer.replace(buffer);
reg_block.trigger().write(|w| w.on().set_bit());
}
/// Stop tracing
///
/// Be aware that valid data might not start at index 0 and you need to
/// account for wrapping when reading the data.
pub fn stop_trace(&mut self) -> Result