你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【源码】STM32的printf重定向解决方案——史上最强?

[复制链接]
radio2radio 发布时间:2020-12-13 19:15
为什么要用printf,废话,不用你用啥? 我在下面的把printf换了一个名,LOG,少打3个字。您也可以换成您喜欢的字母组合,这不是重点。
; T2 K) P& ^* I% R8 ^% Y2 ~8 {4 D) q
1 v  g2 e! b# v! Y说是“解决方案+史上最强”,也不过就是下面的几行代码。 ! K  O5 ~6 e) E. s! }
笔者仅在CubeMX+HAL+MDK+AC5下,测试过F1和F4。 其他环境要修改后使用。; I9 L4 l4 M% n! R7 T
5 \, v  n$ v) ?# {! p8 d; K
  1. #include <stdio.h>( \9 W9 A$ I/ i! f+ ?% ^9 Y
  2. #include <stdlib.h>
    - R" U; `* t: N3 F, {" h! p3 L1 r
  3. #include <string.h>
    " J! {& O+ Z: E6 B" F2 o8 Q: Q" w
  4. 7 N2 Y* P# A. A/ H8 n% d4 O
  5. //Debug mode On/Off switch
    - u! }/ v0 @' ~6 m
  6. #define DEBUG                   1 //set=0, disable all LOG lines
    ( X7 b2 j, l* }/ l9 ~
  7. " U+ K7 @% k' u7 \8 J- _
  8. //select one of the following "printf" retarget methods6 C+ F; m7 [; N$ t% R
  9. #define PRINTF_UART             0 //printf using UART port, 1-use this, 0-not
    - E; M1 G# W2 p& ^, X" {
  10. #define PRINTF_RTT              1 //printf using Segger RTT, 1-use this, 0-not% U, e* @# S* t8 d# \! e, a
  11. #define PRINTF_SWO              0 //printf using SWO port, 1-use this, 0-not
    + |5 {1 G  ^% J9 y2 G
  12. #define PRINTF_CDC              0 //printf using USBD_CDC, 1-use this, 0-not$ Q, t8 c5 p& ^: _- q4 T
  13. + n# }4 z5 M, V$ t$ `3 G
  14. #if ((PRINTF_UART + PRINTF_CDC + PRINTF_SWO + PRINTF_RTT) != 1)1 U* H( [% T" _. z% s3 j# @
  15. #error "!!!!!! printf retarget function Not define or Multi-defined !!!!!!"
    5 \. R. ^' g. e. _5 M2 G: t
  16. #endif2 A% F; T$ P" c

  17. 3 l8 M4 a* Z2 c2 e% `# H
  18. #if DEBUG& w4 e) A' s; p; N" Q7 n
  19.   #if PRINTF_RTT
    ) k6 @, g* _+ T4 m' I
  20.     #include "SEGGER_RTT.h"
    : q" X! e, n) V4 e4 r" x
  21.     #define LOG(format, args...)  SEGGER_RTT_printf(0, "[%s:%d] "format, __FILE__, __LINE__, ##args), R! I# j" q6 l; h) e1 l5 H" ^
  22.     #define printf(format, args...)  SEGGER_RTT_printf(0, format, ##args)9 {. P' D) [9 k* p: P
  23.     / ?9 J) q! [2 ^, [+ J$ Q
  24.   #else //#if PRINTF_RTT
    & g+ @8 K5 l6 t
  25.     #define LOG(format, args...)  printf("[%s:%d] "format, __FILE__, __LINE__, ##args)
    + h, j& J: h; N7 C
  26.    
    ; _9 k' _2 J7 ^: j
  27.     #if PRINTF_CDC
    1 j" ?5 ?2 h2 g6 O" x% [7 M! z( H
  28.     #include "usbd_cdc_if.h"
    5 N9 ^6 R% a+ v* b4 H( q+ g
  29.     #endif
    ' ~0 u: G0 o" q$ I8 P) [
  30.    
    ! R3 T' f  G+ P+ x3 |& S
  31.     int fputc(int ch, FILE *f)
    # @* u( C0 f" I9 P1 B
  32.     {6 w# w: c" ?5 y. J4 m: K, ~
  33.       #if PRINTF_UART" q! `' o  U7 Q9 Z/ V1 s. N8 l$ F+ J
  34.         HAL_UART_Transmit(&huart3, (uint8_t*)(&ch), 1, 1000); //UART37 w8 Y, M/ s! }( Q% M; C2 q
  35.         
    5 i; P, X$ b+ J2 f
  36.       #elif PRINTF_SWO# U& `1 z$ d. @+ F: r3 [% N, _
  37.         ITM_SendChar(ch);
    * c7 l8 u& K) P( N4 B
  38.         7 E+ F* q; _) Q& L+ H
  39.       #elif PRINTF_CDC( I6 B5 j! [$ Y+ ]: M$ U7 z1 E/ m% L1 V
  40.         uint8_t u8Temp = 0;
    2 K8 r7 R* ?2 S6 {  R* z0 U4 b
  41.         while(CDC_Transmit_FS((uint8_t*)(&ch), 1) != USBD_OK)
    1 R" v$ V. J. }7 P3 L" s* C7 o  K
  42.         {& k# F: }# n2 f8 h0 i* A! t
  43.           HAL_Delay(1);
    ' @: m2 H8 `1 X
  44.           if (++u8Temp >= 3) break;
    . N- u- {) w, K2 Q0 X
  45.         }
    ( n8 u( w% A$ J* o
  46.       #endif //#if PRINTF_UART
    ( l+ o, O% K2 n* f. K
  47.         
    4 F( @8 H' l4 s" X% T7 t
  48.       return(ch);
    # s( h& z4 Z6 T8 l3 ]9 P& j
  49.     }3 X0 q1 f0 l4 q! z& a, n
  50.   #endif //#if PRINTF_RTT
    1 f  r% \8 I5 U. R9 W) {0 z! I" t- g
  51.   , a& o2 P4 I1 Z6 e
  52. #else //#if DEBUG == 01 C" f" A' W( r% e8 d: f8 Q, U% ]* a( b
  53.   #define LOG(args...) //disable all LOGs when compiling
    . L, s- O2 \) H8 P
  54. #endif //#if DEBUG
    # Z; E. H" w9 R
复制代码
- ]' a% y6 E8 b
这里有4种方法重定向printf,必有一款适合你:
( Z2 _. {" M; A: D- ?, F2 U
1 Q! z; z% O. A1. PRINTF_UART == 1,串口方法。 ! V9 E8 ~! X) I
优点: 就是最多人使用的,大家也最熟悉。 配置简单,容易使用。 各种“PC终端软件”都能用。6 ~, j3 M7 b7 h# U* G6 e) [
缺点: 硬件上要有串口可以用,有时还需要UART转USB接口板(或者仿真器自带VCP/CDC的东东)配合。3 C4 M8 p* h% _1 F; e& J+ C) w$ N
' H& k0 y3 |: F! \! N1 P( |
2. PRINTF_RTT == 1,Segger_RTT 方法。  (笔者推荐此方法,至少值得尝试一次), 要安装RTT包,简单!# p' e2 u0 Y' O5 h( V
优点: 不占用额外的硬件资源, 据说速度超级快。 有多快,我不知道。
, U1 k2 M; l! c1 ^6 C+ s6 H, {6 O缺点: 要使用专用的PC软件接收,既然是仿真器大佬Segger的产品,自然是Segger的驱动程序功能多多。/ |8 d+ j* j# N% |" t% s
           使用J-LINK仿真器,就一定要用JLinkRTTViewer等终端软件。9 E: O* E/ d! o& ?. _
           使用CMSIS-DAP仿真器,可以用DRTTView终端软件, 多谢XIVN1987网友 ,不然DAP就不能用RTT了。1 o6 Y/ |% s) Q
           使用STLINK仿真器,对不起,用不了。
6 J: O5 z+ q. L- E! L+ Z$ @  g' e3 c- m: }( b$ J! R7 W* ^! v
3. PRINTF_SWO == 1,SWO的方法,这个是启动内核的ITM功能。
& d& J& e2 S" x4 n; J优点: 对原程序流的影响最小。 标准的JTAG/SWD/STLINK连接器,都已经准备好了SWO线,也算方便。2 T. q+ N9 R" f  F
缺点: 相比2线的SWD,需要硬件连接一条SWO的输出线。 不能实现双向通信(其他方法都能)。  T* d# @9 i" b/ v
            软件配置SWO功能比较复杂很容易失败,重点是要做SWO速度匹配。
! s8 c) N# C8 F8 H7 H! L            SWO方法不能在JTAG模式下使用,只能是SWD模式。另外,ARM Cotex-M0/M0+也不能用。
* X( D5 \" j6 ?            MDK/Keil有内置的SWO Viewer,不过不好用,一定要进入Debug模式,好处是各种仿真器都可以用。" |: C8 W1 S: D7 Q9 A' O
            J-LINK 和 STLINK 仿真器,有自己的独立的SWO Viewer,不需要Keil进入Debug模式那么麻烦。7 K4 K+ @- P1 O: a+ e

9 U! g; [; m5 {; M4 a4. PRINTF_CDC == 1, CDC的方法,比较逆天的,属于玩具级别,你想用我都拦不住。
  W( b8 S' F  H! p优点: 用法与UART一样,各种串口终端软件通杀。
, n' ~) A4 ?$ ]1 Y           不占用串口。 利用IC本身的CDC-VCP节省了UART转USB接口板。
: V- ?. s6 R( y8 W) ?6 H8 z缺点: IC要有USB硬件,代码增加,软件复杂度增加。
" \* y0 ]: F* U# f" J* p! K9 @  p% c9 }; L
! U: \+ _: p) A( H实用中,还有一种方法,称为半主机模式(semihosting),据说速度慢和影响原程序运行严重,没有认真研究过。我甚至怀疑,上面的4种方法里面,有可能有后台使用了半主机模式,知道详情的朋友,请介绍一下。- c. U1 |8 X& k% u& p  ^% s- _

4 ?6 V0 l8 \3 s毕竟printf指令对原程序流是多余的操作,或多或少都会干扰原程序流,特别是在一些速度比较慢的MCU上面。因此,printf的输出项要尽量简短,避免大量连续使用。 如果估计占用MCU时间太多,就要做需求评估。
  o8 G3 ?% @1 o/ K3 n2 C( ~, a. h: E

9 i% K6 A/ ~# B! ~( w附件是F103/F407用的完整的工程,与github上传的一样,上面的4种方法都有,可以试一试实现。3 T/ l$ v% u# `
github:https://github.com/RadioOperator/STM32_HAL_retarget_printf) ?8 P9 g. S) w( M: w* |

$ e* C0 ]; U0 s, p. e3 E( P
; @) Q2 d: L9 D2 k! J# U( u+ E5 X- I
* B$ d# R" j! Y! H- ?  ~

STM32_HAL_retarget_printf-master.zip

下载

1.36 MB, 下载次数: 12

评分

参与人数 1 ST金币 +10 收起 理由
子曰好人 + 10 很给力!

查看全部评分

收藏 3 评论5 发布时间:2020-12-13 19:15

举报

5个回答
goyhuan 回答时间:2020-12-14 08:20:52
强大
七哥 回答时间:2020-12-14 09:14:10
纳百家之所长,长己之技能
子曰好人 回答时间:2020-12-14 09:32:46
支持老兄,点个赞
kylixyao 回答时间:2020-12-14 18:21:45
非常不错!
radio2radio 回答时间:2020-12-15 12:22:34
子曰好人 发表于 2020-12-14 09:32$ f* E$ ?* {7 K8 E% i# ]
支持老兄,点个赞
# t- E, ]6 [, g0 }# G; f8 [7 G& j2 {
多谢您的鼓励。! l0 f0 `0 f/ a# N
我还是把F407的例程放出来了,同时也上传了github,留个记录。

所属标签

相似分享

关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版