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

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

[复制链接]
STMCU小助手 发布时间:2021-12-30 14:32
4.1   初学者重要提示
6 H- o6 j$ |% X( H  当前RTX5可以移植到GCC,MDK和IAR三大平台,考虑到仅MDK平台下有RTX5的调试组件,我们这里仅提供了MDK的移植说明。) ?# w) M$ D! M% c) o8 R
  STM32H7使用MDK RTE环境添加RTX5,需要强制运行一次STM32CubeMX,因为H7已经没有配套RTE经典添加方式,而STM32F4是支持经典方式的,所以无需运行STM32CubeMX,详情可以看我们STM32F4开发板对应的RTX5教程。! c2 ~' p0 t6 S' x, D. _
4.2   移植RXT5内核整体说明, a( H8 I/ ]0 q, @* g6 t) C
移植之前,有必要对移植过程有个整体的认识:8 W- ^4 a1 o% V/ Z: T. x) u# n

. y0 W$ k2 w, J+ G8 N  第1步,准备一个工程模板。2 q. V  f" |( M" o0 W4 B
  第2步,移植RTX5。6 y- ^0 ^9 J% g+ x' k% t+ y% o
  移植RTX5是采用MDK的RTE环境直接添加。当前H7芯片使用RTX5强制运行STM32CubeMX,所以需要大家提前安装好STM32CubeMX V5.4或者以上版本。
7 {! T# Z6 }* }# @) \4 P4 e  第3步,处理HAL库时间基准,MPU配置等。$ {4 W! B" Y1 _
  第4步,创建应用。
2 @" H7 g0 ~3 C1 o. h# D; P5 G; J  j, C
总的来说,这4步就可以完成移植, 下面将STM32H7的移植步骤和注意事项为大家做个说明。
) ~# ^; G( g$ q5 @
- e" Y" V) H2 z6 U, V8 ]$ H! _" s1 t% Y4.3   了解RTX5内核模板框架设计
7 m+ D, J" n: M- p0 l9 ?7 C7 B6 T移植RTX5前,我们优先了解下移植好的RTX5内核模板,方面大家后面移植:( g$ D; Z8 X% _; ~0 I: x  X
9 D0 B. O4 c9 J# Q
ebf7bed4831890980f518eaeb842a943.png
3 a3 v( O) @4 \1 Q+ S( P

5 C7 p9 _0 J+ I框图如下:
8 n' Y; a& N- t- E+ L6 V
& e" T* T. p# R9 o: P, N
cc3f4f5af7e41dcb23a03a25e14d8ae7.png

2 k: @7 w  w; x6 o* I: v7 Y1 E0 v
$ G0 B. P1 |8 J' y8 ?4.4   第1步,安装指定的MDK软件包版本
' l7 i- X$ f: u* e3 D6 ~9 Q移植新版RTX5需要大家下载当前最新的MDK软件包版本(如果有最新版,推荐大家用最新版):
  \" t& ^' o5 P% _& F! X4 U2 N1 I  v0 D( M) G8 y( a+ Z
  CMSIS 软件包使用当前最新的:V5.7.0/ `3 \$ [3 J; b
  STM32H7使用当前最新的:V2.6.0
, M4 \( y/ a  b# ?' M+ u  STM32F4使用当前最新的:V2.6.0
, B: C( g# u. O) F  W) o0 j" [8 h  STM32CubeMX使用当前最新的:V6.0.x# p5 x0 V5 W0 z
  ARM_Compiler使用当前最新的:V1.6.1' N7 V& j' R3 c2 @* @4 X

- M: `8 o( K+ O3 [. v* J4 s不管以后MDK的软件包版本如何升级,当前的软件包版本和以后的新版是可以同时安装的,也就是说可以安装多个不同版本,在这里可以选择指定版本:: x! k' }+ E2 }4 D( S) @8 d8 s

( D6 K! u3 I2 y: e1 h! `7 D
bbb84b8c4b3275b1026d2c95b5012294.png
1 u. P  [5 a2 K( }& _/ A* D

( x4 s3 F, O8 d& \4.5   第2步,准备一个工程模板
) R$ r" v0 y# p9 B& S; q) A1 {1 q首先准备好一个简单的裸机工程模板,已经为大家做好:V7-400_Base Template,准备好的工程模板如下图所示(大家也可以制作其它任意的工程模板,不限制):
( [0 J3 T! X  d, V2 `, R
0 ]$ Z9 {4 h4 r1 M8 Y% _
5618d5a487ef825c0a75ce19685c4821.png
; C' `1 L8 d' R8 D+ x- ?3 v
4 d! B0 Q& S9 E
4.6   第3步,添加RTX5并配置* y9 [. M# z  H1 C1 P
RTX5可以方便的通过MDK的RTE环境添加进来。对于H7版本,MDK会强制运行一次CubeMX,并添加很多H7的HAL库文件,这些库文件我们可以使用,也可以不使用。教程配套的工程文件是不使用这些,因为前面的工程模板里面已经添加了。所以要将这些文件全部隔离出来。2 g8 p: t% |: y9 z8 `0 I+ |
; @* _7 B! `' ~# X" }
4.6.1      添加RTX5源码
7 c4 F. g5 |6 ?8 p0 g" W6 W" m) z8 V0 w3 [6 R% p7 B5 n: r
48f11b91f9fc45f3f04431047156434d.png
1 t; B- m, m% Q" f) X6 Z

  |) U5 ?3 d8 f) X7 B* m点击OK按钮后,弹出如下界面:
( U  U8 @4 u& b
0 X( U, J6 X. S5 g, p
b430f5f7b2e1a16de73553adb9dd1f89.png

( L; v3 ?. S- E/ n0 V4 d! J0 t# a$ e/ t# K6 Q7 b
点击Start STM32CubeMX,这里需要大家电脑上已经安装了STM32CubeMX,并且为其安装了H7的软件包。4 C; b  a1 H0 B; D6 q9 G2 j1 N5 P
, d/ R1 S( s- T
af4f52889e56b18313faf6baa5ed1281.png
! v* Z) d( ]8 L; s: f

8 e7 B8 B. T0 Y打开后,用户仅需配置如下地方即可:
. w, {7 O$ z, G$ v7 c3 `- x1 |+ O8 o0 C2 y- z
7c8a9271ba3d0ccb045c81921fd97d0f.png

: }1 P9 a! c, V/ X( o  |4 W% S. m; A. l# \3 p
然后点击右上角的GENERATE CODE:
4 w0 x" [# e' l2 h8 ^
( q4 [4 q$ `4 Q! P' L" Q
62747d5251f02d427c05caf48fc46d77.png
# s' }9 C4 w  C- J6 D5 E! }

" n8 y4 R! P) n) m然后弹出如下对话框,点击Close即可,然后关闭STM32CubeMX。
" H. U  A* S! W
7 a4 V  u, V5 Q5 T
1a4404327c06b66c217f46c74bd48db2.png
' G: a5 w; d/ C

9 H$ c. i( q$ j重新回到MDK,会有一个对话框,点击是即可:
% {) a9 s! E! b1 T3 N
. z) J# l4 c& N$ u7 N( `) @0 B
cdfb3b29fdf8c8b60f0d85f8aaa161ff.png
& j  w3 t: @9 J/ x. u1 g8 a" C
( x5 q. o- S. C+ H9 [3 N4 v5 s
最后就可以看到RTX5源码已经添加到工程里面了:
! V) j4 r5 L% `: ?# t1 f6 ^9 E. Z4 j6 W1 k8 p6 V8 c* u
e49f340b4464ddd3afb5bf5082de0fdd.png
4 O- v2 w7 w& p: d$ G; J# N! D
' L" _/ f$ p6 X1 a' B3 D! L
4.6.2      将自动添加的库文件隔离出来
% `4 e" @8 I/ h' |添加的所有文件中,仅RTX5和文件stm32h7xx_hal_msp.c留下,其它文件全部隔离出来,隔离方法也比较简单,比如隔离生成的main.c函数,鼠标右击此文件选择Options for file ‘main.c’  H/ x6 H' l  q7 l, i+ v4 w
1 f" z/ m( t* l! j: Y: S# F
3b989ad148a2ec7c0522490cd84fcf3c.png
2 M6 X) Y6 G& u8 i) O

  U8 G; x' u0 `/ j" r/ r% C' U然后取消掉include Target Build前的对勾,点击OK:
3 ~8 Y( A, y! |, b% [; t4 t; ]4 {
2 ?" A! ]9 P4 L( Q# R4 x7 U4 j
6652eec0f1078d33b6c1508049d0c922.png

9 ]+ D# ]4 S4 ~  s4 w
) [- `3 u8 _% i+ m$ k* W  [看到main.c文件上有个红色横杠,就表示已经隔离出来了:  X: v# \( m! q4 @$ @! \
1 ]' {; m7 u+ f- Y& \# `, \2 M
cafbe4a03ab78632d36b9cf1b050250c.png

* y- ^- o8 @" \2 _2 w$ N1 y1 r* i. d# e# |5 [* O4 t' P: ~3 i, S
同样的方法,将stm32h7xx_it.c文件也隔离出来,文件stm32h7xx_it.h不用管。% A  Z. Z( ]( w7 x, B

9 c# u+ I" G6 d& K9 E9 z( w2 VDevice下面的这些文件也是同样的隔离方法:7 p/ d& s7 e" ]9 R: |
8 o! x3 D3 _6 `- S( \9 h; b5 P  X" t
f46dbe6e1b27dd459e04cba9849d9ff9.png
4 n3 j! i5 l& f
( V4 R2 P& x& ^& B$ p' N
只是鼠标右击弹出的界面有些不同:. ^6 l+ D- Z, [

- v9 T" O5 n6 D2 {, {: Y$ b8 @% u
aeccd1d366ee4da23ceff332ae2f84e5.png
. c) g. M  I; |& a8 x

2 a0 N! N1 Y7 {$ `8 }. v( ^; W注意stm32h7xx_hal_msp.c无需隔离,其它所有的文件全部隔离,stm32h7xx_hal_msp.c对应的隔离配置是STM32CubeMX,如果也隔离了,编译会有问题:
9 g  [8 D' D2 L( J3 N8 X- h
5 J4 ~- x2 [1 R' G' i! \" o
59f0e5e7d43f7ac7e983147c132a42ce.png
6 F6 X2 J( K8 @1 S' L; |/ ~0 s$ n! v
3 V) }' K" y. i7 y! F$ h* S9 ]9 F
隔离后的效果如下:
6 Q; f9 Z$ v" W
9 J" K- G7 Y0 ]. e, P
573fb2c99aa8ef7ef6f577c106084913.png
% x1 y4 ~: m1 K& {$ I1 Y; S

' U9 F1 s: o4 l* q8 K" G/ D4.6.3      RTX5配置9 Q' `. {4 N# X! X' l/ v# Z  p- F
剩下就是配置RTX5,设置RTX_Config.h文件即可,移植阶段先按照如下设置配置好,后面章节会专门为大家讲解每个参数的配置含义:
; r, T! S  R6 i* b' M* V% x- u& j  n: @% R
576cda809f95be40653ff18b9682f906.png
( I1 {) Q3 \. [. u) F  l
! c: h6 U- P. B  V+ q+ k& b
4.7   第4步,MPU和Cache配置文件bsp.c
- P3 u9 U9 s* o% x4 P+ `/ U# ^这个bsp.c文件也比较重要,移植阶段,直接将我们移植好的模板内容复制过去即可,这里把相关的内容为大家做个说明。
* ?9 ]5 o7 B3 K5 D/ H
" C3 z; n+ H7 B* e( }* ~4.7.1      函数System_Init
+ U$ y4 x- r; O3 ]  ^* w/ B% Z6 @
系统初始化,主要是MPU,Cache和系统时钟配置,需要在RTX5初始化之前调用。/ x: a& _+ s  D7 ?* l
" T$ v  A8 v& M& P( _
  1. /*) M1 X* z. _* Y6 `
  2. *********************************************************************************************************( b" {; S- S% l$ y! p
  3. *    函 数 名: System_Init
    3 }: H0 m- G% ~/ P+ d6 N" x* T
  4. *    功能说明: 系统初始化,主要是MPU,Cache和系统时钟配置9 |2 N/ c. e0 t( s
  5. *    形    参:无
    6 L: y3 A1 X8 a& s5 v
  6. *    返 回 值: 无6 I( H+ C& L# Y- B( W: c: c
  7. *********************************************************************************************************
    / l" S; J4 K1 f& B# _" o  _
  8. */
    ) Q* f, ^! @  K2 S! L0 L9 L
  9. void System_Init(void)( j) v  k, }4 h+ O3 e' w% N+ }
  10. {
    * X" y; t! e1 L5 z4 G
  11. 0 d& D2 {1 F* M" y' S
  12.     /* 配置MPU */# z# K* s; g4 n" l2 p
  13.     MPU_Config();9 M2 f5 P9 W' N8 A) N
  14. 1 X, W) v" }# H; x  k8 h
  15.     /* 使能L1 Cache */9 L; `# s% I. @% F5 w# _6 U5 Y
  16.     CPU_CACHE_Enable();
    / B9 R. y, Z' V! u3 T1 }6 L4 N. i
  17. 4 h) l" |- h3 m. U7 D
  18.     /* 7 b* j' G% [& m2 Q8 q& _9 l
  19.        STM32H7xx HAL 库初始化,此时系统用的还是H7自带的64MHz,HSI时钟:
    ! g, u  @" I% u9 G) ?. k
  20.        - 调用函数HAL_InitTick,初始化滴答时钟中断1ms。
    ( \% {) N1 }5 N1 K6 r+ o( ~
  21.        - 设置NVIV优先级分组为4。2 b- Z4 S, N7 r' }+ K
  22.      */
    3 `! f8 H! G! m) E; i$ N9 s
  23.     HAL_Init();6 H0 {. K' P. t& r
  24. 4 u" L- B2 X# i0 S) z5 t( R
  25.     /* % ^; p" r7 A6 g3 z+ a. V2 ~
  26.        配置系统时钟到400MHz
    ( v7 l8 {1 i9 ], f* H
  27.        - 切换使用HSE。: u6 V/ z: y" J( U' _) N, S
  28.        - 此函数会更新全局变量SystemCoreClock,并重新配置HAL_InitTick。
      T" B% F( Y( W+ Y
  29.     */- Y& A' s" A* v" K* j
  30.     SystemClock_Config();4 V$ B! a5 X) }8 d

  31. , @: j% d+ f4 ]+ J2 |1 p, H5 I
  32.     /*
    . p; i' z/ v( t0 T5 A8 E
  33.        Event Recorder:, H. Q/ P. V  O3 j6 N
  34.        - 可用于代码执行时间测量,MDK5.25及其以上版本才支持,IAR不支持。
    ) s8 P: k  ]# B& t+ l3 v
  35.        - 默认不开启,如果要使能此选项,务必看V7开发板用户手册第8章
    & L8 o2 S. s0 h/ Q1 M
  36.     */   
    ) a, p6 Y% ]2 s) I
  37. #if Enable_EventRecorder == 1  
      O9 A2 M4 D; J% L
  38.     /* 初始化EventRecorder并开启 */
    : |7 C. Q8 ~$ F; n3 c# J- T
  39.     EventRecorderInitialize(EventRecordAll, 1U);
    : K% T0 _/ K; d% q9 Y: ^1 r8 b* M
  40.     EventRecorderStart();! ?" J6 J( Z1 o
  41. #endif
    * e1 g1 A$ a; A9 T, }" I

  42. . g7 m, [" c4 J+ \
  43. }
复制代码
, z+ m) F( U5 ?5 {. c
4.7.2      函数bsp_Init% }: e0 d, X$ J
硬件外设的初始化,这个函数在RTX5的启动任务里面调用。
2 q0 M8 @8 B* X! k* i6 Q' h0 w4 O9 g' Q* D5 I; b
  1. /*
    3 N% ?! c$ {" P& H8 l# @$ R4 H
  2. *********************************************************************************************************- r+ K; D& S7 N
  3. *    函 数 名: bsp_Init  ?0 e! J$ i4 l* o4 G* [" z
  4. *    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
    % e- f% M; i8 Z4 @$ S9 c
  5. *    形    参: 无
    * y" E# h* L; P/ |& m% V
  6. *    返 回 值: 无. e7 o9 N/ i) w
  7. *********************************************************************************************************2 M9 f: M- z3 v! v1 |4 l8 ?1 j3 }
  8. */
    - H$ S: {1 E' \$ I
  9. void bsp_Init(void)
    8 o# a5 w# Q0 s6 f+ U
  10. {
    ' ^2 f7 c! g$ X  |. I
  11.     bsp_InitDWT();     /* 初始化DWT时钟周期计数器 */      
    * M& r# I  K  Q' w. L
  12.     bsp_InitKey();        /* 按键初始化,要放在滴答定时器之前,因为按钮检测是通过滴答定时器扫描 */2 ^' V  h, w8 W  r+ @0 |
  13.     bsp_InitUart();    /* 初始化串口 */! M8 P7 Z4 m+ @% m  e; R' r4 W2 L1 R
  14.     bsp_InitExtIO();    /* 初始化FMC总线74HC574扩展IO. 必须在 bsp_InitLed()前执行 */    & N: D5 \7 m0 y0 ^' @" u
  15.     bsp_InitLed();        /* 初始化LED */   
    6 r. a$ @- A, b- ?4 |0 F) {1 V
  16.     bsp_InitTimer();      /* 初始化滴答定时器 */1 c8 M% j# m- H( V
  17. }
复制代码

& u8 H9 Y9 y! X4.7.3      函数SystemClock_Config+ a! p4 A0 J! M) z  a
这个函数主要是完成系统时钟配置。5 a) o2 n9 J" ?7 B* q0 j0 W& b
8 X: B/ T0 E1 Y: v* x/ D- k
  1. /*: j% }$ \" \% ]+ i0 Q$ w
  2. *********************************************************************************************************5 q: h1 [! C5 O+ ^0 Y2 G, Z1 Z8 ?
  3. *    函 数 名: SystemClock_Config
    9 e7 n9 W9 b- z7 `$ r5 E# J
  4. *    功能说明: 初始化系统时钟! L; i( ]5 S8 t6 b
  5. *                System Clock source            = PLL (HSE)
    & M0 s% ^0 [5 N: r3 d9 [& w3 n
  6. *                SYSCLK(Hz)                     = 400000000 (CPU Clock)) }9 t& y6 `+ v, n* s" g
  7. *               HCLK(Hz)                       = 200000000 (AXI and AHBs Clock)
    8 F' M& G7 y% j/ r3 @- K. u, H
  8. *                AHB Prescaler                  = 2; p: S; M  R# y$ s3 u
  9. *                D1 APB3 Prescaler              = 2 (APB3 Clock  100MHz)
    ' q8 @: Y' v: h4 ~+ D& `
  10. *                D2 APB1 Prescaler              = 2 (APB1 Clock  100MHz): _7 i/ E# K+ s4 V: I
  11. *                D2 APB2 Prescaler              = 2 (APB2 Clock  100MHz)
    ! {0 A. t5 V# P* c# m% s
  12. *                D3 APB4 Prescaler              = 2 (APB4 Clock  100MHz)
    ! V3 p4 k# C" [8 _3 E6 g
  13. *                HSE Frequency(Hz)              = 25000000
    4 R& h. @' w$ x( V
  14. *               PLL_M                          = 5
    2 R3 o; [5 O0 g" I1 H3 ~/ q; B3 w
  15. *                PLL_N                          = 160
    # R$ X7 U' F1 M. `5 h8 Z6 Y
  16. *                PLL_P                          = 2/ d$ U2 k* C) i" R, K7 Y# y
  17. *                PLL_Q                          = 4
    ) e; b  S4 _2 R/ v* x  o% n
  18. *                PLL_R                          = 2
    5 W5 f" y' t5 {' X/ f
  19. *                VDD(V)                         = 3.3
    / E. N7 i3 B6 m3 k2 z& N; r  S
  20. *                Flash Latency(WS)              = 41 Y$ O1 ]5 a; S3 S6 ~! v
  21. *    形    参: 无6 S+ G& z& K9 d5 O$ ]8 {8 A
  22. *    返 回 值: 无+ G& F' d( R+ A0 f; Z
  23. *********************************************************************************************************$ c' k( x: ]( s8 X* X
  24. */5 L) i+ K; I5 i& F$ C1 n
  25. static void SystemClock_Config(void)8 t* t0 A1 N* V! K, h" `9 G# {4 w% J
  26. {0 A& ]; E: o" q) C% d- z
  27.    省略未写/ t& }& w# {1 f) l# n& A  t; F

  28. 5 ~% U2 ~4 H  T' E! ]4 V/ N' l, U( H) E5 n
  29.    /* AXI SRAM的时钟是上电自动使能的,而D2域的SRAM1,SRAM2和SRAM3要单独使能 */    . R4 [( a0 i5 T7 e% f1 B" T7 {
  30. #if 19 y2 p" w; ~5 n/ s, S& v* o1 t
  31.     __HAL_RCC_D2SRAM1_CLK_ENABLE();
    : p& T9 ^' c8 L( F; D3 w
  32.     __HAL_RCC_D2SRAM2_CLK_ENABLE();& G( h5 ~! S# d  _1 a7 O7 ?
  33.     __HAL_RCC_D2SRAM3_CLK_ENABLE();
    , l4 \% s5 i  n1 X1 F

  34. 2 [$ F" Z( Z* N* o; n
  35.     __HAL_RCC_BKPRAM_CLKAM_ENABLE();      
    , Z! P* k9 [' s' Z
  36.     __HAL_RCC_D3SRAM1_CLKAM_ENABLE();
    8 A, a% g# G) A) I
  37. #endif% V. W& i' Q8 ]" l4 v2 }
  38. }
复制代码
1 {7 y# ^4 O: S1 P
这里的RAM时钟初始化比较重要,这几个RAM的时钟都要单独使能。$ b' \4 B/ P0 i: X% K) p& P2 P8 O* h

0 i3 R: C$ B- N/ J+ E4.7.4      函数MPU_Config; t6 N  ?0 y$ r3 m6 X- A+ A/ G" t5 U8 I
RTX5例子默认采用AXI SRAM作为主RAM空间,因为空间比较大,方便我们后制作综合例子使用:( ]+ x  W1 `5 \1 Y( S

9 w+ k. E5 E8 K
  1. /*
    $ B2 x4 [+ l+ u. {4 N* P- B) `' L
  2. *********************************************************************************************************; q' d( j* w6 d! d
  3. *    函 数 名: MPU_Config5 K% ]$ f2 T( a* h2 r# m; S) P. @
  4. *    功能说明: 配置MPU" Y1 `% O# n5 y3 |
  5. *    形    参: 无0 k3 q- {; s0 y
  6. *    返 回 值: 无$ r5 v! Q- V6 Y( e' o' g/ S
  7. *********************************************************************************************************4 H0 E+ J, v& e& g7 e6 `
  8. */% p) n- q( R3 T( k4 S% Y4 [; W
  9. static void MPU_Config( void )" [3 X) d2 f- g; S2 e2 f  N
  10. {
    7 Y) i$ T: M* D& }
  11.     MPU_Region_InitTypeDef MPU_InitStruct;0 w& Y' m1 ~$ }/ j: }

  12. : o* u' x% B. p0 ?
  13.     /* 禁止 MPU */! t9 X+ ^7 U1 p2 F4 v3 M" j
  14.     HAL_MPU_Disable();
    5 G% Q3 }7 D/ t9 G7 J8 R9 c
  15. + I5 S( \, K8 W4 S/ y1 K% x
  16. /* 最高性能,读Cache和写Cache都开启 */   
    ! F3 C# [! Z: v) s+ z5 u6 \0 W
  17. #if 16 c* a, B8 S" c( N
  18.        /* 配置AXI SRAM的MPU属性为Write back, Read allocate,Write allocate */$ u: a# U- Y' k
  19.     MPU_InitStruct.Enable           = MPU_REGION_ENABLE;0 ?& O( [' {" ]- s+ v- Z
  20.     MPU_InitStruct.BaseAddress      = 0x24000000;' S$ S; i3 }! ]7 S) ?3 H4 S. R
  21.     MPU_InitStruct.Size             = MPU_REGION_SIZE_512KB;
      C, e2 E+ `5 H* ?$ }
  22.     MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;: L% y0 P) H" A
  23.     MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;
    % Y8 F5 w  j" `- M. i$ Z/ ^) u: n
  24.     MPU_InitStruct.IsCacheable      = MPU_ACCESS_CACHEABLE;4 f  U3 @9 }" o2 Z2 r- V
  25.     MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;7 f. Y( z% Z5 b4 n$ p
  26.     MPU_InitStruct.Number           = MPU_REGION_NUMBER0;
    5 I5 I# f! \4 O4 v: b
  27.     MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL1;
    $ k  ~# V9 a0 l" k. b1 n2 N+ z
  28.     MPU_InitStruct.SubRegionDisable = 0x00;! _& [, ]4 E' c* c, Q; v" d, z+ J& ~- L
  29.     MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;
    7 ~# n8 S; M- u/ v6 z
  30. : o& {! j$ G9 a$ [1 a
  31.     HAL_MPU_ConfigRegion(&MPU_InitStruct);
    ) g6 I# j. }# b7 w& q- R
  32. 4 F% Y$ N  Q* y8 E& h
  33. /* 最低性能,读Cache和写Cache都关闭 */
    " ~5 D2 q: \1 r
  34. #else0 b6 t: F& e' }( r% \
  35.     /* 配置AXI SRAM的MPU属性为NORMAL, NO Read allocate,NO Write allocate */3 t2 N( }0 T& T* d
  36.     MPU_InitStruct.Enable           = MPU_REGION_ENABLE;( F$ d, T6 V' i% j  F. b
  37.     MPU_InitStruct.BaseAddress      = 0x24000000;
    + E% O3 E$ V+ j, a3 b5 O2 n; M
  38.     MPU_InitStruct.Size             = MPU_REGION_SIZE_512KB;! d* U; g( ?! P) r  z$ n' D
  39.     MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
    & |' |9 c: ~# Q# P. J
  40.     MPU_InitStruct.IsBufferable     = MPU_ACCESS_NOT_BUFFERABLE;: v! F% d4 P& V" C
  41.     MPU_InitStruct.IsCacheable      = MPU_ACCESS_NOT_CACHEABLE;
    ' p+ u9 S6 u7 W3 {0 Z" \
  42.     MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
    $ n% U' [: e1 @! E$ Y" E. e9 A. i
  43.     MPU_InitStruct.Number           = MPU_REGION_NUMBER0;
    ; l' V" L5 N- Z* q- ^4 M2 y
  44.     MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL1;
    1 ~) G+ h* h: }1 R3 c4 j. P8 N
  45.     MPU_InitStruct.SubRegionDisable = 0x00;
    ( e1 E  S; @# p( J1 Q6 A
  46.     MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;
    . b9 m7 i2 N; Y: e$ H. V1 U+ J
  47. : F' v: t, W' d) T4 `" l5 b. b4 L
  48.     HAL_MPU_ConfigRegion(&MPU_InitStruct);; e( d- J; ^' |, Z1 ^
  49. #endif
    ; _2 Z# O& H& R  \+ k* ]( |
  50. ( U, o+ M; `$ y; f7 i/ J, x+ W
  51.     /* 配置FMC扩展IO的MPU属性为Device或者Strongly Ordered */) x% w1 P9 j) ~" R9 C$ j
  52.     MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
    0 v2 ]; ~8 B7 I, ]$ B2 _+ `
  53.     MPU_InitStruct.BaseAddress      = 0x60000000;  I4 j# k! @4 d* H+ x, Y
  54.     MPU_InitStruct.Size             = ARM_MPU_REGION_SIZE_64KB;    $ f* s( o' w/ Y% R$ H3 R( E( F
  55.     MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;( A( o9 `  G) m, Z
  56.     MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;
    9 }  s; j, P- U# b1 |8 \" `" n
  57.     MPU_InitStruct.IsCacheable      = MPU_ACCESS_NOT_CACHEABLE;   
    0 Q' a  R' F8 M8 y/ B9 d/ o/ R7 }8 ^; z5 ]
  58.     MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;% i; [& z  A' i; y. h5 ?3 P- I3 T
  59.     MPU_InitStruct.Number           = MPU_REGION_NUMBER1;
    % o0 d4 f& y3 V& [( w
  60.     MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL0;
    " F) m! h! B( Y) S, N
  61.     MPU_InitStruct.SubRegionDisable = 0x00;
    + B- S  \/ U3 Z8 O* l( ~
  62.     MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;
    ! `# c6 S) O8 M
  63. ' ~6 ^' R$ E5 n+ E& {. ?
  64.     HAL_MPU_ConfigRegion(&MPU_InitStruct);0 j/ Q) S8 L% k6 S
  65. * D5 A1 l  \- }* j) s( G- r. B
  66.     /* 使能 MPU */( T; |$ [, N; J' m' ?
  67.     HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
    7 `4 p8 U1 e9 q/ B8 r3 C
  68. }
复制代码
1 J  `; i$ E" z3 `2 \
4.7.5      函数bsp_RunPer10ms
# f9 R1 i5 s, Q# Z" R这个函数里面默认有个按键扫描,如果大家移植的程序里面没有按键初始化,务必要把这个按键扫描函数注释掉。
8 }+ T4 E" P& J+ p+ Q* U8 q" o: M
' G, z3 r9 z0 v# B1 S9 P4 n
  1. /*
    & V  S+ y! f5 w
  2. *********************************************************************************************************
    ' [1 F5 m, U+ P, R
  3. *    函 数 名: bsp_RunPer10ms' @9 M. G* ~0 ?0 p. X5 ?5 g
  4. *    功能说明: 该函数每隔10ms被Systick中断调用1次。详见 bsp_timer.c的定时中断服务程序。一些处理时间要求
    8 M6 r+ J7 Y- d4 x# e( v: k
  5. *             不严格的任务可以放在此函数。比如:按键扫描、蜂鸣器鸣叫控制等。' z1 l9 C0 I" ?
  6. *    形    参: 无6 {3 S. t# T. J1 m  m
  7. *    返 回 值: 无  o# e) N6 y, y; G0 H# K
  8. *********************************************************************************************************
    $ O  r" D# I+ N* h3 p1 z8 Z, B
  9. */
    + Z( U  @* ~! D2 X# V" k- c  ?
  10. void bsp_RunPer10ms(void)4 @+ m0 p0 O/ n" \! F
  11. {( t8 E) Q$ j- n$ J6 H5 G: g
  12.     bsp_KeyScan10ms();
    1 S+ E2 O; s3 i
  13. }
复制代码
& T7 M0 E# D* A* c5 g4 W$ H; a$ W
4.8   第5步,更新bsp_timer.c和bsp.h文件3 `9 S3 U0 g% d  e
更新bsp_timer.c文件是因为此文件跟RTX5都要使用滴答定时器,有冲突。所以大家直接将我们工程模板里面此文件覆盖移植的这个文件即可。
! e" |+ J6 B: Y4 ]: V! {0 [* U9 a3 {( E2 e
bsp.h文件里面要添加一个宏定义,因为bsp_timer.c文件里面做了些条件编译:) x$ |6 `0 `! H: d1 A! M+ m
( m- Y' ^% [0 A! \) Y( f
#define  USE_RTX    1. f, c4 w" I& ~2 _* ^
& ~( j1 }* F, @8 E% ?2 p
另外,bsp.h文件将大部分头文件都添加进来了,大家可以根据需要,用到那些头文件,使能那些,用不到的,可以注释掉。当然,不注释也是没问题的:
/ X. h- F% O! K  e. P6 a$ B6 R2 W" Q
  1. /* 通过取消注释或者添加注释的方式控制是否包含底层驱动模块 */
    * V6 D2 n. J; t0 T7 O- k
  2. //#include "bsp_msg.h"+ D- Z- {6 g# b0 S- F1 t
  3. //#include "bsp_user_lib.h"
    * K- P% u5 F! l2 ]- J. s+ J5 q9 U
  4. #include "bsp_timer.h"+ e% z+ r$ v" l9 j0 {3 C
  5. #include "bsp_led.h"
    ! s4 a0 e5 L5 Q% u3 j! }$ U
  6. #include "bsp_key.h"$ J8 U/ q% U3 r3 {" O
  7. #include "bsp_dwt.h"9 A9 X# J4 ?4 |

  8. ; s) K" D! n, S  |- x/ Y5 c4 l, G
  9. //#include "bsp_cpu_rtc.h"
    - z# ~% t; }9 ~4 i) R% V
  10. //#include "bsp_cpu_adc.h"
    # x0 S, w4 i; C. O
  11. //#include "bsp_cpu_dac.h"
    9 f. W- I8 s8 J
  12. #include "bsp_uart_fifo.h"! p# J0 l! ]  X) m/ q
  13. //#include "bsp_uart_gps.h"3 M( }; O/ L  T; E  d
  14. //#include "bsp_uart_esp8266.h"
    & x) O$ B) f1 p0 ?2 K
  15. //#include "bsp_uart_sim800.h"
    5 I1 z; P8 ?/ W4 I5 [
  16. " F% {! k0 [( {4 a* Z8 ?9 ^
  17. //#include "bsp_spi_bus.h"+ A/ r( a* b2 V" g* ]) D7 j
  18. //#include "bsp_spi_ad9833.h": h# z4 o, e' ]2 K0 ]9 x% q2 v
  19. //#include "bsp_spi_ads1256.h"
    0 [" E" t; ?1 S! T6 h
  20. //#include "bsp_spi_dac8501.h"
    6 U$ w; H/ o3 J
  21. //#include "bsp_spi_dac8562.h"
      q/ ~8 C% `" }  b
  22. //#include "bsp_spi_flash.h"
      v, N2 L2 E7 ]3 ?4 y
  23. //#include "bsp_spi_tm7705.h"4 [) q* u* A7 w4 r, G
  24. //#include "bsp_spi_vs1053b.h"
    2 }4 U5 G2 ]( n: `8 H4 S  N

  25. / |7 `5 |' L0 s3 t7 ^9 a8 `( I: Q2 O
  26. //#include "bsp_fmc_sdram.h", c$ J4 b* l' v, C% f
  27. //#include "bsp_fmc_nand_flash.h"; s# d+ E0 a$ I. i, u7 Y. Y9 m
  28. //#include "bsp_fmc_ad7606.h"+ j: Z* w# \! V+ I4 b3 p: x
  29. //#include "bsp_fmc_oled.h"
    " V  S0 V" F# V9 d; X: k  ]
  30. #include "bsp_fmc_io.h"
    . N/ P; M6 m( W- X) I; u) ?: i4 c
  31. 9 M  h4 [1 ~% B0 X
  32. //#include "bsp_i2c_gpio.h"2 u8 q7 [. l6 @8 f4 k+ [
  33. //#include "bsp_i2c_bh1750.h"
    3 s' [5 h$ M& \/ J. n" G& W' S
  34. //#include "bsp_i2c_bmp085.h"
    3 o, Q; \. X$ T  x. z
  35. //#include "bsp_i2c_eeprom_24xx.h"2 p* g- M+ q/ L% X( p) \( |
  36. //#include "bsp_i2c_hmc5883l.h"
    - Q  p: P4 ]4 B
  37. //#include "bsp_i2c_mpu6050.h"* x# I! M2 G' e( M9 o0 w. O1 s+ U
  38. //#include "bsp_i2c_si4730.h"- o; E/ r+ g# O9 s
  39. //#include "bsp_i2c_wm8978.h"% N6 Q4 m8 U" A

  40. % k& M- G) ~2 @3 k  I* i
  41. //#include "bsp_tft_h7.h"
    + y& M( A, g* V, k% \
  42. //#include "bsp_tft_429.h"4 C, b2 Z7 n" e6 f) x7 {
  43. //#include "bsp_tft_lcd.h"* w& M4 ?6 G9 D" a: }7 _) v5 n7 N
  44. //#include "bsp_ts_touch.h". v  M3 B9 c* T; c# B
  45. //#include "bsp_ts_ft5x06.h"
    ; D5 z3 ^" p8 ?- M( E: H
  46. //#include "bsp_ts_gt811.h"
    ; S& S; j" z9 ~
  47. //#include "bsp_ts_gt911.h"" y+ N8 C9 I2 x" i# c9 J
  48. //#include "bsp_ts_stmpe811.h"
    # j6 x: Y! c4 d2 w  {6 t( F
  49. + c9 {6 |& ]6 ~% @- _
  50. #include "bsp_beep.h"! e( B8 T+ \* J; ~
  51. #include "bsp_tim_pwm.h"+ W' Q7 ^7 Q  e7 y; \* U
  52. //#include "bsp_sdio_sd.h"4 I) L" N; A: Z2 e2 Q7 f
  53. //#include "bsp_dht11.h"
    , |, n' k# W" s$ |
  54. //#include "bsp_ds18b20.h"  a: @% Y( b' ]5 t
  55. //#include "bsp_ps2.h"
    ! g7 D& k4 k! V! l4 W! g3 T
  56. //#include "bsp_ir_decode.h"
    , `. ^: i; a( m1 A+ @+ ~1 N0 v
  57. //#include "bsp_camera.h"
    / A( {/ _6 K6 a
  58. //#include "bsp_rs485_led.h"4 c! I0 Z5 L" C0 o+ l
  59. //#include "bsp_can.h"
复制代码

5 Y8 D  Q: o" e8 \  L) x4.9   第6步,修改文件stm32h7xx_it.c/ J: i* f) O% Q* V
删除此文件里面带的如下函数,RTX5要使用,冲突了。5 L& l- P7 v3 H2 N, g: u
6 G0 ?. F1 }  W! P
  1. /**
    + F0 b& k5 z: ~+ v) V
  2.   * @brief  This function handles SVCall exception.
    1 B, K1 c$ U  S% r9 q, R1 v
  3.   * @param  None7 B3 \8 |! B3 H6 Y2 Y
  4.   * @retval None
    / @( U8 w+ V& h1 \2 Y
  5.   */2 x  u  a7 _& g
  6. void SVC_Handler(void)$ \% i- L' y* @6 \
  7. {
    9 o8 y9 s& u1 r3 V! v1 I
  8. }
    , Y4 T/ v6 T  ^) l( \, B' \

  9. 5 W1 d3 O1 n( u( T: C+ L% I
  10. /**1 m* _$ Y2 n  T1 U" z, `- \& e( z
  11.   * @brief  This function handles PendSVC exception.
    / M3 T0 Z" a, y. t# E! W6 X- h9 J4 b
  12.   * @param  None
      f& E9 e7 y  j& V0 |; r* k
  13.   * @retval None; ?; T& U$ x3 R+ W" \  e2 v
  14.   */0 g: R% t6 a% Y" V0 X) k. l4 \
  15. void PendSV_Handler(void)8 W; Q# b. d) F* N
  16. {8 Q1 Z* ^$ z' f$ j' }
  17. }
复制代码
: m$ C) [2 {$ I+ T5 x- v2 d7 p
4.10 第7步,添加头文件的汇总文件includes.h, V  {3 I4 a: @& K( S) e, w7 i1 {
在User文件夹下添加文件incudes.h,直接从本章节教程配套例子的User文件夹复制即可。此文件主要用于RTX5的各种头文件汇总。) r; f3 J$ }3 `) ?- r7 C
0 t1 P$ g: ]) M* c
63fafbc927e6b911f6f3b81c4acb6af1.png
" C7 U2 |- Y: H. F0 f
* z/ t$ G. B4 N7 P+ x6 T0 Q! G* L* x
4.11 第8步,HAL库时间基准stm32h7xx_hal_timebase_tim.c

- t* |6 J, O4 l. s% M. ?由于RTX5和HAL库需要一个时间基准,而且默认都是用的滴答定时器,所有要有一个选用其它的时间基准。当前的处理方案是为HAL库提供一个时间基准文件stm32h7xx_hal_timbase_tim.c。此文件
- c* T6 L/ O, I3 T0 p) ~' d2 O4 N  ]2 F& n& K- L: W8 X: Y
里面做了两套方案,一个是使用TIM7做时间基准,另一个是使用RTX5的API做时间基准,通过条件编译做选择。默认是采用RTX5的API做时间基准。9 Q- Z9 A7 ~5 k8 o
/ V) R( D5 R- A, E% t4 x. \
  1. /*
    ( a( x- c, ^, K  f  }
  2. *********************************************************************************************************
    # F4 _( N' q* D& Z
  3. *    函 数 名: HAL_Delay
    4 J. n% _: {6 e
  4. *    功能说明: 重定向毫秒延迟函数。替换HAL中的函数。因为HAL中的缺省函数依赖于Systick中断,如果在USB、SD  H+ Q0 H! b6 w9 h- l: y
  5. *             卡中断中有延迟函数,则会锁死。也可以通过函数HAL_NVIC_SetPriority提升Systick中断8 s/ v6 s9 \! J; p4 ~
  6. *    形    参: 无
    $ I, R. T! a4 T
  7. *    返 回 值: 无) A1 ^7 Z% n3 L) E0 {3 U
  8. *********************************************************************************************************2 n9 W7 q; [, u+ @* _8 D! x
  9. */" ~/ V- i( p9 O7 v" p' n7 R
  10. void HAL_Delay(uint32_t Delay)
    . C* {+ b+ c! N- ?7 H! x8 x' W" Y& q9 H
  11. {
    6 l" ]) \* J7 g; c+ f6 ~% I( {. U: z
  12.     bsp_DelayMS(Delay);5 X+ S8 N% u" g$ m1 H3 H0 c
  13. }$ D( K/ d( C+ `+ f3 J; O0 Q
  14. : N, e; y) ^" Z5 U8 B$ O
  15. HAL_StatusTypeDef HAL_InitTick (uint32_t TickPriority)
    + L- I$ D" E( \: n$ i- J
  16. {# n& `* \% x4 A9 Q8 s& ]8 ^5 R
  17.     return HAL_OK;
    1 z* }3 n+ s5 A# H! A4 r3 j: G- n6 k
  18. }, y, [' i; s# P

  19. 8 ~/ D/ O  g9 W
  20. uint32_t HAL_GetTick (void) - A, W: I  w. P9 Y9 J5 T
  21. {
    6 @9 _+ u9 c! [6 E3 J/ g. k5 m
  22.     static uint32_t ticks = 0U;5 S1 Q, W% m4 h; x  U% a
  23.     uint32_t i;
    5 m' K, S# k; x5 o6 L) s
  24. , Y) P. `0 R- |# s' e
  25.     if (osKernelGetState () == osKernelRunning)% @* @$ z2 L7 {# g# `7 S' s
  26.     {% `% N; T0 B4 }- G1 d/ W& n. l
  27.         return ((uint32_t)osKernelGetTickCount ());
    % @0 n8 a$ q  P. w2 q/ _2 M+ D
  28.     }, e' E1 y/ o4 C, ^. E2 F% d; D
  29. ; o: p1 m. O7 a( x' W" i: J
  30.     /* 如果RTX5还没有运行,采用下面方式 */4 I9 g5 l, k# B5 A# Q/ H
  31.     for (i = (SystemCoreClock >> 14U); i > 0U; i--) . X, R  e+ F# s' F5 h
  32.     {* \% x' t2 c3 Q6 v1 q
  33.         __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP();- X* F" O4 e$ k* ^' m
  34.         __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP();
    : M( U0 S8 b$ m- m
  35.     }
    , o# v8 i0 L5 r9 j+ @4 E
  36. 2 o9 o3 O( D8 t
  37.     return ++ticks;
    2 j5 Z9 d; y* @  K
  38. }
复制代码
% {- Y4 G, \) X
4.12 第9步,添加BSP驱动文件bsp_dwt.c
+ a3 T5 @4 b0 q" ]
添加bsp_dwt.c文件和bsp_dwt.h文件主要是因为第8步中的stm32h7xx_hal_timebase_tim.c文件里面的函数bsp_DelayMS要使用,此函数是基于DWT系统时钟周期计数器实现。' `  V1 T' c1 j" r; `, D

5 V2 G) a7 j& A* A6 Y, ?6 T- }+ V8 D
f0d85f2002a553fa31c8f67b30e2db76.png
& f8 h1 z7 x4 c
1 E- m* E4 r$ Z# C. H9 `' W$ Y
4.13 第10步,创建应用任务(重要,注意启动任务)

; z2 s2 K' }$ f1 Z: ^应用程序比较简单,大家可以直接复制本章教程配置例子的main.c文件中的内容到自己工程里面测试。主要创建了如下几个任务:; t. W/ L% @- X- b1 T2 E
9 |% Z* z- H; D$ ?
AppTaskUserIF任务   : 按键消息处理。( q9 u( F/ V# Y5 R2 J

4 r' Q; |; Q; a: NAppTaskLED任务      : LED闪烁。
1 m4 b& L7 L6 L9 C1 ^. q2 O: c% p# M& M7 w9 X
AppTaskMsgPro任务   : 消息处理,暂未使用。* {% i' i) V$ e; ?+ Q! f

+ P% a1 s8 @& _6 ]AppTaskStart任务    : 启动任务,也是最高优先级任务,这里实现按键扫描。
0 H, e5 D4 D% N8 @3 n2 z/ f& q( O& J& w0 I# v' ^' A
osRtxTimerThread任务: 定时器任务,暂未使用。
( u  P+ b' X# k+ k/ a: q) P
* ?/ R# ]3 ^, m) z$ \任务栈大小和任务控制块定义如下:8 V/ g, U* Z$ @( ?
, P( ]3 F% J" P' U) Y
  1. /*: e' o6 b* Q; o7 b. O3 ^" K, H
  2. **********************************************************************************************************( }) ~6 r  {% X4 a8 \7 a
  3.                                              变量
    " `, E5 Q1 ]7 ?, X! H
  4. **********************************************************************************************************
    ! W( r7 t( v, K- `) y
  5. */, I4 o0 o4 S( [1 M  g
  6. /* 任务的属性设置 */
    0 u3 t% N9 O( a3 H" h& _+ T7 ]  x
  7. const osThreadAttr_t ThreadStart_Attr = 5 o7 G6 _7 Q6 {
  8. {$ m# C  e( i& Q& J* M
  9.     /* 未使用 */
    7 u) S; ^8 i# j
  10. //    .cb_mem = &worker_thread_tcb_1,; k2 C+ }# p' E! {! }) `
  11. //    .cb_size = sizeof(worker_thread_tcb_1),
    % [1 b  z& }9 E9 a. K! q
  12. //    .stack_mem = &worker_thread_stk_1[0],
    1 x  U+ X% P8 c
  13. //    .stack_size = sizeof(worker_thread_stk_1),3 y$ q$ o9 W, X+ Q& R2 R' L
  14. //    .priority = osPriorityAboveNormal,
    % H  l" H. s3 u3 N( T. m! E9 n
  15. //    .tz_module = 07 S9 e8 J7 |% v% p# O* R' g

  16. 7 `0 t3 ~' i5 N9 Q  x
  17.     .name = "osRtxStartThread",% p" [' i4 ]8 d! V3 i& X
  18.     .attr_bits = osThreadDetached,
    . A" ]$ \, ~* X- C* f+ C2 U; F9 B
  19.     .priority = osPriorityHigh4,
    : _  N$ E7 M* a
  20.     .stack_size = 2048,3 ]* Z/ d. \5 v4 r$ Y
  21. };7 R) v/ }1 X2 f# p: `

  22. 2 x, V! ]/ O/ ]0 O# i
  23. const osThreadAttr_t ThreadMsgPro_Attr = 4 j" g6 v$ Z" {7 k6 P+ a  t5 P
  24. {6 R6 m+ f, {2 R5 l
  25.     .name = "osRtxMsgProThread",- \* @3 [9 v# m/ e" U( j
  26.     .attr_bits = osThreadDetached,
    % A' ?( |( |+ m& o! I4 V; k+ h
  27.     .priority = osPriorityHigh3,: x: W' J2 }/ u4 V6 K- f
  28.     .stack_size = 1024,
    1 V  y/ c& ~7 O$ b5 Z" ?# b7 D
  29. };
    ) _, I2 K$ t6 g" o
  30. - a2 j4 B* a0 n# }8 Q& P4 k
  31. const osThreadAttr_t ThreadLED_Attr =
    9 W4 H) A. y; A  y5 F4 r' z
  32. {1 N5 v/ ?# U% e4 r! p8 G
  33.     .name = "osRtxLEDThread",
    1 d* a4 l( r4 b1 e
  34.     .attr_bits = osThreadDetached,
    ! B0 M) f$ `* W2 r! L
  35.     .priority = osPriorityHigh2,
    9 I. g+ p8 ]6 y) J9 L: y' u! n
  36.     .stack_size = 512,
    # z- \6 V  `' L8 b  x
  37. };/ f0 a! L5 \7 J1 R
  38. 5 P: h' ]" o7 B& }9 I: G, e/ a2 v
  39. const osThreadAttr_t ThreadUserIF_Attr = : c! ^8 }, C* x- s# _
  40. {7 \" i0 T" A4 G2 E
  41.     .name = "osRtxThreadUserIF",* I1 m( U# }( F6 H
  42.     .attr_bits = osThreadDetached,
    . i* w' \  d: G  C) n
  43.     .priority = osPriorityHigh1,
    & k: V: J+ z1 X* }0 t: a' _. ]/ x
  44.     .stack_size = 1024,
    % [0 w4 U: V! ?$ Y* X
  45. };
复制代码
' @$ j/ V2 W) F) t, X/ b
任务创建:* X5 m& a/ N5 d3 ~( v
5 P) ~( P- x* v0 i! I
  1. /*8 F+ y' @4 x2 K0 O  F8 ~
  2. *********************************************************************************************************
    $ i# ^7 B5 {5 A
  3. *    函 数 名: main
    ) r9 f6 P( R, L7 C# P/ a# C
  4. *    功能说明: 标准c程序入口。3 {, e1 \1 q5 @5 F( {0 o+ T5 l
  5. *    形    参: 无
      r/ j- M5 k* Z  l
  6. *    返 回 值: 无9 ?, t4 b! H$ |1 j
  7. *********************************************************************************************************
    1 G# m7 ^! b  t* O
  8. */3 y$ U- n9 N. H
  9. int main (void)
    4 v) w4 W' J- K6 ~
  10. {    & K  j! E  [5 r
  11.     /* HAL库,MPU,Cache,时钟等系统初始化 */- i  `3 x- {/ c2 O7 q/ W) _! z
  12.     System_Init();& B5 S5 U! p8 u- t. s- A

  13. 4 ~8 l7 X6 Y2 z5 i! q" m
  14.     /* 内核开启前关闭HAL的时间基准 */2 E" h) U4 c+ }6 |6 V
  15.     HAL_SuspendTick();7 V' {7 l( G; a- Q) k( p: a
  16. 4 c( s5 L/ U9 a  [' ^8 f; C  c
  17.     /* 内核初始化 */' Q3 }7 V- _. j. {" O, U
  18.     osKernelInitialize();                                  ; `  y+ @. @8 P# o/ Q8 ~) X
  19. 4 n) Z5 z2 Z; y' G
  20.     /* 创建启动任务 */
    " ]! B& z$ ~( G' ^, H+ M( k% L  I
  21.     ThreadIdStart = osThreadNew(AppTaskStart, NULL, &ThreadStart_Attr);  
    6 [/ K: o; c8 ]4 ?* t& @
  22. # `1 q' s# C! r* D; ?& r% D: A
  23.     /* 开启多任务 */' Z. c( i$ f4 d
  24.     osKernelStart();  N9 ]4 @5 B  x9 \6 G; F( R
  25. & N6 U1 o" A; o; O
  26.     while(1);7 h  G2 o! d' W1 {3 p
  27. }
    9 D4 W- N; }/ X8 K

  28. + Z' x( h# q) i1 E/ `+ C0 z' ~
  29. /*6 X: e- x+ Q6 C
  30. *********************************************************************************************************
    7 a* u& U9 M* r) D  g/ j% E+ Q4 |
  31. *    函 数 名: AppTaskCreate3 V* X! F! A/ k+ g
  32. *    功能说明: 创建应用任务
    % }2 r9 W# y' ]9 E$ V5 n
  33. *    形    参: 无
    3 ?4 Y/ D6 l$ z% Z+ Y# ^* v
  34. *    返 回 值: 无1 i6 X+ R8 |& N" ~: m
  35. *********************************************************************************************************5 {/ C$ y$ q( `6 p/ c
  36. */
    : S% q( [% ^* R. J% H, Y/ Z' r/ x
  37. static void AppTaskCreate (void)
    9 O$ H8 ^+ C3 l, k- t7 F8 E" w0 ?$ l
  38. {
    2 W! S: d0 C% S$ ]! t
  39.     ThreadIdTaskMsgPro = osThreadNew(AppTaskMsgPro, NULL, &ThreadMsgPro_Attr);  & I: ~, r4 \! J9 q8 s( g# S' N
  40.     ThreadIdTaskLED = osThreadNew(AppTaskLED, NULL, &ThreadLED_Attr);    @# X0 S  D3 U
  41.     ThreadIdTaskUserIF = osThreadNew(AppTaskUserIF, NULL, &ThreadUserIF_Attr);  , E. u4 ?( d& o1 I. d' @3 k7 c
  42. }
复制代码

1 b/ B8 E3 k) G- y5 Z这里我们重点看下启动任务,主要做了四个工作:
8 i% t( V. n+ Z: V& }& H
4 {% q) f" L, m" Y* I5 z' ?  外设初始化bsp_Init。
8 r# Y$ b, e3 r3 r5 n  任务创建AppTaskCreate。
4 J! Q+ C: ~7 W* o  需要周期性处理的程序bsp_ProPer1ms,对应裸机工程调用的SysTick_ISR。这个的实现非常重要,这样之前裸机里面使用的API,就可以直接在RTX5里面直接调用。8 W* o% m" J+ A, C% f
  1. /*) v$ u  d2 F1 _' d  `
  2. *********************************************************************************************************/ ?' V- |- |2 H6 {
  3. *    函 数 名: AppTaskStart
    ; v7 [# s0 K( S; T% b9 c) v5 f7 i
  4. *    功能说明: 启动任务,这里用作BSP驱动包处理。
    ! I7 _# f# m# T4 f% d8 b
  5. *    形    参: 无' h* N' e' b( ^3 f
  6. *    返 回 值: 无$ P* s9 }- F+ N. w% p
  7. *   优 先 级: osPriorityHigh4  % W) M( v  R% S5 l0 v; E( x- ~2 F
  8. *********************************************************************************************************% [/ c- X7 l4 V7 N7 a5 C1 V
  9. */
    ' A; ~7 H3 E6 `  S! W% v4 R
  10. void AppTaskStart(void *argument)
    4 U- _, J2 B6 ~4 Z4 j# v5 k- {$ E
  11. {
    - f& i7 |$ H4 l5 A8 q, U, m
  12.     const uint16_t usFrequency = 1; /* 延迟周期 */
    3 o1 f% h( p% C$ B$ N) p
  13.     uint32_t tick;
    ! i0 D+ X0 o; p0 G: ?! I/ c( g

  14. & W+ d$ [$ x" C" y* I8 s8 q
  15.     /* 初始化外设 */, t# ]. D( f  ]- G; W' ~$ T4 r% `" c
  16.     HAL_ResumeTick();. G/ |4 G9 @  ]; e$ i9 l
  17.     bsp_Init();$ b7 {6 X# l4 m% v  _
  18. 3 p$ {  ?9 _- r5 C3 e- b
  19.     /* 创建任务 */
    , Z4 r9 v" i# v; {$ g' E4 \3 A
  20.     AppTaskCreate();, W  G; }1 }! N4 n; }
  21. * F4 U! H8 M* ]0 m2 {( v
  22.     /* 获取当前时间 */, h( X6 x4 S5 W7 r
  23.     tick = osKernelGetTickCount(); ) Q% }! R9 {) ~
  24. ' M: ~! F# `1 z: D/ }
  25.     while(1)6 E6 m! v, s& B, f; H
  26.     {
    9 l  l2 K/ l9 Z5 z3 l4 t% x, f
  27.         /* 需要周期性处理的程序,对应裸机工程调用的SysTick_ISR */! [& b% L. [3 F
  28.         bsp_ProPer1ms();
    9 W( [0 d+ D) r" o& a' {) V4 ]* K
  29. 8 p$ l6 ^6 m5 t1 Q  \8 ?
  30.         /* 相对延迟 */1 y$ G- f; C6 N+ t% J1 a
  31.         tick += usFrequency;                          4 t" u; x3 r- H8 M' L
  32.         osDelayUntil(tick);
    ; T/ {  h: E) z; D$ E+ ]
  33.     }* U1 G, P5 G) c' R  o& V$ x
  34. }
复制代码
2 D9 _: g# d; ], L/ C  J
4.14 常见移植错误总结

: d: s! G% A+ z) Y* p" S% j; `常见的移植错误主要有下面几种情况:( }$ F% W( r0 V7 t

: Q6 i9 Q8 q( ^! S, h( j  编译后提示如下两种错误:
! x, b8 @# k, f1 z8 x9 E5 ~  RError: L6200E: Symbol PendSV_Handler multiply defined (by irq_cm4f.o and stm32h7xx_it.o).
% R; r- F$ G, P0 L! T# o+ i% p
2 g0 U/ F; K5 {8 zError: L6200E: Symbol SVC_Handler multiply defined (by irq_cm4f.o and stm32h7xx_it.o).1 ?$ P! }7 m& u/ ^' d# ?
8 Z* T& e5 N- |( G3 a
解决办法:这是函数重定义了,直接将stm32h7xx_it.c文件里面的PendSV_Handler和SVC_Handler删掉。
6 o9 N# n/ p9 k, ^5 c0 k
! f& ?2 ?  f. w: W6 ]5 ]. |  提示如下错误, C5 q7 J4 ?* @- t& o9 z4 G
Error: L6218E: Undefined symbol bsp_DelayMS (referred from bsp_fmc_io.o).) a* M2 P4 ^% ^# B) E3 D
* v. U5 H7 t. T4 c
解决办法:打开bsp_dwt.C文件中的条件编译。
$ S" `1 g9 E! P! ?. t, g+ w/ p# v& n' U; a3 d( d
4.15 实验例程
& |1 h; _1 W5 T- {. H0 N+ X本章节配套了如下几个例子供大家移植参考:( ]4 x. j  T) Y1 b8 `% T$ x$ q( F
; I/ X& e% A; h# F2 Z
  V7-400_Base Template
- p' D2 d* k5 ]2 ]裸机模板,方便大家添加RTX5内核源码。/ {# _9 [# u3 t' \' ?$ l
0 u( ?4 C3 v/ |, o
  V7-401_Threadx Kernel Template
  S+ d. ^: A$ @. A; ?5 r7 b! k1 w+ w5 a1 q6 @8 d' J; r$ u2 F
ThreadX内核模板。
( E& [8 T+ r2 U. K9 d! K4 f  R6 |. v" B" e: q9 G
MDK进入调试状态后,选择周期更新:
  F2 ], x/ r% o0 ^$ f. O
7 T8 G2 l4 K+ i
fdce9fac9944ad56faa0dd13307f6ebb.png

+ j0 d$ ~. ]/ b5 m# N! ]2 R6 E5 T3 S% o( S
然后打开调试组件,注意和RTX4的调试组件位置不同:
4 D% S: a2 ^  v: x; z
; T( S  j' w) F! }; F
9482ce7367ba4d7cf08c73a56db28f75.png

$ d  ]& p* r0 m9 R
7 \3 A* B- S2 J然后点击MDK的全速运行,
' {2 b/ D: S4 ^9 l' H% M% b2 _# Y
- q, n. g+ }+ h# \# c
e3038a01781216611f96ae37d5bccb17.png
4 \2 h0 X/ P) t1 H' c

: E1 L4 F1 R  w) D8 h至此,就可以动态实时查看RTX5的运行状态:
3 ?6 q2 V+ K9 l  h+ x, c, e4 U8 ^9 E1 O. u( _. F; K
797f68ea76bd699fe11ce441076df4ec.png

  h2 M5 H" \4 L. M" O' j; }+ u/ o4 y4 w+ _$ H9 A0 G
4.16 总结- Y; R( r+ N# i/ r# ?
本章节为大家讲解了RTX5 在MDK AC5上的移植方法,移植涉及到的知识点比较多,初学的话,建议实际动手操作一遍。: J5 |5 [0 @( h+ ~" l
& Y. e3 M! o* O+ u$ b

" |; q$ Y" F& m! Y
! c1 Z( `2 y* _$ i' l1 Y8 ?7 \
收藏 评论1 发布时间:2021-12-30 14:32

举报

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

好好学习

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