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

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

[复制链接]
STMCU小助手 发布时间:2021-12-30 14:32
4.1   初学者重要提示" p* {  }9 ^2 J4 S# V7 p$ U( u
  当前RTX5可以移植到GCC,MDK和IAR三大平台,考虑到仅MDK平台下有RTX5的调试组件,我们这里仅提供了MDK的移植说明。* f! J7 R/ L$ U
  STM32H7使用MDK RTE环境添加RTX5,需要强制运行一次STM32CubeMX,因为H7已经没有配套RTE经典添加方式,而STM32F4是支持经典方式的,所以无需运行STM32CubeMX,详情可以看我们STM32F4开发板对应的RTX5教程。
' ]5 k8 t$ o" v9 t4.2   移植RXT5内核整体说明5 Z. w4 u- P2 x# i8 Q
移植之前,有必要对移植过程有个整体的认识:
8 q3 j: }# ^9 j) w3 [) R4 |9 a1 h0 v
2 T2 ^+ B% Z7 Q* l  第1步,准备一个工程模板。
4 f2 ^% s0 n9 y  第2步,移植RTX5。2 J7 c; Z% Z' g2 D
  移植RTX5是采用MDK的RTE环境直接添加。当前H7芯片使用RTX5强制运行STM32CubeMX,所以需要大家提前安装好STM32CubeMX V5.4或者以上版本。1 U' B$ {1 E3 B# Z
  第3步,处理HAL库时间基准,MPU配置等。
. h) \$ w2 a% I% }  第4步,创建应用。9 _- ?% B( ~' ~

& v4 ]2 P' \* N总的来说,这4步就可以完成移植, 下面将STM32H7的移植步骤和注意事项为大家做个说明。
- J" i' p! A- }; S4 k" V3 h/ }: E
4.3   了解RTX5内核模板框架设计4 J0 j5 [$ s" {7 d( N7 L
移植RTX5前,我们优先了解下移植好的RTX5内核模板,方面大家后面移植:
# H% y* V$ a2 `! c. L- n4 T8 ?! e* m0 E
ebf7bed4831890980f518eaeb842a943.png

: k; S! ]" g; W1 q- o/ V& q) O7 _( h. N9 K- ~  T
框图如下:( o7 c4 z2 I  q7 X
- j0 L' K! P6 C" L4 i  Q1 g
cc3f4f5af7e41dcb23a03a25e14d8ae7.png

) q7 D7 {' s- ?  B7 _9 H9 h  `% W2 A
/ Z6 |5 j& G' e! y  U% M; y4.4   第1步,安装指定的MDK软件包版本
4 a$ O6 Y0 c+ }2 D+ S5 r9 ^7 R7 \移植新版RTX5需要大家下载当前最新的MDK软件包版本(如果有最新版,推荐大家用最新版):
& g/ c: ?. `, N, Z1 w4 ^. r) y: V9 D. F- M% {9 u0 x, F
  CMSIS 软件包使用当前最新的:V5.7.0+ r6 v& D. o3 {8 u. B
  STM32H7使用当前最新的:V2.6.0
& c3 V6 l$ z7 v. P! R3 f  STM32F4使用当前最新的:V2.6.0* L% [# |# _+ X; @8 L
  STM32CubeMX使用当前最新的:V6.0.x
. s% B, @) n& e4 L! S8 v  ARM_Compiler使用当前最新的:V1.6.1. O. j* g" Z$ b  P( k) P

( H! L# W( A$ @. m不管以后MDK的软件包版本如何升级,当前的软件包版本和以后的新版是可以同时安装的,也就是说可以安装多个不同版本,在这里可以选择指定版本:
! I+ r9 n# F0 V% C) Q5 l
/ x* V) E6 \. h& k* P1 h
bbb84b8c4b3275b1026d2c95b5012294.png
1 Q& ~4 u2 f$ O
! \2 l% `7 P6 p6 t0 G( c4 t
4.5   第2步,准备一个工程模板
* u/ M7 P0 A9 L9 j首先准备好一个简单的裸机工程模板,已经为大家做好:V7-400_Base Template,准备好的工程模板如下图所示(大家也可以制作其它任意的工程模板,不限制):6 ]& D9 v/ {  d, S4 o9 t

; _0 D4 X# m8 u6 v
5618d5a487ef825c0a75ce19685c4821.png
* c3 `0 g/ U, e6 C

! G" \2 L9 h9 d4.6   第3步,添加RTX5并配置
/ U* }$ f( L$ S" v; Z1 t) WRTX5可以方便的通过MDK的RTE环境添加进来。对于H7版本,MDK会强制运行一次CubeMX,并添加很多H7的HAL库文件,这些库文件我们可以使用,也可以不使用。教程配套的工程文件是不使用这些,因为前面的工程模板里面已经添加了。所以要将这些文件全部隔离出来。( }, R; I" z- ]5 b! Q& s& P" @

$ _% Q4 f7 r; ~3 g4.6.1      添加RTX5源码# }7 E# a) O6 Z/ \' j

( l4 Q, K2 q3 n3 l7 w' o
48f11b91f9fc45f3f04431047156434d.png
: {5 r8 N! M6 I/ Q
5 p9 k1 }3 u7 e$ `# T4 d7 t- S5 t
点击OK按钮后,弹出如下界面:3 u2 h$ _9 A7 n

3 _4 E6 a+ e5 K# k
b430f5f7b2e1a16de73553adb9dd1f89.png
% m0 a' h, Y& ~( ?, Y. t
1 ?. u: K$ U6 k+ H# O0 H, d
点击Start STM32CubeMX,这里需要大家电脑上已经安装了STM32CubeMX,并且为其安装了H7的软件包。
7 {8 J6 _+ \( q9 r  k4 p. w6 Y+ J, I6 h. ^% i( Z3 y5 p2 D
af4f52889e56b18313faf6baa5ed1281.png
% {. x/ K% S  [( y5 F2 ]0 ^
# C8 I/ R. O* b# ?& _0 Q, l
打开后,用户仅需配置如下地方即可:
4 h( F- }# j3 k# P8 Q3 v6 V9 {4 @" c, a5 z9 x) o5 W
7c8a9271ba3d0ccb045c81921fd97d0f.png
# W4 r: m% c! }4 i3 P/ G  a0 O

& ~* k; D: `2 C( d7 k然后点击右上角的GENERATE CODE:
* M0 |0 J) v5 E( B2 g8 h7 \/ Z/ z. A+ l" c3 m6 q7 V% F
62747d5251f02d427c05caf48fc46d77.png

3 O) u4 Y$ H7 w2 }, `9 T6 J
) T5 z* p2 j0 J然后弹出如下对话框,点击Close即可,然后关闭STM32CubeMX。! f$ w& ^2 e7 J: G' T
% s" e4 h# H! n% [/ F+ X, L9 C" V
1a4404327c06b66c217f46c74bd48db2.png

& U- m- b$ M* B: U  X4 V2 d: M- c& z3 B% n! B- W3 E
重新回到MDK,会有一个对话框,点击是即可:
& m% h/ V& ]( }" K/ z# J" @* u0 D7 r. _* o  m" y
cdfb3b29fdf8c8b60f0d85f8aaa161ff.png
  [' h# j. y2 |$ Q6 S. @

" w7 T# |- V& `最后就可以看到RTX5源码已经添加到工程里面了:
  s, T0 `6 N3 Y: Y& W; w) d; R
3 X- E6 f# n# J% P- T
e49f340b4464ddd3afb5bf5082de0fdd.png
% q/ c) @7 N! w/ C! Q
" i3 r. O: G; e
4.6.2      将自动添加的库文件隔离出来
9 v0 e( j. T/ H2 o* k添加的所有文件中,仅RTX5和文件stm32h7xx_hal_msp.c留下,其它文件全部隔离出来,隔离方法也比较简单,比如隔离生成的main.c函数,鼠标右击此文件选择Options for file ‘main.c’9 L: C2 i# \2 `; `! v* I

$ L) H  z) o; p5 \4 a
3b989ad148a2ec7c0522490cd84fcf3c.png

9 V" o6 ?# s" [- T
" ]# n2 K' ~( o2 h# K8 S然后取消掉include Target Build前的对勾,点击OK:. C+ |* {, J1 o5 X

7 h4 p* _9 y% e7 W0 x6 L* Y0 r
6652eec0f1078d33b6c1508049d0c922.png
( n6 |7 J; Y5 e0 W2 k7 d
* h" `+ O: h) e# x; ]$ Q
看到main.c文件上有个红色横杠,就表示已经隔离出来了:/ \4 v& `- J9 ?  O7 w

5 D% ?6 ~% j: \8 U6 u( N/ `' c" b
cafbe4a03ab78632d36b9cf1b050250c.png

5 M& ]* e% e$ H/ j# N+ [8 Y
8 y  w. M5 T5 B; F同样的方法,将stm32h7xx_it.c文件也隔离出来,文件stm32h7xx_it.h不用管。
( `1 R' w4 i0 Z
4 A- u2 I$ Y: D, m' o5 @Device下面的这些文件也是同样的隔离方法:
* _0 Z$ [0 [2 X; W- u. ?1 E: t5 `/ u8 K' }
f46dbe6e1b27dd459e04cba9849d9ff9.png
- U# y. p9 R  X$ N
8 v. N: e3 M/ n* t; A3 f% {. I- `/ g
只是鼠标右击弹出的界面有些不同:
: N5 c+ D, y, _$ h( g$ t
5 A0 C8 A; h- h# `) s
aeccd1d366ee4da23ceff332ae2f84e5.png
8 d; q8 c1 s2 N0 k0 i

. `( y  h7 `' F0 w3 w4 S8 l) J注意stm32h7xx_hal_msp.c无需隔离,其它所有的文件全部隔离,stm32h7xx_hal_msp.c对应的隔离配置是STM32CubeMX,如果也隔离了,编译会有问题:
& ]5 |3 e) j/ B6 J, l' T5 f
" B4 b: J! h( ~2 c/ `  x; m
59f0e5e7d43f7ac7e983147c132a42ce.png
' m) @2 D" v4 e6 A; w
1 |" `1 g1 B, B" B# ^! e- o
隔离后的效果如下:
/ {8 Q) z' B# ]6 `; ?$ A7 }/ q8 ]8 s! z
573fb2c99aa8ef7ef6f577c106084913.png

7 S4 }. k% P8 N6 G5 R( s: y: B" @
! ?% W% ?$ r" A& q& w4.6.3      RTX5配置
& X. y! F# h6 _剩下就是配置RTX5,设置RTX_Config.h文件即可,移植阶段先按照如下设置配置好,后面章节会专门为大家讲解每个参数的配置含义:9 j/ W# |4 ^- U3 g# b
, @5 F( C. K$ H' `0 \  Z
576cda809f95be40653ff18b9682f906.png
  F, \" t9 ~8 S
& n- t0 V2 k- \1 M9 H4 ?; ]- \- W9 f% M
4.7   第4步,MPU和Cache配置文件bsp.c
) F0 _2 K# u7 _/ l. k这个bsp.c文件也比较重要,移植阶段,直接将我们移植好的模板内容复制过去即可,这里把相关的内容为大家做个说明。
+ y6 h' \' s1 h" v: F9 |2 j  H& S" Y) M9 c* t. P8 X
4.7.1      函数System_Init

) h: d; Z: U9 j" b+ c/ ~$ @0 @系统初始化,主要是MPU,Cache和系统时钟配置,需要在RTX5初始化之前调用。0 w+ ]' |. i3 n

/ R9 [6 |3 _! p& G/ \; L# i+ D
  1. /*
    8 g, G" X# I. Q; t
  2. *********************************************************************************************************
    6 B5 H  M# ]/ s, g, ^5 g
  3. *    函 数 名: System_Init
    0 r# j! g+ r& \- D
  4. *    功能说明: 系统初始化,主要是MPU,Cache和系统时钟配置
    % s' e2 `# I4 j. q  J7 h3 Y$ r
  5. *    形    参:无
    + K4 j/ U4 m8 u) U
  6. *    返 回 值: 无
    0 {! ?1 p8 E9 s( O) u
  7. *********************************************************************************************************
    / ]% b& W) d( {# ~/ L
  8. */6 k. u* k" H$ b- u, v7 i
  9. void System_Init(void)
    : U2 ~+ k, `! `$ ]) k7 F+ G
  10. {
    2 {# I, Q8 F3 `) G- d3 ]

  11. 1 N% \" r6 t6 u
  12.     /* 配置MPU */
    2 x; C0 Y, f7 \6 R5 H/ B# j
  13.     MPU_Config();
    ( E$ B; X+ h  c: m# \( ?4 D: [
  14. & g8 Z% ?# V3 ?' N
  15.     /* 使能L1 Cache */, H$ D9 w& i2 f  N
  16.     CPU_CACHE_Enable();
    6 Y6 r' J  W) |8 ~& m6 X( ?( U

  17. : u4 C+ M9 O1 h, }+ M0 u& V
  18.     /*
    : ?- r4 F# |# e5 l! L/ Q2 `* C
  19.        STM32H7xx HAL 库初始化,此时系统用的还是H7自带的64MHz,HSI时钟:
    4 J2 N' `4 S- d8 n' }$ N8 F6 Y
  20.        - 调用函数HAL_InitTick,初始化滴答时钟中断1ms。: }1 t& X& A. I  I* l0 _8 x+ S! ]) \
  21.        - 设置NVIV优先级分组为4。7 G0 p* F5 v5 n/ U
  22.      */
    6 d* e- H! p9 r2 t, d
  23.     HAL_Init();
    , ]9 n3 z0 L$ V8 Z
  24. $ Z% L$ a! n. t8 e) p
  25.     /* ! e0 |* }; U0 `$ g' c: G0 ?; z
  26.        配置系统时钟到400MHz
    . v. u5 H  t2 [9 u. g1 _$ Y6 Z1 x
  27.        - 切换使用HSE。* O+ ]& E0 l$ n% M+ K7 [
  28.        - 此函数会更新全局变量SystemCoreClock,并重新配置HAL_InitTick。
    . i) h8 u) q& j' v
  29.     */) t9 |+ j3 K4 t, p9 u8 s2 m* V9 [
  30.     SystemClock_Config();  ^- b" i4 i& t

  31. 9 p4 n1 m5 p0 F: G7 ?
  32.     /* 3 R& y2 K8 D, Q( }4 x
  33.        Event Recorder:; F8 ]5 e- s/ K/ ~# L6 r
  34.        - 可用于代码执行时间测量,MDK5.25及其以上版本才支持,IAR不支持。
    ( y8 l1 J9 g5 y( s
  35.        - 默认不开启,如果要使能此选项,务必看V7开发板用户手册第8章
    3 b) F% U- e% l) Q- [" T) p
  36.     */    / `; R2 N4 K( Y/ Z* h
  37. #if Enable_EventRecorder == 1  
      C2 B7 ?5 U" f! b- U  X
  38.     /* 初始化EventRecorder并开启 */% ]1 u0 `; E  M6 K
  39.     EventRecorderInitialize(EventRecordAll, 1U);+ I& X/ X) h8 t+ }/ D5 {( c6 p8 A
  40.     EventRecorderStart();
    / s8 p; f; a& M+ z5 x( O2 H
  41. #endif
    ! T1 _4 V' `" T  D$ K

  42. $ ?; ^2 _1 O9 B8 D
  43. }
复制代码
( q& f  x- z. X
4.7.2      函数bsp_Init
9 }# G, P+ `/ a  f) G硬件外设的初始化,这个函数在RTX5的启动任务里面调用。
+ Z! [  J5 d; @. x' x* c1 _+ @' m: _/ p* S) u* W
  1. /*  I0 f0 X$ ~+ p% n  k- S  K
  2. *********************************************************************************************************
    * A1 k& F% H- T* a6 x3 H
  3. *    函 数 名: bsp_Init
    & E7 z7 w' g3 h! k$ C
  4. *    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
    7 y4 {" L  O7 k, ]5 E  x
  5. *    形    参: 无) l6 r6 i0 ~5 S* P) `( W
  6. *    返 回 值: 无* g( n2 H: t/ c! ]# \% u
  7. *********************************************************************************************************- ~' f1 v% W2 r, j
  8. */
    . r& P1 S9 E3 H0 H- X7 h1 q
  9. void bsp_Init(void). O& z- `5 T9 x
  10. {$ e# o) [  S+ G! }0 {/ t
  11.     bsp_InitDWT();     /* 初始化DWT时钟周期计数器 */      
    1 t1 N9 ^. }' Z" k
  12.     bsp_InitKey();        /* 按键初始化,要放在滴答定时器之前,因为按钮检测是通过滴答定时器扫描 */* e- c0 B: o& Q' G9 S8 U
  13.     bsp_InitUart();    /* 初始化串口 */
    - _: {2 f0 _* p( I' h: B6 i# i
  14.     bsp_InitExtIO();    /* 初始化FMC总线74HC574扩展IO. 必须在 bsp_InitLed()前执行 */   
    4 d3 _# u! x8 {6 l- V* y1 C4 x
  15.     bsp_InitLed();        /* 初始化LED */   
    + x" s( J6 v2 d. e' |
  16.     bsp_InitTimer();      /* 初始化滴答定时器 */  w3 c6 X% B+ b% z
  17. }
复制代码

& p' f. O( _. R2 v4.7.3      函数SystemClock_Config
0 Q6 a' _9 L( m. x0 r" v  o这个函数主要是完成系统时钟配置。
8 f: I" ^+ A, t' B& j4 ~8 h3 M3 f& F2 T
  1. /*1 y: v- R) N4 ~
  2. *********************************************************************************************************% h, ^* H0 [: d  h8 E
  3. *    函 数 名: SystemClock_Config) S) |- v5 C% |6 b8 G6 _8 Y
  4. *    功能说明: 初始化系统时钟/ ~& x; q5 W/ Y6 N" n
  5. *                System Clock source            = PLL (HSE)
    + @8 y1 j) j9 L2 P. {
  6. *                SYSCLK(Hz)                     = 400000000 (CPU Clock)
    # k9 e1 y) k7 b
  7. *               HCLK(Hz)                       = 200000000 (AXI and AHBs Clock)1 h( s  R2 }+ H* F' Z; J5 N# y' ~/ m
  8. *                AHB Prescaler                  = 26 g4 V" `% j, ?- p7 }
  9. *                D1 APB3 Prescaler              = 2 (APB3 Clock  100MHz)
    & Y- F& U$ w# k5 g" X) Z. E
  10. *                D2 APB1 Prescaler              = 2 (APB1 Clock  100MHz)3 l7 `# o% G' {# {
  11. *                D2 APB2 Prescaler              = 2 (APB2 Clock  100MHz)
    . A2 x( J: _2 j/ [' T1 _/ X8 {& F1 b
  12. *                D3 APB4 Prescaler              = 2 (APB4 Clock  100MHz)2 d. K/ f8 I! i, v- s  G) \
  13. *                HSE Frequency(Hz)              = 25000000
    + O; B4 P9 k$ i2 n
  14. *               PLL_M                          = 5
    8 C0 l/ w7 s5 T2 g4 H7 v
  15. *                PLL_N                          = 1607 M2 I" {; a9 q
  16. *                PLL_P                          = 2
    * j7 j& ^% C' S0 C
  17. *                PLL_Q                          = 4' Q$ l; u1 Y, g6 C( G, K
  18. *                PLL_R                          = 29 a  W( k9 |. p; T: H, W/ m8 s4 @8 H' i
  19. *                VDD(V)                         = 3.3
    ; z8 L) l$ d9 C% m5 c
  20. *                Flash Latency(WS)              = 4" W' f' r- o" S3 Q- T& F- W! M: q, K
  21. *    形    参: 无
    ( w1 l" a( x: l. g( O2 R+ _7 j
  22. *    返 回 值: 无
    ' ^% R: p8 B, T2 T* F
  23. *********************************************************************************************************
    / b+ C% L9 _$ P" I1 B# i
  24. */
      y1 ?6 }  E% g& E
  25. static void SystemClock_Config(void)$ F8 ~9 x' }2 D3 Y
  26. {  R8 ?5 f: O  U$ @
  27.    省略未写) R8 _% d, F+ b+ f7 p

  28. ( t) ]) y) j/ B9 o5 I
  29.    /* AXI SRAM的时钟是上电自动使能的,而D2域的SRAM1,SRAM2和SRAM3要单独使能 */   
    $ y5 }1 o/ |0 c% ]
  30. #if 1  ]7 y% n* M  b* O. N
  31.     __HAL_RCC_D2SRAM1_CLK_ENABLE();
    ; ~$ G2 A2 q* E. |! j" `
  32.     __HAL_RCC_D2SRAM2_CLK_ENABLE();$ v& s4 O/ m# M# U& S
  33.     __HAL_RCC_D2SRAM3_CLK_ENABLE();
    * U0 ~8 _  o; k! ?( x# I; u
  34. + C8 `9 j( n3 \# n  j, G5 r
  35.     __HAL_RCC_BKPRAM_CLKAM_ENABLE();      
    ' S7 o4 m* t3 k" v  D4 l* J
  36.     __HAL_RCC_D3SRAM1_CLKAM_ENABLE();
    $ L( H/ E9 l* h1 v" W) h4 V
  37. #endif% v3 A- U- \" w, q" n& W
  38. }
复制代码
# l$ @9 G' _3 v" A$ \
这里的RAM时钟初始化比较重要,这几个RAM的时钟都要单独使能。4 V6 H% a  T/ R+ c7 O( U: u/ x

% q  i1 o  i1 i/ v" o% I" q8 Z% j4.7.4      函数MPU_Config. V* Y' o8 t. \* W/ M- e0 c
RTX5例子默认采用AXI SRAM作为主RAM空间,因为空间比较大,方便我们后制作综合例子使用:- n/ F. f& [: o7 W

  }4 c8 E  D. ?
  1. /*
    - I+ h" [4 A/ D* Q
  2. *********************************************************************************************************: |2 b" Z- o1 b7 j/ [% d
  3. *    函 数 名: MPU_Config5 j, p2 \  G0 k7 |8 k# `& a* @
  4. *    功能说明: 配置MPU1 y4 W# j& R% D% z, x8 t
  5. *    形    参: 无2 n4 g! N/ f6 o0 r# n! U
  6. *    返 回 值: 无5 \, D& G9 {- W' _8 j6 O
  7. *********************************************************************************************************
    8 d2 w: |! L* y1 ]8 E! E8 O7 G
  8. */3 {/ \' x' ]' _4 Y
  9. static void MPU_Config( void )
    1 H% T/ l1 b8 d( I- j! P5 r
  10. {
    9 w& L, {- E* H2 V7 n
  11.     MPU_Region_InitTypeDef MPU_InitStruct;5 L) }, H+ g2 e' l6 c
  12. 6 {6 ~8 a5 V9 a! X  A& }
  13.     /* 禁止 MPU */1 ~  a3 D' y$ g1 \' D
  14.     HAL_MPU_Disable();& X! b5 o, r& w6 G/ v0 h5 P

  15. 8 i. Q7 d, U! o
  16. /* 最高性能,读Cache和写Cache都开启 */   
    4 H2 d! Y( `( I* v& [: I% L/ D
  17. #if 1' @- I9 i. n  `( E
  18.        /* 配置AXI SRAM的MPU属性为Write back, Read allocate,Write allocate */
    & L7 x; X8 J! V/ o  s
  19.     MPU_InitStruct.Enable           = MPU_REGION_ENABLE;1 t6 s  o) n" a
  20.     MPU_InitStruct.BaseAddress      = 0x24000000;
    6 N. \+ C" m$ S1 Q; G
  21.     MPU_InitStruct.Size             = MPU_REGION_SIZE_512KB;7 L( m" b6 Z9 {; I' I5 M/ s
  22.     MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
    & G2 k6 j  ^; o$ F2 @1 X
  23.     MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;
    + }% |3 ~3 l: \# n7 n; R" T
  24.     MPU_InitStruct.IsCacheable      = MPU_ACCESS_CACHEABLE;( Q7 V) Y- O. }
  25.     MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;1 |) C+ A0 h2 G8 {6 i" A6 \, M8 Y
  26.     MPU_InitStruct.Number           = MPU_REGION_NUMBER0;
    ' t( L$ x3 F& P: {) K/ x
  27.     MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL1;5 U6 k- I" S8 d" w
  28.     MPU_InitStruct.SubRegionDisable = 0x00;
    , ^2 h: L, P+ x" O# s3 W
  29.     MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;& v3 T/ y/ F5 _0 A1 D, }! P( ]
  30. 7 u, q7 X5 s& {, ]0 A6 S
  31.     HAL_MPU_ConfigRegion(&MPU_InitStruct);8 t! j4 q2 @  z5 E4 E6 K. x
  32. , k4 f& m' A( L9 w% o# ~1 u
  33. /* 最低性能,读Cache和写Cache都关闭 */5 V0 }. Y; p8 q2 d- q  f
  34. #else
    5 U: v$ k- k6 Q* a% J/ q! T
  35.     /* 配置AXI SRAM的MPU属性为NORMAL, NO Read allocate,NO Write allocate */* }, g- ?# x) c' `5 b/ t( {( U
  36.     MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
    8 q8 @# \, T( F0 t
  37.     MPU_InitStruct.BaseAddress      = 0x24000000;
    5 V4 Z; u: @- I  T5 I) ?
  38.     MPU_InitStruct.Size             = MPU_REGION_SIZE_512KB;1 k9 ]/ k6 A; F8 u$ d: r9 J
  39.     MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
    7 [$ r8 I9 q. g% C
  40.     MPU_InitStruct.IsBufferable     = MPU_ACCESS_NOT_BUFFERABLE;6 i9 C9 j% Z  F2 f
  41.     MPU_InitStruct.IsCacheable      = MPU_ACCESS_NOT_CACHEABLE;  j6 e$ t) _: b/ i7 _; Q( D, y' C
  42.     MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
    6 O8 `. N- c1 g: r7 S
  43.     MPU_InitStruct.Number           = MPU_REGION_NUMBER0;8 Q7 t5 |- I: }
  44.     MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL1;: R# r( T- i( C$ }4 N' d: I3 p6 p; e
  45.     MPU_InitStruct.SubRegionDisable = 0x00;
    8 s! N: Y% v. V9 Y
  46.     MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;
    ; O, @2 m9 T' |8 t

  47. 7 G/ B; _) I/ [# i! n8 I8 a
  48.     HAL_MPU_ConfigRegion(&MPU_InitStruct);! M4 [- f! K0 k* K$ W
  49. #endif9 n( U1 y7 M( c7 }. B' K; W1 G& g
  50. % c+ l/ m: l) [7 }! C/ W
  51.     /* 配置FMC扩展IO的MPU属性为Device或者Strongly Ordered */
    5 C! v7 \7 k6 R6 }' ^. e  k
  52.     MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
    . B1 k$ C9 C& Y" [6 t) V5 }2 {
  53.     MPU_InitStruct.BaseAddress      = 0x60000000;# i: @. Q8 k6 X1 s6 s: \$ {4 t1 J6 k
  54.     MPU_InitStruct.Size             = ARM_MPU_REGION_SIZE_64KB;    ( K# `% x$ N0 k) D9 S7 T
  55.     MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;* ^/ Q4 j) Y8 s
  56.     MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;& b* m: N5 [7 t5 ]
  57.     MPU_InitStruct.IsCacheable      = MPU_ACCESS_NOT_CACHEABLE;   
    + s9 D0 }) @7 Z
  58.     MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
    + c: F! g* u! d: K
  59.     MPU_InitStruct.Number           = MPU_REGION_NUMBER1;
    7 C" ^: }5 y6 a. O5 u8 O0 m8 a
  60.     MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL0;
    3 z; q7 o- v* e. i4 D0 c
  61.     MPU_InitStruct.SubRegionDisable = 0x00;
    ( T1 @  x, r2 C* Q0 B1 y
  62.     MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;, k1 E4 n0 a9 Q1 L  S
  63. " ^9 h0 j" k9 J; T* y2 q+ A
  64.     HAL_MPU_ConfigRegion(&MPU_InitStruct);+ {) V, b; ~$ p  \  b. C7 a

  65. 1 y) O: J: ^+ }2 Q$ A- l( o- m
  66.     /* 使能 MPU */
    8 z- }. q3 Y+ g5 e/ I7 O
  67.     HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
    6 u2 u; _/ A2 z( u7 }% l3 i
  68. }
复制代码
( W" `$ m+ k9 P0 n
4.7.5      函数bsp_RunPer10ms
* W* T1 V  b( R) G( {% P5 B( ~. D这个函数里面默认有个按键扫描,如果大家移植的程序里面没有按键初始化,务必要把这个按键扫描函数注释掉。
. l8 u6 i/ V' x$ T
) C0 I+ v) j6 M& g8 [* H9 o
  1. /*
    ' g' v  ]' ], _5 y
  2. *********************************************************************************************************
    7 w. u( G' R8 F3 J7 R: V* c
  3. *    函 数 名: bsp_RunPer10ms, Y) y& \0 k! ]
  4. *    功能说明: 该函数每隔10ms被Systick中断调用1次。详见 bsp_timer.c的定时中断服务程序。一些处理时间要求2 Z) X* ~5 `1 f* F2 g4 N
  5. *             不严格的任务可以放在此函数。比如:按键扫描、蜂鸣器鸣叫控制等。
    * {& X/ v/ g: S+ `( L" k1 W  n! J
  6. *    形    参: 无* k* w% W0 N7 ^6 i' l# R
  7. *    返 回 值: 无
      y6 h9 i  Y( M) C' ]: c$ B6 i" n* @) A
  8. *********************************************************************************************************& A! z- d7 {3 v  V9 c
  9. */2 x3 B- n3 o- ^- e
  10. void bsp_RunPer10ms(void)+ p2 c& d1 H- B' E7 B
  11. {5 I3 r* A9 X. x: h/ B
  12.     bsp_KeyScan10ms();
    $ o$ p- }. q- ?9 p8 n" u& U
  13. }
复制代码

2 x6 v+ E5 I: f- k/ y4.8   第5步,更新bsp_timer.c和bsp.h文件& p# }5 J2 Q: a" U, D. B
更新bsp_timer.c文件是因为此文件跟RTX5都要使用滴答定时器,有冲突。所以大家直接将我们工程模板里面此文件覆盖移植的这个文件即可。( C+ s9 L8 V/ O* H$ p4 ?" o

2 W- }* ~9 o0 m' pbsp.h文件里面要添加一个宏定义,因为bsp_timer.c文件里面做了些条件编译:
  W" D, w4 P, E0 `$ G( q
2 N$ C/ J5 Y+ a#define  USE_RTX    1, f3 I0 E; b/ b( t! e+ g5 C; P) Q. q1 Z5 j

1 N: I: n8 o$ `+ i3 I5 v另外,bsp.h文件将大部分头文件都添加进来了,大家可以根据需要,用到那些头文件,使能那些,用不到的,可以注释掉。当然,不注释也是没问题的:
# r& m' A, X2 M( g! k3 p, `: d8 Y5 B6 L: h' F
  1. /* 通过取消注释或者添加注释的方式控制是否包含底层驱动模块 */. S8 G2 M+ g3 I8 |
  2. //#include "bsp_msg.h"" K% R( e  D$ w8 E
  3. //#include "bsp_user_lib.h"- U) s0 T% A! P/ o; c5 M# y5 }3 F
  4. #include "bsp_timer.h"' ~* e2 \$ M4 |  ~6 D
  5. #include "bsp_led.h"
    * ~. K" X/ T+ D8 ]6 K: R; `
  6. #include "bsp_key.h"7 y# S1 Y4 X+ F
  7. #include "bsp_dwt.h"$ n& M/ v6 o; I2 ]$ I/ p, z. O

  8. 7 N+ Z; \& x( ?' a9 f/ N. n! H4 x
  9. //#include "bsp_cpu_rtc.h"
    / \0 Y6 y( [3 G5 I
  10. //#include "bsp_cpu_adc.h"
    ( Y. ?! c- D* K9 }1 w8 ?0 F  Z
  11. //#include "bsp_cpu_dac.h"
    7 x. |( q3 u7 s& o
  12. #include "bsp_uart_fifo.h"  W8 \1 w. d$ o& Q+ k9 ~
  13. //#include "bsp_uart_gps.h"
    3 j- T% `" Y3 _0 r
  14. //#include "bsp_uart_esp8266.h"% t3 \2 T( j) E
  15. //#include "bsp_uart_sim800.h"
    7 @) E# q8 \: j9 {4 @  ~

  16. ' _# ~( t+ Z) k! s+ B0 n) _) o
  17. //#include "bsp_spi_bus.h"# k; p8 @4 S8 L8 w9 P) D- b
  18. //#include "bsp_spi_ad9833.h"
    - R7 V/ O, V  L" Z
  19. //#include "bsp_spi_ads1256.h"
    % r6 X8 P! R+ @0 @  b" x' Q5 Z
  20. //#include "bsp_spi_dac8501.h"1 O3 _1 M" _+ X3 h, Z
  21. //#include "bsp_spi_dac8562.h"
    7 P6 ^$ t" X! G2 x5 m: S4 _
  22. //#include "bsp_spi_flash.h"
      N1 C' t. y* [6 F! g! k
  23. //#include "bsp_spi_tm7705.h"! ~0 m4 w; `$ ^4 N& `
  24. //#include "bsp_spi_vs1053b.h"5 R# h# W# ?+ w; X

  25. 0 [' E- G6 U4 P/ m9 G7 s3 ]0 }
  26. //#include "bsp_fmc_sdram.h"
    8 @  X, R! i% V
  27. //#include "bsp_fmc_nand_flash.h"
    " P) p) ^$ S( Y4 }0 U: O
  28. //#include "bsp_fmc_ad7606.h"/ X6 ^8 L) c6 N: w6 j5 r
  29. //#include "bsp_fmc_oled.h"  ?& Q5 ~1 _# F" B
  30. #include "bsp_fmc_io.h"
    4 X8 x2 z( _9 S8 Y7 U6 k. v

  31. : T1 ~6 ]: ~) F' ?
  32. //#include "bsp_i2c_gpio.h"
    3 V6 `3 x, {+ h! Q! _
  33. //#include "bsp_i2c_bh1750.h": ^7 ^0 w& K, o! O
  34. //#include "bsp_i2c_bmp085.h"
    ) S) D, a+ W/ m0 O* n( c+ U6 e7 A; U2 p
  35. //#include "bsp_i2c_eeprom_24xx.h"
    ) a/ `' Y% W4 u" G7 k$ N! D/ y
  36. //#include "bsp_i2c_hmc5883l.h"- I4 k9 a, a; c% X$ }
  37. //#include "bsp_i2c_mpu6050.h"7 E- E6 K& s7 _$ A* i3 `1 D
  38. //#include "bsp_i2c_si4730.h"1 _7 i% @, ]- L6 z$ A9 s
  39. //#include "bsp_i2c_wm8978.h"
    , j& ~6 O$ Z9 ]

  40. 8 [! H6 ]( e, C
  41. //#include "bsp_tft_h7.h"
    ' Z3 M1 o% x8 k' e6 G2 P$ d6 ~
  42. //#include "bsp_tft_429.h"
    $ A: G5 }- h5 t, r/ J3 P, O! t
  43. //#include "bsp_tft_lcd.h"
    & `$ B# f8 O' r) o' B1 m$ F2 C
  44. //#include "bsp_ts_touch.h"
    % M, H! i/ P9 u; V0 l5 B3 j: c
  45. //#include "bsp_ts_ft5x06.h"
    & B/ s$ a, x9 {, ^
  46. //#include "bsp_ts_gt811.h"2 P' f% h  f/ e0 l* M, o) Y
  47. //#include "bsp_ts_gt911.h"; O* r' o! ]! D3 W! z9 I7 ]
  48. //#include "bsp_ts_stmpe811.h"
    & z8 P2 B# Q2 y

  49. % D4 ~; X& }2 K+ U, Z! K$ U' L
  50. #include "bsp_beep.h"1 [3 c2 N' q$ s! N
  51. #include "bsp_tim_pwm.h"
    - ^. A' n2 U* I9 L$ H
  52. //#include "bsp_sdio_sd.h"* {. x/ `+ {4 k$ h
  53. //#include "bsp_dht11.h"' S7 L4 u- h- I* R2 c
  54. //#include "bsp_ds18b20.h"0 C5 o; W8 ^) Y+ D4 W# Q
  55. //#include "bsp_ps2.h"5 j1 f1 a  A6 X  ]+ `
  56. //#include "bsp_ir_decode.h"
    # Z' p. D, e! m% t& l
  57. //#include "bsp_camera.h"
    ) A: @8 h- s/ f6 h/ v
  58. //#include "bsp_rs485_led.h"
    * l2 V+ u  _+ Y
  59. //#include "bsp_can.h"
复制代码
- a% T! R. u7 r: X5 ]
4.9   第6步,修改文件stm32h7xx_it.c% F! H8 N1 U( O' r3 A
删除此文件里面带的如下函数,RTX5要使用,冲突了。8 [/ x, @& W: p  _3 K* t
1 J" V4 f3 b5 l% R& p
  1. /**, `, g6 d1 }+ s. `& R5 D0 B
  2.   * @brief  This function handles SVCall exception.
    / t# C3 n6 a# D$ g
  3.   * @param  None
    ( M' n1 F3 `5 V2 j, z; O
  4.   * @retval None
    # k( W$ x2 j8 j3 X" t# [# _: e2 ]4 F
  5.   */
    1 {* m$ Q9 j# A: K7 g8 F
  6. void SVC_Handler(void)& d% U7 R3 \% ]
  7. {0 ?0 ~" F) i- s$ V1 S
  8. }# ~6 |6 Z1 b0 M7 r2 v/ R5 `
  9. . _* I* _5 O+ f' k7 I5 J) n
  10. /**
    ( F8 y9 V9 J9 X/ F! K. i
  11.   * @brief  This function handles PendSVC exception.8 V" b8 M: P3 X/ m6 d5 W! E
  12.   * @param  None9 I0 R: r* X2 m( L% K3 z5 ]
  13.   * @retval None
    ) ]" s% S+ `* a, Y) C9 `1 ?# f
  14.   */
    0 r/ |4 X6 a/ P! o) n
  15. void PendSV_Handler(void): c' n8 h' m# _' N- q
  16. {+ g0 W4 ~9 d) P! m/ K! S9 U% \
  17. }
复制代码

/ i3 Z2 m* l8 r" y; R0 M# l+ z  N4.10 第7步,添加头文件的汇总文件includes.h/ ~* @6 [# B4 k. i4 }
在User文件夹下添加文件incudes.h,直接从本章节教程配套例子的User文件夹复制即可。此文件主要用于RTX5的各种头文件汇总。( k" d  j0 t3 A: p4 ]8 i4 W

* B; U& a2 e6 o
63fafbc927e6b911f6f3b81c4acb6af1.png

" u% {$ L  @/ t, T1 d* |. ^% q2 x" e, V% G  I/ I2 w% R
4.11 第8步,HAL库时间基准stm32h7xx_hal_timebase_tim.c

: O( x! O8 d9 W# ~由于RTX5和HAL库需要一个时间基准,而且默认都是用的滴答定时器,所有要有一个选用其它的时间基准。当前的处理方案是为HAL库提供一个时间基准文件stm32h7xx_hal_timbase_tim.c。此文件+ ~$ Z  P7 U' v7 x

! q  ], O& [3 q: L) b里面做了两套方案,一个是使用TIM7做时间基准,另一个是使用RTX5的API做时间基准,通过条件编译做选择。默认是采用RTX5的API做时间基准。/ u, C# H, U9 H' ?( r
9 Q, B0 A1 ^6 L: c: W3 S
  1. /*
    % H4 t8 _& \: T5 q+ Z9 a
  2. *********************************************************************************************************, u3 e6 o1 l* T* M! r  u, A! ?
  3. *    函 数 名: HAL_Delay
    + I8 [9 V! \/ l% d3 b
  4. *    功能说明: 重定向毫秒延迟函数。替换HAL中的函数。因为HAL中的缺省函数依赖于Systick中断,如果在USB、SD# f( Q5 ]; q7 U% V( o# ]
  5. *             卡中断中有延迟函数,则会锁死。也可以通过函数HAL_NVIC_SetPriority提升Systick中断
    - |8 m/ }" O9 \9 R
  6. *    形    参: 无
    : \! b5 N' q, j) `
  7. *    返 回 值: 无
    / t9 m1 Z2 t, A* s6 ^
  8. *********************************************************************************************************7 W( A- T! C( I. ^9 X: {8 O
  9. */: t* M: w" U4 V+ N8 `$ w
  10. void HAL_Delay(uint32_t Delay)
    + I2 d5 A# ?' e4 b; |, @0 }7 v
  11. {; B4 p5 ?8 o& ^
  12.     bsp_DelayMS(Delay);
    # y* |3 Y! v% e4 v: F4 K
  13. }* f6 c: G# \1 v; {, H

  14. 6 G+ b- d3 F; {0 i, O' n- Z
  15. HAL_StatusTypeDef HAL_InitTick (uint32_t TickPriority)
    , T$ U. j" j" Y+ Y, ]5 j3 C
  16. {  u3 a3 v/ B( o! A8 r/ y( j
  17.     return HAL_OK;/ n$ a* ~! i, I# _
  18. }
    : ?8 u) w8 f- q
  19. * E& h/ `3 y, O$ z. b% ~( P; O
  20. uint32_t HAL_GetTick (void)
    ; P4 r" J6 S9 W7 w( j$ f9 `
  21. {8 g) C5 d3 @9 ?+ f8 {* S, ?7 l) E6 C* y
  22.     static uint32_t ticks = 0U;
    " A  c/ Q; x' ~: N
  23.     uint32_t i;
    , W% l! N0 T5 o) |6 f. H

  24. ' C! W) }# I+ n# f: |. y% {# b
  25.     if (osKernelGetState () == osKernelRunning)% Z, h9 e6 S. Q  D( ?  I& N
  26.     {  t& m5 H) c; \1 e' h6 ^: g
  27.         return ((uint32_t)osKernelGetTickCount ());- \0 X' @; w3 C+ g8 O6 Y- \
  28.     }% g3 S$ {2 u$ i# S6 k

  29. + s' @8 y% w! U" ^/ ?1 x6 c5 {
  30.     /* 如果RTX5还没有运行,采用下面方式 */4 l; h0 Y; }1 B  b: y
  31.     for (i = (SystemCoreClock >> 14U); i > 0U; i--) 7 g3 \% d# N% {
  32.     {
    8 w" k+ k) D5 b+ z' H% O
  33.         __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP();
    $ Y7 H/ _  [* R2 d) a5 `6 H
  34.         __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP();
    ( w+ r) v: m2 o
  35.     }
    , h  e: A8 h9 P4 p/ x7 F. Z/ b% ]
  36. ( M( v, {0 _  n% j6 y7 _
  37.     return ++ticks;
    - Q6 @2 i9 e; y( F% g+ r- B
  38. }
复制代码
! U( l5 D; ^' T: s$ A& m4 `$ ]' f9 d
4.12 第9步,添加BSP驱动文件bsp_dwt.c
: C" u7 z/ Z- }: f0 \! S, Q
添加bsp_dwt.c文件和bsp_dwt.h文件主要是因为第8步中的stm32h7xx_hal_timebase_tim.c文件里面的函数bsp_DelayMS要使用,此函数是基于DWT系统时钟周期计数器实现。6 ]8 O) M0 [8 l$ a6 m: C3 p
! M, F, G9 m" U7 S# |+ G6 |. n
f0d85f2002a553fa31c8f67b30e2db76.png

& V) m! M/ [5 H+ j, ]; V5 y7 I2 V8 Y) J0 `
4.13 第10步,创建应用任务(重要,注意启动任务)
8 H7 f) T9 w) |9 k7 a
应用程序比较简单,大家可以直接复制本章教程配置例子的main.c文件中的内容到自己工程里面测试。主要创建了如下几个任务:0 m3 I2 s- c2 o' c/ L' |

: {8 D+ j( s# p& ]# j: I2 G- }! r4 `. ?AppTaskUserIF任务   : 按键消息处理。
% Z, h# Q$ \! D5 G* x( X: ^" a3 u" x7 `
AppTaskLED任务      : LED闪烁。) W: h% `5 _$ t& q8 n0 x

) ~6 j8 T0 W# o, O7 }AppTaskMsgPro任务   : 消息处理,暂未使用。5 T  r& }' W5 v0 i! K6 T. D
: \9 l( P$ X' c
AppTaskStart任务    : 启动任务,也是最高优先级任务,这里实现按键扫描。
  Z% A0 b  x1 k/ B6 N* m% \  a% M& V. u. \4 s4 U
osRtxTimerThread任务: 定时器任务,暂未使用。
) l, T- v4 I1 O
0 m- y( \$ c6 a0 l任务栈大小和任务控制块定义如下:' o/ U! @9 r6 ^2 \3 |" N

9 ]# j$ z; z- {( o' V- `
  1. /*4 j9 G. E& \( z
  2. **********************************************************************************************************! I% u: P. z3 Z% q4 `' V9 a2 B
  3.                                              变量
    % A1 V$ n( d! t3 k$ o  V
  4. **********************************************************************************************************
    5 F. z& x5 b5 S" L: T5 U, j; d% k+ P
  5. */
    ( d8 ]5 X- n0 l( z
  6. /* 任务的属性设置 */
    ; O0 o; w' J0 a, [3 l
  7. const osThreadAttr_t ThreadStart_Attr = 0 O$ K7 A# n& ?% s% b
  8. {6 @* j4 w5 X) I. j; J
  9.     /* 未使用 *// r8 M& S0 }  ^. H1 `8 o" o/ u
  10. //    .cb_mem = &worker_thread_tcb_1,
    3 q# p! y! z8 E5 J& F, U1 c$ A0 C
  11. //    .cb_size = sizeof(worker_thread_tcb_1)," Z$ V+ C' F6 V& w. R; C3 q5 T3 b
  12. //    .stack_mem = &worker_thread_stk_1[0],
    4 L  d( O7 T$ X7 _. W$ B
  13. //    .stack_size = sizeof(worker_thread_stk_1),
    1 L  j' ?  O- i4 o: o5 F
  14. //    .priority = osPriorityAboveNormal,
    : d3 a. H* R6 U- c
  15. //    .tz_module = 0
    " m- ]/ A, S# z% M& J7 m$ R9 h. ~
  16. * O3 r" ^$ L1 |5 g( e
  17.     .name = "osRtxStartThread",. q/ B" {4 Z  c( j! b; Q
  18.     .attr_bits = osThreadDetached,
    / S+ z& G; ~0 j
  19.     .priority = osPriorityHigh4,
    3 z! f  R/ J. X& o+ z
  20.     .stack_size = 2048,/ [& \; }- m; q5 R" p7 o* @
  21. };
    % t9 e! X! S* S  |! C$ Z0 u

  22. 5 ]/ j, |+ d- F; M) l
  23. const osThreadAttr_t ThreadMsgPro_Attr = 5 D# a: j9 F7 K; g" q. E
  24. {
    7 q: x& {7 s" i; p
  25.     .name = "osRtxMsgProThread",. i2 K8 A- V$ t5 G! j% Q8 _! E1 N
  26.     .attr_bits = osThreadDetached,
    ( v# y) P1 x6 z& A+ K" V6 x
  27.     .priority = osPriorityHigh3,
    * d# F& k5 }' ~( |$ }5 o3 `
  28.     .stack_size = 1024,6 y% J5 n$ p" v) Z" h6 Q  P
  29. };
      T, N* h7 v* M. s: T$ L' G, P

  30. , s, A8 _0 X% T9 n1 @- Y/ D
  31. const osThreadAttr_t ThreadLED_Attr =
    2 A9 l4 \# N  Z2 c& n+ \& l
  32. {( w9 K; G$ K& b
  33.     .name = "osRtxLEDThread",. u! s: z, B7 l3 [& |  ^, _
  34.     .attr_bits = osThreadDetached,
    ; p- d( @! [+ c1 J! e9 P
  35.     .priority = osPriorityHigh2,
    ( H  l* W( Z; j7 d
  36.     .stack_size = 512,% T6 `& X9 z2 m* y
  37. };% ^% ^+ n; k% Q) a4 j4 e2 D
  38. 1 f" \. c; B  L
  39. const osThreadAttr_t ThreadUserIF_Attr = - f- i, g" y8 V0 [
  40. {/ [; [) r# }% Y4 I2 e
  41.     .name = "osRtxThreadUserIF",. j; e/ V. H' Z6 o2 D6 D
  42.     .attr_bits = osThreadDetached,
    ' [7 u/ L' B: _. S
  43.     .priority = osPriorityHigh1,* X0 _( D6 {- l3 h& s
  44.     .stack_size = 1024,
    7 A8 b* |! q& N: W8 g7 Z! g
  45. };
复制代码
) V% _1 l' E" ?3 t* R, S/ Q7 ~7 D; M% Y
任务创建:
! L4 O; R: n; Y; X
  F4 _# d- u! J/ a& e" j7 w
  1. /*
    * }0 @' }, a% y" w$ _
  2. *********************************************************************************************************+ T8 ~0 W! _8 `3 n
  3. *    函 数 名: main
    ; x* n- K5 E+ q/ M& A/ i( Y
  4. *    功能说明: 标准c程序入口。
    / S" P5 c! ?9 n5 n& i
  5. *    形    参: 无
    1 r- X0 a  s; |! H# p
  6. *    返 回 值: 无
    ) z/ K/ F6 l6 z# _& t' {
  7. *********************************************************************************************************
    2 C- a* Q' y6 W! N% P$ p
  8. */
    ' I# p6 h) k# ?% G- J! b! w
  9. int main (void)
    2 Q3 ?& U# h& D/ g# f% p3 g9 \
  10. {    ; Z3 @6 o. G# l' h; E
  11.     /* HAL库,MPU,Cache,时钟等系统初始化 */* U/ [0 M/ Y) \& F1 e
  12.     System_Init();- t1 `3 M# {/ X- k6 f6 B
  13. & t( U; r( }+ S  O% m0 ^* u+ S2 ]
  14.     /* 内核开启前关闭HAL的时间基准 */+ i4 N% ]+ Y4 K8 G% i
  15.     HAL_SuspendTick();( P5 c9 K( l( ^: b6 G8 i: p
  16. 9 [8 l6 r8 T. L: x
  17.     /* 内核初始化 */8 V  ~% K7 X: F/ q( k
  18.     osKernelInitialize();                                 
    5 J5 N  {/ J# Q6 L

  19. 4 |- Z3 w9 W; m* `% q& h
  20.     /* 创建启动任务 */
    5 ~$ W6 Z) P3 J$ n7 n
  21.     ThreadIdStart = osThreadNew(AppTaskStart, NULL, &ThreadStart_Attr);  " S% R& {0 o( P+ m; m

  22. ! @  m# O, u( a* p8 C3 c
  23.     /* 开启多任务 */( p) m6 k4 |8 S; Y+ p* s9 S! a
  24.     osKernelStart();
    # K* k" Z$ @( g% k3 k1 y6 ~
  25. ! S4 U& A3 X8 S" o3 K- m! H8 p
  26.     while(1);
      Y- f8 o" O$ ^% p4 e
  27. }
    4 v( C- I: l; v( D

  28. 4 f- F' }6 e, n1 u) F
  29. /*& a  h. S) i' I: }! ~7 ?
  30. *********************************************************************************************************/ L4 J) Y+ P/ K: t
  31. *    函 数 名: AppTaskCreate
    , r  r5 C/ ?+ k
  32. *    功能说明: 创建应用任务
      J2 \6 K3 l& |! w' \# E3 p
  33. *    形    参: 无5 H3 n+ ]% s  H# I- s5 z& q" I
  34. *    返 回 值: 无/ q0 m1 j4 H$ `5 a: d  C5 P
  35. *********************************************************************************************************! Z" q# d% D. b6 C* ]) }$ x8 `
  36. */6 [' X1 H  J8 S4 M
  37. static void AppTaskCreate (void)5 i7 y5 o! k; u9 }$ a$ [+ |8 O
  38. {) B) p; i: x# o- n- |% ^9 K
  39.     ThreadIdTaskMsgPro = osThreadNew(AppTaskMsgPro, NULL, &ThreadMsgPro_Attr);  
    % \$ P. ]7 |, ]  i. f! I: h
  40.     ThreadIdTaskLED = osThreadNew(AppTaskLED, NULL, &ThreadLED_Attr);  0 C0 w0 x% O" @8 d% \3 L
  41.     ThreadIdTaskUserIF = osThreadNew(AppTaskUserIF, NULL, &ThreadUserIF_Attr);  6 |: Z5 c" b" r2 |4 H- _% u* W3 [
  42. }
复制代码
1 d! y6 M" ^! ~8 J! ]
这里我们重点看下启动任务,主要做了四个工作:6 O( `  x' ?# V6 {7 u8 @) q
+ L+ }. @2 j( ~' _
  外设初始化bsp_Init。
  G+ o' E$ ]8 p7 x  任务创建AppTaskCreate。
9 k% N/ R* V; d9 e3 C  需要周期性处理的程序bsp_ProPer1ms,对应裸机工程调用的SysTick_ISR。这个的实现非常重要,这样之前裸机里面使用的API,就可以直接在RTX5里面直接调用。1 x! }' I# J/ k3 m5 h6 I, c6 Z3 x
  1. /*
      ~5 B5 e; C# A  l! S- k, E
  2. *********************************************************************************************************+ z1 J" m2 [7 i8 H+ ?
  3. *    函 数 名: AppTaskStart
      a0 P  w: f# g  p
  4. *    功能说明: 启动任务,这里用作BSP驱动包处理。
    " o  w& V# D! b$ ^3 c, v& o  z8 G
  5. *    形    参: 无3 B7 L' ^+ S* A7 n% ^. _/ R
  6. *    返 回 值: 无9 o! F9 R' d! Q' ?
  7. *   优 先 级: osPriorityHigh4  # m' W8 h( A" y/ F8 G
  8. *********************************************************************************************************
    0 O# t# t  v2 p7 ?
  9. */
    : f& b% [3 Z8 X7 k& R
  10. void AppTaskStart(void *argument)
    & z) b: e( p2 A* `) r$ v  a' \& z; L
  11. {
    3 t  |; H) P; k0 M( l6 B, n
  12.     const uint16_t usFrequency = 1; /* 延迟周期 */
    * m. I) g( F7 D  I
  13.     uint32_t tick;% _+ C* W& L: M' `  D. Y+ M

  14. 9 ]- [( u" _0 M/ e
  15.     /* 初始化外设 */! J) \' C% k+ W# e! C
  16.     HAL_ResumeTick();
    / P" f& n; j4 v
  17.     bsp_Init();
    5 `7 H4 X& `2 O# ]6 w7 [- _
  18. 8 C7 O- l: |& \) j
  19.     /* 创建任务 */
    , }! h; H9 J! O( h. N- Q* G4 t2 A" J+ X
  20.     AppTaskCreate();$ b5 j8 W, U' K& X1 {
  21. 4 f: L7 I$ z  o
  22.     /* 获取当前时间 */
    7 z: J( C% |/ H5 |( B
  23.     tick = osKernelGetTickCount(); $ q6 W3 s/ O- v" ]7 z

  24. $ q9 B/ `. j7 Q
  25.     while(1)2 C! u9 D# U6 Z6 {; T- O
  26.     {
      r6 p0 Z- G/ m
  27.         /* 需要周期性处理的程序,对应裸机工程调用的SysTick_ISR */! F9 X/ `# G2 `. O# ^3 F: x& V
  28.         bsp_ProPer1ms();
    ) O$ S8 O* x; |7 K& Z) X* S; l+ s2 i

  29. ) a9 Q% S3 O9 Z$ Y) v- f. A
  30.         /* 相对延迟 */
    8 f+ ]4 k: q( S/ `& g
  31.         tick += usFrequency;                          - A. N/ @4 ^8 |0 _& R# G
  32.         osDelayUntil(tick);
      O. P, c( `1 v# I3 t" D
  33.     }; l. x8 M* g6 K0 c; `1 q
  34. }
复制代码

4 c! a% \5 F! y9 R4 Q4.14 常见移植错误总结
3 E$ v2 G* n9 u! e  B- d
常见的移植错误主要有下面几种情况:
' E4 i- t3 C$ o1 R! ?4 @- ~9 Y
! S  H. U9 Q2 P. W6 N  编译后提示如下两种错误:- Z& n5 J5 }" G# y+ A; V+ }
Error: L6200E: Symbol PendSV_Handler multiply defined (by irq_cm4f.o and stm32h7xx_it.o).8 m) T! M# t* z2 M( t

& L8 M0 K' i' C9 s- ]Error: L6200E: Symbol SVC_Handler multiply defined (by irq_cm4f.o and stm32h7xx_it.o).
/ D' m) M/ [& F$ u4 s1 V7 ~7 M
  z' ?5 A. ~* h; ~5 B+ Y# s解决办法:这是函数重定义了,直接将stm32h7xx_it.c文件里面的PendSV_Handler和SVC_Handler删掉。& r" ~+ X& o& Z7 D
0 d+ N2 i& J0 y1 w+ {0 J
  提示如下错误& e; b+ K( p/ ?
Error: L6218E: Undefined symbol bsp_DelayMS (referred from bsp_fmc_io.o).0 O; X4 Z5 i+ K
2 v6 g  n! g; D+ Z
解决办法:打开bsp_dwt.C文件中的条件编译。* K8 l7 z  A/ S; j/ T7 t

* l5 f. y# U8 f& o) a4.15 实验例程
8 R( k/ W% N7 I  Z  r) Q本章节配套了如下几个例子供大家移植参考:$ U- M* c: K+ r( L
5 t+ M' l$ b, `6 B: Z. E! j
  V7-400_Base Template; D  ?8 @# j5 k: u9 J/ L
裸机模板,方便大家添加RTX5内核源码。+ c* ?! \6 W, X& y; U

  F9 w+ z" [5 ?+ m# V  V7-401_Threadx Kernel Template
- |% O* p; h7 x3 z  X, G
0 W! `! I/ {. d' r$ {ThreadX内核模板。$ Q% `2 L& l3 d6 g
( @$ x% d: G5 k: E0 {- ^
MDK进入调试状态后,选择周期更新:
) _7 K/ H. X, t1 h' a% T
0 u# t" v& k7 q! f
fdce9fac9944ad56faa0dd13307f6ebb.png
: ^, |) z  e$ P6 r" ?, i

7 I3 v; R% c! Q* r# U$ A然后打开调试组件,注意和RTX4的调试组件位置不同:# `3 o4 p2 a& l3 ^: f

% D. _& H, q) x) i
9482ce7367ba4d7cf08c73a56db28f75.png

7 y5 F7 z5 R: ?0 T' |
0 V# S& J  N! h  c0 S' }* L- _然后点击MDK的全速运行,
% X& Z+ Z" B9 s/ V) A! f, e: Y8 \2 p+ E5 X  s4 v( W
e3038a01781216611f96ae37d5bccb17.png
( a. m! ]# S3 F5 y# W
1 h0 W) J# s/ i; l2 C/ m  t
至此,就可以动态实时查看RTX5的运行状态:
: p1 k; l& U  B$ I/ ~2 n' [0 X2 o2 N
797f68ea76bd699fe11ce441076df4ec.png
) B, }3 Q7 b# e2 x0 Y
3 K/ B% ?/ j0 L9 B  R5 q, ~
4.16 总结
; Y2 M0 m+ e3 L4 \! W  y$ D  ?5 J( G2 I本章节为大家讲解了RTX5 在MDK AC5上的移植方法,移植涉及到的知识点比较多,初学的话,建议实际动手操作一遍。1 o9 U, n( q' P5 e' f4 ^: j

# Q. b' V8 w( ]3 F' l0 M( s+ q5 f
5 V7 M: o/ n; Q! G$ r4 E, N
  j+ g& [0 |/ l2 J
赞 收藏 评论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 手机版