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

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

[复制链接]
STMCU-管管 发布时间:2024-10-30 16:57
! v# g+ E5 y) _9 D/ n4 L
01引言) m" U) Z: v5 y' r
客户在使用 STM32G474 时,希望使用 FPU 进行浮点运算,并最大化其性能。本文 从 STM32G474 系统的角度、ARM DSP Lib、编译选项的影响等几个方面探讨如何提升整体性能,并介绍如何使用 KEIL 工具进行测量。4 F9 J' A' V: g, f4 R7 y6 M+ }

/ R/ _' }+ F" s02STM32G474 FPU 运算性能优化 3 m# G; q& e% Y7 C" N2 c
2.1. STM32G474 系统性能优化
( S- Z/ T% e0 j+ ^! W1 g! W& K' O8 a2 t
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 并发访问产生的性能下降。应用则需要根据实 际情况,合理使用内存区域。0 s1 m4 R, y8 M& c
12.png
▲ 图1. STM32G474 架构
/ B8 r! G0 L( A# C
3 f& e6 h3 }7 _7 \9 P( I
2.2. ARM DSP Lib 的使用
/ D" N' c; p5 ^, a在 ARM DSP 库实现了很多 math 算法,可进行浮点乘加、点积、卷积、FFT、NN 等 多种算法 API,可以使用 ARM DSP 库高效使用 FPU。ARM DSP 代码位置如下:
0 T7 }3 A) H0 q0 l, k1 L5 l6 |& }
14.png
; y8 H6 D8 Q( |# |  u
2.3. 示例代码
! w& K2 y/ D: z6 X' M! M下面示例代码中对浮点乘法运算进行了测试。用户可以使用 STM32CubeMX 生成 STM32G474 KEIL 工程,在 main.c 文件中加入如下示例代码:8 f8 d4 i0 U( g8 p+ _- g5 |: T
  1. 5 m! K$ j5 \/ L# j' c8 s( E0 `
  2. __attribute__((section (".TEST_INPUT_A"))) float32_t testInputA[1024] =
    / B/ I% ^0 a/ t% {, e5 u' L+ V
  3. {
      v6 a# u4 i2 a( O- m
  4. 0.623234f, 0.799049f, 0.940890f, -0.992092f, 0.212035f, 0.237882f, -- Q" U6 y7 x; k- j" j3 o# W$ E6 ]
  5. 1.007763f, -0.742045f,0 C# u1 q2 V  D. y$ m5 O5 g
  6. ~~ 这里数组使用动态生成的float数据,数据量较大,略, T# F( Z# a3 Z; m  Q
  7. -0.417470f, -0.205806f, -0.174323f, 0.217577f, 1.684295f, 0.119528f,+ b+ Q, U( w  ]& Q, Y
  8. 0.650667f, 2.080061f% L: V8 n+ _* `( V. V4 a( c5 k. r5 ?
  9. };
    * E5 K2 j: v7 i3 r% e5 e* r2 f
  10. __attribute__((section (".TEST_INPUT_B"))) float32_t testInputB[1024] =
    4 M' }+ l3 u2 Y+ b  v! t
  11. {0 h( H$ ]6 i. J5 w# z% C& M
  12. -2.423957f, -0.223831f, 0.058070f, -0.424614f, -0.202918f, -1.513077f, -
    ! H9 Z! b% E% n: A2 u3 I) e
  13. 1.126352f, -0.815002f,. G- k# L0 C6 [% R) r: z+ f
  14. * @& \+ U  L* f9 a% |
  15. ~~ 这里数组使用动态生成的float数据,数据量较大,略 ( T$ B' N* F2 R, d
  16. -0.447001f, -0.725993f, 0.354045f, -0.506772f, -2.103747f, -0.664684f, 1.450110f, -0.329805f
    1 J' n. \/ n* S
  17. }; . k& [9 V. {1 t0 h5 |. r

  18.   ~/ |' Q8 @' j# H+ I! g" w
  19. __attribute__((section (".TEST_RESULT_D"))) float32_t testResult[1024]; & R; a6 |7 L& ^2 f/ M8 \8 l
  20.   L* g% O; E/ R, P# u# n
  21. float32_t* pA;3 O& r. M7 @" k) g, L# k& |! R6 E3 ^9 ?
  22. float32_t* pB;
    , [: j+ y0 z, X( H/ K7 O8 w: I
  23. float32_t* pR; . A4 p' T) l* ?
  24. /* Private user code --------------------------------------------------*/ % |0 w- w0 b% V- c: }, n- @
  25. /* USER CODE BEGIN 0 */ : H0 }' V8 N) Q' s  a
  26. void test_normal_mul(uint32_t kLoops, float32_t*
    2 i; C3 y% g, b1 D5 R, [
  27. pSrcA, float32_t* pSrcB, float32_t*
    2 s3 t8 j6 \; c& U9 `
  28. pResult, uint32_t lenVector)
    ; T9 @; M% a2 i+ F5 _0 b9 T
  29. {
    ' H. D2 y3 k2 R) H
  30. for (uint32_t j = 0; j < kLoops; j++)
    0 o/ `. v8 a1 p$ C0 ]
  31. { 5 g. R# |2 A0 M5 Z5 S) ^; e
  32. pA = pSrcA; 2 {* |2 N7 @( J# |& g
  33. pB = pSrcB;
    . W; [$ n, C' E; h
  34. pR = pResult;
    * g' Q6 ~) B: @: B6 C
  35. 7 R3 f/ X, c0 _+ H/ E
  36. for (uint32_t i = 0; i < lenVector; i++) 7 G1 `. k. S! `+ m4 a& r$ r
  37. { *pR++ = (*pA++) * (*pB++) ; 1 ?/ \9 _+ \1 B6 e& E
  38.    } & {/ f$ t' O7 ]8 w+ K& `6 V, M
  39.   } - ~0 A; }8 V2 }0 I( h' X
  40. } ' Q+ e4 n: r8 ^. R3 m8 M& z1 e

  41. 7 \* f4 c' [  E
  42. #if defined (__FPU_USED) && (__FPU_USED == 1U) 6 E, r! ]+ O2 @; Q* T" r
  43. /* Use arm dsp lib to test basic operation Multiply, FPU enabled */
    3 Y7 X2 D2 c/ h1 w$ z" ^
  44. void test_arm_math_mul(uint32_t kLoops, float32_t* pSrcA, float32_t* pSrcB, float32_t*
    ' C, r' g! n4 j* N; C5 ~3 Z$ d
  45. pResult, uint32_t lenVector)
    ) M& x* X0 K: ]. `& Q
  46. { $ W( e9 b1 O' }  _
  47. for (uint32_t j = 0; j < kLoops; j++) 3 j5 w* h* m, N% K# U% k
  48. {
    ; i$ R# l$ Y* A: k4 ?5 R' B
  49. pA = pSrcA; //Code alignment with the function without FPU 0 m! g5 v( F& i. T' t
  50. pB = pSrcB;
    8 ~; I4 C( [4 C6 k
  51. pR = pResult;
    / z% e1 s* w) I% X
  52. arm_mult_f32(pA, pB, pR, lenVector); ' q! B4 q7 [. f" I( h& B' [3 W
  53. } $ q3 Z/ c7 ^5 B
  54. } 4 V! |! Q4 \- ~. {2 x! y. D
  55. #endif 3 d; x8 j+ l2 \8 X+ Q* ^

  56. 6 |) S" C, D( R" x) q) n; V* }
  57. /** 6 [1 N- `6 L4 C2 a# h+ \( N
  58. * @brief The application entry point. ( E4 L9 q! K% v
  59. * @retval int
    ' e, b' }8 D9 _
  60. */ 6 q  ^! l" c- w+ _
  61. int main(void)
    + \) Y* L; ]  C" _
  62. {
    . j6 t0 w8 n" p$ \
  63. /* MCU Configuration------------------------------------------------*/ + Y% }$ l' ~! ]9 T" }, @& b3 ^

  64. ! U" {0 X5 r  t4 y; ?  ^5 u. \5 @+ d7 {
  65. /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ ( \4 m$ l- A6 {# {" |9 C
  66. HAL_Init(); 8 l9 h* J  y8 w/ h4 c

  67. ) U" q6 v, s+ `4 `' R3 i
  68. /* Configure the system clock */
    ! f0 [6 F& m& \5 ?
  69. SystemClock_Config(); , R2 i0 P2 U3 |$ V) z( K
  70. % k, K/ D1 J4 D
  71. - p+ [/ x, L) n
  72. 0 X* {/ c! r* m. P
  73. HAL_Delay(100);
    ; c0 p/ {8 k/ n/ P* Q
  74. 2 M; v1 B) U( O$ d
  75. /* USER CODE BEGIN 2 */
    8 I- J" u8 g* ^! }% u8 w$ M* X
  76. test_normal_mul(10, testInputA, testInputB, testResult, 1024);; G0 h# ^" X: E
  77. test_normal_mul(10, testInputA, testInputB, testResult, 1024);
    ( r; h' L, Y* u. K

  78. ( B# k) ?$ ]  g" Q1 \( ^) R
  79. #if defined (__FPU_USED) && (__FPU_USED == 1U) 7 X, v7 ?+ }* v9 y
  80. // Multiply calculation with arm dsp lib
    ' m9 r! f4 B7 ]9 S! B" a6 y4 a
  81. test_arm_math_mul(10, testInputA, testInputB, testResult, 1024);3 @9 N; M# _+ T8 _% B" ?- e
  82. test_arm_math_mul(10, testInputA, testInputB, testResult, 1024); " ^; B7 ?1 |. L1 i- k
  83. #endif
    6 }* W9 x% B+ J! R- J1 _2 c
  84. # q" s6 Y5 }7 U! [: D/ B
  85. /* USER CODE END 2 */ & D& |8 `% }" K% _5 B
  86. . H$ N1 J: y: E, q9 Z1 P# r
  87. /* Infinite loop */ " N5 l5 G  f$ E3 B* }+ V
  88. /* USER CODE BEGIN WHILE */ * L3 A% D. V/ A2 `* k8 C! v5 L1 h
  89. while (1)
    , h7 c2 z" r* E& y
  90. {
      g2 @- X2 u: q; H' g7 g
  91. /* USER CODE END WHILE */
    1 n$ |% M6 H( N1 U. @5 F7 K

  92. 0 s& G4 W$ Y! |, e; W$ C1 r- B, w
  93. /* USER CODE BEGIN 3 */
    % V" P$ [! E0 m
  94. }
    / j4 j' ]+ O! {. q3 b8 U
  95. /* USER CODE END 3 */
    1 P8 r; H! a5 I/ f
  96. }
复制代码
2.4. 工程配置
2 q  z7 b% t% I$ s/ E0 T7 w; {; t通过 KEIL 工程 Options / Target, Floating Point Hardware, 确定 FPU On/Off。
- h, {; c* {0 F0 f$ S% J
15.png
% C6 N4 K. ?3 M) R

6 }/ z: q( S; o6 a/ J: o
▲ 图3. KEIL 项目工程 FPU 单精度浮点设置
通过 STM32G474_FPU_TEST.sct 文件配置 Data 存放区域,如下例,将测试数据置 于 SRAM2。1 T8 ^2 y  p4 S2 ]: C, g

  1. 5 }' H/ G  I$ e: v
  2. RW_IRAM1 0x20000000 0x00014000 { ; RW data
    : Y2 h0 E  F! M; j
  3. .ANY (+RW +ZI)3 _  L, w$ y( o& f+ m4 @& J
  4. }- I8 S4 v4 P4 ^' n% h2 {% m. t
  5. RW_IRAM2 0x20014000 0x00004000 {
    # a4 s2 v; T/ v' h0 q; z
  6. *(.TEST_INPUT_A)2 h3 M5 H5 F! {& W' _- ?
  7. *(.TEST_INPUT_B)
    ' |3 W+ _% t; Q8 A7 S& P$ i
  8. *(.TEST_RESULT_D)
    2 c) u8 d$ z' }; _
  9. }6 s- T% H2 W( n# @2 d/ a. c
  10. RW_CCM 0x20018000 0x00008000 {
    % R' Y8 S  g& C) E6 S6 V' U
  11. }
复制代码
完成后,进行编译链接,即可进行 STM32G474 FPU 性能的测试。
1 b: x3 C0 D' U- G! X- w4 s, w6 h
& P& I! V! V6 [8 ]$ B; h. H( l2.5. 编译选项 / k3 m/ N5 V% i0 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 浮点运 算扩展)等选项,不过一般使用默认即可。
: p  Y2 F. b/ ~& U* e6 a3 z
16.png
▲ 图4. KEIL 工程,编译选项设置
03使用 KEIL Trace 工具进行测量 . V7 h0 W* M3 ?8 N1 L) l
3.1. KEIL 工程设置
, G  E5 {5 h; h7 Z
7 X" `0 `; v8 [5 EKEIL 工程下,首先选择工程选项设置,在 Debug 选项页中,右上部使用 Debugger 工具栏中选 Settings,如下图 5 和图 6 设置。注意 KEIL Trace 设置的时钟必须要与实际 STM32 使用的系统时钟相一致,如图 6 中,STM32G474 使用了 170MHz 的系统时钟, KEIL Trace 中也要相应设置为 170MHz。7 j3 O) Q8 Z# w1 i5 W
17.png
▲ 图5. KEIL 工程,Debugger 设置入口
18.png
▲ 图6. KEIL 工程,Cortex-M Trace 功能设置
运行KEIL debugger,如下图7所示,将断点设置在要测量的语句前及其后,执行 代码,当Debugger停在断点时,其状态栏中t1指示的即为当前代码的已执行时间。测试代码起止时间差即为代码执行用时。该Trace功能计时是比较准确的。当然如果您希望掌控更多,也可以通过代码来实现,如增加诸如如下代码:
& K4 ^  S1 g8 c& r3 U1 T/ ?2 |$ u6 EnStart = DWT->CYCCNT; / h; O, m' s% \* x' u6 M
~~~需测试执行时间的代码~~~ # f: s3 j% x0 f) a  A
nStop = DWT->CYCCNT;' ^2 T) r# U) \7 o
然后用(nStop – nStart)/系统时钟,换算成时间即可。(我们这里没有考虑中断,一 般测量前需要禁用中断)
* y& V% Q$ `# m: G# L, {
19.png
▲ 图7. KEIL 工程,Debug 模式下 Trace 程序执行时间
3.2. 测试结果8 P  e9 f2 B% ?% D- U: V
下表列出了STM32G474 10K次 浮点“乘”用时统计。
9 Z+ T, j& }: B3 c2 }) u! u
20.png
▲ 表1. STM32G474 10K 次 浮点“乘”用时统计表
10 X 1024次浮点乘! n' w! E" C5 O( \

7 }# f$ ^8 r  C4 @& z7 t增加--loop_optimization_level=2 编译选项
) W5 r1 }% \" d6 C
3 ?$ x- l1 u: I4 K* _
FPU 核心汇编代码的比较,见图8和图9。
: k: d$ A3 h2 Y' l- q
21.png
▲ 图8. 使用--loop_optimization_level=2 编译选项的常规代码汇编
22.png
▲ 图9. ARM DSP 库 arm_mult_f32 函数汇编
( c: \. }) [6 I2 `3 W( b# e

; ~: Q7 n; O$ L) L$ d使用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是很高效的。
# u/ q4 n6 `- G$ g2 a' V1 R" C' q
04小结
. K; ~# e1 c1 l7 U' V+ R3 G本文介绍了使用 STM32G474 FPU 进行浮点运算,从系统的角度、ARM DSP Lib、 编译选项的影响等几个方面探讨如何提升整体性能,并介绍了如何利用 KEIL Trace 工具进 行测量。以供在系统性能方面有需求的客户参考借鉴。; T8 s0 U/ S2 O' N
' k7 B) O$ p* H) |; p1 D9 Q

4 O8 o6 Z' o0 \, `. t1 e" n( {' l" a如果你有其他想要的实战笔记,可评论区留言,管管来跟工程师沟通!9 h, K+ E1 K# g2 J: R) q: s4 o( |
) B8 i4 X* H0 E. ]# U8 w4 R

% k8 _7 Q, e* @; S- B) |( i; A- b% a" p+ _3 _9 x
% B! `' f$ E3 N, q) r% \3 I
  a( W0 |% n, R

3 l# g( \7 x7 p
# {9 O0 q" W: @. h, J9 v) n! P! M# b. S( {
6 O: v$ \1 B" e9 g- b1 U* K  Z

1 ?  m1 ~. q  @5 U6 V& [6 p1 F* ?: U+ J/ q+ {  p3 L
! ]9 K9 U- Q& a8 R. q5 W/ y

) r& }, a1 s& s/ N+ o& k( \% u/ L
收藏 评论0 发布时间:2024-10-30 16:57

举报

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