Deep Debugging of Embedded Systems: SEGGER RTT and SystemView for FreeRTOS
Effective debugging and performance analysis of embedded systems are cornerstones of microcontroller development. SEGGER RTT (Real-Time Transfer) and SystemView technologies offer powerful tools for these tasks, enabling developers to obtain detailed debug information and perform in-depth monitoring of a real-time operating system (RTOS), such as FreeRTOS, without halting the target device's operation. This article will explore the principles of operation and practical aspects of configuring RTT Viewer for log output and SystemView for RTOS event visualization, which is critically important for diagnosing complex behavioral patterns in embedded software.
Fundamentals of Embedded System Debugging and the Role of SEGGER RTT
Debugging embedded systems requires specialized approaches that minimize impact on the target device's behavior. Traditional methods, such as JTAG/SWD debugging with breakpoints, can introduce undesirable delays. This is where mechanisms like DAP (Debug Access Port), ITM (Instrumentation Trace Macrocell), and RTT (Real-Time Transfer) come to the rescue.
- DAP (Debug Access Port): A hardware block that provides access to the microcontroller's buses and core for debugging.
- ITM (Instrumentation Trace Macrocell): A specialized block in Cortex-M cores (starting from M3), designed for high-speed output of debug messages with minimal time overhead.
- RTT (Real-Time Transfer): A proprietary technology from SEGGER that uses a circular buffer in the microcontroller's RAM for bidirectional data exchange with the host computer. RTT's key advantage is its non-intrusiveness: the microcontroller's CPU is not halted, and debug information is transmitted at very high speeds, making it ideal for real-time log output (
printf).
To integrate RTT into a project, you need to add the SEGGER RTT library source files. The process is not tied to a specific Integrated Development Environment (IDE), whether it's Keil uVision or another. After compilation and execution, the J-Link debugger automatically searches for the RTT Control Block (CB) structure in the microcontroller's RAM. This block contains an identifier, the number of channels, and a description of the circular buffers for reading and writing, providing an entry point for data exchange. In most cases, the search is automated, but manual address configuration is also possible.
Example of RTT connection and usage:
Including header files:
#include <stdio.h>
#include "SEGGER_RTT.h"
Wrappers for typed messages (optional, for convenience):
#define LOG_INFO(msg, ...) { SEGGER_RTT_TerminalOut(0, "INFO: "); SEGGER_RTT_printf(0, msg, ##__VA_ARGS__); }
#define LOG_ERR(msg, ...) { SEGGER_RTT_TerminalOut(0, "ERROR: "); SEGGER_RTT_printf(0, msg, ##__VA_ARGS__); }
void LOG_FLOAT(const char* prefix, float value, const char* suffix) {
char buf[64];
snprintf(buf, sizeof(buf), "%s%.2f%s", prefix, value, suffix);
SEGGER_RTT_TerminalOut(0, buf);
}
Initializing the Control Block and outputting logs:
SEGGER_RTT_Init();
// ...
LOG_INFO("Central Heating: %s\r\n", Boiler.isCentralHeatingActive(response) ? "on" : "off");
LOG_ERR("Error: OpenTherm is not initialized");
The RTT Viewer utility, included in the J-Link driver package, allows viewing these logs. It supports outputting information to various tabs (terminals) and using multiple RTT channels for more advanced custom data transfer. RTT's advantages include the ability to output printf via SWD without using additional microcontroller pins (e.g., SWO), compatibility with Cortex-M0/M0+, ease of setup, and very high operating speed compared to other methods.
SystemView: In-Depth Real-Time RTOS Performance Analysis
SystemView is a powerful SEGGER tool for analyzing and visualizing embedded system operation in real-time, using RTT as its transport layer. It allows developers to gain a deeper understanding of FreeRTOS behavior by tracking task switches, interrupt handling, and other system events. SystemView configuration is more complex than RTT and involves several key steps:
- Include source files: Add the necessary SystemView files to your project.
- FreeRTOS configuration: SystemView works by intercepting FreeRTOS trace macros, which are located at key points in the kernel (e.g., during task creation or context switching). To activate this mechanism in the
FreeRTOSConfig.hfile, you must:
* Set #define configUSE_TRACE_FACILITY 1.
* For FreeRTOS V10+, add #define INCLUDE_xTaskGetIdleTaskHandle 1.
* At the very end of the FreeRTOSConfig.h file, include SEGGER_SYSVIEW_FreeRTOS.h.
Example trace macros:
```c
#define traceTASK_SWITCHED_IN() SEGGER_SYSVIEW_OnTaskStartExec((U32)pxCurrentTCB)
#define traceTASK_SWITCHED_OUT() SEGGER_SYSVIEW_OnTaskStopExec()
#define traceISR_ENTER() SEGGER_SYSVIEW_RecordEnterISR()
// etc.
```
- Using DWT_CYCCNT for precise timing: Cortex-M3/M4 cores contain a built-in DWT (Data Watchpoint and Trace) module with a 32-bit cycle counter (CYCCNT). SystemView uses this as a high-precision time reference. In the
SEGGER_SYSVIEW_Conf()function, you need to activate this counter:
```c
void SEGGER_SYSVIEW_Conf(void) {
// ---- Setup DWT (for Cortex-M3/M4) ----
#define DEMCR ((volatile U32)0xE000EDFCu)
#define DWT_CTRL ((volatile U32)0xE0001000u)
#define DWT_CYCCNT ((volatile U32)0xE0001004u)
#define DEMCR_TRCENA (1u << 24)
#define DWT_CTRL_CYCCNTENA (1u << 0)
DEMCR |= DEMCR_TRCENA; // Enable access to TRCENA
DWT_CYCCNT = 0; // Clear counter
DWT_CTRL |= DWT_CTRL_CYCCNTENA; // Start DWT count
SEGGER_SYSVIEW_Init(SYSVIEW_TIMESTAMP_FREQ, SYSVIEW_CPU_FREQ,
&SYSVIEW_X_OS_TraceAPI, _cbSendSystemDesc);
SEGGER_SYSVIEW_SetRAMBase(SYSVIEW_RAM_BASE);
}
```
Also, ensure that the SYSVIEW_RAM_BASE macro matches your microcontroller's RAM address.
- Interrupt Service Routine (ISR) handling: Unlike task switching, which SystemView intercepts via FreeRTOS macros, interrupts require explicit calls. You must add
SEGGER_SYSVIEW_RecordEnterISR()andSEGGER_SYSVIEW_RecordExitISR()functions to your interrupt handlers:
```c
void EINT15_10_IRQHandler()
{
SEGGER_SYSVIEW_RecordEnterISR();
if(EINT->IPEND & EINT_IPEND_11) {
// Your code
}
SEGGER_SYSVIEW_RecordExitISR();
}
```
- Naming interrupts: For clarity in SystemView, you need to inform the tool of interrupt names by extending the
_cbSendSystemDesc()function (found inSEGGER_SYSVIEW_Config_FreeRTOS.c):
```c
static void _cbSendSystemDesc(void) {
SEGGER_SYSVIEW_SendSysDesc("N="SYSVIEW_APP_NAME",D="SYSVIEW_DEVICE_NAME",O=FreeRTOS");
SEGGER_SYSVIEW_SendSysDesc("I#15=SysTickIRQ");
SEGGER_SYSVIEW_SendSysDesc("I#46=ModbusIRQ");
//...
}
```
- Functions for getting interrupt ID and timestamp: Add two functions required for correct SystemView operation to
main(or another convenient location):
```c
// A function to get the number of the current active interrupt (ISR)
U32 SEGGER_SYSVIEW_X_GetInterruptId(void) {
// In the Cortex-M core, the interrupt number is stored in the lower 9 bits of the IPSR register.
return (((volatile U32)(0xE000ED04u)) & 0x1FFu);
}
// In Cortex-M3/M4, we use the DWT_CYCCNT core clock counter register
U32 SEGGER_SYSVIEW_X_GetTimestamp(void) {
return ((volatile U32)(0xE0001004u));
}
```
- Final initialization: After initializing the hardware and peripherals in the
mainfunction, callSEGGER_SYSVIEW_Conf(), then start the task schedulervTaskStartScheduler():
```c
InitPhy();
SEGGER_SYSVIEW_Conf(); // Segger SystemView Initialization
CreateDeviceTasks();
vTaskStartScheduler(); // Start the real time scheduler
```
After successful configuration, the SystemView utility will provide a detailed visualization of system behavior. One of SystemView's most valuable advantages is its ability to operate even when the target microcontroller is not in debug mode. This allows for monitoring in real-world operating conditions, connecting J-Link as needed for diagnostics, which significantly simplifies the identification of complex, time-dependent errors.
Integration and Tool Selection: RTT Viewer vs. SystemView
SEGGER RTT Viewer and SystemView are complementary tools, each addressing specific tasks in embedded software development. RTT Viewer is ideal for outputting text logs and debug information, replacing traditional printf while offering significantly higher performance and non-intrusiveness. SystemView, in turn, elevates analysis to a new level by providing a graphical representation of FreeRTOS events such as context switches, task execution, and interrupt handling, which is critically important for performance optimization and identifying scheduling issues.
The choice between SEGGER_RTT_printf and SEGGER_SYSVIEW_Print (if used for text messages in SystemView) depends on the context: SEGGER_RTT_printf is for general logs, while SystemView functions are for events that need to be integrated into the analysis timeline. It's important to note that SystemView uses its own internal RTT channel for trace data transmission, which is typically not intended for direct user interaction. Although SystemView can operate without an RTOS, its functionality will be severely limited, as many of its capabilities rely on operating system hooks.
The use of DWT_CYCCNT instead of SysTick for timestamps in SystemView is due to several factors. DWT_CYCCNT is a dedicated hardware processor cycle counter that provides the highest possible accuracy and is independent of the system timer settings used by the RTOS. This ensures that timestamps in SystemView are as reliable as possible and are not subject to distortion due to the operating system's own operation.
Other tools for RTOS tracing and analysis exist, such as Tracealyzer by Percepio, which also offer rich functionality for visualizing and analyzing embedded system behavior. However, SEGGER RTT and SystemView stand out due to their deep integration with the J-Link ecosystem and high performance, making them preferred solutions for developers working with Cortex-M microcontrollers.
What's important:
- SEGGER RTT provides high-speed, non-intrusive output of debug logs (
printf) via a circular buffer in RAM. - SystemView is a powerful tool for real-time FreeRTOS visualization and analysis, using RTT as its transport.
- For an accurate timeline, SystemView relies on the hardware DWT_CYCCNT counter (Cortex-M3/M4).
- Both tools significantly simplify the diagnosis of complex problems by allowing system monitoring without halting the CPU.
- SystemView enables system behavior analysis even outside debug mode, by connecting J-Link on demand.
— Editorial Team
No comments yet.