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

【经验分享】STM32H7 RTX5操作系统移植(MDK AC5)

[复制链接]
STMCU小助手 发布时间:2021-12-30 14:32
4.1   初学者重要提示
0 x$ r8 f: O) ^% F1 J7 e, `% z  当前RTX5可以移植到GCC,MDK和IAR三大平台,考虑到仅MDK平台下有RTX5的调试组件,我们这里仅提供了MDK的移植说明。) d2 B, O3 r# C/ h4 r0 w" @# }
  STM32H7使用MDK RTE环境添加RTX5,需要强制运行一次STM32CubeMX,因为H7已经没有配套RTE经典添加方式,而STM32F4是支持经典方式的,所以无需运行STM32CubeMX,详情可以看我们STM32F4开发板对应的RTX5教程。
! n% Y& w  C) U$ X# D4.2   移植RXT5内核整体说明
: u9 L; K3 ]2 ?- j5 m移植之前,有必要对移植过程有个整体的认识:
  A. I" c% J' M% y1 Q3 t; Q
% U  g; ]& ?: q" O) q  第1步,准备一个工程模板。% t' ]% X/ |; @9 Q" E
  第2步,移植RTX5。
0 t* J3 C& @9 H7 P8 o0 x9 e  移植RTX5是采用MDK的RTE环境直接添加。当前H7芯片使用RTX5强制运行STM32CubeMX,所以需要大家提前安装好STM32CubeMX V5.4或者以上版本。% m! j$ F. o" m/ _
  第3步,处理HAL库时间基准,MPU配置等。( q9 s: _, E0 Q2 W
  第4步,创建应用。
5 @, ?# w7 I7 \$ e' Z) k. P2 l' w
! q9 P5 L5 e8 i总的来说,这4步就可以完成移植, 下面将STM32H7的移植步骤和注意事项为大家做个说明。6 X- z, I. r# ~& p4 E. K

% J1 y- j4 O' Z- y) a4.3   了解RTX5内核模板框架设计
4 o0 {* I0 z9 ^! M- M; ~* T) i0 d* }移植RTX5前,我们优先了解下移植好的RTX5内核模板,方面大家后面移植:
& E2 F* k( Z+ {5 ?0 G0 Z4 y9 h# h/ P. D" ]! J" a) V* j
ebf7bed4831890980f518eaeb842a943.png

. d, V+ j1 K7 X0 n2 H5 T" R. X( [' ?: p( u
框图如下:
4 m' B! d3 l0 z" |) E; F( j  |7 Q5 ~& n" n, [+ E+ o
cc3f4f5af7e41dcb23a03a25e14d8ae7.png

1 y- [6 ^! |, q$ ~/ `  K- r: I1 f, Q5 E( ]
" ]) t1 N* Z2 O( _! R" Q7 ]4.4   第1步,安装指定的MDK软件包版本" G1 H: K$ M0 `8 @5 o
移植新版RTX5需要大家下载当前最新的MDK软件包版本(如果有最新版,推荐大家用最新版):
. a# V; D& b3 j7 J, Z
: w$ x' n5 U1 ^) |9 j  CMSIS 软件包使用当前最新的:V5.7.0" q: D6 M8 g6 P6 e- F) c
  STM32H7使用当前最新的:V2.6.0- o2 L7 E$ a- g. y: [3 x9 L  _
  STM32F4使用当前最新的:V2.6.04 e  I* }. O  O! W# J) z0 D
  STM32CubeMX使用当前最新的:V6.0.x
' F6 D7 {- W* N/ ^  ARM_Compiler使用当前最新的:V1.6.1
6 X4 D% _/ U; I+ j
( n& G/ G+ F) X; g; ~不管以后MDK的软件包版本如何升级,当前的软件包版本和以后的新版是可以同时安装的,也就是说可以安装多个不同版本,在这里可以选择指定版本:) K8 Z  ^: [/ U

8 D& u( |0 a/ a9 T
bbb84b8c4b3275b1026d2c95b5012294.png

' l# C. j& Z$ W- N8 W5 d
2 C9 c8 @. ?2 F7 _0 p4.5   第2步,准备一个工程模板8 I$ |  [# N! h2 a- z) V
首先准备好一个简单的裸机工程模板,已经为大家做好:V7-400_Base Template,准备好的工程模板如下图所示(大家也可以制作其它任意的工程模板,不限制):
8 h$ a4 y1 |7 {$ |& _! ~3 |# l! r4 \
5618d5a487ef825c0a75ce19685c4821.png

% h& z, ]( v3 b2 Y# m; N: {
" D! m- ]7 E: {1 F# S1 E6 K8 D  d4.6   第3步,添加RTX5并配置
( N2 {0 ~" i: [RTX5可以方便的通过MDK的RTE环境添加进来。对于H7版本,MDK会强制运行一次CubeMX,并添加很多H7的HAL库文件,这些库文件我们可以使用,也可以不使用。教程配套的工程文件是不使用这些,因为前面的工程模板里面已经添加了。所以要将这些文件全部隔离出来。
% S$ b  N( f6 T2 K' }: j6 r
" D  @  d0 V1 a4.6.1      添加RTX5源码
: x1 e$ P4 j% |4 E" S; C5 R* T3 d; l: @9 i' c
48f11b91f9fc45f3f04431047156434d.png
% e- n8 e- U& N3 i3 R7 _* x, \
' l- n+ o2 A+ R' K: P' B
点击OK按钮后,弹出如下界面:
4 h% l- I% }6 g1 |% C4 T
9 I8 @+ s$ R1 R8 p* j; o, U
b430f5f7b2e1a16de73553adb9dd1f89.png
- k3 L. o  F$ k7 l" J3 Z2 ^

  L1 R; J* J& b; J' K点击Start STM32CubeMX,这里需要大家电脑上已经安装了STM32CubeMX,并且为其安装了H7的软件包。7 a& t  H' W8 {) S+ Q) }

0 _+ W4 I* j# i, M, b% s6 N. B7 F) Y# I
af4f52889e56b18313faf6baa5ed1281.png
4 a2 ^& z1 ^6 G$ E$ |+ J: K1 `

, t  F4 a1 @. q- o- w打开后,用户仅需配置如下地方即可:
, J' k7 ], A6 e8 A4 z" @3 ~- f; A) ~5 X  j
7c8a9271ba3d0ccb045c81921fd97d0f.png
8 t4 C9 m7 ?% W/ F! z# e4 u2 b

  I6 p7 B% Y( ~6 {然后点击右上角的GENERATE CODE:
; F- K0 ]9 A. ^- I0 g6 U/ x7 g8 X4 ^+ A/ H( g  G4 e. }0 X8 A2 j
62747d5251f02d427c05caf48fc46d77.png
4 F: Z3 j7 w. N8 h- H
& t0 U  i/ I3 A4 s% X
然后弹出如下对话框,点击Close即可,然后关闭STM32CubeMX。6 l: R9 a- r8 u8 v9 f6 U
  H6 n8 v/ e2 p2 w
1a4404327c06b66c217f46c74bd48db2.png

; b9 Y$ N; o& d8 ~! m) O$ _
  H  ^1 I/ p9 G; R: R5 B1 q重新回到MDK,会有一个对话框,点击是即可:
: B. A) L; Q  m1 `7 }- A% x8 d# P" j: F6 S: k3 f9 U- ^5 h) [
cdfb3b29fdf8c8b60f0d85f8aaa161ff.png

  k9 ~0 a3 a. E- g5 F  M, d+ K6 D: G1 N1 q1 E% b6 o+ p7 w
最后就可以看到RTX5源码已经添加到工程里面了:9 K% E2 o: C) p
- w9 |1 J; P5 K4 g2 G: q
e49f340b4464ddd3afb5bf5082de0fdd.png
9 e2 P4 u: J4 v( n7 m3 x; Z) _+ I& j
- D( r7 S% @+ m: w2 X6 @( s# z2 d
4.6.2      将自动添加的库文件隔离出来' v! o5 f) n7 K  p9 R! O
添加的所有文件中,仅RTX5和文件stm32h7xx_hal_msp.c留下,其它文件全部隔离出来,隔离方法也比较简单,比如隔离生成的main.c函数,鼠标右击此文件选择Options for file ‘main.c’
4 h4 [5 o3 m) {; }9 J- {7 T0 c& |; J" Y4 I  l
3b989ad148a2ec7c0522490cd84fcf3c.png
3 W5 D( w% j8 U3 C* u* i

6 O& v5 w2 j6 `6 Z" [: M然后取消掉include Target Build前的对勾,点击OK:, [: m- [( y/ y. t7 P
' A, q$ f  L+ }! A8 F
6652eec0f1078d33b6c1508049d0c922.png
: Y. R& i+ `: J" l: q3 T8 {

$ Z* O3 ?  S1 ?0 M看到main.c文件上有个红色横杠,就表示已经隔离出来了:
  K6 ]% Y; J) X. b  f% `+ a! D3 l) |: c: `! B5 o' \/ G- ^9 ~# J
cafbe4a03ab78632d36b9cf1b050250c.png
6 Y! T! }# I, h% K5 U: V# i4 j

! H* |# N) n+ q& @0 f0 p同样的方法,将stm32h7xx_it.c文件也隔离出来,文件stm32h7xx_it.h不用管。, G. m2 u( ~- ^( F( r$ }+ A& [
# J: Q* B3 H: \" [
Device下面的这些文件也是同样的隔离方法:
, S" a# e( o( Z* A) s. L+ R) W# v! {7 W1 u4 a" y; u5 c$ d- |
f46dbe6e1b27dd459e04cba9849d9ff9.png

7 j" _8 J8 P4 Y' D
7 J& L, ?! n+ K+ q) _* c只是鼠标右击弹出的界面有些不同:9 @8 J8 a7 b' |% r/ a( n& {
" l* K4 N$ v9 y% l; J: I3 Y
aeccd1d366ee4da23ceff332ae2f84e5.png
7 n) G% ~& L5 _
+ ^8 T0 N( P, a
注意stm32h7xx_hal_msp.c无需隔离,其它所有的文件全部隔离,stm32h7xx_hal_msp.c对应的隔离配置是STM32CubeMX,如果也隔离了,编译会有问题:7 U9 r  V! x* m

+ }4 p# [' m9 g
59f0e5e7d43f7ac7e983147c132a42ce.png
% u$ d& D# I3 q4 L. \0 K: Q

# ]7 N* z' \* P8 W& I2 f, ?隔离后的效果如下:' m# f" T" ]& T; p; `" u9 B. i9 u4 w
: _: y& F) f! O: q
573fb2c99aa8ef7ef6f577c106084913.png
1 k& M7 g( K1 u9 _) C
, B9 a: V% x' |* S9 _5 L
4.6.3      RTX5配置: ]) {- [1 D+ b  O5 _8 K& R+ S  M7 r
剩下就是配置RTX5,设置RTX_Config.h文件即可,移植阶段先按照如下设置配置好,后面章节会专门为大家讲解每个参数的配置含义:
/ x5 z( Z" L" h- R5 @5 c; F% ~
: J( j; X; F) [
576cda809f95be40653ff18b9682f906.png
$ y! D4 w3 x3 C3 C! z$ J- ]

4 x* x! \. A$ A! D7 T4.7   第4步,MPU和Cache配置文件bsp.c
) O, @% u  Z# S6 u8 i4 H( e这个bsp.c文件也比较重要,移植阶段,直接将我们移植好的模板内容复制过去即可,这里把相关的内容为大家做个说明。
. k4 B$ ?- Y8 K: \: H& f9 K+ N  V. W) v7 I4 m. i0 W
4.7.1      函数System_Init

; d- |0 L) K0 k8 m% O系统初始化,主要是MPU,Cache和系统时钟配置,需要在RTX5初始化之前调用。- l! \9 F4 [+ t( j' w% I
+ W  q3 ]- s' J- Y. D6 A( ^( ?' N
  1. /*
    " n8 d3 d/ o- |  a% d
  2. *********************************************************************************************************
    9 r$ e+ u/ e) r9 Z1 H
  3. *    函 数 名: System_Init& ~6 m) j( J& z  W) v, H5 D
  4. *    功能说明: 系统初始化,主要是MPU,Cache和系统时钟配置
    ' D/ R5 J$ U+ \! P. g
  5. *    形    参:无
    ) t$ c) J0 G9 C# [+ |, w7 S/ n
  6. *    返 回 值: 无
    : q9 j5 F" x( e( }6 S! b5 u% L2 W2 u
  7. *********************************************************************************************************6 C0 Y5 w7 t2 k/ n  E* F# p
  8. */5 L# F2 h* v. W. K9 i6 Q* I1 L
  9. void System_Init(void)2 _6 {" |2 x5 K
  10. {0 b# @' ~5 o! f4 ^2 Z0 s

  11.   e( \  `7 }7 H# ~- k
  12.     /* 配置MPU */  G" t1 K( r/ Y
  13.     MPU_Config();! G- \# S0 C, b

  14. # Z) h! `2 Z8 U% h! _/ L; Y
  15.     /* 使能L1 Cache */- [' F0 e8 G6 q
  16.     CPU_CACHE_Enable();
    0 ^, h! ~* I" k/ {/ ^( w

  17. ! @) Y0 }! e- J2 j7 S( W) B* q# y
  18.     /*
    * C& P/ y8 X7 I+ n! q
  19.        STM32H7xx HAL 库初始化,此时系统用的还是H7自带的64MHz,HSI时钟:
    - K& @6 N. w+ L2 N, B0 [
  20.        - 调用函数HAL_InitTick,初始化滴答时钟中断1ms。
    9 z  K* ^. f% d# S7 O7 e
  21.        - 设置NVIV优先级分组为4。
    2 K5 c  f4 q9 _5 |. g
  22.      */3 |0 _3 k. N( v( v+ A5 t; H
  23.     HAL_Init();7 H6 {$ T& m" N1 S% u
  24. ' J& X7 o; c; W9 r. R# c& b
  25.     /* / K; z1 q. m# n
  26.        配置系统时钟到400MHz
    ; e* x# E' s; m, |
  27.        - 切换使用HSE。( U8 }: o/ D3 e# Q" L
  28.        - 此函数会更新全局变量SystemCoreClock,并重新配置HAL_InitTick。. D6 z0 Y/ L! J% T8 g3 G
  29.     */; [( r3 A! T6 A: |9 ]% j# \) e' `$ ]
  30.     SystemClock_Config();, ^8 e+ ^- ~+ k8 ~& V( P

  31. 8 e% g3 @  Z/ \0 d8 a$ y4 l
  32.     /*
    3 y3 y: u* |% @/ Y# T0 ^0 l
  33.        Event Recorder:  r! ^- K3 k( \1 Y9 u
  34.        - 可用于代码执行时间测量,MDK5.25及其以上版本才支持,IAR不支持。
    & l, Q+ y: n% R8 l. I' Y2 Z) N
  35.        - 默认不开启,如果要使能此选项,务必看V7开发板用户手册第8章
    . U' P0 }* l- q( A8 F
  36.     */   
    6 E% ?; E" S# J& V- R
  37. #if Enable_EventRecorder == 1  
    # R! @: x% p# b1 J8 B( m
  38.     /* 初始化EventRecorder并开启 */. e5 t9 D: d0 \3 }
  39.     EventRecorderInitialize(EventRecordAll, 1U);
    ( v; Q+ p3 [- C, e
  40.     EventRecorderStart();
    " h5 |! D3 c$ K$ y
  41. #endif  A. t4 F: {( Y# d

  42. 9 ?& A. C$ T* t
  43. }
复制代码

% U* m# ^! Q# \/ ]0 W8 H4.7.2      函数bsp_Init. h3 Z% i. R- ^0 O; n
硬件外设的初始化,这个函数在RTX5的启动任务里面调用。& }8 {9 U6 m8 L
% ^4 F- D% a. ]2 V) H; E
  1. /*
    ' Y% q  t0 D3 }4 c# }* h
  2. *********************************************************************************************************
    9 t) K) I$ `: Q: f) S
  3. *    函 数 名: bsp_Init
    & O# D" G9 r) p& T
  4. *    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
    0 K: C. }- e( I% {+ \
  5. *    形    参: 无$ K  }% r0 l2 u5 [* u
  6. *    返 回 值: 无
    + L3 F! w/ Y( D$ `" h$ L* `
  7. *********************************************************************************************************
    / M; [& n2 x3 i" z4 c* C' n
  8. */
    # U8 V, R1 Q: t( M- x9 T3 {  k
  9. void bsp_Init(void)) b8 _/ D% J( ?$ p( q7 J# o1 h
  10. {& x$ h, ]- Y8 [, d" ?
  11.     bsp_InitDWT();     /* 初始化DWT时钟周期计数器 */       , ?4 B3 q" g9 u. o; e7 C
  12.     bsp_InitKey();        /* 按键初始化,要放在滴答定时器之前,因为按钮检测是通过滴答定时器扫描 */
    & w9 N3 ~+ Q/ g/ y
  13.     bsp_InitUart();    /* 初始化串口 */
    2 z# }: d0 m) n3 M
  14.     bsp_InitExtIO();    /* 初始化FMC总线74HC574扩展IO. 必须在 bsp_InitLed()前执行 */    ! K  p4 x4 r( A( L) ?( Y6 H
  15.     bsp_InitLed();        /* 初始化LED */    0 j7 k( d0 ?+ u1 B: N. Q
  16.     bsp_InitTimer();      /* 初始化滴答定时器 */0 a$ K- j: f, N* [. ^+ j4 T2 ]* `7 G6 X- I
  17. }
复制代码

7 |; h8 f$ G+ o" `9 n4.7.3      函数SystemClock_Config# E' {0 N! K2 B6 F" U5 E
这个函数主要是完成系统时钟配置。/ K" s( V& U: F  R5 p
7 U, r* u" Z# h# _; A$ u
  1. /*9 W, U( E4 W1 n
  2. *********************************************************************************************************
    - `. ]$ ?) v' |; c+ e  t5 Y
  3. *    函 数 名: SystemClock_Config
    : S- L5 V# X& ]
  4. *    功能说明: 初始化系统时钟2 {: P( V# D- Y  s% a/ z4 x
  5. *                System Clock source            = PLL (HSE)
    + _& [; w3 Y! i
  6. *                SYSCLK(Hz)                     = 400000000 (CPU Clock)1 g* [4 |! c( X
  7. *               HCLK(Hz)                       = 200000000 (AXI and AHBs Clock)/ Z/ b4 L; v0 O7 v
  8. *                AHB Prescaler                  = 21 V0 J9 U# t: j5 r& T5 o
  9. *                D1 APB3 Prescaler              = 2 (APB3 Clock  100MHz)" K- w- T( l- U, _5 b
  10. *                D2 APB1 Prescaler              = 2 (APB1 Clock  100MHz): k7 ~+ A( u7 q3 o) y3 h
  11. *                D2 APB2 Prescaler              = 2 (APB2 Clock  100MHz)
    # _7 W$ y, t! N# m6 o% y
  12. *                D3 APB4 Prescaler              = 2 (APB4 Clock  100MHz)
    : N& g; k9 `9 j3 d2 @- c$ i  S7 s
  13. *                HSE Frequency(Hz)              = 25000000
    ; r6 p( A2 F4 v
  14. *               PLL_M                          = 5
    # d$ D3 @+ k0 }& U7 A) r  R
  15. *                PLL_N                          = 160  J( q' h* I. ^6 z
  16. *                PLL_P                          = 2. r% L' e1 R$ W& a& e% m' O
  17. *                PLL_Q                          = 4- [  ~  \" L4 h" b) t, J1 a5 h& r
  18. *                PLL_R                          = 22 u9 Y! t$ Q9 d- v4 w: M5 ?2 J
  19. *                VDD(V)                         = 3.3
    . Q1 y- ]. E* B1 d: l' O. y) Q$ ]3 @
  20. *                Flash Latency(WS)              = 4
    7 l1 N3 J# _% U& m) p5 m, p
  21. *    形    参: 无- i! a; F4 \( M: {
  22. *    返 回 值: 无5 o2 x# i' e: R; |1 Y. n1 @
  23. *********************************************************************************************************/ n! \; z: G  S5 r1 h  G5 ]
  24. */
    3 b) ]! a  g7 i6 ]3 v; v5 x' T4 Y' S
  25. static void SystemClock_Config(void)
    & L- U3 u( S4 {3 \1 o2 k1 r) p' I
  26. {1 R1 V' i' }7 W- [& A4 ^, i
  27.    省略未写0 C  z+ H: P, w
  28. 7 s/ f/ L# W! r& o, @2 p
  29.    /* AXI SRAM的时钟是上电自动使能的,而D2域的SRAM1,SRAM2和SRAM3要单独使能 */   
    ; e# j9 b% m: O& l* r; _
  30. #if 1
    ; U6 {6 n# @+ n
  31.     __HAL_RCC_D2SRAM1_CLK_ENABLE();/ K6 n5 E( D( u" K* R8 p
  32.     __HAL_RCC_D2SRAM2_CLK_ENABLE();
    ( q/ [$ q5 m% w1 X
  33.     __HAL_RCC_D2SRAM3_CLK_ENABLE();
    + {! G% }% F" F, s8 n
  34. * t/ E* R0 w8 _& E+ x$ |' n  [
  35.     __HAL_RCC_BKPRAM_CLKAM_ENABLE();      
    ! Z, V" H7 l8 _0 U. x
  36.     __HAL_RCC_D3SRAM1_CLKAM_ENABLE();# H$ J* O/ A& B  S) v( F
  37. #endif
      ?: W  ^$ _3 L; m. a' Y" u
  38. }
复制代码

3 O; a3 j9 w/ u! l4 ^! M# h5 C8 K* |这里的RAM时钟初始化比较重要,这几个RAM的时钟都要单独使能。- ^/ H$ C+ J) g$ L& N

7 ^% e* o6 b' R6 g4.7.4      函数MPU_Config
& ]2 N4 u+ I; ^0 vRTX5例子默认采用AXI SRAM作为主RAM空间,因为空间比较大,方便我们后制作综合例子使用:* A5 D' @8 V, q, ?1 C( h4 ]

$ R; @4 k6 {  P; H# K
  1. /*
    ) ?1 G: b7 x" Y' ]& k
  2. *********************************************************************************************************7 w' Z% c7 F% c" U
  3. *    函 数 名: MPU_Config; u' k  Z& h! ?4 J! ]0 F  U
  4. *    功能说明: 配置MPU
    * V! Y# j& k# l( x! K- N
  5. *    形    参: 无2 V0 L9 s5 \& X1 k# z, ]
  6. *    返 回 值: 无6 P7 t% Y# g. o. u
  7. *********************************************************************************************************
    2 z( o' C/ m5 R% o* {+ r" C
  8. */  M8 i. f& A$ l: e0 M
  9. static void MPU_Config( void )
    " [1 d4 ?# L8 g2 A
  10. {6 N1 e/ o. q/ t3 L( q# L! P- k% `, m0 R
  11.     MPU_Region_InitTypeDef MPU_InitStruct;: C- V, d/ _" a9 X$ e( @

  12. 8 r' v8 ]  e, [- X8 `0 |+ ]" u. _
  13.     /* 禁止 MPU */: ~) [3 e5 w* a$ V) o
  14.     HAL_MPU_Disable();
    7 |, V0 P5 }9 d, j1 l+ D0 d6 j
  15. $ Y* P$ g# Y" ]% {0 u9 w& w) ~
  16. /* 最高性能,读Cache和写Cache都开启 */   
    % v6 E; y* e0 x+ _- R: k
  17. #if 1: z; v4 B$ `* |0 U8 n% u) `4 C$ I2 o
  18.        /* 配置AXI SRAM的MPU属性为Write back, Read allocate,Write allocate */" k3 L# V2 t' G. F  W$ `" a
  19.     MPU_InitStruct.Enable           = MPU_REGION_ENABLE;6 y9 m$ u6 w% n+ j- w' Y( H& S
  20.     MPU_InitStruct.BaseAddress      = 0x24000000;! F$ n7 b# a4 s0 T) J, [
  21.     MPU_InitStruct.Size             = MPU_REGION_SIZE_512KB;* [' f  a. [1 p2 h' _# Q
  22.     MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;: g: I8 C. E8 p" h; b8 {& d+ |
  23.     MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;
    4 o8 N1 D# J( |5 K
  24.     MPU_InitStruct.IsCacheable      = MPU_ACCESS_CACHEABLE;
    9 U' Y6 P$ Q2 \9 x: h
  25.     MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
    + D* |( ~  u" E4 Y  E
  26.     MPU_InitStruct.Number           = MPU_REGION_NUMBER0;
    6 o0 U7 @+ ]* G; F7 G0 [
  27.     MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL1;
    * w" M! }8 e* `1 A1 F
  28.     MPU_InitStruct.SubRegionDisable = 0x00;6 m0 L' R& m# j  v4 O. y3 x
  29.     MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;/ l- c1 N# x$ u6 H" y8 g3 W

  30. ' F# J& D  h3 K! F# i6 W
  31.     HAL_MPU_ConfigRegion(&MPU_InitStruct);
    ! @8 ?* x& Z& ~9 @7 P3 I

  32. # O+ `0 K9 \- f
  33. /* 最低性能,读Cache和写Cache都关闭 */, X; d' R5 y* R# U
  34. #else
    - _" \0 l% Z$ g
  35.     /* 配置AXI SRAM的MPU属性为NORMAL, NO Read allocate,NO Write allocate */
    4 V4 ^. D! e( m
  36.     MPU_InitStruct.Enable           = MPU_REGION_ENABLE;1 L% G6 |5 U' m, A5 y1 e
  37.     MPU_InitStruct.BaseAddress      = 0x24000000;1 `% g5 l3 C# U) R+ U5 {: @
  38.     MPU_InitStruct.Size             = MPU_REGION_SIZE_512KB;' F' `. [) z$ s; q0 H$ m8 ~; b
  39.     MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
    * B% ?4 S0 |, Z- D
  40.     MPU_InitStruct.IsBufferable     = MPU_ACCESS_NOT_BUFFERABLE;3 o/ i  C  U- g& V# v7 v& V" b
  41.     MPU_InitStruct.IsCacheable      = MPU_ACCESS_NOT_CACHEABLE;1 _  l, S4 F( ~1 K; ^' x
  42.     MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;  v4 L% q& C" M
  43.     MPU_InitStruct.Number           = MPU_REGION_NUMBER0;
    - p& G3 G0 }' q8 I( X+ [0 X
  44.     MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL1;
    " ?1 `: l  Y* }8 C' j6 q
  45.     MPU_InitStruct.SubRegionDisable = 0x00;
    0 E; m, E' }) O$ c9 G% Y
  46.     MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;
    8 A3 e  T6 c# z! n! ]
  47. & Y6 {  f5 F& j) Z" y$ z: ~5 Y2 E' U
  48.     HAL_MPU_ConfigRegion(&MPU_InitStruct);' M2 ^7 u6 V2 _, C  b  D7 g
  49. #endif5 w! G" Z8 M, |

  50. 9 X- |" c4 Z6 p
  51.     /* 配置FMC扩展IO的MPU属性为Device或者Strongly Ordered */* ], f. i; X* G, X' H+ d/ t" v
  52.     MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
    : I8 e6 @% P" [) e, l
  53.     MPU_InitStruct.BaseAddress      = 0x60000000;
    4 `: Y# N) S/ o2 |* @
  54.     MPU_InitStruct.Size             = ARM_MPU_REGION_SIZE_64KB;    9 ?* I0 |7 g9 b/ C' S
  55.     MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
    7 h- ]. e$ k! I6 f
  56.     MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;
    8 o& y6 }* C& n* B% X  L! F
  57.     MPU_InitStruct.IsCacheable      = MPU_ACCESS_NOT_CACHEABLE;    5 W! Y4 q, p  B8 K; f+ G* K
  58.     MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;5 n2 C$ a: |6 p, z) c- Y0 ?
  59.     MPU_InitStruct.Number           = MPU_REGION_NUMBER1;
    7 r8 l& X0 R" l1 {! h
  60.     MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL0;# g4 _# `$ j# I
  61.     MPU_InitStruct.SubRegionDisable = 0x00;* ^: m+ F3 J& _
  62.     MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;( r$ @+ c  w+ N* p" W
  63. 9 l" X  Y" d  u2 W9 T
  64.     HAL_MPU_ConfigRegion(&MPU_InitStruct);( Y+ t& h( S; h" s" c* a7 n- Q
  65. " b$ ], e5 C/ J9 x
  66.     /* 使能 MPU */- g; P' C# a' M4 @( F
  67.     HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
    ( D- S/ X& Y- h' o
  68. }
复制代码

+ [0 w0 M1 x9 `8 @4.7.5      函数bsp_RunPer10ms
) o) f( |5 q/ h. B+ b这个函数里面默认有个按键扫描,如果大家移植的程序里面没有按键初始化,务必要把这个按键扫描函数注释掉。
9 d1 ^- l% Y! t  b2 F7 W
7 P. e- v1 U8 {( _5 Q' n
  1. /*6 _9 t$ D5 C  O8 T" @' }$ l* c
  2. *********************************************************************************************************6 l8 G# x' L9 `  i6 A
  3. *    函 数 名: bsp_RunPer10ms
    ; U5 z& u# g* d" E* T8 K$ B: t% W6 M
  4. *    功能说明: 该函数每隔10ms被Systick中断调用1次。详见 bsp_timer.c的定时中断服务程序。一些处理时间要求
    . j3 @  _  V9 P" N: Z
  5. *             不严格的任务可以放在此函数。比如:按键扫描、蜂鸣器鸣叫控制等。
    ; I4 Y5 a( i, R: k" l$ s7 k
  6. *    形    参: 无
    , r1 @) p# k: e: F6 |
  7. *    返 回 值: 无
    # ]" z# w& \$ h4 N6 u; [9 M8 i
  8. *********************************************************************************************************. B0 D5 w( I+ x: K, U  ^7 m
  9. */
    ; Q. G# m# y5 {5 ~- m
  10. void bsp_RunPer10ms(void)
    " p7 S7 j& f% N
  11. {
    ! H. l# K6 }& E/ N
  12.     bsp_KeyScan10ms();6 P6 Q4 C4 \* \; {% k4 Y8 m' [9 G
  13. }
复制代码
7 o0 |0 K% u: p& s: z) R
4.8   第5步,更新bsp_timer.c和bsp.h文件
9 d# |! s$ f2 j7 X+ G. Y  V! `& A: D更新bsp_timer.c文件是因为此文件跟RTX5都要使用滴答定时器,有冲突。所以大家直接将我们工程模板里面此文件覆盖移植的这个文件即可。
  X& q* [, K- z/ ^
8 [' J/ }! D: _+ ]% p& g. Vbsp.h文件里面要添加一个宏定义,因为bsp_timer.c文件里面做了些条件编译:
! {9 k* S% V! @/ A# o8 U
9 X+ G: x7 b3 ?; Q9 C#define  USE_RTX    1, A4 K2 y; Y, c% Z* `/ g
, ]5 \* d- R5 N: u+ {& s8 E
另外,bsp.h文件将大部分头文件都添加进来了,大家可以根据需要,用到那些头文件,使能那些,用不到的,可以注释掉。当然,不注释也是没问题的:
; ~! d, N8 V% r9 ]/ q4 `9 ^# L' `- J; ?2 n% S7 Y' B8 Z
  1. /* 通过取消注释或者添加注释的方式控制是否包含底层驱动模块 */
    + `0 D/ M0 r, j% U
  2. //#include "bsp_msg.h"
    1 d  R( Q' W, W8 p
  3. //#include "bsp_user_lib.h"
    3 `# `) d$ {6 t5 |
  4. #include "bsp_timer.h"
    6 [* e- b' Z; P; R4 `0 S0 f# f' A
  5. #include "bsp_led.h"( a+ ?* F' z& r" X! _
  6. #include "bsp_key.h"
    ; G: B, R; p/ n. m# |
  7. #include "bsp_dwt.h"* j& v$ H# _. c3 x2 ~

  8. ; R% C6 M2 {3 S- j; U* {# q- v
  9. //#include "bsp_cpu_rtc.h"
    * l4 [5 n9 h. R5 Q2 d
  10. //#include "bsp_cpu_adc.h"
    % L% ?1 t: C0 C3 H
  11. //#include "bsp_cpu_dac.h"
    ( ^1 a- F5 y7 O7 g
  12. #include "bsp_uart_fifo.h"
    7 w( n6 [) \- v/ \3 u
  13. //#include "bsp_uart_gps.h"
    , K, [# {" f1 p# K  F
  14. //#include "bsp_uart_esp8266.h"
    , p3 M7 t) Q5 m) ~; g( q( h
  15. //#include "bsp_uart_sim800.h"
    8 f/ W5 v6 K# o# z% V

  16. 9 {: y$ [: O2 P5 v& }+ d7 A4 K) {
  17. //#include "bsp_spi_bus.h"4 r3 C& E4 I9 N) w, Q0 e0 P- b
  18. //#include "bsp_spi_ad9833.h"
    / G1 f2 z3 y, {& R* T
  19. //#include "bsp_spi_ads1256.h"5 Y& G) f+ C# Q% L" Z
  20. //#include "bsp_spi_dac8501.h"% p- {/ M% {) G5 O# @
  21. //#include "bsp_spi_dac8562.h", q$ ^) X" w/ l5 u; Z
  22. //#include "bsp_spi_flash.h"
    8 H' q  m/ ?. [
  23. //#include "bsp_spi_tm7705.h": B/ h  |( T" u# R6 G! d3 _5 N
  24. //#include "bsp_spi_vs1053b.h"
    " F! a' h# q9 K  Q  Q" v$ O
  25. 0 Z, p) v. ~7 g8 t) Y8 i* a
  26. //#include "bsp_fmc_sdram.h"
    + E% L- E3 S7 v' j( a7 W% {1 W
  27. //#include "bsp_fmc_nand_flash.h"
    & L: t/ u+ o, C; j
  28. //#include "bsp_fmc_ad7606.h"
    . R/ L1 o  W4 T; d. e% W  L
  29. //#include "bsp_fmc_oled.h"
    + P; G7 j5 T) t# B! \) Y
  30. #include "bsp_fmc_io.h": h5 i+ L3 K& F% w, d: d
  31. 0 V, Q/ g, z: n8 u) b5 V) v
  32. //#include "bsp_i2c_gpio.h"
    * i- u6 H/ Y3 ^+ U" _
  33. //#include "bsp_i2c_bh1750.h"
    & z* x# S) N: ]7 K8 j# Y; L9 Z5 m8 d
  34. //#include "bsp_i2c_bmp085.h"
    # P: {. C, o! @$ c% p; K7 U! E" t
  35. //#include "bsp_i2c_eeprom_24xx.h"2 P8 M5 S. E0 @$ ^
  36. //#include "bsp_i2c_hmc5883l.h"
    : Z3 @9 O/ ^$ O0 n( ^
  37. //#include "bsp_i2c_mpu6050.h"
    , S5 L" D7 ]! B4 F2 X- X
  38. //#include "bsp_i2c_si4730.h"
      f' u# a' X: v$ U6 [  W
  39. //#include "bsp_i2c_wm8978.h"8 b! w! `/ g; o$ a& V( ^
  40. ' G5 J4 o& E" h/ C: W$ ?7 Z! h3 O
  41. //#include "bsp_tft_h7.h"
    2 w; u' G% Y) }2 {
  42. //#include "bsp_tft_429.h"  s- B6 b& t! q/ X/ i/ O, `4 |
  43. //#include "bsp_tft_lcd.h"
    - A# f& e( g) }8 }1 b  P
  44. //#include "bsp_ts_touch.h"
    1 Z; `. r1 H9 X0 g
  45. //#include "bsp_ts_ft5x06.h": ?9 M  W# V4 k* a: q
  46. //#include "bsp_ts_gt811.h"
    6 G9 }1 w( O9 _  m
  47. //#include "bsp_ts_gt911.h"9 `/ Y( e7 q& T# }$ ?& `
  48. //#include "bsp_ts_stmpe811.h"0 ~: a% t/ H/ O0 p* ~9 U
  49. ) F; U) z$ Q. z  v; R
  50. #include "bsp_beep.h"6 f: ?1 H* k1 q" a; F+ A
  51. #include "bsp_tim_pwm.h"
    : z, {  v; ]; z; Q' M
  52. //#include "bsp_sdio_sd.h"4 H, a8 E$ e9 ?  K1 d9 e! B1 ~
  53. //#include "bsp_dht11.h"
    ( {& x9 f8 q( s& Y
  54. //#include "bsp_ds18b20.h"
    . j- g" y( S2 \2 w/ ~# c/ T: g0 p
  55. //#include "bsp_ps2.h"4 ]  }9 U2 K2 @7 o/ B4 i: n) K
  56. //#include "bsp_ir_decode.h"2 h0 p2 `) o7 K- D# M* m
  57. //#include "bsp_camera.h"
    + a7 q% w# C1 y) N. i3 ~
  58. //#include "bsp_rs485_led.h"( U3 `& z& d9 }# `
  59. //#include "bsp_can.h"
复制代码

1 |* {6 ?8 e! r9 x# G# I4.9   第6步,修改文件stm32h7xx_it.c
8 p- M9 w( }$ n( _; N删除此文件里面带的如下函数,RTX5要使用,冲突了。
; \2 _2 Q, n( y9 ?( T9 P
! L4 _1 w& s- C& S# y1 K
  1. /**" k3 Y/ _. H9 K" g
  2.   * @brief  This function handles SVCall exception.* ?1 s2 Q; n' X: j+ ]- c3 p6 K
  3.   * @param  None
    + h" @7 \* ~3 `* z5 I
  4.   * @retval None8 N) ?/ V# K/ W  i6 J
  5.   */! W, O# a+ `' |; s" x
  6. void SVC_Handler(void)1 U* }& r* K. h. g2 d2 ?
  7. {
    ( R) m) o; F3 Y6 a# @  P+ W  i
  8. }
    ! D  B7 H# Q5 ?+ c  n

  9. $ y9 O6 \6 B2 k2 U: K2 v/ M
  10. /**5 R; t. y) r+ O2 {9 R" [
  11.   * @brief  This function handles PendSVC exception.
    ' h. A, X* B. G4 ]( ]4 i
  12.   * @param  None
    4 T. Q3 ^6 M! W
  13.   * @retval None" u" p( }- F2 d5 n7 t* ?
  14.   */8 o# K2 [9 l. M6 q: f3 o; A
  15. void PendSV_Handler(void)
    " v# d( O8 S, {$ i8 ?4 M
  16. {
    % e9 t# \6 S% T& V- C, j- ?
  17. }
复制代码

& P% c+ D8 k  H# s# x/ |# N# @4.10 第7步,添加头文件的汇总文件includes.h  O. Z) f; t; J& b
在User文件夹下添加文件incudes.h,直接从本章节教程配套例子的User文件夹复制即可。此文件主要用于RTX5的各种头文件汇总。
2 ~4 j! n# e, S" E/ A4 ?
) G( p  P) w6 v3 K4 _& S
63fafbc927e6b911f6f3b81c4acb6af1.png

8 |1 Y% i+ n  e, R# R; i; {4 A: m( m8 q& R, c5 ]; a1 E
4.11 第8步,HAL库时间基准stm32h7xx_hal_timebase_tim.c
' Q+ ?9 ~/ N3 ]
由于RTX5和HAL库需要一个时间基准,而且默认都是用的滴答定时器,所有要有一个选用其它的时间基准。当前的处理方案是为HAL库提供一个时间基准文件stm32h7xx_hal_timbase_tim.c。此文件
) O8 }) G1 T. E# k) M& n4 ?
1 H* O, P1 I! B' ~1 E! S* D1 y0 K9 I里面做了两套方案,一个是使用TIM7做时间基准,另一个是使用RTX5的API做时间基准,通过条件编译做选择。默认是采用RTX5的API做时间基准。. x# u6 g4 _. T' N$ N7 v
, [9 q; r8 c: Q. m
  1. /*2 G+ B: ]8 ~8 q  c( f
  2. *********************************************************************************************************
    + S( A$ J% Z( G0 l- T& p- v7 B1 |" j
  3. *    函 数 名: HAL_Delay
    ( \! M/ h% N5 D5 g
  4. *    功能说明: 重定向毫秒延迟函数。替换HAL中的函数。因为HAL中的缺省函数依赖于Systick中断,如果在USB、SD
    & p' D0 M0 D  N* t& D+ d% h1 c: p. x
  5. *             卡中断中有延迟函数,则会锁死。也可以通过函数HAL_NVIC_SetPriority提升Systick中断8 e8 s  o" m8 M1 e& q/ R) h
  6. *    形    参: 无
    / X; k- b1 K+ j% i3 W, m
  7. *    返 回 值: 无
    $ b% w/ u/ s: m. a$ \, w
  8. *********************************************************************************************************% E6 M7 f6 D4 ^  z  }# v6 L& a
  9. */# u, w& a' Q& @3 r. r
  10. void HAL_Delay(uint32_t Delay)
    ; V8 J1 T. ]1 A# O2 r! _2 u5 q) a
  11. {0 j- A  s- J4 C
  12.     bsp_DelayMS(Delay);* f) j, A9 O4 C) ~- ^& g$ {: ]
  13. }
    . L. t  P: b! X) s' h4 j: F# w& J
  14. 0 i1 i6 Q  d- n1 ?3 g/ A* y6 D
  15. HAL_StatusTypeDef HAL_InitTick (uint32_t TickPriority)7 K. s  H# z8 l  p, D8 ^' ^
  16. {
    9 o9 [+ Q: A) I
  17.     return HAL_OK;5 w+ }3 z4 i  d
  18. }: e/ l' y! R' ]) R* b, R) P

  19. 1 u; L  }5 o/ R1 y
  20. uint32_t HAL_GetTick (void)
    ; `: }) G- u# @+ L+ g  L" t
  21. {2 [3 X8 Z; b1 [; j/ x# e
  22.     static uint32_t ticks = 0U;) I# f; C; o: n3 X$ [. a
  23.     uint32_t i;
    9 y- \% m. t8 K' w( W# |9 f

  24. # n5 {7 X: \. x7 N: @) H
  25.     if (osKernelGetState () == osKernelRunning)  B- u4 G0 w6 _& w
  26.     {# [1 c, K  J4 Q( V  A# h* E
  27.         return ((uint32_t)osKernelGetTickCount ());
    % n' h( d  y- V) N; E
  28.     }9 u0 z* [, @4 N9 a. m0 \

  29. % }( p; N7 Y2 C# I' w$ `& p
  30.     /* 如果RTX5还没有运行,采用下面方式 */! C* {  W- `' O0 \! Y8 O
  31.     for (i = (SystemCoreClock >> 14U); i > 0U; i--)
    7 P+ C& r- u% N+ p% f
  32.     {
    0 o& k5 j& V/ d$ y, G* w! f5 O
  33.         __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP();
    5 U; R2 A' }( u
  34.         __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP();$ B5 Q7 p+ v5 g+ a
  35.     }  ~( \4 H# Q% G3 E0 ]& I: ?, _

  36. / i6 q5 W( U3 L$ b3 ]0 w: x
  37.     return ++ticks;- P' R; K, i  s3 F
  38. }
复制代码

3 V( B: t6 o" H; U" o( v: }2 t4.12 第9步,添加BSP驱动文件bsp_dwt.c
1 V; V3 n. e9 I* ]& h- Q
添加bsp_dwt.c文件和bsp_dwt.h文件主要是因为第8步中的stm32h7xx_hal_timebase_tim.c文件里面的函数bsp_DelayMS要使用,此函数是基于DWT系统时钟周期计数器实现。# `0 K( F! S- Y) g6 s
* C5 o! x. d2 K: U9 b7 y
f0d85f2002a553fa31c8f67b30e2db76.png

' |/ j: R/ j4 D* J# A8 z1 l2 r3 y. y4 T$ T- n& D
4.13 第10步,创建应用任务(重要,注意启动任务)

6 ^' y. f4 v* ^7 N7 X5 C. t应用程序比较简单,大家可以直接复制本章教程配置例子的main.c文件中的内容到自己工程里面测试。主要创建了如下几个任务:
# b8 w( g( _- N1 u, E6 H! i; y
1 m" H: j8 V5 E) QAppTaskUserIF任务   : 按键消息处理。
7 O6 d. a" u" w3 O1 S  B# Z. y, ^: r+ E4 A4 O
AppTaskLED任务      : LED闪烁。- C: F. P/ T( |, Q7 r% C5 a( C; ~" \

* m2 @  G1 n/ z7 JAppTaskMsgPro任务   : 消息处理,暂未使用。
" k7 a; @- z! {) K' e6 O! F- c
AppTaskStart任务    : 启动任务,也是最高优先级任务,这里实现按键扫描。
& h1 N0 d8 I. Q8 D9 [8 j0 v/ n  i  y& F3 z$ |
osRtxTimerThread任务: 定时器任务,暂未使用。% z. B% C5 S+ n, X. P! h, q

$ m; S: S, k6 y( I任务栈大小和任务控制块定义如下:  L2 o; y9 T7 i& ]! [

; d9 {/ C' Z& ]
  1. /*
    6 _) r: k2 e( h; N. M0 ^- v' ^
  2. **********************************************************************************************************+ E7 |+ R+ E5 G# n8 Z1 A6 g( i3 @
  3.                                              变量
    8 Q& c, |/ \7 f' S
  4. **********************************************************************************************************0 j) |) E! Y$ t; g- S% ?
  5. */
    7 W' e$ p: J2 G. s
  6. /* 任务的属性设置 */
    ' ?. z9 C8 J, J6 g$ u1 [9 e8 ~
  7. const osThreadAttr_t ThreadStart_Attr =
    ' d( _% O" H# w- h  n
  8. {8 t4 G! t) }  x5 N9 z/ e
  9.     /* 未使用 */
    1 z0 J: P- u9 a" C" K" \
  10. //    .cb_mem = &worker_thread_tcb_1,
    5 z. J( |% m2 C
  11. //    .cb_size = sizeof(worker_thread_tcb_1),
    8 M: D" Q2 P$ Q6 ^+ ^, y8 |: ]
  12. //    .stack_mem = &worker_thread_stk_1[0],
    : R1 d3 ?8 S: Z( Z8 ]5 @/ F8 Q
  13. //    .stack_size = sizeof(worker_thread_stk_1),' `9 P% `" }# w
  14. //    .priority = osPriorityAboveNormal,0 d8 K( \% p, H. t  |) [6 Z* F
  15. //    .tz_module = 0
    / v; s7 z$ g9 m1 w4 H7 T
  16. ( \7 L! U6 W/ N8 }6 R6 L
  17.     .name = "osRtxStartThread",. k! k  a1 c. m+ K- Z/ h/ ~
  18.     .attr_bits = osThreadDetached,
    0 F! i, g" j5 X3 q
  19.     .priority = osPriorityHigh4,
    ' x4 b# A' a7 ^
  20.     .stack_size = 2048,% g" w( t( A0 W4 R  G
  21. };
    ) }9 J& ]# V$ h2 a9 J3 T* v# c

  22. : P$ R% z4 k. C: o5 Y
  23. const osThreadAttr_t ThreadMsgPro_Attr = 0 X+ ~; n9 n# n8 f9 u
  24. {4 X8 ?. X9 |; I' W) S
  25.     .name = "osRtxMsgProThread",
    " g% e& P4 G% u/ h
  26.     .attr_bits = osThreadDetached,
    3 s* k' s/ b1 S- g) G, s, M! ~8 O
  27.     .priority = osPriorityHigh3,
    8 f0 F$ f  I: ~/ M
  28.     .stack_size = 1024,& `- M7 [6 v& N
  29. };$ \7 j' U& h5 }/ m. Q
  30. : J* J! `) B9 ?; C  d
  31. const osThreadAttr_t ThreadLED_Attr = , X3 O1 F/ _% p7 h
  32. {
    1 t1 p- ]. l4 O  U1 f6 |
  33.     .name = "osRtxLEDThread",
    + ]; S( J, {9 d+ s# o
  34.     .attr_bits = osThreadDetached,
    * ?8 d  J* n: Y* ]4 w% ]1 Q
  35.     .priority = osPriorityHigh2,' y4 k& C3 z7 j/ `7 H1 O% h
  36.     .stack_size = 512,8 [, R# v/ p4 g- p$ `5 A
  37. };: l: O* ~4 o/ r5 n8 Z

  38. 1 j8 }( {* s5 M, j2 O
  39. const osThreadAttr_t ThreadUserIF_Attr =
    6 |0 @& {; d8 w6 h+ \( X/ [; e, ~; d
  40. {' f# q  A! _( L; Y8 `3 ?, G+ m$ R
  41.     .name = "osRtxThreadUserIF",( j/ N5 M5 ?4 S" M9 [4 |& i
  42.     .attr_bits = osThreadDetached,
    9 h* r, M8 n0 S, J. I
  43.     .priority = osPriorityHigh1,
    6 s% c0 B& S2 l9 Z8 J
  44.     .stack_size = 1024,
    : o, o) q1 [9 ^$ k) ^& h  {6 r. Y
  45. };
复制代码
( T& H% z% t3 k& c" q: T
任务创建:
9 ~' q' Q% N1 O$ S9 K. H3 r* [
3 J; j( g) d/ A0 Q) s# g& b' j
  1. /*
    8 ]. `! @9 n0 V2 z9 \! N0 d! B
  2. *********************************************************************************************************( U: I# A( O) g
  3. *    函 数 名: main
    ' d( Q' r; a, ^* Q. `
  4. *    功能说明: 标准c程序入口。
    ( W0 `$ F$ g! `7 e+ M
  5. *    形    参: 无
    ) d# j6 c5 S  p7 j
  6. *    返 回 值: 无
    ' t* g1 e2 N3 w& X& a
  7. *********************************************************************************************************- y8 j6 c* S4 ?
  8. */+ b+ C: y% B$ k) c
  9. int main (void) - I1 V% x, Y  U$ S+ Y9 Y: l
  10. {   
    8 t3 ^# H9 ], ~  `+ u" m
  11.     /* HAL库,MPU,Cache,时钟等系统初始化 */+ c) T; V% t2 y' Q8 c
  12.     System_Init();
    & E) _* g1 S; e& ?# X3 e: y

  13. 4 T* w  |2 n  p
  14.     /* 内核开启前关闭HAL的时间基准 */
    4 w! ?5 g+ v# U8 d  b" O! N
  15.     HAL_SuspendTick();/ d  D5 f! a- P; V: R2 c# y

  16. 7 Z! U" |7 o& `: ^6 y
  17.     /* 内核初始化 */
    ) D2 W5 ], v+ E- @! n: H4 C
  18.     osKernelInitialize();                                 
    & L* ~3 o3 q8 k8 T' x

  19. . U5 C; v1 ^: [
  20.     /* 创建启动任务 */
      X  M9 e6 [+ p9 L* Y3 A
  21.     ThreadIdStart = osThreadNew(AppTaskStart, NULL, &ThreadStart_Attr);  
    ! g3 }/ h6 v# p! T$ X4 ^

  22. 2 n2 I5 {- H6 c1 ]% Y, x3 v3 @$ H
  23.     /* 开启多任务 *// L* u/ a1 |9 v& ~( c
  24.     osKernelStart();+ Z* e6 n% V: c3 M, s7 \# r

  25. 8 ]6 t  ~- n% @" ^- w$ \
  26.     while(1);
    # M3 M8 U7 J! H. u1 Z2 S
  27. }2 h1 Q& z6 B  w4 K6 h
  28. 4 `+ B+ S! O$ U+ j9 p) _
  29. /*
    ! p! V+ }6 e4 ?, O# ?1 Q
  30. *********************************************************************************************************1 F) K) T5 v3 @% W2 E) o
  31. *    函 数 名: AppTaskCreate
    2 S7 w4 z  K+ X. c% ^4 c8 p6 G
  32. *    功能说明: 创建应用任务
    # g) `$ W2 ?% j- O, @- l+ R. s+ \  J  p
  33. *    形    参: 无3 i$ f0 n8 X& \1 l6 c* C4 o
  34. *    返 回 值: 无, A( G3 N, {+ P* D' i8 K6 k
  35. *********************************************************************************************************
    ( N" ^  w4 H" q4 S) A
  36. */  [/ z; |; e9 {5 G( H" ?
  37. static void AppTaskCreate (void)
    $ I, L4 m7 o% V* Y
  38. {- @) x2 a) W4 D9 k
  39.     ThreadIdTaskMsgPro = osThreadNew(AppTaskMsgPro, NULL, &ThreadMsgPro_Attr);  4 @7 E9 G5 Y* R
  40.     ThreadIdTaskLED = osThreadNew(AppTaskLED, NULL, &ThreadLED_Attr);  
    / w( ^' K# {- B$ Q
  41.     ThreadIdTaskUserIF = osThreadNew(AppTaskUserIF, NULL, &ThreadUserIF_Attr);  
    $ u5 w. |) G& V5 ]/ ^8 w& [
  42. }
复制代码

) h+ P4 Y- i3 }1 G# x7 b这里我们重点看下启动任务,主要做了四个工作:
$ V5 N/ }% U2 L6 r
/ e0 C2 r! t! I, X; y  外设初始化bsp_Init。
- x: |. \( o4 G! Q8 H  任务创建AppTaskCreate。- x& L" s; S1 p6 M$ l
  需要周期性处理的程序bsp_ProPer1ms,对应裸机工程调用的SysTick_ISR。这个的实现非常重要,这样之前裸机里面使用的API,就可以直接在RTX5里面直接调用。' i3 e) \$ e2 A+ Z8 O$ _9 Y& E
  1. /*
    ; V: e2 c4 R# E# O* i$ r/ n8 f
  2. *********************************************************************************************************+ N) p+ H6 V  r1 D
  3. *    函 数 名: AppTaskStart
    - K) G- r& w& Y1 d2 C) {
  4. *    功能说明: 启动任务,这里用作BSP驱动包处理。4 P) ^& l8 m- I  x/ E
  5. *    形    参: 无5 q9 T7 F( R# B- d
  6. *    返 回 值: 无$ {1 p+ @$ b  j. A( A
  7. *   优 先 级: osPriorityHigh4  
    - D. E% |' ]: X8 X' E/ [
  8. *********************************************************************************************************3 K8 l, f; \2 v7 G( p. L
  9. */
    # r3 S* a6 d' Y0 Q; d, K
  10. void AppTaskStart(void *argument)
    . v! z2 U: u# ~
  11. {; a5 K3 a0 A1 i* e, N6 S: b7 U
  12.     const uint16_t usFrequency = 1; /* 延迟周期 */5 Z+ o5 q" h9 v* r" U* [& R
  13.     uint32_t tick;
    ' y8 M! G9 A/ s: r* p9 B
  14. 7 F8 B0 ]( l+ Z5 a# G. M
  15.     /* 初始化外设 */9 \( v3 u! }0 Y8 A0 p; T, ~7 h
  16.     HAL_ResumeTick();& T! n; v7 ]& P/ C& {# X3 f3 }
  17.     bsp_Init();
    1 w8 U0 r- V! K5 O
  18. " y9 V! ~8 W, _6 Q! p; E
  19.     /* 创建任务 */
    & Y2 U3 x" g# `) f, q
  20.     AppTaskCreate();
    0 t8 T& |5 R0 I
  21. ! C; h1 x5 P8 Z) e  n/ j9 Y8 l
  22.     /* 获取当前时间 */
    " x  m" P0 F" }
  23.     tick = osKernelGetTickCount();
    5 J8 w7 {, n9 j1 r9 d  U* k+ f1 w4 R
  24. , Y* Z/ b0 e3 n% G  e
  25.     while(1)
    4 \- S) u* S( t1 J+ v) c; ~
  26.     {' I4 f) r% q% d* T: v2 ]7 {
  27.         /* 需要周期性处理的程序,对应裸机工程调用的SysTick_ISR */
    7 ]2 i) a! n& }; W. Y
  28.         bsp_ProPer1ms();( ~4 C, T& ~+ H$ @& a6 D
  29. ( p# V0 m! W# U0 |$ Y4 z, J
  30.         /* 相对延迟 */7 D$ t+ O8 d2 e
  31.         tick += usFrequency;                          
    " o0 l# V: x( U: Q% D
  32.         osDelayUntil(tick);+ H# S, H# t) @  l, b
  33.     }
    . ~2 V* v* k3 h$ v* `
  34. }
复制代码
. w+ k; e0 P& M2 \! j2 B
4.14 常见移植错误总结
  j* _- o$ [- l$ s8 E. v$ @
常见的移植错误主要有下面几种情况:
6 K% A1 F3 h  P/ g
, c' Y; j+ O4 e2 w: v  编译后提示如下两种错误:& _: m9 @0 b% |# l7 [
Error: L6200E: Symbol PendSV_Handler multiply defined (by irq_cm4f.o and stm32h7xx_it.o).
2 W; n- Z1 ]( O( h/ ?, G/ Q- m' d! I: e+ A+ U9 Q$ t
Error: L6200E: Symbol SVC_Handler multiply defined (by irq_cm4f.o and stm32h7xx_it.o).
! x& z; N/ m! N( K# R+ C+ @% g& S! ^  g5 ?' l
解决办法:这是函数重定义了,直接将stm32h7xx_it.c文件里面的PendSV_Handler和SVC_Handler删掉。0 ]8 ]4 k2 c/ j1 M+ w
9 S6 I& v$ b: Q* P
  提示如下错误
. l( L5 g2 F# n8 x, L7 I. LError: L6218E: Undefined symbol bsp_DelayMS (referred from bsp_fmc_io.o).
4 w  H/ e. o/ g. f) l& T5 G0 F- B* ^
+ i) |' N9 ?" \+ @, I1 W解决办法:打开bsp_dwt.C文件中的条件编译。+ |& Q8 b& b) l
! D0 z" G% {( g
4.15 实验例程
$ f9 ]) f9 k: j8 i( |) }& B. i本章节配套了如下几个例子供大家移植参考:
, L) |; X  E4 p
( e+ W# L. j/ f8 E7 b& M1 v( B  V7-400_Base Template8 H  L8 y( t* e" ^3 J, ^% x
裸机模板,方便大家添加RTX5内核源码。
: E  F# |+ M1 ]3 k4 m! J$ M2 e% y7 g* ~$ I  _
  V7-401_Threadx Kernel Template
- t0 X+ m7 ]7 H) d4 c. y- D( [! w4 H% K' @
ThreadX内核模板。
) I6 j( U, b* m5 W: w, ~# Y# {
! }! F; K- c: p- _( ]3 A- zMDK进入调试状态后,选择周期更新:" Y; e2 `" f2 B# G$ i/ r3 P
3 b. @. w- f) b3 v( ?* i0 ^- K1 D
fdce9fac9944ad56faa0dd13307f6ebb.png
$ k$ p: m0 N6 ?  ^
$ r% ^8 p1 j* T# A5 D
然后打开调试组件,注意和RTX4的调试组件位置不同:! [: ^: I& O& a2 G

& r) m  u1 P- \& A  W. V
9482ce7367ba4d7cf08c73a56db28f75.png

" S) L# W% i& Q- h5 r6 J4 b( G' s2 g! r
然后点击MDK的全速运行,
4 R9 m4 C$ g$ ]+ M9 d
6 p0 o9 m' U' G' v5 d
e3038a01781216611f96ae37d5bccb17.png
* u5 H) T. |8 W9 y

& c) S/ A* {" O" \0 ]' {' |# B至此,就可以动态实时查看RTX5的运行状态:9 ]# D2 m9 J! W9 b" n* H' Q
. E- N+ E) a0 l( [3 K% {- Q+ G& J
797f68ea76bd699fe11ce441076df4ec.png

  O4 j+ `8 I6 K+ m" m
9 j1 R5 v# S' _+ W& f4.16 总结/ b9 y' q# ?9 q! v; e+ I  {* u
本章节为大家讲解了RTX5 在MDK AC5上的移植方法,移植涉及到的知识点比较多,初学的话,建议实际动手操作一遍。
. d2 I$ D1 M3 p3 Y' F& @; g: L' M3 F

, x( z$ s/ V$ @7 z  I% P, s  M, m& n
赞 收藏 评论1 发布时间:2021-12-30 14:32

举报

1个回答
STMWoodData 回答时间:2021-12-30 15:31:46

好好学习

所属标签

相似技术帖

官网相关资源

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