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

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

[复制链接]
STMCU小助手 发布时间:2021-12-30 14:32
4.1   初学者重要提示1 d9 P; I1 j7 ^4 U! ]: a, }
  当前RTX5可以移植到GCC,MDK和IAR三大平台,考虑到仅MDK平台下有RTX5的调试组件,我们这里仅提供了MDK的移植说明。
1 L) s- C% L! L1 |* a( e  STM32H7使用MDK RTE环境添加RTX5,需要强制运行一次STM32CubeMX,因为H7已经没有配套RTE经典添加方式,而STM32F4是支持经典方式的,所以无需运行STM32CubeMX,详情可以看我们STM32F4开发板对应的RTX5教程。' m9 r! P- r% r, L  x2 w
4.2   移植RXT5内核整体说明
% G' `" l0 g. B# c/ ?' j- _移植之前,有必要对移植过程有个整体的认识:
0 c+ d- A; |" X3 J
9 _  V. Q. m" |  第1步,准备一个工程模板。: X, u" `  o0 C9 X/ e: y9 y, k
  第2步,移植RTX5。) u. c! R; l7 o/ }: K
  移植RTX5是采用MDK的RTE环境直接添加。当前H7芯片使用RTX5强制运行STM32CubeMX,所以需要大家提前安装好STM32CubeMX V5.4或者以上版本。- O, d; f( w1 e6 H
  第3步,处理HAL库时间基准,MPU配置等。4 @. {+ d& H* k$ Q0 `- \
  第4步,创建应用。, L( R% j* R! K0 r

  h* W8 y, X3 {总的来说,这4步就可以完成移植, 下面将STM32H7的移植步骤和注意事项为大家做个说明。
6 ?- v* ]5 R. O, g8 ?# Q
- ^8 x. `$ {" q7 Q- D& o4.3   了解RTX5内核模板框架设计
! a# {/ J4 e2 o: t/ E! k移植RTX5前,我们优先了解下移植好的RTX5内核模板,方面大家后面移植:
# W  y; w( q; N( s
* f' G0 ?( Y4 A, Y
ebf7bed4831890980f518eaeb842a943.png

& a4 h& A/ X$ g: T( P" f" ~( E
框图如下:
& K3 M; t' b, L' @- d1 g) `2 I# ]
. X0 @  x5 m1 K9 G6 \+ Q
cc3f4f5af7e41dcb23a03a25e14d8ae7.png
/ [* p& L7 S8 c6 P6 ?+ S

8 S3 e7 J& R& A9 V4.4   第1步,安装指定的MDK软件包版本
8 n! `) l' w8 C+ k9 M移植新版RTX5需要大家下载当前最新的MDK软件包版本(如果有最新版,推荐大家用最新版):/ k: |/ p7 {+ ?( b+ f& Y: U  h4 B5 ]

: ]- Y: X5 ?$ C. E( e3 [' K: O  CMSIS 软件包使用当前最新的:V5.7.0
8 B9 }9 r- B" |% c4 i6 @6 y1 Q  STM32H7使用当前最新的:V2.6.0
& N  R7 G1 F7 O2 V" k" M5 g  STM32F4使用当前最新的:V2.6.0% |% `) N, @4 r+ `, f
  STM32CubeMX使用当前最新的:V6.0.x
- d4 i2 w' t8 U$ ]+ b  t  ARM_Compiler使用当前最新的:V1.6.1
# F3 {$ X9 V9 w' s  J9 A8 }; ~9 D! t* V. h
不管以后MDK的软件包版本如何升级,当前的软件包版本和以后的新版是可以同时安装的,也就是说可以安装多个不同版本,在这里可以选择指定版本:: g8 e# P. W# Y4 O% ~9 A6 R
: {+ t( Q5 ~$ ~. ?3 B. s
bbb84b8c4b3275b1026d2c95b5012294.png

. }2 t+ |4 Z" O( o
' e2 O! k- G0 X) d* O0 ?: i4 O4.5   第2步,准备一个工程模板8 X6 ^" X% d  Q) V: r
首先准备好一个简单的裸机工程模板,已经为大家做好:V7-400_Base Template,准备好的工程模板如下图所示(大家也可以制作其它任意的工程模板,不限制):
) Y9 a4 W! b# L2 u" G3 {; b! M
# |8 m9 |+ G* M6 S- ]' f
5618d5a487ef825c0a75ce19685c4821.png

) p  ^5 N" a0 n/ u) C/ D
: }9 K! G  B: h3 y* J2 w4.6   第3步,添加RTX5并配置
: a& [+ n( |, N& S3 w0 P% {+ VRTX5可以方便的通过MDK的RTE环境添加进来。对于H7版本,MDK会强制运行一次CubeMX,并添加很多H7的HAL库文件,这些库文件我们可以使用,也可以不使用。教程配套的工程文件是不使用这些,因为前面的工程模板里面已经添加了。所以要将这些文件全部隔离出来。
9 S9 q; m& T' H3 z) ^" Q
9 ?. w& j9 d7 F0 D4.6.1      添加RTX5源码
& _; h  G: J9 L7 h/ e
7 D8 h: W4 P7 G; U' U* e9 }
48f11b91f9fc45f3f04431047156434d.png
$ [) h4 V  a8 c0 A
+ B' \' m3 ~4 ?6 G% n6 b
点击OK按钮后,弹出如下界面:9 P4 {8 m! o7 a3 I# R( _
, O! K$ _8 u( N" A6 r* c  |. o
b430f5f7b2e1a16de73553adb9dd1f89.png

5 f1 R) H! X0 O6 `
8 b0 S: k- h. H, R点击Start STM32CubeMX,这里需要大家电脑上已经安装了STM32CubeMX,并且为其安装了H7的软件包。
0 @& B: E% w) `0 I- M8 C5 g; I6 H- g' N+ s3 A$ q  Z" t
af4f52889e56b18313faf6baa5ed1281.png
) X2 m0 _; V( w* B- F, j% B8 I/ D

( W2 ?5 G5 [1 Y. l: [/ Q1 \7 k$ A- `打开后,用户仅需配置如下地方即可:
7 O4 o2 b  H7 [  x7 ]+ c4 W5 H+ \0 c  G3 y" N) h$ U7 `
7c8a9271ba3d0ccb045c81921fd97d0f.png
1 b+ K8 s# Y5 D8 E1 B0 {7 R. f

, ^3 b4 V+ v$ V2 ?: S然后点击右上角的GENERATE CODE:' Y5 J$ R; f  B

1 ~, I/ {, K% R0 I  e
62747d5251f02d427c05caf48fc46d77.png
0 q4 U( t6 t+ K* ]; Q8 A

3 z& ]8 \4 B/ F0 Y! K; Y6 T' O: b8 X然后弹出如下对话框,点击Close即可,然后关闭STM32CubeMX。7 ?2 l! l% A: P) K$ E1 h- o0 R! T

( r' I/ C: u6 j
1a4404327c06b66c217f46c74bd48db2.png
  X( Z: `$ }% ^  u+ e3 @) _

- j/ e! F" d5 B0 k$ Y/ b) _6 N重新回到MDK,会有一个对话框,点击是即可:
. w! j, H( u) o7 z* ^
( V8 H& u6 y; c
cdfb3b29fdf8c8b60f0d85f8aaa161ff.png
- {- \0 U) X7 P9 `

* x" O: W  z/ x7 }1 Y最后就可以看到RTX5源码已经添加到工程里面了:5 l+ _  B. }  B" O1 Z/ R

1 Z. Y. p7 I0 X4 {
e49f340b4464ddd3afb5bf5082de0fdd.png

" v2 Q- j4 Q9 p) k* i
' ~1 X* \2 l. I& E: n0 o4.6.2      将自动添加的库文件隔离出来
9 V" z, u6 ^) g" J添加的所有文件中,仅RTX5和文件stm32h7xx_hal_msp.c留下,其它文件全部隔离出来,隔离方法也比较简单,比如隔离生成的main.c函数,鼠标右击此文件选择Options for file ‘main.c’
* h- G; w$ y5 ?
9 X/ u9 v+ v; \
3b989ad148a2ec7c0522490cd84fcf3c.png

$ A0 d; W# G" ^: v# N: d: B+ U, i" W; |+ _' l& w, `
然后取消掉include Target Build前的对勾,点击OK:/ E$ ^' [+ H* `; W6 b3 s& i

( T5 O0 m1 Z: L8 b# b
6652eec0f1078d33b6c1508049d0c922.png

1 M( h& a+ Z9 L- y1 m, R- Q, `" ^
+ F0 w6 Y# r+ C; J( |5 c  H看到main.c文件上有个红色横杠,就表示已经隔离出来了:
1 S  G; @5 n7 R# t3 a. I
( q5 P# @7 D# y! F
cafbe4a03ab78632d36b9cf1b050250c.png

. w4 ?( t. D: m: p8 u
9 M: v. n1 i/ ?9 u% G" D% |同样的方法,将stm32h7xx_it.c文件也隔离出来,文件stm32h7xx_it.h不用管。# z' z; q4 E$ h- [2 B- `, g
. u3 y0 u7 R: _
Device下面的这些文件也是同样的隔离方法:  \5 ~0 R7 {4 {
5 R, A/ ~9 j+ p6 p  z
f46dbe6e1b27dd459e04cba9849d9ff9.png
. ~3 D& u. D5 r
- p$ [% F* K1 Q7 b6 h) U2 U
只是鼠标右击弹出的界面有些不同:9 r$ V4 Q' g( B( e0 M
2 S9 z  x0 A- W, d( }' q. R: s* S
aeccd1d366ee4da23ceff332ae2f84e5.png

- }# I! X7 ~0 [- w+ S8 W/ x
1 N9 Z! y. \/ C注意stm32h7xx_hal_msp.c无需隔离,其它所有的文件全部隔离,stm32h7xx_hal_msp.c对应的隔离配置是STM32CubeMX,如果也隔离了,编译会有问题:
  L5 k3 A& }6 C9 K% B* g  l2 I$ ]( @
59f0e5e7d43f7ac7e983147c132a42ce.png
4 b: m  j) c  W( o1 \

1 t3 @" H* v% g3 M隔离后的效果如下:& x, H3 ^7 r9 r9 F: S; i

5 O8 ~/ L) D6 d% h; x% f0 D
573fb2c99aa8ef7ef6f577c106084913.png
4 \* @# t( x) M8 z% |) z

, _" y/ N& H0 C: q4.6.3      RTX5配置
+ @3 C3 ~; O4 n: Q6 E剩下就是配置RTX5,设置RTX_Config.h文件即可,移植阶段先按照如下设置配置好,后面章节会专门为大家讲解每个参数的配置含义:( u$ d3 H) J/ h# g, P

0 K' c" L4 f) M+ q
576cda809f95be40653ff18b9682f906.png
: d, @; z9 R  w; H
( ?' e9 q" L' b) X+ `# W3 E
4.7   第4步,MPU和Cache配置文件bsp.c
0 N+ B$ _- o+ t) s* E) L+ {, t; r这个bsp.c文件也比较重要,移植阶段,直接将我们移植好的模板内容复制过去即可,这里把相关的内容为大家做个说明。
. Y4 a" b& x6 w3 {# l. P  p
5 q2 }9 e! m/ |4.7.1      函数System_Init
  L7 A  m* T" M' P9 e
系统初始化,主要是MPU,Cache和系统时钟配置,需要在RTX5初始化之前调用。- ]0 Z) B; Z- n& F6 x8 o

* j5 G9 m% j) W$ N! }
  1. /*$ S* U' a+ E: P; k, r& y
  2. *********************************************************************************************************' b* Z9 G* v" t) Z) ~
  3. *    函 数 名: System_Init
    5 y: ^; {. U; n! |( @& m; k
  4. *    功能说明: 系统初始化,主要是MPU,Cache和系统时钟配置
    9 O* `* l* V9 t/ t
  5. *    形    参:无9 z! a, d$ F+ V/ J+ B6 r
  6. *    返 回 值: 无8 Z$ L. t3 E3 e
  7. *********************************************************************************************************! T8 O+ i4 ^* U/ X
  8. */
    7 E4 s. P* S* S  w1 ]
  9. void System_Init(void)
    9 c; m+ y! l7 M0 S
  10. {
    ' v# w. |/ H* s# s9 f

  11. 6 d& @' }% H8 w/ R6 N; b4 h$ O
  12.     /* 配置MPU */# v$ k, q) H1 e( {  i# }7 E7 j4 I
  13.     MPU_Config();' X% i- a( i1 t9 U( m0 z

  14. ; m2 P9 M1 H. @+ [* k8 w, ^5 P: {) H
  15.     /* 使能L1 Cache */
    3 M+ P  M7 t3 B; y. d7 a2 G
  16.     CPU_CACHE_Enable();2 ^, c. N, k$ A, ~
  17. % k- D; ?* u) d5 C. l# [' k* y! C
  18.     /*
      o: m) X# d% U. y' I
  19.        STM32H7xx HAL 库初始化,此时系统用的还是H7自带的64MHz,HSI时钟:, ~: N" ]. C) I$ R$ m/ [# M5 o1 e
  20.        - 调用函数HAL_InitTick,初始化滴答时钟中断1ms。9 q( _1 r/ o8 B& c( [
  21.        - 设置NVIV优先级分组为4。" r1 J2 s2 P: g5 a
  22.      */1 h  R8 t' H% y
  23.     HAL_Init();, A; S# W" _" z. l
  24. 0 ^8 B& a9 t  T. C( H' x
  25.     /*
    . U% i1 a# E* g1 b. g
  26.        配置系统时钟到400MHz) b' V$ e$ |9 F' |4 V% `! g
  27.        - 切换使用HSE。5 i/ |5 _1 v$ T) [
  28.        - 此函数会更新全局变量SystemCoreClock,并重新配置HAL_InitTick。
    ! @0 x: ~: \' j" a7 m; D
  29.     */
    5 n' G5 u. F# y( K: Q3 W
  30.     SystemClock_Config();$ |& B6 B3 X, D
  31. : J8 J6 @8 Q$ J
  32.     /* 0 V& O4 s  I+ R* X1 E1 S
  33.        Event Recorder:, F3 u" k) M* i" U6 [+ V* {, c& \1 j$ }# g
  34.        - 可用于代码执行时间测量,MDK5.25及其以上版本才支持,IAR不支持。/ h) e$ I) Q- Q# p2 [
  35.        - 默认不开启,如果要使能此选项,务必看V7开发板用户手册第8章
    9 ^3 E5 U0 O3 e
  36.     */   
    ) R, v) C: F# n9 P: J
  37. #if Enable_EventRecorder == 1  ; w5 X! J% A. H: f2 c* i5 |! K' ^
  38.     /* 初始化EventRecorder并开启 */
    & ^/ b- z" `! a% |% U- x
  39.     EventRecorderInitialize(EventRecordAll, 1U);4 O8 O: n- W  z4 F* q
  40.     EventRecorderStart();  X4 j" I6 V" w+ J1 J
  41. #endif
    # Z4 [; U8 M( m9 N" m
  42. ( i& y* U8 m4 {) H- _; `  K; L" E
  43. }
复制代码

- P2 S  {9 f1 `4.7.2      函数bsp_Init, n; ~- r, @; x* J, k8 b
硬件外设的初始化,这个函数在RTX5的启动任务里面调用。2 D! r# _$ j8 O

* c8 M$ U  f, e' x/ _8 J3 H; ~+ H, p
  1. /*
    1 |& l: @. v# I
  2. *********************************************************************************************************
    # R- [+ t$ r# A5 X$ X
  3. *    函 数 名: bsp_Init$ d0 Z5 I2 f8 |- \+ |8 n2 j
  4. *    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
    + t8 i3 F, N* H& }3 {
  5. *    形    参: 无
    + U4 y0 K4 K' ^9 D: C6 o
  6. *    返 回 值: 无
    , }( T  X% A3 H% z3 P" e
  7. *********************************************************************************************************
    ! `) a( Z( H& R7 p  z% j3 p7 M
  8. */
    ' o+ Y& n7 f1 a) v
  9. void bsp_Init(void)0 C+ `4 ]* A, O& V0 c7 k/ |
  10. {$ ^* ^# P1 o9 k& v$ j
  11.     bsp_InitDWT();     /* 初始化DWT时钟周期计数器 */       % m& \* P. ]7 o. _5 x
  12.     bsp_InitKey();        /* 按键初始化,要放在滴答定时器之前,因为按钮检测是通过滴答定时器扫描 */
    6 O7 k/ t9 E% E; i9 w
  13.     bsp_InitUart();    /* 初始化串口 */
    + F9 ~" t$ g4 G$ ]% [) H) W
  14.     bsp_InitExtIO();    /* 初始化FMC总线74HC574扩展IO. 必须在 bsp_InitLed()前执行 */    3 T5 z' O+ I7 a
  15.     bsp_InitLed();        /* 初始化LED */   
    . M2 I; X9 M8 c$ J
  16.     bsp_InitTimer();      /* 初始化滴答定时器 */6 ]6 h" m; t3 I+ T( u" C
  17. }
复制代码

" X1 j7 h" I! [3 k$ ]  F4.7.3      函数SystemClock_Config
; r8 K7 |6 M# W" ?1 N6 m; x这个函数主要是完成系统时钟配置。5 r' I5 m7 B4 Z6 M6 D
9 O) C& ?. _2 {) i
  1. /*7 e, R, R& t  N
  2. *********************************************************************************************************' A9 _" y7 S- v$ _
  3. *    函 数 名: SystemClock_Config
      N6 l6 @# x4 P, ]0 _3 z1 _7 _
  4. *    功能说明: 初始化系统时钟$ }2 H! O/ k" n2 u+ B
  5. *                System Clock source            = PLL (HSE)
    * J/ _; l( r; f0 {+ L
  6. *                SYSCLK(Hz)                     = 400000000 (CPU Clock)1 j5 T) a5 z9 w
  7. *               HCLK(Hz)                       = 200000000 (AXI and AHBs Clock)' T6 k. ^' X! f# {
  8. *                AHB Prescaler                  = 2# S% c9 H3 h- |: {8 I- N. Z; \* r
  9. *                D1 APB3 Prescaler              = 2 (APB3 Clock  100MHz)
    - z( t) I; l2 x5 u4 k& N% J
  10. *                D2 APB1 Prescaler              = 2 (APB1 Clock  100MHz)2 w3 x( O% J' T9 V' S: Q* E3 n
  11. *                D2 APB2 Prescaler              = 2 (APB2 Clock  100MHz); ?' B; T) G; ?" @! N0 E
  12. *                D3 APB4 Prescaler              = 2 (APB4 Clock  100MHz)
    & a+ l& _9 p/ ?" C
  13. *                HSE Frequency(Hz)              = 250000003 |5 a( x8 I5 n5 H! g! Q
  14. *               PLL_M                          = 5$ [" y3 A$ y& ]$ m# g1 E$ D
  15. *                PLL_N                          = 160+ c. f/ j" ?2 h% [0 I) R
  16. *                PLL_P                          = 23 [/ f9 @* d5 |
  17. *                PLL_Q                          = 4
    % N# l2 Q- ?( \7 \7 R
  18. *                PLL_R                          = 2
    : f3 i: z% O( @: Z
  19. *                VDD(V)                         = 3.3! H* G3 D- d7 O& v6 K' j* A2 z
  20. *                Flash Latency(WS)              = 4' ~; i3 u) s" `- ]
  21. *    形    参: 无
    9 f1 c1 R6 |7 X
  22. *    返 回 值: 无0 E8 O+ h. E; }5 G4 Z8 c: D! r
  23. *********************************************************************************************************4 N* b- e8 |/ E5 k6 m8 h' P! I
  24. */  {# ]! p0 v, k& D
  25. static void SystemClock_Config(void), J% K# }! z. c4 ^+ p0 M
  26. {
    8 V& L6 s9 N5 t0 d5 \
  27.    省略未写0 H" G) \% c4 y/ W# u

  28. " r* _8 n4 Z$ v* K
  29.    /* AXI SRAM的时钟是上电自动使能的,而D2域的SRAM1,SRAM2和SRAM3要单独使能 */    2 Z2 k- y& S) t3 @
  30. #if 1# }! @* c3 v0 |* ~2 A
  31.     __HAL_RCC_D2SRAM1_CLK_ENABLE();  {; g# ]2 Y: s1 K0 x1 L+ n: v4 U. D
  32.     __HAL_RCC_D2SRAM2_CLK_ENABLE();8 \1 t+ j! k; g2 k# K
  33.     __HAL_RCC_D2SRAM3_CLK_ENABLE();( R' u  ~# k! J( \: c
  34. . N1 h1 H- N" p1 ]# ~: }
  35.     __HAL_RCC_BKPRAM_CLKAM_ENABLE();       & o. q0 z. `) `0 O  v! a1 e
  36.     __HAL_RCC_D3SRAM1_CLKAM_ENABLE();
    7 }  v, o% k0 y1 k3 J
  37. #endif& {  }3 z% F# w
  38. }
复制代码

# x$ r4 h  e8 T6 |6 _9 i这里的RAM时钟初始化比较重要,这几个RAM的时钟都要单独使能。0 c/ z6 a+ @3 }+ S

" f* S. [  d' m  u( E4.7.4      函数MPU_Config( }/ }3 g7 R: W! p
RTX5例子默认采用AXI SRAM作为主RAM空间,因为空间比较大,方便我们后制作综合例子使用:
) ^- @9 y. O) n1 Y9 w' c& g: ~: T" K0 W. K# T9 C% ]
  1. /*2 J& ^" v2 C  U; q1 v% }) A# U! f7 T
  2. *********************************************************************************************************' V* a3 l: f( ?8 R
  3. *    函 数 名: MPU_Config
    1 N# j8 G! q% a, k. U
  4. *    功能说明: 配置MPU; N' s- o7 e% z0 W
  5. *    形    参: 无& u7 l5 Q' i( a: f  F! g% V* m
  6. *    返 回 值: 无% I4 z* P# `. S7 z2 W
  7. *********************************************************************************************************- q7 [2 J7 S. |9 b" U$ g
  8. */
    - s/ k1 b: U7 M: x$ I, @. J
  9. static void MPU_Config( void )
    - X/ n# P6 F& N) u" m! e
  10. {5 Y- e8 Z. w+ a+ g2 P* G* n; \
  11.     MPU_Region_InitTypeDef MPU_InitStruct;
    + _8 L* b7 {. g) ?. s6 C

  12. & [1 \$ Z& u& ?/ H3 r7 l
  13.     /* 禁止 MPU */
    1 k- C4 h1 ?) ^" M( v' p" a
  14.     HAL_MPU_Disable();
    9 X$ o- d1 C" ]. p/ ]2 I6 K- F

  15. , A8 M4 \. [- \( Y7 O
  16. /* 最高性能,读Cache和写Cache都开启 */   
    & \3 ]. T7 D% K  J0 j! f0 w( b
  17. #if 13 L3 r  |" M$ T& B* U
  18.        /* 配置AXI SRAM的MPU属性为Write back, Read allocate,Write allocate */- N4 Z+ }- W1 n! r6 A" h# @
  19.     MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
    % G( I, i4 R! F* c% t2 ^
  20.     MPU_InitStruct.BaseAddress      = 0x24000000;% t5 X" T8 i' |4 l
  21.     MPU_InitStruct.Size             = MPU_REGION_SIZE_512KB;
    0 ?% c  t" [& S$ |
  22.     MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;: N, \9 p( e7 B  `) J6 Z, R
  23.     MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;  ^1 u. q# v  i4 T" y8 K- e6 n- A
  24.     MPU_InitStruct.IsCacheable      = MPU_ACCESS_CACHEABLE;1 i; w" W* k7 M$ Q
  25.     MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;) r7 o; n/ \2 K
  26.     MPU_InitStruct.Number           = MPU_REGION_NUMBER0;
    & e7 m) ]- \6 V( ^* R7 A
  27.     MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL1;
    - Y; C" D% X% D# @
  28.     MPU_InitStruct.SubRegionDisable = 0x00;2 h0 U6 S; w  S9 M3 W1 ^( `8 I( E
  29.     MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;0 f2 h' ]- H; R4 ?6 h

  30. 3 {3 P2 k- Q) F1 H) U* m/ ^( M; [4 o
  31.     HAL_MPU_ConfigRegion(&MPU_InitStruct);
    ' J7 D; ?4 T1 H4 Y6 l9 t0 Y
  32. 2 ^  ^6 p+ S  V
  33. /* 最低性能,读Cache和写Cache都关闭 */
    ) p7 z% r: s! u1 B0 k4 o
  34. #else7 h! S0 F% B) g
  35.     /* 配置AXI SRAM的MPU属性为NORMAL, NO Read allocate,NO Write allocate */! x5 q: s8 ~! H
  36.     MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
    * l8 ~6 g- y. T! v! r
  37.     MPU_InitStruct.BaseAddress      = 0x24000000;4 d) _/ ]6 v" a" e! Y6 W
  38.     MPU_InitStruct.Size             = MPU_REGION_SIZE_512KB;
    ; l( m4 I5 y' A0 j. b
  39.     MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
    5 C2 b  z8 }  j' c
  40.     MPU_InitStruct.IsBufferable     = MPU_ACCESS_NOT_BUFFERABLE;% s8 G9 k7 n4 C. q7 |
  41.     MPU_InitStruct.IsCacheable      = MPU_ACCESS_NOT_CACHEABLE;* y% ?4 s5 p7 h) I- Y; {7 _3 F
  42.     MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
    % w2 J  [- t  b6 {+ |
  43.     MPU_InitStruct.Number           = MPU_REGION_NUMBER0;7 c, z$ ^) H7 p
  44.     MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL1;( W9 x; z' n1 X7 I$ W+ G; t
  45.     MPU_InitStruct.SubRegionDisable = 0x00;
      }7 U+ r0 ^. H& |$ i8 M
  46.     MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;7 n' i0 U- @: n8 s
  47. . m. [/ D: U3 i9 v( X. l& w! l$ c& R
  48.     HAL_MPU_ConfigRegion(&MPU_InitStruct);
    9 B2 Y% u$ F! J1 b* u
  49. #endif
    $ C6 ~$ y0 |$ }; V1 o0 \3 Z

  50. & s+ c" ~: B+ k9 b; F( Y3 R/ \
  51.     /* 配置FMC扩展IO的MPU属性为Device或者Strongly Ordered */
    ; N% W0 _. d! N, W2 X1 m/ ^
  52.     MPU_InitStruct.Enable           = MPU_REGION_ENABLE;7 p) z3 v& t5 ~' R' S% d
  53.     MPU_InitStruct.BaseAddress      = 0x60000000;; n% w: B. h9 d
  54.     MPU_InitStruct.Size             = ARM_MPU_REGION_SIZE_64KB;   
    ! Q2 t  I+ C4 e- j1 J( b
  55.     MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;, K8 D: o3 u9 K4 z4 t! \( e& t
  56.     MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;, U- [: R( k, |/ Q5 Q
  57.     MPU_InitStruct.IsCacheable      = MPU_ACCESS_NOT_CACHEABLE;   
    * }; w% e0 c' ?5 j# f$ v# G
  58.     MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;/ a+ b* Q' ?2 O2 [
  59.     MPU_InitStruct.Number           = MPU_REGION_NUMBER1;
    % u) A; s: j/ l2 a# X5 z
  60.     MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL0;
    ( q) J# T1 h+ [( X
  61.     MPU_InitStruct.SubRegionDisable = 0x00;
    , M- A- K9 v5 p7 J; W" u; b2 |0 N) r
  62.     MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;
    5 l$ a: ?7 k  J/ G6 ^. ~
  63. ' r& c/ v. p" n  s) M3 l4 X
  64.     HAL_MPU_ConfigRegion(&MPU_InitStruct);6 \0 Q) c0 j* J! L
  65. * V7 x. `0 O! B1 |4 q6 H
  66.     /* 使能 MPU */1 K* {  _& @( s6 S8 ~$ j5 M+ w
  67.     HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);6 ?2 R$ J5 u- c0 l5 w
  68. }
复制代码
, ~: k1 q4 v5 R9 [* x- p
4.7.5      函数bsp_RunPer10ms
: n# h' V1 Q$ V, |- ^3 u这个函数里面默认有个按键扫描,如果大家移植的程序里面没有按键初始化,务必要把这个按键扫描函数注释掉。
0 U# ?. o( k8 U: _2 b- J% F; Y7 B, ^8 b) F$ C) K1 ~% ~
  1. /*
    / y. c+ N. _; I0 G; C4 E6 z+ \
  2. *********************************************************************************************************
    - j# I3 }4 H  g" e4 H. L* K
  3. *    函 数 名: bsp_RunPer10ms
    7 R3 y5 j* p- C. R3 F, U
  4. *    功能说明: 该函数每隔10ms被Systick中断调用1次。详见 bsp_timer.c的定时中断服务程序。一些处理时间要求
    5 A- g- D! l" k1 c+ G
  5. *             不严格的任务可以放在此函数。比如:按键扫描、蜂鸣器鸣叫控制等。' I! }# E' L; n! Y! ?
  6. *    形    参: 无/ C8 g$ D" O7 R1 ]
  7. *    返 回 值: 无, `& `& `3 ^/ g
  8. *********************************************************************************************************
    " m( T& B, {. h, f$ ^
  9. */
    - s1 O, E) C! n6 S& H, ]
  10. void bsp_RunPer10ms(void)& R1 r' R* @' b! Q0 ]- E1 _
  11. {
    6 E' ~- U/ R8 d2 _/ D
  12.     bsp_KeyScan10ms();; a+ ?; c& j" X/ y# P) o
  13. }
复制代码

" K/ v6 O) `8 @2 i% X4.8   第5步,更新bsp_timer.c和bsp.h文件0 |6 N! u9 r8 j; M
更新bsp_timer.c文件是因为此文件跟RTX5都要使用滴答定时器,有冲突。所以大家直接将我们工程模板里面此文件覆盖移植的这个文件即可。3 K6 R: j8 _6 }( r, M: m

7 p2 f  N7 u& Y; T1 @) \( n; N, Ibsp.h文件里面要添加一个宏定义,因为bsp_timer.c文件里面做了些条件编译:
% h7 h/ P  p) f' O; a: A3 Y8 T% J6 p# q7 c0 G$ ^
#define  USE_RTX    1
% m7 j3 z# C2 ~6 o7 f$ s0 p& X" z; y3 `% t" y" `6 e5 ~, |( C5 _8 D2 X
另外,bsp.h文件将大部分头文件都添加进来了,大家可以根据需要,用到那些头文件,使能那些,用不到的,可以注释掉。当然,不注释也是没问题的:
1 E+ |4 u1 n$ j# u& l2 g) t7 t: l. X
  1. /* 通过取消注释或者添加注释的方式控制是否包含底层驱动模块 */
    - u: h7 o! F  d& c  {6 g
  2. //#include "bsp_msg.h"
    2 E) j$ g. t3 G/ W- I3 Q
  3. //#include "bsp_user_lib.h"2 |, N3 Q; a6 p! i
  4. #include "bsp_timer.h"5 H4 e$ ?5 d# g/ x8 U- s+ J3 g
  5. #include "bsp_led.h": x8 Z2 T# T4 h+ F  x- K$ x: H! R. X
  6. #include "bsp_key.h"* N$ v0 O1 ]; r/ l& I
  7. #include "bsp_dwt.h"3 E& x( t( s( G! @  @

  8. 2 j5 @- \+ x7 _' c. U
  9. //#include "bsp_cpu_rtc.h"; \, @$ e" A; ]  U  @# r) a& n6 {8 s
  10. //#include "bsp_cpu_adc.h"" p/ |, A% Y+ l
  11. //#include "bsp_cpu_dac.h"8 h3 V' b& e" X+ i$ Z- H% @: @. M/ d
  12. #include "bsp_uart_fifo.h"
    . \+ v  W5 v8 \) X% @( b
  13. //#include "bsp_uart_gps.h"
    : F% {. ~/ g. ]8 J2 U1 {/ u
  14. //#include "bsp_uart_esp8266.h": k' @2 r5 k# R* ?) {% b
  15. //#include "bsp_uart_sim800.h"0 k& @! t* R* `9 F9 w
  16. # Z6 e7 t. K8 p0 R; Y8 L- `
  17. //#include "bsp_spi_bus.h"! r/ n4 [. P. J1 l; y6 \- L) ^
  18. //#include "bsp_spi_ad9833.h"
    ! B; w; n% @+ ?6 H7 ^
  19. //#include "bsp_spi_ads1256.h"7 e# s6 G9 `5 N  Y0 U0 J
  20. //#include "bsp_spi_dac8501.h"
    7 `) K6 u1 ?, t* N" L
  21. //#include "bsp_spi_dac8562.h"
    ' I9 j& i/ v6 p
  22. //#include "bsp_spi_flash.h"9 f: f5 P' t  r# z+ l
  23. //#include "bsp_spi_tm7705.h"' u& X3 I/ ]3 k1 |, x/ J
  24. //#include "bsp_spi_vs1053b.h"
    : m! s0 X& f6 ]0 ?0 M
  25.   s3 S6 Z/ [3 p' C9 R2 g8 t+ o) y
  26. //#include "bsp_fmc_sdram.h"2 L# `' ~& ^* i5 Q
  27. //#include "bsp_fmc_nand_flash.h"
    9 J/ e8 }. a$ ?  [$ p
  28. //#include "bsp_fmc_ad7606.h"! q% X; Q% {+ k! i# l
  29. //#include "bsp_fmc_oled.h"' w8 {/ Y6 h9 w/ q) v4 M$ g
  30. #include "bsp_fmc_io.h"& E- t+ R$ u- C
  31. & }: K1 X( A- Y" V( ^7 z6 n& ^
  32. //#include "bsp_i2c_gpio.h"
    & X: Q5 ^7 g8 f2 J& O1 V
  33. //#include "bsp_i2c_bh1750.h"
    8 l- W9 L6 o0 o
  34. //#include "bsp_i2c_bmp085.h"
    - E, s" ~8 S( c6 H% v: f1 h/ v/ {
  35. //#include "bsp_i2c_eeprom_24xx.h"9 y7 w5 g1 C1 p5 k
  36. //#include "bsp_i2c_hmc5883l.h"
    2 O2 y) Z9 A. d4 |1 G$ T% r+ X" T
  37. //#include "bsp_i2c_mpu6050.h"* |! c1 E5 r2 L9 `/ F
  38. //#include "bsp_i2c_si4730.h"  t1 S: e( v: H( G' ^8 p' P) f
  39. //#include "bsp_i2c_wm8978.h"- |3 m: \  n8 O- i! t! Y, o
  40. + U: o# O- k+ X; Z7 ^' |- O8 T
  41. //#include "bsp_tft_h7.h", k9 u7 L3 h7 ^+ x4 Z
  42. //#include "bsp_tft_429.h". y( e5 Q' r. Z+ A9 K
  43. //#include "bsp_tft_lcd.h"1 l/ j2 W, }  J
  44. //#include "bsp_ts_touch.h"
    ( i' Q+ G$ g* M, P/ f/ K/ j3 x
  45. //#include "bsp_ts_ft5x06.h"
    7 F' _4 u1 |8 }9 r3 ^" [- H
  46. //#include "bsp_ts_gt811.h"6 C  p- q0 l9 D& e: _( D- G
  47. //#include "bsp_ts_gt911.h"( M) f) z4 U% m% d4 \* p& H$ R* r
  48. //#include "bsp_ts_stmpe811.h"
    3 H% V6 _( r  ^9 o, n
  49. , t1 K" x3 m$ L  }- G* y. Q, C
  50. #include "bsp_beep.h"/ ~" @) T2 t6 _
  51. #include "bsp_tim_pwm.h"+ I5 _. d( K% n- h% W
  52. //#include "bsp_sdio_sd.h"
    / g0 x3 I1 P0 m; z; r$ X
  53. //#include "bsp_dht11.h"# m  v) m) N) o& D% d* h2 W# o
  54. //#include "bsp_ds18b20.h"; k6 K! z! y. {0 a" Z
  55. //#include "bsp_ps2.h"
    6 D1 R% n# I/ m3 X+ i. u( t
  56. //#include "bsp_ir_decode.h"5 X, @$ N* j: j3 ]
  57. //#include "bsp_camera.h"
    . ?' \5 v* U" f" |$ t
  58. //#include "bsp_rs485_led.h"3 a1 I7 K1 M- h4 _
  59. //#include "bsp_can.h"
复制代码
6 C' c# W7 c& }2 }
4.9   第6步,修改文件stm32h7xx_it.c& \, @3 j; P$ m" l" r2 y
删除此文件里面带的如下函数,RTX5要使用,冲突了。
+ ^, q) V% g7 F1 X4 t# Y
6 e* p  R3 p% T) O  Z* \
  1. /**
    1 H/ R! @' V' ?4 a) z. {# k
  2.   * @brief  This function handles SVCall exception.. N9 M4 ]/ e2 T% Z" g
  3.   * @param  None! g" r9 @! v7 ?
  4.   * @retval None. i, r' R: S0 |3 ?( W
  5.   *// S& `  i. O0 L& a/ g% C
  6. void SVC_Handler(void)
    + U( `# f. c" |1 a/ x$ @8 I/ t0 |
  7. {
    " v. |) }; N+ Q; ]* ]
  8. }
    / ?1 E& h+ D* Z3 }

  9. 4 q* @! b5 E) z, C. `/ j$ @( e
  10. /**2 z# a* M2 ?0 y+ h# r( g- F
  11.   * @brief  This function handles PendSVC exception./ `/ _- ?* j) D
  12.   * @param  None
    - d7 w) k" F$ Q' V9 c
  13.   * @retval None
    6 N8 F2 Z& i. y/ @' U; m. G) {
  14.   */- p, }  v* i% i+ I5 g
  15. void PendSV_Handler(void)8 l/ _5 {; x% v( `4 G
  16. {! t$ B$ f+ T! c& W1 O) l
  17. }
复制代码
/ `& ^. }+ Y) h- G& l; D% m; `
4.10 第7步,添加头文件的汇总文件includes.h
' U/ I/ Z9 V, b0 r: O( ~在User文件夹下添加文件incudes.h,直接从本章节教程配套例子的User文件夹复制即可。此文件主要用于RTX5的各种头文件汇总。
6 ^3 h- G1 _' J8 t* }
: r1 p4 Y! A' O  q& t
63fafbc927e6b911f6f3b81c4acb6af1.png
9 ^9 j, L+ d* l( u- H  }( v& \

+ h# o/ [- I5 ]5 v4 C) P4.11 第8步,HAL库时间基准stm32h7xx_hal_timebase_tim.c
: m0 }) F2 s) h7 b3 I1 N
由于RTX5和HAL库需要一个时间基准,而且默认都是用的滴答定时器,所有要有一个选用其它的时间基准。当前的处理方案是为HAL库提供一个时间基准文件stm32h7xx_hal_timbase_tim.c。此文件
) T( {6 h; m* M6 [2 ~. n" i2 r  F
) A8 l& x% f$ f2 \% _里面做了两套方案,一个是使用TIM7做时间基准,另一个是使用RTX5的API做时间基准,通过条件编译做选择。默认是采用RTX5的API做时间基准。
( B& L. F9 z1 L8 [/ U
7 p8 d2 [- L" D& d. ~9 k
  1. /*
    % z5 o  r3 ~: B7 y
  2. *********************************************************************************************************
    ! e' H, ^1 E* x3 t: H
  3. *    函 数 名: HAL_Delay4 s% `5 l/ }" j* M
  4. *    功能说明: 重定向毫秒延迟函数。替换HAL中的函数。因为HAL中的缺省函数依赖于Systick中断,如果在USB、SD4 Y% w3 a( p' {8 i
  5. *             卡中断中有延迟函数,则会锁死。也可以通过函数HAL_NVIC_SetPriority提升Systick中断
      H  L' R  |4 n8 W! b( `
  6. *    形    参: 无
    * M( s5 p0 C$ X& Q
  7. *    返 回 值: 无
    $ O8 Z3 c! h$ E6 @
  8. *********************************************************************************************************1 b/ a3 R' G1 Z  S
  9. */; {* L! c# ^; N1 G9 ?) Z
  10. void HAL_Delay(uint32_t Delay)
    ; J* b; `; U4 m1 J& j
  11. {" `1 \- k8 W6 m6 W7 L
  12.     bsp_DelayMS(Delay);
    3 E; n# g& [* I' s9 b9 c
  13. }
    1 F, ~; |# N5 v, q! o' H. O

  14. ; j' g# G* K! \8 D# O
  15. HAL_StatusTypeDef HAL_InitTick (uint32_t TickPriority)  e5 o& n( ~  U9 d1 V4 A# ^2 p( d( [
  16. {9 D8 L; s* q$ l7 b/ e+ ]& Z& t
  17.     return HAL_OK;9 X9 x; _7 J/ a& f
  18. }
    ! @" z3 K2 Y, X3 h: g4 K: O0 m' e

  19. ! w' b# X8 G% o7 f# A
  20. uint32_t HAL_GetTick (void) ! |  A: l, s3 i, f  `
  21. {
    ; z8 B9 f  @& @$ O! w! @
  22.     static uint32_t ticks = 0U;6 g( O: F  j% Q6 W  o: ?
  23.     uint32_t i;
    / e& A  W2 ]2 r2 J
  24. ' s* B9 u* A' T, d
  25.     if (osKernelGetState () == osKernelRunning)  q  p) j4 G8 ~! V, B) l- n6 q
  26.     {
    * O3 r. c8 J# Q7 h3 I  h6 ^
  27.         return ((uint32_t)osKernelGetTickCount ());
    : E; c4 i; u& u( x- d* C
  28.     }% y7 e9 _& w: e+ a5 l0 ?5 l: C
  29. ! F4 w' `$ M" L% P4 {  j) H' P2 I
  30.     /* 如果RTX5还没有运行,采用下面方式 */9 m/ V0 L& {! m  g+ |& j4 m
  31.     for (i = (SystemCoreClock >> 14U); i > 0U; i--)
    , [' x8 \3 F/ F  o; s
  32.     {2 ]: [( v5 d0 l! @
  33.         __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP();' M- r0 G  z) V/ C
  34.         __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP();# D9 I6 G0 T" H+ _6 F  Z$ z
  35.     }
    % `: U/ m' z4 @8 M7 x' W& c  W# |
  36. 5 s+ B, Z/ A9 x; h. n- C
  37.     return ++ticks;
    9 u* o, \# `9 z# ~
  38. }
复制代码

+ y) S/ T9 ]9 E; l0 ]* Y) C, L  F4.12 第9步,添加BSP驱动文件bsp_dwt.c
4 q& w% S1 N" l3 j) C
添加bsp_dwt.c文件和bsp_dwt.h文件主要是因为第8步中的stm32h7xx_hal_timebase_tim.c文件里面的函数bsp_DelayMS要使用,此函数是基于DWT系统时钟周期计数器实现。" k2 X: ]+ z& h2 C5 \) z

( q# G8 X  `' z1 e$ M' v* L* P
f0d85f2002a553fa31c8f67b30e2db76.png
3 S* ]/ o+ g* O8 i
8 `5 ?1 k. `# o, @; T
4.13 第10步,创建应用任务(重要,注意启动任务)

8 e  W# l' W, v) Q7 U5 D应用程序比较简单,大家可以直接复制本章教程配置例子的main.c文件中的内容到自己工程里面测试。主要创建了如下几个任务:
' {8 C9 x3 ^/ O# P  s. f6 r
8 t7 J& |7 L5 p& a' W, s3 hAppTaskUserIF任务   : 按键消息处理。% A; Q& I% s. w
1 m( I4 v! |& X/ k, R7 H/ p8 ^
AppTaskLED任务      : LED闪烁。
, r4 ^! m: ?9 U% h7 t9 I4 x
4 Q% a5 `; ?: E# }AppTaskMsgPro任务   : 消息处理,暂未使用。% Z- H* g9 G4 z. v
+ h3 X8 u, |( u" z; V
AppTaskStart任务    : 启动任务,也是最高优先级任务,这里实现按键扫描。/ \* L* P2 r9 c; W  |0 `

- C" l' f0 q4 O( J0 PosRtxTimerThread任务: 定时器任务,暂未使用。
0 K' @) n1 x3 Y2 B
" W5 _6 @: H/ b$ b8 f0 c  ]任务栈大小和任务控制块定义如下:, v4 d- T, `- k
0 X+ }- M, s; |' N3 `8 b
  1. /*
    5 l/ ^6 h7 D' A6 H$ s, A: h- W
  2. **********************************************************************************************************: H) J4 x% b" B8 V) [
  3.                                              变量
    , V6 e2 H# o' S2 d1 S
  4. **********************************************************************************************************
    * r1 h! B+ J3 \  E/ j, |2 X
  5. */
    0 ]) Q& L; H0 h. |
  6. /* 任务的属性设置 */+ \2 a: l6 [# i" F' C( K- A5 |
  7. const osThreadAttr_t ThreadStart_Attr =
    2 q; j: A/ I+ t8 q0 w6 u
  8. {  l3 V# A7 g; E1 v, f
  9.     /* 未使用 */
    ; l3 {; G6 |6 n/ e- Y& x- \
  10. //    .cb_mem = &worker_thread_tcb_1,
    / ^3 W3 _/ `8 j
  11. //    .cb_size = sizeof(worker_thread_tcb_1),
    - t/ G! r. \" C1 b0 V* M8 V- S5 ]
  12. //    .stack_mem = &worker_thread_stk_1[0],
    % m  n3 X3 p9 w+ Z" P0 U
  13. //    .stack_size = sizeof(worker_thread_stk_1),; e( |4 H# B# G. z3 u1 y$ Y5 B) ^
  14. //    .priority = osPriorityAboveNormal,
    $ X; q1 O1 a) O) G& t- X
  15. //    .tz_module = 03 c) }% c* i" l: M( a; B1 h

  16. # J- E' Z+ @' T9 ^8 H# T+ t( [
  17.     .name = "osRtxStartThread",5 P7 a. X- `$ n$ O
  18.     .attr_bits = osThreadDetached, ! e* |) B3 b' Y" i3 e. {9 e
  19.     .priority = osPriorityHigh4,
    ; S- `3 S( Y1 Z4 U  @0 i* g
  20.     .stack_size = 2048,
    - g# _+ d; E0 W' V! w
  21. };
    2 h1 y8 O0 n3 Z- M7 E2 Z! K" {  c
  22. + i) d  d$ l1 D9 Q4 e, e
  23. const osThreadAttr_t ThreadMsgPro_Attr = # n5 z/ S( O4 W" z4 i
  24. {% D9 ~8 S1 e( v, Z7 A3 q
  25.     .name = "osRtxMsgProThread",
    ( M! _+ H9 I9 C  F
  26.     .attr_bits = osThreadDetached, # a# R/ X) k, t; \& S( x  f- J. H0 o
  27.     .priority = osPriorityHigh3,9 `9 W: t5 _/ P2 F1 g, r2 {9 I
  28.     .stack_size = 1024,& D: c6 U6 ]2 [0 U2 g
  29. };: y  ^" [0 A# V, m, P- E' R
  30. ) t# c! M& p( y  A. |. F
  31. const osThreadAttr_t ThreadLED_Attr = 8 J4 T+ y' U9 ]* b% E
  32. {
    0 Z2 N% n! y& q7 v4 G2 Z0 |( M1 V
  33.     .name = "osRtxLEDThread",
    " D4 J4 T4 K: k# X' q# c
  34.     .attr_bits = osThreadDetached,
    # h1 x. F. }6 W5 P7 k! @
  35.     .priority = osPriorityHigh2,
    4 u% _% N  }# {5 D2 n. C  n
  36.     .stack_size = 512,0 [3 x9 u5 a( Y& |5 U
  37. };- w' p2 W& Z( ^: a0 p

  38. 3 B( L0 ^# L# \
  39. const osThreadAttr_t ThreadUserIF_Attr =
    ; m# Y# h; }4 ]% ]1 |/ T  V
  40. {
    . D% {$ k+ a) z* K
  41.     .name = "osRtxThreadUserIF",
    ' O- ^1 X; ~' r% o& N
  42.     .attr_bits = osThreadDetached,
    ' r: Y1 p1 D  a2 x& k
  43.     .priority = osPriorityHigh1,
    . v: r, x: \) {  L* l; k
  44.     .stack_size = 1024,
    2 ^' D( r/ K6 M3 K; t' g* Y+ ~% l
  45. };
复制代码

$ N- `8 ~  Z# x5 s0 Z, R. c任务创建:2 v  P3 M. G# P0 M" V. b2 Z. z
0 N" [7 N$ f/ `- N* \; R9 y1 L! }
  1. /*. i4 a* K% R; v( S' A. `4 o
  2. *********************************************************************************************************1 h1 i3 y# X; {, m4 U. f* J
  3. *    函 数 名: main3 o) ~" H) ~" Y" H# V$ f% A5 }
  4. *    功能说明: 标准c程序入口。
    3 j  n& D+ E- D
  5. *    形    参: 无
    3 l2 U! G: {$ I, e* f3 V2 }
  6. *    返 回 值: 无$ I3 H) _% \1 I! ^
  7. *********************************************************************************************************' E0 g1 P1 H" N3 F' P: T
  8. */% s+ X) T& _  _: D
  9. int main (void)
    1 `: s! @/ Q4 ~# {
  10. {   
    $ X/ J% Q1 ?( ^. c
  11.     /* HAL库,MPU,Cache,时钟等系统初始化 */
    " v, a! n4 b2 z
  12.     System_Init();
      i2 o; }9 |" A& X, @- r$ ]5 g

  13. ' G) X4 D: _2 z- q
  14.     /* 内核开启前关闭HAL的时间基准 */
    & S/ V, ^" h% w) _
  15.     HAL_SuspendTick();
    ( `5 P5 k7 ]  i6 ]" ~7 |
  16. 5 O% a( ?0 {' N
  17.     /* 内核初始化 */- P. o2 S5 }  f' [, h% B9 B5 X
  18.     osKernelInitialize();                                 
    7 p( ^0 \, Q. a8 |" O" r# Z: X1 h/ I9 ~
  19. 7 @9 l- q% Q0 d
  20.     /* 创建启动任务 */  V% [% |( q2 N/ V: I' i& S
  21.     ThreadIdStart = osThreadNew(AppTaskStart, NULL, &ThreadStart_Attr);  
    % f2 ^: ], |. F; C' J% `
  22. 8 K( R7 n$ X8 |
  23.     /* 开启多任务 */3 Y" i, v: @0 N
  24.     osKernelStart();. |1 ^7 q# t# i! ?! c& K
  25. " X6 v1 E5 L. C( ^7 G  l/ \
  26.     while(1);
    $ a% R4 N2 J' v, ~2 w. C( |7 ]
  27. }( }2 r1 g/ S- U. T) \- c$ t# n
  28. 3 {, s) u% P8 d: J* N; A7 @6 i
  29. /*
    , h% T$ A& I6 T! o& y
  30. *********************************************************************************************************& P7 G) k7 m; G3 Y; M3 z
  31. *    函 数 名: AppTaskCreate% y) W/ z. N/ i
  32. *    功能说明: 创建应用任务
    ; C) e4 H5 S5 z$ |4 S4 M( b" ]
  33. *    形    参: 无+ q* k. ^& F" N4 Z! W
  34. *    返 回 值: 无
    " J+ [) b9 S$ P; c
  35. *********************************************************************************************************
    $ |$ N" R" E; F' x2 H
  36. */
    % ?' Q3 K# a3 X4 W# Y
  37. static void AppTaskCreate (void)& k# K. U+ B, {1 k! o8 v. T
  38. {
      M3 |5 r) k# F  P
  39.     ThreadIdTaskMsgPro = osThreadNew(AppTaskMsgPro, NULL, &ThreadMsgPro_Attr);  % A% \! l2 Y- q+ S% N& X
  40.     ThreadIdTaskLED = osThreadNew(AppTaskLED, NULL, &ThreadLED_Attr);  & W1 o! Z3 O8 Y" A; V
  41.     ThreadIdTaskUserIF = osThreadNew(AppTaskUserIF, NULL, &ThreadUserIF_Attr);  3 J. g/ y& @$ K3 R
  42. }
复制代码
3 d" w- k/ t) G
这里我们重点看下启动任务,主要做了四个工作:$ G& |5 m3 l4 G5 l
+ G1 t* n3 ], @5 p) R
  外设初始化bsp_Init。
9 i) d% n5 B+ h' x  任务创建AppTaskCreate。
- W# O: Z8 v$ D& {  需要周期性处理的程序bsp_ProPer1ms,对应裸机工程调用的SysTick_ISR。这个的实现非常重要,这样之前裸机里面使用的API,就可以直接在RTX5里面直接调用。" k4 y  e) T7 m9 j) T" e; s. |/ _8 m
  1. /*
    0 Y2 f; P: b6 F/ K$ _3 |8 |6 ]
  2. *********************************************************************************************************
    4 o4 W5 o3 }6 a" P
  3. *    函 数 名: AppTaskStart1 l9 a: Y1 X  d, s% p
  4. *    功能说明: 启动任务,这里用作BSP驱动包处理。
    6 d/ q2 t) A" ]3 t5 f* a
  5. *    形    参: 无
    3 B( y& Z4 I0 S6 D3 T
  6. *    返 回 值: 无. X; Y6 f' [) _: Y" M6 a* @
  7. *   优 先 级: osPriorityHigh4  + F' T( B8 W$ ^7 ^* L
  8. *********************************************************************************************************9 [& h/ ^9 A8 \4 b3 d
  9. */: C  R; c! v/ m; T) R
  10. void AppTaskStart(void *argument); Q. j7 B0 z8 T/ T6 R3 j
  11. {
    9 J) }& q: @1 J) _9 r2 ?, c0 G
  12.     const uint16_t usFrequency = 1; /* 延迟周期 */5 R$ ~* P" c7 O8 f' J
  13.     uint32_t tick;% i5 s! P# ~) \( b( y$ L3 g
  14. 0 a& L% ?1 C4 }# j" r; ?
  15.     /* 初始化外设 */
    * P5 W  D* Q  j; N( ?
  16.     HAL_ResumeTick();
    : C* f2 C% ]. N5 V
  17.     bsp_Init();6 X2 E& `2 N6 E3 E0 S& R
  18. , c& ^# `7 S' l  L
  19.     /* 创建任务 */
    ; @* A+ |. r1 d- ]7 O, T- A
  20.     AppTaskCreate();
    2 w9 w4 N( m& q" Q, s

  21. - C! d6 B0 B! K1 p5 |2 W
  22.     /* 获取当前时间 */
    1 q9 u) e# b' l  V  L, l
  23.     tick = osKernelGetTickCount();
    , r8 i; K% U2 u/ m1 U/ X
  24. + o2 Z9 I/ B* ^( y% C2 x
  25.     while(1)
    & l6 ], S; X6 M; l1 Z: G3 b, y3 s
  26.     {
    ) N0 q0 }1 V  ^
  27.         /* 需要周期性处理的程序,对应裸机工程调用的SysTick_ISR */; r$ [+ M: E6 X8 d! w
  28.         bsp_ProPer1ms();: [; H! c4 ~" y# L. B& u
  29. - k2 d7 T1 Z3 T- N9 e2 W% f1 e
  30.         /* 相对延迟 */
    0 ]2 J' d% d8 u# N& N& _
  31.         tick += usFrequency;                          
    ! N) H) E$ e( T2 U9 D- f; u
  32.         osDelayUntil(tick);) J% o! X$ A' U' g$ ?0 s
  33.     }% Z% P) Q8 ?$ d* M5 V" T
  34. }
复制代码
6 o: ~; K: q1 p) s
4.14 常见移植错误总结

' ?1 V5 X8 i$ x0 H+ k, I5 y常见的移植错误主要有下面几种情况:
/ P! ?. f4 ]+ ^! f/ |6 l& ]% a; |+ u4 l
  编译后提示如下两种错误:, v+ o% a' ?5 d$ |
Error: L6200E: Symbol PendSV_Handler multiply defined (by irq_cm4f.o and stm32h7xx_it.o).5 ?+ v7 w) Q9 d$ L( G9 }
( }7 [6 x+ n/ e  Y
Error: L6200E: Symbol SVC_Handler multiply defined (by irq_cm4f.o and stm32h7xx_it.o).
5 s2 m3 p, j) f7 t( T( \4 M
# Y* E8 K& r. U! u2 ?解决办法:这是函数重定义了,直接将stm32h7xx_it.c文件里面的PendSV_Handler和SVC_Handler删掉。
1 G) @  b& [, C% U$ {6 U- Y$ L! Z# }3 q, W6 o+ n9 K
  提示如下错误; X- K% Q" M2 Y* p( u" ?6 L
Error: L6218E: Undefined symbol bsp_DelayMS (referred from bsp_fmc_io.o).
3 l; x" G' o1 W! Y. ?# h7 t
7 m: C6 i; j+ b$ u# A& h& F4 \解决办法:打开bsp_dwt.C文件中的条件编译。
0 U& ~1 y) s! y) {0 [- t
) }! z1 `! L, y3 Q% B4.15 实验例程- \) W& K% p: ]/ M" D* g% d/ U% Q
本章节配套了如下几个例子供大家移植参考:9 V+ u: E+ y% J9 ]& |

4 i8 q! H8 `1 q  s8 o: Y( G  V7-400_Base Template
5 p6 y! t) b  E+ F裸机模板,方便大家添加RTX5内核源码。
1 V. t, u3 u6 f  H- H# d3 }6 m7 [* |3 _5 S' x8 V6 V
  V7-401_Threadx Kernel Template+ n* `% [8 N2 V9 b! e
/ q- M) F* k6 v8 d! e- |( v
ThreadX内核模板。! X) y5 ]$ {( o5 W$ v  P4 E" O

7 a* ^; X% _8 [7 n3 W& U: E) ~% bMDK进入调试状态后,选择周期更新:
5 Y' a1 q, c' p* y% D! V- \8 C9 s1 b' f' D3 {$ A% H. `0 s
fdce9fac9944ad56faa0dd13307f6ebb.png
. I' B. V/ {( j3 K- m1 p0 x

; K) {+ r" U* u5 f, e然后打开调试组件,注意和RTX4的调试组件位置不同:
5 m  U2 @3 ~; s, K  h9 A% \: F, `' R/ j3 T
9482ce7367ba4d7cf08c73a56db28f75.png
2 ^( b3 q  ]: B6 Q: b( O. Z( f7 W

- z6 ]# K0 N: |+ @# h$ r, I然后点击MDK的全速运行,1 b6 o- B2 C9 Z, v# V

( a9 d* O, Q# j9 w7 M
e3038a01781216611f96ae37d5bccb17.png

# Z5 a$ Q3 o. @2 Q( n1 N+ j5 A& g. x& z  n5 F2 ?
至此,就可以动态实时查看RTX5的运行状态:
* c! S6 d5 b7 Z! b  X1 y) p' A! b  W/ S0 j/ M+ S) Q
797f68ea76bd699fe11ce441076df4ec.png

9 a4 H# ]* |% f7 ~9 ~  X& N
5 V9 c. ^- O& ~4.16 总结
0 L1 U* M! u/ w% L* }! I+ b+ Z本章节为大家讲解了RTX5 在MDK AC5上的移植方法,移植涉及到的知识点比较多,初学的话,建议实际动手操作一遍。$ ]! b. ^+ n7 J

& r$ F9 m! x+ u0 {5 I5 n# w$ J6 n1 M6 O7 z
; ?5 J" E2 f; @1 T
收藏 评论1 发布时间:2021-12-30 14:32

举报

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

好好学习

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