This repository has been archived on 2026-08-31. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
donglora/vendor/esp-hal/src/trace.rs
T
swaitsandClaude Opus 4.6 3102fc747a feat: add display UI with splash screen, dashboard, and RSSI sparkline
Implement full SSD1306 OLED display support:
- Splash screen on boot (1.5s) with project name, version, board
- Dashboard showing radio state, config, counters, RSSI/SNR
- RSSI history sparkline (64-sample ring buffer, 2px-wide bars)
- DisplayOn/DisplayOff host commands routed via dedicated channel
- Pure render functions against generic DrawTarget (no hardware coupling)
- Display on/off control bypasses radio task entirely

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 20:42:54 -06:00

217 lines
6.2 KiB
Rust
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! # 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<P = T> + '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<TraceResult, Error> {
let reg_block = self.peripheral.register_block();
reg_block
.trigger()
.write(|w| w.off().set_bit().restart_ena().clear_bit());
if self.buffer.is_none() {
return Err(Error::NotStarted);
}
let buffer = self.buffer.take().unwrap();
while !reg_block.fifo_status().read().fifo_empty().bit_is_set() {}
let overflow = reg_block.intr_raw().read().mem_full_intr_raw().bit();
let idx = if overflow {
reg_block
.mem_current_addr()
.read()
.mem_current_addr()
.bits()
- &buffer as *const _ as u32
} else {
0
};
let len = if overflow {
buffer.len()
} else {
reg_block
.mem_current_addr()
.read()
.mem_current_addr()
.bits() as usize
- buffer.as_ptr() as *const _ as usize
- 14 // there will be 14 zero bytes at the start
};
let mut valid = false;
let mut fourteen_zeroes = false;
let mut zeroes = 0;
let start_index = if !valid {
let mut i = 0;
loop {
let b = unsafe {
buffer
.as_ptr()
.add((i + idx as usize) % buffer.len())
.read_volatile()
};
if !valid {
if b == 0 {
zeroes += 1;
} else {
zeroes = 0;
}
if zeroes >= 14 {
fourteen_zeroes = true;
}
if fourteen_zeroes && b != 0 {
valid = true;
}
}
if valid {
break i;
}
i += 1;
}
} else {
0
};
Ok(TraceResult {
valid_start_index: start_index,
valid_length: len,
})
}
}
/// Trace peripheral instance
pub trait Instance: crate::private::Sealed {
/// Get a reference to the peripheral's underlying register block
fn register_block(&self) -> &RegisterBlock;
}
impl Instance for crate::peripherals::TRACE0 {
fn register_block(&self) -> &RegisterBlock {
self
}
}