Crate rtt_target[][src]

Target side implementation of the RTT (Real-Time Transfer) I/O protocol

RTT implements input and output to/from a debug probe using in-memory ring buffers and memory polling. This enables debug logging from the microcontroller with minimal delays and no blocking, making it usable even in real-time applications where e.g. semihosting delays cannot be tolerated.

Hardware support

This crate is platform agnostic and can be used on any chip that supports background memory access via its debug interface. The printing macros require a critical section which is platform-dependent. Built-in ARM Cortex-M support can be enabled with the “cortex-m” feature, and RISC-V support can be enabled with the “riscv” feature.

To interface with RTT from the host computer, a debug probe such as an ST-Link or J-Link is required. The normal debug protocol (e.g. SWD) is used to access RTT, so no extra connections such as SWO pins are needed.

Initialization

RTT must be initialized at the start of your program using one of the init macros. See the macros for more details.

The initialization macros return channel objects that can be used for writing and reading. Different channel objects can safely be used concurrently in different contexts without locking. In an interrupt-based application with realtime constraints you could use a separate channel for every interrupt context to allow for lock-free logging.

Channels and virtual terminals

RTT supports multiple channels in both directions. Up channels go from target to host, and down channels go from host to target. Each channel is identified by its direction and number.

By convention channel 0 is reserved for terminal use. In the up direction there is a set of escape sequences that further enable the single channel to be treated as up to 16 virtual terminals. This can be used to separate different types of messages (for example, log levels) from each other without having to allocate memory for multiple buffers. As a downside, multiple threads cannot write to the same channel at once, even if using different virtual terminal numbers, so access has to be synchronized. Down channel 0 is conventionally used for keyboard input.

Note: Some host side programs only display channel 0 by default, so to see the other channels you might need to configure them appropriately.

The other channels can be used to either enable concurrent use from multiple sources without locking, or to send e.g. binary data in either direction.

Channel 0 can also be used for arbitrary data, but most tools expect it to be plain text.

Channel modes

By default, channels start in NoBlockSkip mode, which discards data if the buffer is full. This enables RTT to not crash the application if there is no debug probe attached or if the host is not reading the buffers. However if the application outputs faster than the host can read (which is easy to do, because writing is very fast), messages will be lost. Channels can be set to blocking mode if this is desirable, however in that case the application will likely freeze when the buffer fills up if a debugger is not attached.

The channel mode can also be changed on the fly by the debug probe. Therefore it may be advantageous to use a non-blocking mode in your microcontroller code, and set a blocking mode as needed when debugging. That way you will never end up with an application that freezes without a debugger connected.

Printing

For no-hassle output the rprint and rprintln macros are provided. They use a single down channel defined at initialization time, and a critical section for synchronization, and they therefore work exactly like the standard println style macros. They can be used from any context. The rtt_init_print convenience macro initializes printing on channel 0.

use rtt_target::{rtt_init_print, rprintln};

fn main() -> ! {
    rtt_init_print!();
    loop {
        rprintln!("Hello, world!");
    }
}

The macros also support an extended syntax to print to different RTT virtual terminals.

Please note that because a critical section is used, printing into a blocking channel will cause the application to block and freeze when the buffer is full.

Macros

rprint

Prints to the print RTT channel. Works just like the standard print.

rprintln

Prints to the print RTT channel, with a newline. Works just like the standard println.

rtt_init

Initializes RTT with the specified channels. Channel numbers, buffer sizes and names can be defined.

rtt_init_default

Initializes RTT with default up/down channels.

rtt_init_print

Initializes RTT with a single up channel and sets it as the print channel for the printing macros.

Structs

DownChannel

RTT down (host to target) channel

TerminalChannel

An up channel that supports writing into multiple virtual terminals within the same buffer.

TerminalWriter

Formatted writing operation. Don’t store an instance of this, but rather create a new one for every write.

UpChannel

RTT up (target to host) channel

uWriter

Writer for ufmt. Don’t store an instance of this, but rather create a new one for every write.

Enums

ChannelMode

Specifies what to do when a channel doesn’t have enough buffer space for a complete write.

Functions

set_print_channel

Sets the channel to use for rprint and rprintln.

set_print_channel_cs

Sets the channel to use for rprint and rprintln and the critical section function used to synchronize printing. You should only use this function if the set_print_channel function isn’t available on your platform.

Type Definitions

CriticalSectionFunc

Type-erased critical section function used to synchronize printing.