rtt-target

repository·master·Indexed 41 days ago

https://github.com/probe-rs/rtt-target

A target-side implementation of the Real-Time Transfer (RTT) I/O protocol for Rust, enabling high-speed, non-blocking debug logging from microcontrollers via in-memory ring buffers and a debug probe. It provides integration with the log crate and defmt, as well as panic logging via the companion panic-rtt-target crate.

Tokens
5K
Snippets
23
Records
29
Agent score
41%

What's inside rtt-target

  1. How RTT I/O works in rtt-target

    master

    The rtt-target crate implements the RTT (Real-Time Transfer) I/O protocol. It uses in-memory ring buffers and polling to facilitate input and output via a debug probe. This approach allows for debug logging from a microcontroller with minimal delays and no blocking, making it suitable for real-time applications where semihosting delays are unacceptable.

    Note on Locking:

    • Using a platform-specific critical-section is required for standard printing.
    • Writing directly to a channel object using the write! macro or the binary write method does not require locking and therefore does not require a platform-specific critical section.
  2. Configure rtt-target with defmt

    master

    To use rtt-target as a backend for defmt, you must:

    1. Enable the defmt feature in your Cargo.toml.
    2. Initialize the system by either calling the rtt_init_defmt! macro OR manually setting up your channels and calling set_defmt_channel before any defmt calls are made.
    # In Cargo.toml
    features = ["defmt"]
  3. Set up panic-rtt-target for logging panics over RTT

    master

    Use panic-rtt-target to automatically log panic messages over an RTT channel.

    Requirements:

    • You must initialize RTT using one of the rtt_init macros (e.g., rtt_init_default!()), otherwise you will encounter a linker error at compile time.
    • The panic handler runs in a non-returning critical_section. You must provide a critical_section implementation for your target.

    Behavior:

    • Panics are logged to the print channel.
    • Upon panicking, the channel mode is automatically set to BlockIfFull to ensure the complete message is captured.
    • If a panic occurs before RTT is initialized or if no print channel exists, no logs will be produced.
    #![no_std]
    
    use panic_rtt_target as _;
    use rtt_target::rtt_init_default;
    
    fn main() -> ! {
        // Initialize RTT (required to avoid linker errors)
        rtt_init_default!();
    
        panic!("Something has gone terribly wrong");
    }
  4. Basic usage of rtt-target for printing

    master

    To use rtt-target for simple debug printing, you must provide a platform-specific critical-section implementation. Once configured, you can initialize the RTT print system using the rtt_init_print! macro and use rprintln! to print formatted messages to the RTT channel.

    use rtt_target::{rtt_init_print, rprintln};
    
    fn main() {
        rtt_init_print!();
        loop {
            rprintln!("Hello, world!");
        }
    }
  5. Configure rtt-target with log

    master

    To use rtt-target as a backend for the log crate, you must:

    1. Enable the log feature in your Cargo.toml.
    2. Initialize the system by either calling the rtt_init_log! macro OR manually setting up your channels and calling init_logger or init_logger_with_level before using log macros.
    # In Cargo.toml
    features = ["log"]
  6. Understand the RTT protocol implementation details

    master

    The rtt::RttHeader and rtt::RttChannel types implement the core RTT (Real Time Transfer) protocol.

    Note: This module is intended for use via the rtt_init! macro and is not meant to be used directly in user code. Most of its functionality is undocumented because it is an internal implementation detail of the protocol.

    Key components include:

    • RttHeader: The control block header that identifies the RTT setup and the number of available up/down channels.
    • RttChannel: Represents an individual RTT channel with a name, a buffer, and read/write pointers.
    • RttWriter: A helper for performing cancellable write operations to an up-channel.
  7. Enable defmt support for panic logging

    master

    By enabling the defmt feature in panic-rtt-target, panic messages will be printed to the defmt channel.

    If you have configured both a print channel (via rtt-target) and a defmt channel, the panic message will be sent to both channels.

    Note: Enabling this feature does not automatically enable the defmt feature in the rtt-target crate itself, allowing you to choose a different defmt backend if desired.

  8. How RTT channels and virtual terminals work

    master

    RTT uses channels for communication between the target and host:

    • Up channels (target to host): Support binary data or strings. Channel 0 is the default for terminals. Up channels can support up to 16 virtual terminals using escape sequences, allowing you to separate different message streams (e.g., log levels) within a single buffer without extra memory allocation.
    • Down channels (host to target): Conventionally, channel 0 is used for keyboard input.

    Concurrency Note: While different channel objects can be used concurrently in different contexts without locking, multiple threads cannot write to the same channel simultaneously (even if using different virtual terminals) without external synchronization.

    Channel Modes:

    • NoBlockSkip: Discards data if the buffer is full. Prevents application crashes if no debugger is attached.
    • NoBlockTrim: Writes as much as possible and discards the rest.
    • BlockIfFull: Spins/blocks if the buffer is full. Warning: If used within a critical section (like rprintln!), this will freeze the application if the host is not reading the buffer.
  9. Integrate defmt with RTT

    master

    To use the defmt crate for efficient message formatting over RTT, you must enable the defmt feature in your Cargo.toml and initialize the channel using set_defmt_channel or the rtt_init_defmt macro.

    Dependency Setup:

    [dependencies]
    defmt = { version = "0.3" }
    rtt-target = { version = "0.6", features = ["defmt"] }
  10. Initialize RTT logging with rtt_init_log!

    master

    The rtt_init_log! macro is the recommended way to set up RTT-based logging. It performs two main tasks: it initializes the RTT printing channel (using rtt_init_print!) and sets up the log crate backend with the specified level.

    This macro is available when the log feature is enabled.

    Macro Variants

    SyntaxDescription
    rtt_init_log!()Initializes with log::LevelFilter::Trace, ChannelMode::NoBlockSkip, and a buffer size of 1024 bytes.
    rtt_init_log!(level)Initializes with the specified level, ChannelMode::NoBlockSkip, and 1024 bytes.
    rtt_init_log!(level, mode)Initializes with the specified level, mode, and 1024 bytes.
    rtt_init_log!(level, mode, size)Initializes with the specified level, mode, and size in bytes.
    // Default initialization (Trace, NoBlockSkip, 1024 bytes)
    rtt_init_log!();
    
    // Custom initialization
    rtt_init_log!(log::LevelFilter::Info, ChannelMode::Block, 2048);
  11. Integrate the log crate with RTT

    master

    To forward log crate messages to RTT, enable the log feature and initialize the logger with rtt_init_log!. You can pass a log::LevelFilter as an argument to set the minimum log level.

    use rtt_target::rtt_init_log;
    
    fn main() -> ! {
       rtt_init_log!(); // Pass a log::LevelFilter to set min log level
       loop {
           log::info!("Hello, world!");
       }
    }