-
Notifications
You must be signed in to change notification settings - Fork 243
SEGGER RTT support
Now that OpenOCD also supports SEGGER RTT (Real-Time Trace), Cortex-Debug has also added support for RTT. This is Cortex-Debug's own implementation of SEGGER RTT on the host side. You will find information about RTT
- https://www.segger.com/products/debug-probes/j-link/technology/about-real-time-transfer/
- https://wiki.segger.com/RTT
We highly recommend using RTT as it is very performative and less intrusive. This is compared to other methods like SWO or using a UART. However, RTT only works with a debugger (or one of the JLink tools) attached.
Cortex-Debug automates the setup of RTT on the host side, while still allowing customization. A lot of the implementation for viewing RTT data was borrowed from our own SWO implementation. Here are the main features (and limitations) which may be different from tools from SEGGER:
- Setup of RTT is automatic by default. For this to work, your executable needs to have symbols so we can locate the address of the global symbol
_SEGGER_RTT
- The start of the RTT control block contains a string that OpenOCD/JLinkGDBServer looks for. If the address is auto-detected, we clear out the string. This will help with cases where you might have stale information from a previous run.
- For OpenOCD, you can customize the
polling_interval
, and the search string. The defaultpolling_interval
is 100ms as of today. 10ms seems more acceptable as a tradeoff between creating bus traffic and not losing/blocking data. If nothing changes in the MCU, then OpenOCD does not do much even if the interval is small. - It is perfectly fine to have Cortex-Debug enable RTT but do not use any decoders. This way you can use external tools (like JLink tools or custom ones)
- You can plot RTT data just like you could with SWO. The setup in launch.json is identical. See this comment.
- Channel sharing: You can use the same RTT channels in multiple ways. Cortex-Debug reads the channel data from OpenOCD/JLink once and distributes to all subscribers (terminals & graphs & logfiles). For instance, you can plot a channel and also look at its binary data in a terminal. Just use two decoders with the same channel (actually called port) number.
- Note: JLink GDB Server has a limitation that it only exposes one channel (it can be any channel 0-15 and the default is 0). There is another artifact with RTT channels where you may see output from a previous run at the very beginning.
- Note: This implementation does not support Virtual Terminals that you see in the JLink RTTViewer. All output from Channel '0' goes to the same terminal.
- OpenOCD may not work for everyone. This gdb-server queries checks for the existence of the RTT block as it starts much before main and never tries again. You can set
clearSearch
tofalse
to partially work around this. It may still not work the first time the board is powered up or work wrongly if the RTT control block has moved. We are trying to patch OpenOCD but it could take a while since there are so many forks. In the meantime, we are experimenting withrtt_start_retry
to attempt to periodically start RTT and if this works, other workarounds may not be needed. - Output at the beginning of a session. Since in most cases SRAM is not cleared on a reset, there may be some data left over from a previous run. This is especially true with JLink when we terminate a session, will continue to run the program. There are other situations as well. Assume any data seen before entering main is from a previous session.
The best way to do this is to use the FW that is distributed with any release of JLink Software. You may have to register but it is a free download.
https://www.segger.com/downloads/jlink/
Once installed, you can find the FW and examples in <install-dir>/Samples/RTT
. There is a zip file that contains the FW. The FW is free to use but please do read the licensing included in the zip file. Although, it has been very stable, use the latest version. Beware of the copies on the web of this and they can be a bit out of date.
Channel 0, gets automatically configured but you can initialize the other channels by supplying the memory required. Although very simple, we do recommend studying the firmware and the examples. Also, do not change the data structures or the identifier string as this may cause incompatibilities.
In the classical VSCode way of doing things, you configure everything via the launch.json
file -- no fancy dialog boxes, etc. While there is much customization, you can get started with very little. See Examples.
There is only one property needed to get started: enabled
.
Property | Type | Default | Description |
---|---|---|---|
enabled |
boolean | false |
Global enable/disable for RTT functionality |
address |
string | "auto" |
Start address to search for RTT control block (CB). Use a hex (0x prefix) or decimal number |
searchSize |
number | 16 |
OpenOCD only. Number of bytes to search for the beginning of RTT CB |
searchId |
string | "SEGGER RTT" |
OpenOCD only. the string to search for at the beginning of the RTT CB |
polling_interval |
number | 0 |
0 means use gdb-server default. Or use a number in milliseconds |
decoders |
array | N/A | N/A |
clearSearch |
boolean | false |
When true, clears the search-string. Only applicable when address is "auto". Potential workaround for OpenOCD users until it is patched |
rtt_start_retry |
number | 1000 | Keep trying to start RTT for OpenOCD until it succeeds with given internal in milliseconds. <= 0 means do not retry. Only used for OpenOCD |
This is almost identical to our SWO implementation but added some properties for allowing bi-directional communication. There are four types of decoders
-
console
: As the name implies, a VSCode terminal is used to stream text to and from the FW -
binary
: This also uses the terminal but assumes the data stream is binary format and prints values in hex format. It is still bidirectional. All data is currently assumed to be 4 bytes long, little-endian -
graph
: This is used to create charts and graphs. Data is streamed from the RTT channel and routed to a graph/plot generator. All data is currently assumed to be 4 bytes long, little-endian -
advanced
: You supply your own javascript code to handle the data stream
Property | Type | Default | Description |
---|---|---|---|
port |
integer | 0 |
This is the RTT channel #. Also called RTT Buffer Index. We use the same nomenclature for both RTT and SWO so it is called port
|
type |
string | "console" |
Default: A bi-directional text input/ouput, shown in a Terminal window |
"binary" |
A bi-directional binary data, decoded text shown in a Terminal window. See also encoding
|
||
"graph" |
A unidirectional decoder similar to "binary", but decoded data is used in plotting | ||
"advanced" |
User defined decoder in JavaScript | ||
label |
string | "" |
A label to use for a Terminal Window or a plot. A default one is provided if empty |
prompt |
string | "" |
A prompt for "console" and "binary" terminals. A default one is provided if empty |
noprompt |
boolean | false |
Totally disable any prompt if true |
noclear |
boolean | false |
Normally the terminals are cleared on a new session. If this option is set to true , then new output is simply appended |
logfile |
string | "" |
The raw data read from the RTT channel is saved to a log file. The noclear options also apply to log files |
encoding |
string | "unsigned" |
For "binary" and "graph" type s. Encoding for parsing binary data. "unsigned" (Default), "signed" , "Q16.16" and "float" are valid values |
iencoding |
string | "utf8" |
This is the encoding used when data is sent from the terminal to the FW. Valid choices are "utf8", "ascii", "ucs2", "utf16le". It is best to use "utf8" because of its compatibility with 7-bit ascii |
scale |
number | 1.0 |
For "binary" and "graph" type s. The decoded values are multiplied by this number |
inputmode |
string | "cooked" |
Valid values are "cooked" , "raw" , "rawecho" , "disabled" . These names resemble the good old Unix stty modes |
"cooked" : The input is handled a line at a time and bash style line editing is supported. The data is sent to the FW, when Enter/Return key is pressed" |
|||
"raw" : Zero input processing is done. Keys are sent to the FW as you type. The FW has to do any input processing it wishes to do. Not even backspace will work as expected |
|||
"rawecho" : Same as "raw" except characters are echoed and new-lines are handled |
|||
"disabled" : All keystrokes are ignored |
|||
graphId |
string | "" |
Required when type is "graph" . This is the name of the decoder that can be referenced when generating plots/graphs |
decoder |
string | Required when type is "advanced" . Path to a javascript module to implement the decoding functionality |
|
config |
object | {} |
When type is "advanced" . Arbitrary JSON data that is used by the "advanced" decoder |
ports |
integer[] | [] |
An array of channel numbers that the "advanced" processor handles. Not valid for any other decoder type |
This is identical to the SWO graphing. See https://github.com/Marus/cortex-debug/wiki/SWO-Output#output-graphing-graphing. Of particular interest is the "graphConfig"
that has details on how to produce a plot/graph. In that page "graphConfig"
is used alongside with "swoConfig"
but it can also be used alongside "rttConfig"
or a combination of the two.
While not fully tested, you can have both SWO and RTT graphs in one program and display both. The requirement is that all graphId
must be unique.
"rttConfig": {
"enabled": true,
"address": "auto",
// "clearSearch": false // OpenOCD users may have to un-comment this
"decoders": [
{
"port": 0,
"type": "console"
}
]
}
"rttConfig": {
"enabled": true,
// "clearSearch": false // OpenOCD users may have to un-comment this
"address": "auto",
"decoders": [
{
"port": 0,
"type": "binary",
"encoding": "unsigned",
}
]
}
Note that the binary decoder outputs a line every four bytes and buffers any incomplete data until more bytes arrive.
In the pictures above, we combined both console and binary decoders although they both use channel '0'.