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

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

[复制链接]
radio2radio 发布时间:2020-12-13 19:15
为什么要用printf,废话,不用你用啥? 我在下面的把printf换了一个名,LOG,少打3个字。您也可以换成您喜欢的字母组合,这不是重点。  }, |4 W- X1 |1 @

, R' ?7 r5 M" ?) o# S4 G/ Q说是“解决方案+史上最强”,也不过就是下面的几行代码。
5 E5 a; \5 O3 o8 b' q笔者仅在CubeMX+HAL+MDK+AC5下,测试过F1和F4。 其他环境要修改后使用。+ @) d' m; D9 _. W
6 }+ P- j* n/ d+ z/ _
  1. #include <stdio.h>
    & Q' \0 Q1 d' v$ d# L
  2. #include <stdlib.h>
    6 q- a6 J5 L1 i9 M
  3. #include <string.h>
    # i# y2 S; {0 c4 y3 [

  4. ) c; Q4 ]0 r# d8 N4 U, F6 g
  5. //Debug mode On/Off switch
    2 L* f7 p1 S# H
  6. #define DEBUG                   1 //set=0, disable all LOG lines* C/ g6 s* {. C! A

  7. : m5 W; {, y2 G5 {
  8. //select one of the following "printf" retarget methods, r& E' f6 j& }1 }$ X
  9. #define PRINTF_UART             0 //printf using UART port, 1-use this, 0-not
    % h# G$ q& I/ |2 l9 U; m0 Z9 f
  10. #define PRINTF_RTT              1 //printf using Segger RTT, 1-use this, 0-not; f6 i  D5 f/ @9 r1 B% b8 ]. v+ j
  11. #define PRINTF_SWO              0 //printf using SWO port, 1-use this, 0-not
    7 p, l9 C( S/ Q, w) u% b6 Q) U
  12. #define PRINTF_CDC              0 //printf using USBD_CDC, 1-use this, 0-not9 P  r3 {! w0 p
  13. , i& N+ l5 g" z8 ]' ~' T" N% z0 u
  14. #if ((PRINTF_UART + PRINTF_CDC + PRINTF_SWO + PRINTF_RTT) != 1)# V# k: ^0 I$ g. ~
  15. #error "!!!!!! printf retarget function Not define or Multi-defined !!!!!!"7 k4 o+ E" k% L, C3 k( @5 t% W
  16. #endif8 r8 E) m7 k( C

  17. / K0 r* `) ]& i7 d: @0 _' a2 X/ l, h
  18. #if DEBUG9 t* q& x! P, N9 c$ n
  19.   #if PRINTF_RTT% N8 |5 ^8 s0 r7 d) h  H
  20.     #include "SEGGER_RTT.h"
    3 |- Q( p- y6 t# s1 E
  21.     #define LOG(format, args...)  SEGGER_RTT_printf(0, "[%s:%d] "format, __FILE__, __LINE__, ##args)$ t4 ]3 {& p! z# r
  22.     #define printf(format, args...)  SEGGER_RTT_printf(0, format, ##args)+ d2 M" y' n9 l% d  \% r
  23.       t' i, W( ]; v+ K
  24.   #else //#if PRINTF_RTT
    + O: i. b4 {& X4 {$ c4 F3 A
  25.     #define LOG(format, args...)  printf("[%s:%d] "format, __FILE__, __LINE__, ##args)
    6 v2 r! ?6 D) K+ R+ d" G; n
  26.    
    : b4 ]4 I  N3 i; n0 D4 i% |& J
  27.     #if PRINTF_CDC+ f1 n# ^# ]( w; S8 A" y
  28.     #include "usbd_cdc_if.h"
    $ P( I$ m& Q; f+ Y3 C7 i* ~
  29.     #endif
    / i3 i: q3 p( {0 `
  30.    
      V0 C8 ~* N7 T
  31.     int fputc(int ch, FILE *f)
    7 Q6 t. b! d/ n+ w
  32.     {( V3 V% \$ Y5 z, Z/ R+ ?' }  A$ |. G
  33.       #if PRINTF_UART
    8 P/ C8 R0 a8 F. G7 \, ^
  34.         HAL_UART_Transmit(&huart3, (uint8_t*)(&ch), 1, 1000); //UART3
    4 a$ Y7 K" v- q& D1 ]
  35.         1 X7 V& d% V  d5 a4 i& [5 H
  36.       #elif PRINTF_SWO
    - ~1 E* s8 B2 X# `( ^0 D, Z
  37.         ITM_SendChar(ch);2 N( d( X. v8 {! |: e8 i3 y
  38.         8 ]4 m6 _$ r/ k; z( h& d( }" k: f) h
  39.       #elif PRINTF_CDC1 j0 X2 J( t3 {2 }9 n
  40.         uint8_t u8Temp = 0;0 R- v) R3 ^$ y/ q0 Y
  41.         while(CDC_Transmit_FS((uint8_t*)(&ch), 1) != USBD_OK)- i# i, o1 ~6 c( Y
  42.         {
      \4 T  e0 \% y  N
  43.           HAL_Delay(1);7 W! ?$ r0 Z; k  v
  44.           if (++u8Temp >= 3) break;% p5 o4 {  d0 s0 m
  45.         }% c6 Z! ?) W) Q2 ?+ h
  46.       #endif //#if PRINTF_UART3 ]! x& J& }. _" K. F! s; m
  47.         
    " V, v3 n7 y, M; x
  48.       return(ch);! n" L7 ?( g7 {% i6 H
  49.     }+ e6 ?6 O  w1 ?2 l: |5 u, @
  50.   #endif //#if PRINTF_RTT
      l# ?* j2 C1 X4 \$ N+ M
  51.   
    + s: K. f% ^) M# ~; b
  52. #else //#if DEBUG == 0
    ! H$ t2 S) ^: `
  53.   #define LOG(args...) //disable all LOGs when compiling
      X. r' b+ ]* i' I( }
  54. #endif //#if DEBUG
    0 ]1 K) p9 A" d) X8 t
复制代码
8 `9 Z" T. p; I/ g- j" H' r7 ~
这里有4种方法重定向printf,必有一款适合你:3 R# R; T6 r) R' c- ]

2 h% l5 h2 D* {5 S) s; }) l: O/ e1. PRINTF_UART == 1,串口方法。
& B. v0 W- w: [6 }! j" T优点: 就是最多人使用的,大家也最熟悉。 配置简单,容易使用。 各种“PC终端软件”都能用。
( T6 ?, Y2 t9 p8 i; z5 A缺点: 硬件上要有串口可以用,有时还需要UART转USB接口板(或者仿真器自带VCP/CDC的东东)配合。
, y! p4 A( W. J8 Y/ l% n: q( O" U4 O5 P" Z1 d9 ?
2. PRINTF_RTT == 1,Segger_RTT 方法。  (笔者推荐此方法,至少值得尝试一次), 要安装RTT包,简单!5 G1 k) j1 Z# Y, A9 T2 k$ q; ?
优点: 不占用额外的硬件资源, 据说速度超级快。 有多快,我不知道。# f& {, K$ z. \5 i6 a8 e. K/ W% _
缺点: 要使用专用的PC软件接收,既然是仿真器大佬Segger的产品,自然是Segger的驱动程序功能多多。
, N5 h0 \/ H. A' O$ k           使用J-LINK仿真器,就一定要用JLinkRTTViewer等终端软件。
" I$ w0 r; w1 O) e; c- s5 q% G           使用CMSIS-DAP仿真器,可以用DRTTView终端软件, 多谢XIVN1987网友 ,不然DAP就不能用RTT了。
8 }; S6 k$ P+ Y- J           使用STLINK仿真器,对不起,用不了。
) j5 ?2 y9 Y- F0 w1 f5 K0 r6 e' X+ w4 A" B& U
3. PRINTF_SWO == 1,SWO的方法,这个是启动内核的ITM功能。, w, d5 d! N- D9 a: y
优点: 对原程序流的影响最小。 标准的JTAG/SWD/STLINK连接器,都已经准备好了SWO线,也算方便。
' X) L* v; P6 _' W! Z缺点: 相比2线的SWD,需要硬件连接一条SWO的输出线。 不能实现双向通信(其他方法都能)。
0 i8 i0 S( L% X0 a9 E8 S/ Y            软件配置SWO功能比较复杂很容易失败,重点是要做SWO速度匹配。
, W: N% `& i) x( @% K+ }- L            SWO方法不能在JTAG模式下使用,只能是SWD模式。另外,ARM Cotex-M0/M0+也不能用。; F+ S& h: c/ r4 D
            MDK/Keil有内置的SWO Viewer,不过不好用,一定要进入Debug模式,好处是各种仿真器都可以用。
0 l1 K1 h0 a$ J8 r# r6 m9 e6 S$ _            J-LINK 和 STLINK 仿真器,有自己的独立的SWO Viewer,不需要Keil进入Debug模式那么麻烦。
; Y* K4 h# S) f$ x! H( i
* Y" F% ~# Z$ k5 |' X/ L8 e  D% Q3 ?4. PRINTF_CDC == 1, CDC的方法,比较逆天的,属于玩具级别,你想用我都拦不住。
6 ~$ E  i" j$ f5 u2 S8 F优点: 用法与UART一样,各种串口终端软件通杀。
3 }" }) R9 x( {0 E5 N           不占用串口。 利用IC本身的CDC-VCP节省了UART转USB接口板。2 Y0 J3 t* {1 m) f# N
缺点: IC要有USB硬件,代码增加,软件复杂度增加。
. @: I$ @% @& s. t3 f
' P" s4 s; N7 N  v0 D实用中,还有一种方法,称为半主机模式(semihosting),据说速度慢和影响原程序运行严重,没有认真研究过。我甚至怀疑,上面的4种方法里面,有可能有后台使用了半主机模式,知道详情的朋友,请介绍一下。
* T6 a. o% ?. v& W2 B0 N  @% Z3 N0 a. \2 G: i7 q7 g
毕竟printf指令对原程序流是多余的操作,或多或少都会干扰原程序流,特别是在一些速度比较慢的MCU上面。因此,printf的输出项要尽量简短,避免大量连续使用。 如果估计占用MCU时间太多,就要做需求评估。6 d  y8 c- Z% x' r( [; ^3 R, @2 r

( y) R1 E6 M  ^4 h2 s+ j0 j
0 ^+ F5 Q) F2 |3 `) `9 x$ G附件是F103/F407用的完整的工程,与github上传的一样,上面的4种方法都有,可以试一试实现。
) P: ~) f, D* @github:https://github.com/RadioOperator/STM32_HAL_retarget_printf
* }0 x. T4 j) G% t. @
8 C& n: h4 R  r  `/ ~( r
' A) ]: H" u+ ~" o1 V# N
' Z" G. D* ^( @- A, H# J6 y/ I2 B& b2 K

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' V, O: m/ I+ o: w
支持老兄,点个赞
- d, h" q; e+ }+ c& h2 E
多谢您的鼓励。. R* C8 f3 U: m! @
我还是把F407的例程放出来了,同时也上传了github,留个记录。
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版