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

实战经验 | STM32G474 FPU 性能优化与测量

[复制链接]
STMCU-管管 发布时间:2024-10-30 16:57

5 o' P5 b, T! V7 L* F01引言) Y" b) F8 Q% C8 A1 S3 k' v4 s
客户在使用 STM32G474 时,希望使用 FPU 进行浮点运算,并最大化其性能。本文 从 STM32G474 系统的角度、ARM DSP Lib、编译选项的影响等几个方面探讨如何提升整体性能,并介绍如何使用 KEIL 工具进行测量。8 z9 T0 b0 m! Y  v
0 x) N2 j5 \! ]
02STM32G474 FPU 运算性能优化
6 E, R% w2 l4 @$ Z( T2 }% B* J2.1. STM32G474 系统性能优化 9 P' t, H" I# q8 [" V1 e
. d# b* X' |4 P( b7 b( M
STM32G474 使用的是 ARM Cortex-M4 内核(+FPU)。一般代码会放在 FLASH 区, 通过 I-Bus 读取。这里 STM32G474 有 FLASH 预取指及 CACHE Line, 无需放入 IRAM 或 CCM。因为 Cortex-M4 DSP 指令中没有运算指令与加载指令并行的混合指令,所以数据 存放区域及 Bus 的选择理论上对性能的影响不大。如下图 1 所示,可将 FPU 运算数据放 在 SRAM1。另外还需尽量避免 SRAM 的并发访问,如使能了 DMA,DMA 传输目的地 可以使用 SRAM2,从而减少潜在的 SRAM 并发访问产生的性能下降。应用则需要根据实 际情况,合理使用内存区域。
! }7 l5 J% K5 Q" h4 \4 c
12.png
▲ 图1. STM32G474 架构
/ Q* T- ^' [1 Q' ]& S4 ^; q$ p

! S" M) ~2 i2 v, ~/ |# ]6 k2.2. ARM DSP Lib 的使用 / g$ ~0 S$ ]+ k6 d" I0 T1 v+ [
在 ARM DSP 库实现了很多 math 算法,可进行浮点乘加、点积、卷积、FFT、NN 等 多种算法 API,可以使用 ARM DSP 库高效使用 FPU。ARM DSP 代码位置如下:  x2 G/ c2 e3 S; ~
14.png

. q, J& r7 M. [' `" u1 I. V$ Q2.3. 示例代码
: w: n$ y# i2 r3 j# i下面示例代码中对浮点乘法运算进行了测试。用户可以使用 STM32CubeMX 生成 STM32G474 KEIL 工程,在 main.c 文件中加入如下示例代码:% k# M- u+ `- C( T  g

  1. 0 R1 W- M& t8 g/ i
  2. __attribute__((section (".TEST_INPUT_A"))) float32_t testInputA[1024] =
    ' r6 R0 v8 M* a2 t! K% {
  3. {
    0 c( I4 t, N+ }( \+ b* D0 G; W
  4. 0.623234f, 0.799049f, 0.940890f, -0.992092f, 0.212035f, 0.237882f, -
    - d; k6 k% p' w# W6 \: Z" s
  5. 1.007763f, -0.742045f,
    2 S# H4 Y5 z6 X6 T# P/ V
  6. ~~ 这里数组使用动态生成的float数据,数据量较大,略8 L& d( X, F, |2 ]
  7. -0.417470f, -0.205806f, -0.174323f, 0.217577f, 1.684295f, 0.119528f,+ y: i* @& x2 @) {
  8. 0.650667f, 2.080061f
    9 Z/ B" Q4 ], d* a+ ]+ ]& Q! y1 a
  9. };8 W- J1 g2 M+ d: H# I
  10. __attribute__((section (".TEST_INPUT_B"))) float32_t testInputB[1024] =
    & _* ?* g0 h+ ~' S3 }4 W' t
  11. {
    : K* _  k- |! F5 Z  s" {
  12. -2.423957f, -0.223831f, 0.058070f, -0.424614f, -0.202918f, -1.513077f, -
    6 N4 y) _- u& V8 L) w2 i
  13. 1.126352f, -0.815002f,9 F  N& U0 t, n( l, @$ n" A+ U" g
  14. 2 v! W5 o* P4 B8 o6 k
  15. ~~ 这里数组使用动态生成的float数据,数据量较大,略 1 m% S6 l# S1 {7 Q0 w9 T  v- z
  16. -0.447001f, -0.725993f, 0.354045f, -0.506772f, -2.103747f, -0.664684f, 1.450110f, -0.329805f 0 G8 |: a0 X4 P, \4 h  L$ T
  17. };
    3 J  L, w4 O- U* @0 N' v& e

  18. " R/ T  l- U$ ?9 b/ d: e* Q( R9 b7 b% a
  19. __attribute__((section (".TEST_RESULT_D"))) float32_t testResult[1024]; * @/ r4 ~. ?0 }) H3 T6 i4 H
  20. $ A" G9 M6 ^! E4 h  d% f' m
  21. float32_t* pA;# m! L/ N: D3 n" x
  22. float32_t* pB;
    % j+ B$ f6 M; b, U
  23. float32_t* pR;
    6 G3 ~6 f5 h4 u3 q; y
  24. /* Private user code --------------------------------------------------*/
    ' |9 F) X$ q, A, ]
  25. /* USER CODE BEGIN 0 */ . g( x2 C4 E) x. `, @& J) `% D
  26. void test_normal_mul(uint32_t kLoops, float32_t* 4 A0 j7 Z( c5 C5 d3 O
  27. pSrcA, float32_t* pSrcB, float32_t*
    ! J5 r3 \( H+ l
  28. pResult, uint32_t lenVector)
    2 x; Y% C) Y( H2 W
  29. {   c; |4 D' z7 [7 I
  30. for (uint32_t j = 0; j < kLoops; j++)
    - y7 Z& R0 S  `
  31. {
    3 F& q6 S' _, N# R
  32. pA = pSrcA; * l7 c$ j: y+ f* x- r
  33. pB = pSrcB; % K4 {. [( ]5 d7 J' ?. d6 J
  34. pR = pResult;
    : u$ w8 Y* f0 t7 [1 |' j1 q- `

  35. * O5 ]) r6 L: X  q7 ^9 H+ Y
  36. for (uint32_t i = 0; i < lenVector; i++)
    , U$ B3 g$ W0 j. H5 b
  37. { *pR++ = (*pA++) * (*pB++) ; # e& W5 h: T- K) T
  38.    } 9 \. G. r+ n0 w( O0 ]
  39.   }
    2 V. q+ U" }' N) C/ u. q9 T
  40. } ; {1 g  Y5 H2 u( j9 ?$ d" r) O
  41. : ^4 Q1 U& G+ t* R2 A1 m
  42. #if defined (__FPU_USED) && (__FPU_USED == 1U)
    $ Q' ?0 y7 U, L2 x2 f& _
  43. /* Use arm dsp lib to test basic operation Multiply, FPU enabled */
    1 P. K% u# A& T5 @
  44. void test_arm_math_mul(uint32_t kLoops, float32_t* pSrcA, float32_t* pSrcB, float32_t* - I; t' t* T$ @+ Y  M$ i
  45. pResult, uint32_t lenVector)
    ; \1 X; O( ]9 Y1 W
  46. { 4 ]) b/ m+ w0 u: C) x
  47. for (uint32_t j = 0; j < kLoops; j++) ' \2 q& c3 x9 @) X7 _
  48. {
    " V; ]) ]6 E3 y4 I9 g: g
  49. pA = pSrcA; //Code alignment with the function without FPU 5 V! j* I( @/ X/ ~+ ?' n) z
  50. pB = pSrcB;
    . I; t( Z2 g" ?; l! R, U6 }
  51. pR = pResult;3 ~( L" |6 C0 @5 P' d
  52. arm_mult_f32(pA, pB, pR, lenVector);
    3 ]" u6 v# G$ m- T! w6 I9 m
  53. }
    0 @% F& M" v3 \, M( o4 t. O
  54. } 7 A2 x0 r0 l( H- ]
  55. #endif 9 x$ p  ?4 \% N, G/ a1 K7 g
  56. ) A! A  @8 |2 e  q* V% ?+ M- {) m
  57. /**
    5 h% P& B, k# u: T8 T. Z* r
  58. * @brief The application entry point. " C. W. J6 b- q* j9 R( d) n
  59. * @retval int
    4 y2 L- o6 o4 {" Y( M: q
  60. */
    3 X9 ^6 p: p- D3 S2 k! M0 [1 k
  61. int main(void)
    ) u! n7 b# P% o* F. B1 U
  62. { 3 K9 n/ T+ y! Y: [
  63. /* MCU Configuration------------------------------------------------*/
    - ?9 i2 }* x# |0 g$ ]( ]
  64. 3 `8 S2 K: N8 C4 b! k6 @6 \) s
  65. /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
    ' x& |& p# y; T& _5 r' }5 Y
  66. HAL_Init(); - Q3 |4 U3 |$ R2 c" R0 R
  67. # ^: d7 |# O9 {. p6 g+ J% F" W5 |
  68. /* Configure the system clock */
    + t7 V. X& K% M  k# Z
  69. SystemClock_Config();
    3 ~: I8 f6 a8 T5 i/ k

  70. 6 s; u" y" d% V5 |

  71. 1 L8 K1 n) f/ b( c. B5 t' E+ W
  72. . \1 Q: i1 o1 V
  73. HAL_Delay(100); 5 {8 T0 b# n9 e* W8 Z! |' O0 b; e
  74. 3 z: h! s/ A# c( s0 w
  75. /* USER CODE BEGIN 2 */
    5 }7 L9 l9 Z" \1 m& u5 p- d7 ~
  76. test_normal_mul(10, testInputA, testInputB, testResult, 1024);7 g" r5 B3 d! _  L1 [
  77. test_normal_mul(10, testInputA, testInputB, testResult, 1024);
    ( {9 q/ c4 F4 N7 A8 ]
  78. . C8 U$ S  s4 H+ j/ {' o- O) S) Q
  79. #if defined (__FPU_USED) && (__FPU_USED == 1U) ! l9 E" q& R8 z' E! t
  80. // Multiply calculation with arm dsp lib ' y8 U4 P: B3 h6 G6 _" X/ S
  81. test_arm_math_mul(10, testInputA, testInputB, testResult, 1024);3 j' k: Y" b& t$ Z4 e
  82. test_arm_math_mul(10, testInputA, testInputB, testResult, 1024);
    - K1 n/ E+ y+ T: M1 K" H/ g
  83. #endif
    8 K! g; x! h# g4 i1 J

  84. 1 k2 I; W! b+ n, G0 [% p5 s! g
  85. /* USER CODE END 2 */
      z& N/ N: c% a1 M3 v0 D
  86. 4 e6 D. Q  H+ C# I* _
  87. /* Infinite loop */ ' H8 Y8 Y4 C$ |
  88. /* USER CODE BEGIN WHILE */ 5 c* G3 F' I( y; x! K
  89. while (1) ! k2 Z- U1 x6 _) L# d
  90. {
    7 _1 y: L" B# h
  91. /* USER CODE END WHILE */ 5 x; L# G0 Y" s+ F& Z$ X

  92. 6 l* y/ ~7 L( {- S1 t) Q
  93. /* USER CODE BEGIN 3 */ ) \6 e% h9 J. U3 t, S
  94. }
    # x; i7 A( B. w) G  t
  95. /* USER CODE END 3 */ / D( R8 u% R3 n0 z! [
  96. }
复制代码
2.4. 工程配置 2 P; O8 Z  ]; i+ n
通过 KEIL 工程 Options / Target, Floating Point Hardware, 确定 FPU On/Off。
( C- ]' ^* x, h7 q0 |
15.png

) x% @* v' n# f' p( @) j' h

! f  I7 x) f7 {* Z: w
▲ 图3. KEIL 项目工程 FPU 单精度浮点设置
通过 STM32G474_FPU_TEST.sct 文件配置 Data 存放区域,如下例,将测试数据置 于 SRAM2。
. ^2 B7 U3 Z: L. W

  1. 2 e- ]* I* G- M- j" {
  2. RW_IRAM1 0x20000000 0x00014000 { ; RW data
    2 e# D, Y! l/ y* X* a
  3. .ANY (+RW +ZI)
    ! T" }; B1 k! ]$ h! \
  4. }
    - A; R5 d" u/ o$ F3 Q; M; ?
  5. RW_IRAM2 0x20014000 0x00004000 {+ N: b! J7 w& j
  6. *(.TEST_INPUT_A)$ p0 {. W4 E; P
  7. *(.TEST_INPUT_B)1 C! R- s- @6 d! N4 E6 y
  8. *(.TEST_RESULT_D)
    * b, I6 h9 j, j* T" f& W
  9. }/ F% f$ I. I8 k" w  v: M5 p* A
  10. RW_CCM 0x20018000 0x00008000 {7 j7 C( y) I3 M4 ~" z, h' F+ R% K! Z
  11. }
复制代码
完成后,进行编译链接,即可进行 STM32G474 FPU 性能的测试。, X& r8 U- l8 e3 T

3 L, C4 O4 E" }! B8 t2.5. 编译选项 ; R1 e$ S4 }, F5 X
本文中我们使用的是 KEIL IDE,设置使用的是 KEIL Compiler V5。为了获得代码最 大程度上优化,我们使用了-O3 优化选项,与-Otime(Optimize for Time)结合使用。该组合选项意味着会进行更多代码优化,如循环展开,更激进的函数内联和自动函数内联 (-O3 默认使用--autoinline)等,当然副作用是二进制代码大小会有所增加。另外,增 加设置 --loop_optimization_level=2 来控制循环展开的优化等级。(注意:-- loop_optimization_level=2 选项只能与-O3 -Otime 一起使用。)如果您对 FPU 架构比 较熟悉,也可以尝试增加—fpu=fpv4-sp(Cortex-M4F FPU 实现的是 FPv4-SP 浮点运 算扩展)等选项,不过一般使用默认即可。
# f8 m; M& c% Q7 w5 Y9 `; I
16.png
▲ 图4. KEIL 工程,编译选项设置
03使用 KEIL Trace 工具进行测量
; h! o" f+ V, A8 k9 P) ]3.1. KEIL 工程设置
0 ?4 j# [* i) g; U5 ]7 N: w
' i* j% @9 E2 ^KEIL 工程下,首先选择工程选项设置,在 Debug 选项页中,右上部使用 Debugger 工具栏中选 Settings,如下图 5 和图 6 设置。注意 KEIL Trace 设置的时钟必须要与实际 STM32 使用的系统时钟相一致,如图 6 中,STM32G474 使用了 170MHz 的系统时钟, KEIL Trace 中也要相应设置为 170MHz。3 y) Z8 D* l0 ^7 F
17.png
▲ 图5. KEIL 工程,Debugger 设置入口
18.png
▲ 图6. KEIL 工程,Cortex-M Trace 功能设置
运行KEIL debugger,如下图7所示,将断点设置在要测量的语句前及其后,执行 代码,当Debugger停在断点时,其状态栏中t1指示的即为当前代码的已执行时间。测试代码起止时间差即为代码执行用时。该Trace功能计时是比较准确的。当然如果您希望掌控更多,也可以通过代码来实现,如增加诸如如下代码:
7 V2 o% P1 G# i! G1 h' G" VnStart = DWT->CYCCNT;
# z) M3 V& X0 b5 e8 y~~~需测试执行时间的代码~~~
8 j- c7 X  b: q2 _2 H" W0 HnStop = DWT->CYCCNT;
- K0 ^& @! E  x. N' s; ]0 T; J1 H然后用(nStop – nStart)/系统时钟,换算成时间即可。(我们这里没有考虑中断,一 般测量前需要禁用中断)
; e+ ?% q; K' b2 o3 v4 c
19.png
▲ 图7. KEIL 工程,Debug 模式下 Trace 程序执行时间
3.2. 测试结果
* u: K$ i, ^; T7 U) D% h下表列出了STM32G474 10K次 浮点“乘”用时统计。' C, M! j/ r, n  [2 N
20.png
▲ 表1. STM32G474 10K 次 浮点“乘”用时统计表
10 X 1024次浮点乘
' c- P4 S4 }! E0 r6 k9 Q

$ B+ [$ r: k. X8 J1 e增加--loop_optimization_level=2 编译选项
% H3 n) D% x) q" P, O
: R! g+ G! O3 r& Q$ I- {" x; x
FPU 核心汇编代码的比较,见图8和图9。9 _; d+ v: {, \: |+ I) h$ {3 r
21.png
▲ 图8. 使用--loop_optimization_level=2 编译选项的常规代码汇编
22.png
▲ 图9. ARM DSP 库 arm_mult_f32 函数汇编
1 N! s- ^; [3 ~2 _+ J
$ O5 k, R, p6 y; V- O$ Y2 Z: a7 C  @
使用loop_optimization_level=2, 常规代码使用KEIL compiler V5编译结果与 arm DSP Lib 的核心汇编基本相同。如果不使用loop_optimization_level=2编译选项, 则可以看到其主要区别在于KEIL Compiler V5 与ARM库对loop的unroll 处理程度不 同。在实际应用时,需要根据应用自身需求判断是否需要使用ARM DSP Lib,基本上 ARM DSP Lib是很高效的。0 p. b! Q7 s3 p$ \5 P

* ]% h0 E  a2 p9 v, R* J1 {; ~04小结
- `" s( [5 w% V0 `' m本文介绍了使用 STM32G474 FPU 进行浮点运算,从系统的角度、ARM DSP Lib、 编译选项的影响等几个方面探讨如何提升整体性能,并介绍了如何利用 KEIL Trace 工具进 行测量。以供在系统性能方面有需求的客户参考借鉴。
* j4 _* U* u0 I6 K6 N5 ~' j, @3 x  R7 e& Z
; Z- M& t1 K( a* }/ S$ |
如果你有其他想要的实战笔记,可评论区留言,管管来跟工程师沟通!
9 l  \) D& l  S
- G7 J" B$ i' A. b8 O! `: i/ a; @% x- l" }6 t
/ J( t! c8 g$ U3 [* ~5 {* m+ `& s  r

' e. j, b+ K( l1 I$ G( Y1 }- G
& _  v' ^% u% b' `2 L1 w# a! J/ Y7 ]$ K) b4 M$ ]2 P

5 x, c2 M& s- C' H$ ^- h% z: d, N, ^+ w& `: @

  X+ f( t6 M; }$ @, u5 \( `/ a6 R0 G. i" b* S4 n' w% O7 U( x
! ^  w6 i2 g% f; l

$ G- Y9 y2 a( s8 L/ T- {5 \8 I3 Q# @
收藏 评论0 发布时间:2024-10-30 16:57

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版