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

STM32G071跑分?看看你的能跑多少分!

[复制链接]
STMCU小助手 发布时间:2021-9-13 13:06
大家好,我是张巧龙,提起MCU性能测试,最著名的就是CoreMark和Dhrystone。" k, F+ @9 D) e0 ^- \7 H8 x5 B

6 F" Q2 e: d9 @# [/ {; ?CoreMark以每秒迭代次数作为性能评价,而Dhrystone的DMIPS与Dhrystone标准相关。( X- t; U  }" W6 p7 k+ ?3 v( t) q
: M/ `2 ?/ p" g  j
9 F: E4 u' A2 N8 v8 K
本文讨论CoreMark,先来看看MCU厂家如何宣传自家产品性能。7 j$ n+ D0 ~1 ^4 O* t+ X
; K) b; r2 g4 R1 J* i* e2 t
▍揭开神秘面纱:CoreMark是什么?为什么它可以作为MCU的性能指标?这个数是怎么计算出来的?
/ y+ v  a- ^  l9 n( s+ [
8 D4 M. g5 q  z) f) p1 f  T1 Y

9 C: D* ~8 S% I7 T3 P! HCoreMark是衡量嵌入式系统中微控制器性能的基准。通过包含列表处理(查找和排序)、矩阵处理(常见的矩阵操作)、状态机(确定输入流是否包含有效数字)和CRC(循环冗余校验)等算法的测试给出性能评价。
; n# n: y# B1 _0 Y* R5 z5 g: g# v- f9 I8 o& Q6 [- K7 R4 [

. u! C7 V) f; K) f需要下载的软件包是免费开源的, 可以在官方网站找到:EEMBC’s CoreMark®,网页截图如下。
' F1 f$ P: R% {- V1 l" `2 h
13.png
▍作业不难:怎么将CoreMark移植到自己的MCU上?运行CoreMark需要哪些外设支持?" ^' Y$ [! H# A, ~* j  Z1 Z# }
) A& d! S( `; _% L8 ~  D7 F0 C* n
- ?7 U! `+ N: U! i8 ?( ]6 [7 H& \) T3 v
51单片机也可以跑CoreMark的,所以硬件上不用担心。运行CoreMark,需要定时器提供计时功能,还需要一种向外部打印消息的手段。6 N; O# j; ~5 K3 o1 o; ^
, N( J0 Y" \) j4 g

& J5 y! F, i' S8 k1 A一个比较简单的方法是,调用stdio.h中定义的printf()函数,将其重定向到串口。现以使用STM32CubeIDE将CoreMark移植到STM32G071为例进行说明。. n$ Y+ e# E2 I

) y$ `! n# I& r. s
: `; }: z! W* B$ i4 m' M
● Step1:复制必要文件到目标工程。现已准备好目标MCU的软件工程,其文件结构如下图右侧所示。从CoreMark官网获得软件包,软件包解压后文件结构如下图左侧所示。
( h% L: B4 |7 f
- q* Y- d7 s% v5 k* g  b, z
: ^5 x) ]0 _1 x7 V; g8 n, b. k
在右侧软件工程中新建文件夹CoreMark,将左侧绿色框中,core_list_join.c、core_main.c、core_matrix.c、core_state.c、core_util.c、coremark.h等文件放到CoreMark文件夹里。
: F6 g- Z, E/ d4 T6 s
% ?, T' y  p- D* C' S3 [
  m+ s6 y0 V6 v, _- ^
打开左侧simple文件夹,将core_portme.c复制到Src文件夹中,将core_portme.h复制到Inc文件夹中。" P2 K9 K+ s+ @; F8 S. j
14.png
(彩色高亮标记与图中颜色标记对应,共5个步骤)
' o1 Y9 N' N2 U- d
6 A" {5 R+ w% z! v
● Step2:由于core_main.c文件已定义了main()函数,该main()函数执行时调用core_portme.c中的portable_init()函数作为MCU初始化接口,因此需要将MCU工程中原main.c文件MCU初始化代码移动到到portable_init()函数里并删除原有main.c文件。
3 C' t- u; \$ }
. F3 P; z1 F9 r: @

/ F1 o& a8 h( b9 v' p1 B4 s3 V以STM32CubeIDE工程为例,需要移动SystemClock_Config和一堆MX_开头的初始化函数(注意相关结构体、函数原型与函数实现要一起移动)。
8 K  E; X8 o  ~1 d0 T0 q' v) v$ |* l0 g7 S! t
9 k% R! G" n: f' x. {1 z7 K
● Step3:CoreMark的分数最终表示为Iterations/Sec,也就是每秒迭代数,而Sec和系统Ticks相关。用过RTOS的朋友应该对这个概念很熟悉,考虑文字不太好解释,直接看core_portme.c里这个宏定义。
  n1 L: t7 m+ o( A- X- y
  1. #define EE_TICKS_PER_SEC    1000
复制代码
● 这里我定义每秒1000个Tick,每个Tick时长1ms,对应定时器每1ms触发一次中断。使用一个计数变量,定时器进入中断一次,该变量值+1;对该变量值/1000即可求得定时器运行时长,也就是上文的Sec。5 U* a( \; T) a* _" r7 w& r0 @! E- w0 e

' C5 `  _- N) f; t

5 y% J0 G; ~: `: N# e* N! G所以EE_TICKS_PER_SEC并非一定要设置为1000,和定时器中断频率对应即可。与定时相关的函数有以下三个。0 x5 q& h+ ]( s! A
  1. void start_time(void);//启动计时器;
    ( [+ P- `& j. J  L& ]
  2. void stop_time(void);//停止计时器;
    9 J3 j6 I( e0 r. `9 \% i
  3. CORE_TICKS get_time(void);//获取计时器的计数值。
复制代码
● 在start_time()里实现定时器启动功能,在stop_time()里实现定时器停止功能,在get_time()中获取中断计数值。数据类型“CORE_TICKS ”实际上就是“unsigned long”。
- x  ?# ^! u* b1 q, r: e5 }$ j2 T" A
8 p5 a0 ~4 S# x8 o) B

  }  O5 ]% @4 M. b9 h为方便操作,推荐将计数变量设置为全局变量,这样可以通过extern关键字直接访问。此处以TIM1为例,代码如下:
: H: ?# V9 R" M$ I& f
  1. 4 v$ G( U$ J0 ^5 b$ S. x
  2. //计数变量
    & x8 S8 S1 {& [2 W8 \
  3. unsigned long time_ms_ticks=0;! U" T+ _; C' L

  4. & X$ j: S$ g( z: g
  5. //定时器启动
    & E9 r3 {$ F! e
  6. void start_time(void)
    # {9 O: E9 y8 Q( c( w
  7. {
    ( h2 F8 n5 C  {
  8.   (&htim1)->State = HAL_TIM_STATE_BUSY;7 v5 P, ^2 G7 Q! I* n/ ~
  9.   __HAL_TIM_ENABLE(&htim1);
    ( g! I" Q# Y* J- g# ?
  10.   __HAL_TIM_ENABLE_IT(&htim1, TIM_IT_UPDATE);
    " f- d# K/ Y9 K- {0 J% g& W
  11. }0 G: Z) f1 @9 M" I/ }6 N

  12. 1 c2 d/ z5 d$ R9 w0 Y8 j
  13. //定时器停止; D/ ]" |4 K; i
  14. void stop_time(void)! j4 A0 s+ R! F1 j; G1 e0 n2 ?8 L
  15. {
    / D/ x! J  i; x7 q6 V, ?, |
  16.   __HAL_TIM_DISABLE_IT(&htim1, TIM_IT_UPDATE);
    - v* |" y& t9 c9 Q
  17.   __HAL_TIM_DISABLE(&htim1);
    + P1 {0 q) t6 e- W" ^1 @
  18.   (&htim1)->State = HAL_TIM_STATE_READY;" L( K6 m& A& J' N4 Y' \8 H
  19. }
    / ?7 C$ u5 ?' q; ?% u& }& Y

  20. 4 `4 R" u5 G5 R
  21. //获取中断计数值. Q# K7 |+ p' X) l, E2 Z7 h$ g4 z
  22. CORE_TICKS get_time(void)
    / ^+ U' v4 A6 ?( k1 f
  23. {$ O/ k! u, J* n: W5 ^
  24.   return time_ms_ticks;% [6 H  s7 e9 ~
  25. }; I3 ]( V2 y; j# l$ A& M' Q9 g

  26. $ D  M, |/ i3 p" ^& d4 J7 Z; `
  27. //中断处理函数. [' e# _- x; b) ~! c/ a# l- J
  28. extern unsigned long time_ms_ticks;6 e. d; F" g6 ~) O- i  `- Z5 L
  29. void TIM1_BRK_UP_TRG_COM_IRQHandler(void)/ K" V" T; f, O
  30. {
    2 l+ z  x$ z0 p% ~' _! ?
  31.   HAL_TIM_IRQHandler(&htim1);! o0 U- Y, U# r3 ^$ O) ]
  32.   time_ms_ticks=time_ms_ticks+1;
    2 O4 T2 [7 d4 `/ }
  33. }
复制代码
● 注释部分不使用的代码。以下代码位于core_portme.c中,需要注释掉:) n; l# r9 Z# @7 j( M
  1. //#define NSECS_PER_SEC              CLOCKS_PER_SEC
      Z- q1 G0 W: B. u
  2. //#define CORETIMETYPE               clock_t
    5 |3 v% |' ^5 Z5 G% A
  3. //#define GETMYTIME(_t)              (*_t = clock())7 B2 F2 @: r+ P, S1 V) @
  4. //#define MYTIMEDIFF(fin, ini)       ((fin) - (ini))8 {+ c3 r! l6 `9 v% \& O; v, ~$ w$ K
  5. //#define TIMER_RES_DIVIDER          1
    6 `/ ?: I! v3 ?: l* O: `$ V& A
  6. //#define SAMPLE_TIME_IMPLEMENTATION 1
    9 r: J1 a9 i: r1 }, Z8 r. d# w; ]9 b

  7. : B  e9 {/ q0 y8 H. K
  8. //static CORETIMETYPE start_time_val, stop_time_val;
复制代码
● CoreMark要求的最短测试时间为10s,若测试时间低于10s则会报错,见下图:% f& w0 R" Y* a2 S1 T6 x+ o
15.png
● 为获得有效的测试结果,需修改core_portme.c中关于ITERATIONS的设置,官方代码中ITERATIONS没有定义:0 q' {9 @: t$ n
  1. volatile ee_s32 seed4_volatile = ITERATIONS;
复制代码
此处使用STM32G071,主频64MHz。经测试ITERATIONS修改为1200左右即可。
$ R7 c! w- x- {1 C' \7 A
  1. volatile ee_s32 seed4_volatile = 1200;
复制代码
● Step4:打印测试结果时,编译器优化等级和调试等级也可以打印出来。这类信息可在core_portme.h中通过宏COMPILER_FLAGS修改。这里我使用-Ofast优化,调试等级-g3,修改如下:, f; H" k# c' n7 N: w$ w
  1. #ifndef COMPILER_FLAGS: u) o& X3 F+ |/ b; Z
  2. #define COMPILER_FLAGS "-Ofast -g3"
    : _' s3 g6 C: P
  3. #endif0 n# e# R/ G8 U
复制代码
● 重定向printf到串口,可参考以下代码(以STM32 LPUART1为例),根据IDE不同可能需要添加float类型支持:
: i: }0 v+ z& d- x
  1. __io_putchar (int ch)
    # Y1 b! w' `, I9 U! k
  2. {
    * O& Y7 O" a0 R5 o" M& `
  3.   HAL_UART_Transmit (&hlpuart1, (uint8_t*) &ch, 1, 0x0F);
    3 r* |- [! ]. Z4 j
  4.   return ch;
    0 s- B$ b. y1 x# Q% k* v" i# d! s) S
  5. }
复制代码
● Step5:移植完成!编译程序下载运行,得到跑分结果:
7 [1 E( `3 {. u' K1 E
16.png
4 V/ _6 ^. J# e3 y1 H$ {
STM32G071RB,64MHz,108.9分!
+ Q, B# _$ X0 b$ c
8 c( s8 Z& M, F( P: G
# q& K1 {5 a9 x2 a5 ^
通常使用最高主频和-Ofast优化可以获取最大分数,欢迎大家把自己的跑分放到评论区
; Y, x. |2 L- S, s! e6 D; ]& W
/ w1 K. c) p- |7 v4 c( s
& m9 H' K) r+ E3 p* Y5 R6 z1 x" S

; O7 K3 h5 o# |% r& c- A0 H4 D) N9 _+ v' ~/ Q5 W
收藏 评论0 发布时间:2021-9-13 13:06

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版