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

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

[复制链接]
radio2radio 发布时间:2020-12-13 19:15
为什么要用printf,废话,不用你用啥? 我在下面的把printf换了一个名,LOG,少打3个字。您也可以换成您喜欢的字母组合,这不是重点。
) h3 l' A% j7 e) K# O8 s* A) P% y7 r/ B8 g* e7 x, J
说是“解决方案+史上最强”,也不过就是下面的几行代码。 - S$ {5 f& W; F- o7 |
笔者仅在CubeMX+HAL+MDK+AC5下,测试过F1和F4。 其他环境要修改后使用。
- U7 x; C& w$ U7 a0 J5 v2 B, c; X
3 O' ^0 U# V# {; {! }
  1. #include <stdio.h>0 }% e5 @8 {- S; ]
  2. #include <stdlib.h>6 h: `4 V( `( L
  3. #include <string.h>8 V: |3 }3 y4 L* A$ T# c: a* u) d
  4. ( r. B* N. a9 h( [& Y( ?( O
  5. //Debug mode On/Off switch + ~- p1 }2 I1 |4 W1 C4 }
  6. #define DEBUG                   1 //set=0, disable all LOG lines9 Q& u, @" N: r

  7. ( Z* h$ t1 X- z' Z1 p+ Z9 @7 ]6 C' q
  8. //select one of the following "printf" retarget methods8 V7 p0 u0 k( n- H4 L
  9. #define PRINTF_UART             0 //printf using UART port, 1-use this, 0-not
    0 B7 [, B& Q7 \( N  I* u8 |
  10. #define PRINTF_RTT              1 //printf using Segger RTT, 1-use this, 0-not: p8 ^& c: e& D: b# i
  11. #define PRINTF_SWO              0 //printf using SWO port, 1-use this, 0-not& q9 h+ \9 N* J% @, q0 @
  12. #define PRINTF_CDC              0 //printf using USBD_CDC, 1-use this, 0-not
    . z9 ~  u& [% t4 i) O
  13. ( Z. O; j9 q& x& b7 a% P/ ^
  14. #if ((PRINTF_UART + PRINTF_CDC + PRINTF_SWO + PRINTF_RTT) != 1)% F4 t# R0 U$ W+ @: K' Z) ^5 M
  15. #error "!!!!!! printf retarget function Not define or Multi-defined !!!!!!"
    % S: J5 o( T% Y7 T" o  W; t# b" Q
  16. #endif
    5 `8 [% S& ?4 o

  17. % u" f1 i" ?0 f5 n2 K3 M9 T+ L# {8 S" O
  18. #if DEBUG( T+ t* ~' @2 w' }" c
  19.   #if PRINTF_RTT) |$ P. [4 b( y) B# F8 q9 j* S
  20.     #include "SEGGER_RTT.h"# _7 c9 U, h& R% X6 r- l4 Z
  21.     #define LOG(format, args...)  SEGGER_RTT_printf(0, "[%s:%d] "format, __FILE__, __LINE__, ##args)& k8 v% r! M1 |
  22.     #define printf(format, args...)  SEGGER_RTT_printf(0, format, ##args)
    % D3 r6 T8 n; G) N
  23.     0 U4 s, t* `5 ?) X9 X9 }$ m
  24.   #else //#if PRINTF_RTT% ^5 {7 G8 ]! ~& Z# s
  25.     #define LOG(format, args...)  printf("[%s:%d] "format, __FILE__, __LINE__, ##args)
    ) V$ O% L+ J; ~
  26.    
    ( T$ o0 I) U) J" s. l
  27.     #if PRINTF_CDC* H8 O1 G2 b3 y: Z2 L
  28.     #include "usbd_cdc_if.h"8 y# d' ~& h1 {! D$ ^& z
  29.     #endif
    % m8 Z% @1 h! [% o) O
  30.    
    / D% h9 H& z4 s$ ~- _
  31.     int fputc(int ch, FILE *f)
    " |, b2 t: J* ^1 S* U! q
  32.     {
    ; B# [4 F, u0 Q: }
  33.       #if PRINTF_UART' [0 i& |/ g. [* B+ M) O6 z
  34.         HAL_UART_Transmit(&huart3, (uint8_t*)(&ch), 1, 1000); //UART3# ~* x! E# m% t
  35.         * b- n; c5 e; d- ~. j" m4 ~
  36.       #elif PRINTF_SWO
    $ [' A5 l3 |9 E& V. N
  37.         ITM_SendChar(ch);
    + ^& H2 j- G# J0 W
  38.         6 [$ k( t0 F  J5 X
  39.       #elif PRINTF_CDC- a# t3 ]$ s. X- Y9 h  q
  40.         uint8_t u8Temp = 0;6 D) `$ K( `; `/ r/ g" O  a
  41.         while(CDC_Transmit_FS((uint8_t*)(&ch), 1) != USBD_OK)  R/ R# X/ M5 T# A; G9 \5 L5 S
  42.         {
    $ R5 V2 m5 j2 b1 {4 M( [
  43.           HAL_Delay(1);4 H% v+ J* I! z0 `
  44.           if (++u8Temp >= 3) break;
    4 q0 Z7 E) x& k! p; t" h- _
  45.         }! p- ^: M+ s' J5 }+ q5 x
  46.       #endif //#if PRINTF_UART
    ) D& ]! {6 ^1 u- d# _
  47.         
    8 Z* f' v6 z7 r' z" Z1 c
  48.       return(ch);
    * s9 Y! ]' b# A0 @* E  ^7 B
  49.     }
    . X! d5 |8 t9 u3 X$ q" d3 E* t- y
  50.   #endif //#if PRINTF_RTT- c! {( N( U+ b: j2 F( U
  51.   
    & r- P$ @4 K& e* a! F! T! E6 `; v
  52. #else //#if DEBUG == 0
    % \7 {6 x) [2 P  @& P" n/ R
  53.   #define LOG(args...) //disable all LOGs when compiling
    0 E4 h8 o7 S  M# ]0 N
  54. #endif //#if DEBUG
    3 F& s) ^* t( u% O
复制代码

; P! [, U; b, B& z! n$ G这里有4种方法重定向printf,必有一款适合你:
2 g) N1 r% ~2 z. t
5 G6 I% x  I2 ]( y2 k6 T# s# R1. PRINTF_UART == 1,串口方法。
- k- @" ^+ Z* U' F+ l' s2 E优点: 就是最多人使用的,大家也最熟悉。 配置简单,容易使用。 各种“PC终端软件”都能用。
6 e. l) E" I6 d& [/ g$ X. [: G* q3 L缺点: 硬件上要有串口可以用,有时还需要UART转USB接口板(或者仿真器自带VCP/CDC的东东)配合。
7 O8 q5 Q8 L( b0 h8 q. c% ?) e6 I7 _$ v2 t1 j4 u8 J) {8 B
2. PRINTF_RTT == 1,Segger_RTT 方法。  (笔者推荐此方法,至少值得尝试一次), 要安装RTT包,简单!- R" O0 o) E- p' _
优点: 不占用额外的硬件资源, 据说速度超级快。 有多快,我不知道。% J" s9 U+ C1 U, X9 x/ a- M# F
缺点: 要使用专用的PC软件接收,既然是仿真器大佬Segger的产品,自然是Segger的驱动程序功能多多。7 _2 U. _! @) H( u$ f* E1 _
           使用J-LINK仿真器,就一定要用JLinkRTTViewer等终端软件。
6 V. H8 y0 ?" [           使用CMSIS-DAP仿真器,可以用DRTTView终端软件, 多谢XIVN1987网友 ,不然DAP就不能用RTT了。
! F# f$ X3 Q# p/ _( H0 [* z! m  x           使用STLINK仿真器,对不起,用不了。9 d+ m0 Q8 ?( |7 W+ ~
' c% S- [$ U$ q. I+ ]5 B4 W' L
3. PRINTF_SWO == 1,SWO的方法,这个是启动内核的ITM功能。" H0 c  a* Y! z& E0 [4 h
优点: 对原程序流的影响最小。 标准的JTAG/SWD/STLINK连接器,都已经准备好了SWO线,也算方便。4 \, M; W4 ~  u+ b) J
缺点: 相比2线的SWD,需要硬件连接一条SWO的输出线。 不能实现双向通信(其他方法都能)。" B* ^5 T. T7 z, U
            软件配置SWO功能比较复杂很容易失败,重点是要做SWO速度匹配。
6 h: f$ b! w3 d) h8 j; I& G            SWO方法不能在JTAG模式下使用,只能是SWD模式。另外,ARM Cotex-M0/M0+也不能用。
7 ~3 F# d/ u& L# S            MDK/Keil有内置的SWO Viewer,不过不好用,一定要进入Debug模式,好处是各种仿真器都可以用。  }/ q- b- m) c. S
            J-LINK 和 STLINK 仿真器,有自己的独立的SWO Viewer,不需要Keil进入Debug模式那么麻烦。
! r$ }3 h* H; x2 u8 U
; X5 E2 I; |8 T( [3 [. U* `4. PRINTF_CDC == 1, CDC的方法,比较逆天的,属于玩具级别,你想用我都拦不住。
4 a1 M1 z/ P8 k7 v  j$ t6 [优点: 用法与UART一样,各种串口终端软件通杀。" c7 h& Z6 Y: U1 J1 ]; b& s0 J$ j
           不占用串口。 利用IC本身的CDC-VCP节省了UART转USB接口板。$ F9 d+ l1 y$ D5 L% J& O6 c: J
缺点: IC要有USB硬件,代码增加,软件复杂度增加。* w! P6 U+ [! A- K" _6 t

+ |: u9 B: F$ m: H' N1 n实用中,还有一种方法,称为半主机模式(semihosting),据说速度慢和影响原程序运行严重,没有认真研究过。我甚至怀疑,上面的4种方法里面,有可能有后台使用了半主机模式,知道详情的朋友,请介绍一下。0 c1 a( P) I# U8 q* M  C& ^
; e$ c0 y- O7 T7 H; m  \$ w
毕竟printf指令对原程序流是多余的操作,或多或少都会干扰原程序流,特别是在一些速度比较慢的MCU上面。因此,printf的输出项要尽量简短,避免大量连续使用。 如果估计占用MCU时间太多,就要做需求评估。: G) ?: W" C4 U  R
6 m  J# Y' D* p' l, y1 Q

5 U9 C8 L1 }+ b附件是F103/F407用的完整的工程,与github上传的一样,上面的4种方法都有,可以试一试实现。
; G7 U* c) L, K# S9 C& Jgithub:https://github.com/RadioOperator/STM32_HAL_retarget_printf* k0 k6 I# ^$ v: p- ?* U

( w2 O1 Q; a4 g4 ~
2 v+ n  H' J' V9 e$ b2 s# v3 W+ G& ~7 P2 Z. Y

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  E# f: e+ A- |
支持老兄,点个赞
! w4 R$ i$ r' Q  W. }
多谢您的鼓励。4 Z5 p7 d6 U6 W( X5 S7 A8 b
我还是把F407的例程放出来了,同时也上传了github,留个记录。

所属标签

相似分享

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