1.什么是Jlink RTT。" W5 k% \& a0 [
全称为SEGGER’s Real Time Transfer(RTT),一种基于SEGGER公司的基于JLink调试器的交互式用户I/O的技术。故名思义,就是一种基于jlink的和用户进行交互的技术,可以直观的显示调试芯片的信息,以及可以让用户和调试芯片进行互动的技术。$ T* c4 G1 J0 }8 U
4 A! G- ~+ F, U) Q% r/ |2.为什么要使用Jlink RTT。
# m& L F( w( O; Q4 s. p1 y1>不需要额外的引脚和硬件配置,支持SWD方式,两根线就可以使用。
+ S+ h/ O0 e! U4 f/ s2>速度快,与debug和run并行使用,平均一行文本可以在一微秒或更少的时间内输出。官方给出了一个速度对比图。
- q7 C; Z8 Y+ _: A0 P
: N8 w1 O8 D& o1 [$ ?1 F3>RTT的通信可以通过不同的应用程序完成,可以使用SDK集成到自定义的应用程序中,可本地连接,可远程连接。* d* ?: C" g. J. q
基于以上3个优点,如果你还在调试ARM芯片的时候傻傻的使用USART进行用户交互,那实在是效率太低了。0 E5 a! D5 C5 H- u
, s$ i/ S0 Q/ ~3 Z
3.Jlink使用RTT的准备/ `4 `. q! {3 ?: _/ i; h
1>jlink软件包 N6 z8 d: `6 j, j( W
$ z# I& r2 b8 T& p
: s( P& ?' ~* W- K* f; z6 y' X$ v
2>Jlink仿真器一个,官网没找到到底哪一个版本的Jlink版本开始支持RTT的,看到网上说V9是支持的,我这里用的是Jlink V11的仿真器。
( n% @; o4 t$ i8 O; MHW:V11.00
: r/ f. P. i7 I. G% k- p7 ddll:V6.98c9 [, h7 a) w$ w3 r/ f. H; K
5 ]! G, c( |/ d$ D4 `% X) D. q
4.移植RTT的SDK代码到MDK的工作8 H# m5 E3 u- U9 B
1>在上一步Jlink软件的安装路径下找到RTT的SDK包,我这里在D盘安装的。
1 `! @! l G/ f, S! |2 pD:\Program Files (x86)\SEGGER\JLink\Samples\RTT\RTT
' E2 c: r* J: I; R' W2 |4 z4 C1 E$ f Y' [
, T% S3 G0 `/ O0 h+ D* ?2 Q, M+ ^
2>MDK工程下新建一个RTT的文件夹,把下面四个文件复制到RTT目录下,将这些文件添加到MDK的工程中。" v( b" S/ Z7 p6 w4 e- f8 d' W% W, Z
- H$ l/ s5 j9 C e: `5 E
1 t3 f9 Y; x' V. ?* L1 t% g9 W将代码添加到工程中4 Q" W8 O0 k! T

# b2 V+ Q/ D' Q8 |9 u) O; l5 \$ }' `
" c* V# q. a" l5 R头文件包含
0 y' t1 |6 e" a1 ]/ Z) B2 N# T
# j* s0 H9 U4 C X% f, b: l. e+ W
9 u9 L1 d, {0 E4 _; T& q
5.支持RTT的三个软件
# {9 H3 \6 A7 T. t, J4 k3 v1 TJlink提供了三个软件RTT Viewer、RTT Client、RTT Logger,这三个软件可以在SEGGER目录下找到:- n5 N E& f% h# X- W

( Y* N; S1 v- n( ?
$ X" o3 V5 O" \7 b2 v6.使用RTT前的一些需要了解的几个概念。/ i2 l# H' e2 H2 c& C- `9 p
使用RTT需要了解两个概念,即所谓的channel和terminal。这里我也只是根据我现在的认知做了一个解释,不一定恰当。% q4 U% F/ H' y0 ]
由于没有详解RTT的内部运行机制,我在这里把channel和terminals理解为软件的概念。. T3 ^; m! p+ `4 Y9 N) E
RTT的SDK默认支持2个channel,分别是0和1。% c, }) b9 p! s% \9 T: t4 k0 I
每个channel支持16个terminal,分别是0-F。, C& h$ p G; r% V! W2 I9 B4 O* w
在这两个概念的基础上,我把RTT Viewer、RTT Client、RTT Logger这三个软件做了一个对照表。了解下面这个表格,才能更好的使用和配置RTT。
% @/ c) Y: M5 o5 f
& M; ^2 M0 v) w+ y: T8 x) X
% p4 r/ }5 Y/ h% y
( P5 m# @' q2 ?8 f k9 Q: q. k6 f- [7.MDK的代码编写
& V, e0 p/ p- d -
3 ~; i; {9 \! E* k - /*********************************************************************************************************
. N- o' p4 X9 D, V; l% | - * 主程序+ I- l7 `2 ~3 k- d
-
+ D4 r' Y# y% T9 N3 \ - *********************************************************************************************************/6 o; A3 G$ R" ~( J$ i+ F2 O
- int main (void) ; R3 w# k& L5 z
- {' d6 h! {: f( d
- FLASH_ReadOutProtection(DISABLE); //读保护& u+ a) R) X: q; x- |4 _6 C
- SystemInit(); //CPU时钟初始化
- s. b b+ ~: T6 _* x+ \ - NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4); //使用优先级组4(4:4结构)( B H, g9 b4 Q4 J- r
- SEGGER_RTT_Init(); 3 R' n8 ]; \- e& b' c/ M6 o
- #ifdef DEBUG_MODE //调试模式' z% w+ H* g' x
- SEGGER_RTT_printf(0,"Demo Init!\r\n");" L7 E& n5 f4 V; {
- #endif 2 q2 r" q4 y: A2 w- N J1 F
- while(1)
( a! @, k/ F- y1 L, B6 a4 g - {; o; s3 C" ?: s9 a3 D' w
- SEGGER_RTT_SetTerminal(0);
+ Y3 l B: B7 `. G! P! l - SEGGER_RTT_printf(0,"Demo Run Terminal 0!\r\n"); # M" |. r5 x( s, q" {& q
- SEGGER_RTT_SetTerminal(1); ' a2 Y, B: Y" n3 r$ `+ F
- SEGGER_RTT_printf(0,"Demo Run Terminal 1!\r\n");
4 ^0 S4 o/ p* K - }: r% a- Q4 L e6 B; b: W
- return (0);
2 {- j$ L# ?% V; I2 U - }
复制代码. G: ?. k3 e: N& v4 |' m
1>头文件引用#include "SEGGER_RTT.h"6 o8 a+ q. v) Z* Y6 R% p r* F4 `4 T
2>RTT的初始化函数 SEGGER_RTT_Init();
7 K/ F) T( Z# V% G" A# r上面两项是通用代码,下面是使用通道0,用RTT Viewer、RTT Client输出一段调试信息。
' M/ a6 {( o, d9 x+ O2 m
- ! u8 u1 q: p* b8 A, ^* l- Y
- /*********************************************************************************************************7 [5 Q5 j1 ` M# @' ~
- * 主程序
1 b. u* B: T5 V& B9 ` D( _ -
) Q) v, S/ ~/ n" x( P m - *********************************************************************************************************/
( S) x+ E$ W$ k8 |& u J3 l& e - int main (void) 8 G& v, D/ v4 T& c/ H3 x" n
- {2 Q G: m, m/ i3 y; g
- FLASH_ReadOutProtection(DISABLE); //读保护0 {* Q' O5 K6 {" s4 i) p3 u% _
- SystemInit(); //CPU时钟初始化
4 \: n2 M# D* Y/ i - NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4); //使用优先级组4(4:4结构)
0 y1 z% D7 P( j# c& ]# } - SEGGER_RTT_Init();
: u# V8 ^: D3 e8 i - #ifdef DEBUG_MODE //调试模式
8 n+ u/ [! T D/ B& L - SEGGER_RTT_printf(0,"Demo Init!\r\n"); E/ F3 a+ l4 Z' w
- #endif ( Z$ w1 F, x1 P; N+ C7 o
- while(1)4 u; w" F' D9 T/ Z( @* W9 m0 f4 {
- {
; n( s9 U# Q$ a5 D* X - SEGGER_RTT_SetTerminal(0); / H9 ^+ Z' @7 @2 i5 K, D
- SEGGER_RTT_printf(0,"Demo Run Terminal 0!\r\n");
6 D" o: G! d, u# A5 H2 W - SEGGER_RTT_SetTerminal(1);
5 O6 }6 o& v6 W - SEGGER_RTT_printf(0,"Demo Run Terminal 1!\r\n");
/ |- x0 H P3 W7 C+ f - }
S& W1 |& |, f; J1 ~7 \' g - return (0);
; i4 X% m! M1 I, ^, o- H( J - }
复制代码 7 g- a% Y! l# }8 e/ \
0 B4 G9 n9 X8 e
上面的代码就是用通道0的terminal0和terminal1输出调试信息。RTT的SDK中默认已经配置好channel 0的参数了,我们使用channel 0的时候,直接使用打印函数即可。
2 u/ \9 j4 A. n6 @8 J0 t上述代码编辑后编译无错误,然后下载。
2 _+ U7 X* e- ]3 X6 q- Q( D7 D) e6 E; W
打开RTT Viewer后显示如下,按照实际情况配好参数后点击OK。 $ Y3 I8 k2 M/ l1 `3 U
9 q3 S! K/ C, t# B5 b8 U9 W: T
) ]4 F: m, w2 x; z
2 U% [* \3 I# n# H- M; M, G: v2 ~+ l可以看到控制窗口已经输出了调试信息。>前面的数字即为当前使用的terminal ID。 ' V) s6 r* L" b* | v
/ B9 T. T8 O6 v1 s
5 w+ v b; W% f* N5 V) r3 `
% X" q# E& r2 x7 O0 m. i! y3 ~
打开RTT Client后显示如下:% n3 n' `" D* n% C4 W
- i& Q+ e: h) Y* E0 T2 t
" N6 B2 S4 D# P* a这时候会发现没有数据输出。不要着急,重点来了。
4 O7 n* }5 b) p( d2 S0 F1 `# E5 X- H
1)先关闭RTT Client,点击MDK的Debug按钮进去Debug模式。
3 l6 z; z) h) t i: p" r. Z H
. _) D# z% H: r @4 d- c/ n* L ?' j# P
% F$ A5 m7 q& U7 q; m
2)再次打开RTT Client,显示如下:7 g4 K/ s5 w( Y! K* O! t
, m/ j: S% u0 F, `
: \8 d ?; ^+ { @$ Z: x/ e' }% H9 I
3)点击MDK的Run全速运行。控制台开始输出调试信息。
' ~; m. S4 Q" ]1 z0 n% }9 }; X, u6 j' Z$ W4 ?9 q

. E+ E! j. l+ v& e5 Y$ E$ Y8 D; P& M7 h9 W& I
下面继续使用通道1,使用RTT Logger输出调试信息在log文件中。因为RTT Logger使用的是通道1,RTT的SDK中是没有给通道1分配缓存区和名称的,必须进行手动设置。) k' p$ T( v7 t0 v7 e5 O4 i
还有要注意的是,通道0和通道1是并行的,两者输出调试信息是不冲突的。
/ V$ k5 o" F, A, O+ N. j5 e使用通道1的代码如下所示:
( u4 K, K4 K: {, i
- uint8_t _UpBufferCH1[64] = {0};5 Z% x8 S4 I. q/ r
- uint8_t _DownBufferCH1[64] = {0};0 J! H1 h8 z5 m8 ]9 ^( h& a3 s
- 4 S' n/ W+ ^9 x6 l: H
- N, s5 s; m& {; v
- /*********************************************************************************************************
' u( H# L/ k( X3 c" C - * 主程序
, a: t& F5 Y8 l+ Q! Y' B: Y: M - *********************************************************************************************************/
, Z$ a4 `4 v8 T$ ?6 G7 E! H - int main (void)
9 t) w& J) W0 R2 V$ k. F) G - {
: \0 ?% R1 Q- f9 G- x - 4 w9 @: D+ h/ W4 ~7 l6 C
z+ M N( ]1 E5 m" v0 t- FLASH_ReadOutProtection(DISABLE); //读保护
: M( Y, \3 ~ x" q( D% y( m
( R: n. a! ?* B, e- 0 r0 d0 w$ u8 ~& ^" Z8 d3 @# b
- SystemInit(); //CPU时钟初始化0 t: x/ e# O/ b) h
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4); //使用优先级组4(4:4结构)
7 v8 j7 @: L6 R& W/ F( M" B - & s' l& ~; ]0 t7 E: L4 Q" G) ]
- SEGGER_RTT_Init(); : x7 j. z- H( U* _6 i8 Y4 w/ z
2 \) w" H) E9 P$ X! J
& O( f T; F, j' `, ^- /* 配置通道1,上行配置(STM32->RTT Viewer软件) */
3 e/ |2 [! c: J: f - SEGGER_RTT_ConfigUpBuffer(1, "RTTUP", _UpBufferCH1, 64, SEGGER_RTT_MODE_NO_BLOCK_SKIP);( K' ^! z6 R7 e1 F& J
' N6 i- q' h5 B7 P5 b- /* 配置通道1,下行配置(RTT Viewer软件->STM32) */ + p; D2 d3 ?+ c
- SEGGER_RTT_ConfigDownBuffer(1, "RTTDOWN", _DownBufferCH1, 64, SEGGER_RTT_MODE_NO_BLOCK_SKIP);
& J! ?" C: g5 @% O8 p! p: S* |
4 e5 t, B' p% Z9 n! m- #ifdef DEBUG_MODE //调试模式+ s4 d1 s& l. C
- SEGGER_RTT_printf(0,"Demo Init!\r\n");
! X8 \% S$ N% m1 P2 z - #endif
8 O- x* z' i* I1 u9 b0 ^ - ! W R' T6 O4 F+ T$ m1 z G+ D
1 f6 w4 ?# W" `( Y; o1 h- while(1)! ]- ]6 n Y6 ^/ D# U4 t
- {
' F+ J# t7 e& `$ ? - SEGGER_RTT_SetTerminal(0); ' O" E& y3 f" _& G) E' {$ t! l
- SEGGER_RTT_printf(1,"Demo Run Terminal 0!\r\n");
$ s! P/ ?$ `) t& U' F - SEGGER_RTT_SetTerminal(1); 3 }* L- d! s0 {2 r2 D
- SEGGER_RTT_printf(1,"Demo Run Terminal 1!\r\n"); 0 w. Q. d' s5 L, @! U4 |) b1 d
- }
: e# j, f2 K; y
( E0 a6 x$ V7 h# y7 I! D" e- + J" Y4 D; h9 A @6 q2 R
2 @0 K0 b0 \0 w0 _! ?- return (0);
) I- g; C$ e$ R# p4 d - }
复制代码
0 q) h2 M. n( l# b6 v3 j0 Z上述代码编辑后编译无错误,然后下载。 打开RTT Logger后如下所示:: M1 D! a4 @5 L$ \% P" k6 x5 _
I% t& \/ Y& Y5 C& W' h; W

* f9 ?/ `2 m; D
" J6 L/ l5 n- T# I这里要注意的是,在RTT Logger中,>后面可以自由输入>前面表示的参数,按回车键确认。无输入的情况下,按回车键跳过。& r. N. P, @ l9 o9 N
一直回车键,如果程序配置通道1正确的话,会出现下面图片的画面,不停的给log文件中写数据。
. V. x3 |& @$ Q- g, f2 O注意:如果程序中没有配置通道1,RTT Logger检测不到通道1的情况下就会自动关闭。
3 d4 k1 S- S2 c正确的RTT Logger显示画面如下:
' W/ p' O' ?( p( ?- j
3 H6 Z' p' d% T
+ t, d, Q& L9 l* N& ]: X+ }打开上述路径中的.log文件,里面的内容如下所示,这说明成功的生成了log文件。
6 Q P9 Z* F- R9 L/ G6 c# g# F- V. Q0 \1 k! [# n+ i

# l) k6 M9 Q% }7 q) {
5 M: N; {8 d. D7 y, D只要弄懂上面的内容,你就可以很爽的使用RTT来输出调试信息了,我们一般只使用RTT Viewer这个软件就足够了。他还可以设置显示的颜色,格式化输出等,具体的函数说明可以查看
* x6 Q! E7 v2 ?) p$ P3 cJlink安装目录下的使用手册16.4.1章节即可。& N& P/ [3 N* `- N( z
手册路径如下:D:\Program Files (x86)\SEGGER\JLink\Doc\Manuals。 ---------------------# J9 |5 v6 R3 W) v9 i& V
作者:xyz549040622 * l. a7 \* f- Q
|