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

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

[复制链接]
STMCU小助手 发布时间:2021-12-30 14:32
4.1   初学者重要提示" P( t( y8 d  Y7 [% m2 M" M
  当前RTX5可以移植到GCC,MDK和IAR三大平台,考虑到仅MDK平台下有RTX5的调试组件,我们这里仅提供了MDK的移植说明。& W, y$ j1 W& b* O8 i
  STM32H7使用MDK RTE环境添加RTX5,需要强制运行一次STM32CubeMX,因为H7已经没有配套RTE经典添加方式,而STM32F4是支持经典方式的,所以无需运行STM32CubeMX,详情可以看我们STM32F4开发板对应的RTX5教程。" D! j( V7 W/ M$ }8 z* u$ m
4.2   移植RXT5内核整体说明  f! Z4 J6 X& {
移植之前,有必要对移植过程有个整体的认识:
( X1 {' @7 H( g  l! O* C1 c9 ?7 |+ S4 O4 e+ R; Q: }- p- ]
  第1步,准备一个工程模板。2 X! L. A2 q" L5 C0 r7 Z
  第2步,移植RTX5。
" {  _* B: O6 a0 l1 B  移植RTX5是采用MDK的RTE环境直接添加。当前H7芯片使用RTX5强制运行STM32CubeMX,所以需要大家提前安装好STM32CubeMX V5.4或者以上版本。
2 Z# H& r2 ^" S2 m6 E. v" n  第3步,处理HAL库时间基准,MPU配置等。
3 C( o7 L- n  ]  r  第4步,创建应用。& U6 Y4 J/ R3 w  Q9 x5 X! M

& G% R* U% e& `8 S/ r总的来说,这4步就可以完成移植, 下面将STM32H7的移植步骤和注意事项为大家做个说明。
# L2 @) E$ T% N5 ^! L1 l2 X. T  k" N8 J/ [0 x
4.3   了解RTX5内核模板框架设计
+ _4 a9 M' ~; p! O1 s. L& b移植RTX5前,我们优先了解下移植好的RTX5内核模板,方面大家后面移植:
4 n# \3 |4 @! s, n  `. M; @' M! }% ^( j- p
ebf7bed4831890980f518eaeb842a943.png
! n5 X# A2 V& D0 N

  C* t0 p! _9 D% d框图如下:
4 ~" ?& P; C/ _  f7 E9 U* ?* |2 ]6 g; S; `3 w" _% U& g" J
cc3f4f5af7e41dcb23a03a25e14d8ae7.png

3 {/ r, b* {5 M- o$ ?2 A5 x' g
- W$ t7 X9 Y( v+ M$ ]4.4   第1步,安装指定的MDK软件包版本
5 J  W8 i" ^$ i0 s- \( g5 V- p移植新版RTX5需要大家下载当前最新的MDK软件包版本(如果有最新版,推荐大家用最新版):
6 R5 ?! ?+ Z+ p2 O6 r3 B! n- W) |. j' \5 d
  CMSIS 软件包使用当前最新的:V5.7.0
2 n9 }1 d* p" N- q2 T. [4 m; B  STM32H7使用当前最新的:V2.6.0
0 V  @7 g, n3 V# x* r  STM32F4使用当前最新的:V2.6.0$ M- n. F1 Q# Z8 `4 H( b( G; e: V
  STM32CubeMX使用当前最新的:V6.0.x
# x/ C7 }  }; X$ ~( }  b. l+ h, r7 ?  ARM_Compiler使用当前最新的:V1.6.1
: B1 `$ }* _; i# w; \% y: D* p2 R* F7 Q* h) L9 @
不管以后MDK的软件包版本如何升级,当前的软件包版本和以后的新版是可以同时安装的,也就是说可以安装多个不同版本,在这里可以选择指定版本:9 V, ^/ t! j0 c6 U0 ?5 v
3 J- V$ v: G. A1 [% d
bbb84b8c4b3275b1026d2c95b5012294.png
1 v# ~3 \4 i1 Z, e, q. ]' i
; F2 X5 }. F* Q. E5 i& _$ X- N
4.5   第2步,准备一个工程模板3 A" H  _* k& P* K, l
首先准备好一个简单的裸机工程模板,已经为大家做好:V7-400_Base Template,准备好的工程模板如下图所示(大家也可以制作其它任意的工程模板,不限制):8 @7 Y+ R+ U9 n! D. H/ F
; E" B. m9 \$ h4 p
5618d5a487ef825c0a75ce19685c4821.png

7 n' T$ S! }: s6 }* d! d" c! G
4.6   第3步,添加RTX5并配置
" o2 [2 d, W0 J. ^! J' y" uRTX5可以方便的通过MDK的RTE环境添加进来。对于H7版本,MDK会强制运行一次CubeMX,并添加很多H7的HAL库文件,这些库文件我们可以使用,也可以不使用。教程配套的工程文件是不使用这些,因为前面的工程模板里面已经添加了。所以要将这些文件全部隔离出来。
+ d- d3 m' v2 c: m: F+ Q& J; |5 h% F/ G$ f  n. |$ @% T
4.6.1      添加RTX5源码  i7 {8 c4 w) z' I3 D3 \* a, o% B
4 k$ O: _' I7 A7 ^9 F! c
48f11b91f9fc45f3f04431047156434d.png
! Q) n3 F) f' A: C
4 w3 A% q2 ^/ L; M' c! n9 L
点击OK按钮后,弹出如下界面:
% T3 R9 N+ M! `0 v% r' `
9 k8 O! y# K8 E5 ^
b430f5f7b2e1a16de73553adb9dd1f89.png
) t- J6 @) X8 {7 [3 g$ z

. n6 v& z8 Q) J# g4 U" i# c) F点击Start STM32CubeMX,这里需要大家电脑上已经安装了STM32CubeMX,并且为其安装了H7的软件包。# G% Z$ F. M( m* T2 \( q

0 m0 F( Z4 s" q
af4f52889e56b18313faf6baa5ed1281.png

; n3 y5 S% s0 ^; d
- ]: p# Y3 `5 A! `1 t, B打开后,用户仅需配置如下地方即可:
+ S7 }6 o* `$ V
: N2 Z( I! L( z0 P* y
7c8a9271ba3d0ccb045c81921fd97d0f.png
1 a" Z( h( {: x5 b
1 n2 V2 w* v$ }9 ]
然后点击右上角的GENERATE CODE:
* Q2 ^2 t7 m" C( i8 ^& [, D, n9 f- F  M9 B+ k! f
62747d5251f02d427c05caf48fc46d77.png
9 G5 ^9 f0 ]. B( ?
: l9 i- y$ s  ]6 Z  q2 ?
然后弹出如下对话框,点击Close即可,然后关闭STM32CubeMX。) z  a4 c4 b  Q. Q( U

. }) q* y& Z$ O$ {
1a4404327c06b66c217f46c74bd48db2.png
% I; L+ h. _+ g6 P  z. m, Y

7 l+ ^* m6 k7 @  ^( a& S重新回到MDK,会有一个对话框,点击是即可:( s0 J) V$ J- L! L5 `& m. N, |% T! |. l

- b! Z* X# p, X: J/ t
cdfb3b29fdf8c8b60f0d85f8aaa161ff.png

- q$ n# e4 `7 ^# U! `( a. `
, O  x- Z+ k" U+ j7 n: F最后就可以看到RTX5源码已经添加到工程里面了:9 O! Q0 Y2 L, d/ T7 A4 V

2 I3 A9 G0 ~" B" |2 v2 ]
e49f340b4464ddd3afb5bf5082de0fdd.png
4 f& a, q$ c! x7 y0 F8 y' [" ~+ U

8 ?, U% [& L2 U  M, _4.6.2      将自动添加的库文件隔离出来
7 }/ m- r- w+ V" ~4 x添加的所有文件中,仅RTX5和文件stm32h7xx_hal_msp.c留下,其它文件全部隔离出来,隔离方法也比较简单,比如隔离生成的main.c函数,鼠标右击此文件选择Options for file ‘main.c’
" W8 K% B; C5 \
* O7 i" E4 R" m9 L: }2 d
3b989ad148a2ec7c0522490cd84fcf3c.png
( i0 J0 E. o# L% R3 C  f: Z

/ A" A" U( ~! j然后取消掉include Target Build前的对勾,点击OK:
# ?: j$ g! X$ M
2 w/ b' l+ A9 J' R
6652eec0f1078d33b6c1508049d0c922.png
& o+ q; d/ a, N+ n; o2 x
+ T( J% S* G8 h, P
看到main.c文件上有个红色横杠,就表示已经隔离出来了:
# t2 R9 ~& v. n1 D3 c  v
8 V2 {- T$ h' t. Y6 @3 S
cafbe4a03ab78632d36b9cf1b050250c.png

% J5 m" w% _1 n3 G, u. t+ l) e
! i( j4 s4 P4 R0 w' j( l: f/ E同样的方法,将stm32h7xx_it.c文件也隔离出来,文件stm32h7xx_it.h不用管。
1 ~3 i/ d( a" H" b( V/ l' r* V. R6 q; l) G7 W
Device下面的这些文件也是同样的隔离方法:8 h- R, W9 F1 v, X3 t
6 {1 b8 O- v4 j
f46dbe6e1b27dd459e04cba9849d9ff9.png
; m" }2 [# e* A) V6 @3 I7 D& m* O

/ w0 p) K; L, `只是鼠标右击弹出的界面有些不同:
: [9 W; g+ o) }" n/ C
. |* D% B3 g4 H, a7 j' J) u& j# {: ~
aeccd1d366ee4da23ceff332ae2f84e5.png

  }6 B  V9 p4 f& W& X+ i0 }4 `3 [& F3 ^. ^% g" t
注意stm32h7xx_hal_msp.c无需隔离,其它所有的文件全部隔离,stm32h7xx_hal_msp.c对应的隔离配置是STM32CubeMX,如果也隔离了,编译会有问题:
% e+ n. K5 p) R( c/ Q
7 {' D8 Y( p% j: _3 j, E" R- G( \
59f0e5e7d43f7ac7e983147c132a42ce.png

) e& O, e; q( L  v
+ X- N0 Y2 T8 Y0 J8 ?隔离后的效果如下:
* l. {  ^- Y& r4 r1 C% v
$ T4 i* t. p& |7 ~9 T
573fb2c99aa8ef7ef6f577c106084913.png
' J7 D. y3 D4 [3 a  R5 G2 ^- |
5 y6 `0 T+ v) o$ Y& Y# i
4.6.3      RTX5配置' H( @  s/ W( Z% z( o
剩下就是配置RTX5,设置RTX_Config.h文件即可,移植阶段先按照如下设置配置好,后面章节会专门为大家讲解每个参数的配置含义:6 P" G% f" ^& z* ?7 n  y: e. x

6 v+ X# D9 w) w/ \) f. B- p  c; l  [
576cda809f95be40653ff18b9682f906.png

) ~. J4 `3 F. \; r! }# f# r  B5 C3 s$ Q2 u1 }! j
4.7   第4步,MPU和Cache配置文件bsp.c
# s4 p5 t$ @! i; a1 G: r这个bsp.c文件也比较重要,移植阶段,直接将我们移植好的模板内容复制过去即可,这里把相关的内容为大家做个说明。
9 E# @5 J& ^3 O6 y4 d/ p& W$ |" p/ r0 @
4.7.1      函数System_Init

2 E, k, n. {+ K/ H4 v+ A系统初始化,主要是MPU,Cache和系统时钟配置,需要在RTX5初始化之前调用。! B! E) b) V/ H# _! T# w4 q

* P8 A& C2 n$ s% V+ z
  1. /*
    3 t7 t3 p" N; ?3 T2 h) a4 t
  2. *********************************************************************************************************+ U* v( w7 U& z5 C  `
  3. *    函 数 名: System_Init
    + G0 i( Y$ L: ?  k6 F! l7 ?9 ?
  4. *    功能说明: 系统初始化,主要是MPU,Cache和系统时钟配置
    . w# C! t2 c3 e" X" I5 h7 X
  5. *    形    参:无
      G6 ^8 K# m" M  P- ]( e- w
  6. *    返 回 值: 无
    " _- w  E, \% w, e  @) W. m8 i
  7. *********************************************************************************************************
    + Y6 z) P1 p8 v7 x  |3 h+ u
  8. */; n4 i( X0 b/ T2 d0 t
  9. void System_Init(void)
    . [+ I, ^0 \3 X5 h
  10. {' K6 ?, q3 f/ w$ H; t# q

  11. ; F5 f* e2 g% r8 k2 _
  12.     /* 配置MPU */3 n6 J6 c9 p3 H, L/ @* O: J
  13.     MPU_Config();
    ' v# y% k$ _) o& L7 G# f

  14. # R; X2 S! c' T
  15.     /* 使能L1 Cache */- v9 R  Q6 X. G5 D
  16.     CPU_CACHE_Enable();# O% f  [1 @8 w4 G/ q
  17. , a, Z, Q7 Q8 M3 y) q: I6 i
  18.     /* 8 a. W0 `0 b) m5 K* q( O+ }
  19.        STM32H7xx HAL 库初始化,此时系统用的还是H7自带的64MHz,HSI时钟:3 g8 A" P. E, m3 B6 E
  20.        - 调用函数HAL_InitTick,初始化滴答时钟中断1ms。
    % q" \+ Z# P7 _0 w
  21.        - 设置NVIV优先级分组为4。
    % [) m. n# y; z2 z3 T2 _
  22.      */! ^" U. S& s, E
  23.     HAL_Init();& Q0 A3 L5 A& V& U' l+ P. y

  24. 2 p7 @" m$ u3 H1 s  t! l
  25.     /* 0 c% f: E' C9 W; g
  26.        配置系统时钟到400MHz
    8 W7 K* I1 m; `. f3 a6 X
  27.        - 切换使用HSE。, x5 V  p8 g2 g4 {: {
  28.        - 此函数会更新全局变量SystemCoreClock,并重新配置HAL_InitTick。" P/ ^% R9 t6 [$ K- i  m  B# j5 R
  29.     */4 h5 S* u3 @7 C) X) I, [
  30.     SystemClock_Config();
    . r6 g  i$ e$ w& l6 p. r: x
  31. 5 Y" n1 G5 Q( t. ?8 [, q' ?+ I
  32.     /* . t; R4 T1 t+ m0 J* C+ R3 R
  33.        Event Recorder:
    " d8 O+ W7 L0 K. X, ?0 D
  34.        - 可用于代码执行时间测量,MDK5.25及其以上版本才支持,IAR不支持。
    $ p9 z- e& v8 C" S/ t
  35.        - 默认不开启,如果要使能此选项,务必看V7开发板用户手册第8章: Z7 V3 B: ~8 E
  36.     */   
    5 L# I7 n6 s# F. n6 Z5 Z8 J6 m! V+ @8 Z
  37. #if Enable_EventRecorder == 1  6 s) B: E- V4 n+ u1 H% N5 K
  38.     /* 初始化EventRecorder并开启 */
    3 y. v* `* P  b5 A2 Q0 p
  39.     EventRecorderInitialize(EventRecordAll, 1U);
    - b; n8 w" |/ r3 t! o2 x" n
  40.     EventRecorderStart();
    6 A6 q. k3 w/ m2 v9 C
  41. #endif
    ( q$ B* v6 y$ K; W$ p6 G  C
  42. . Y( v, N* ?# n) c
  43. }
复制代码
# G0 _! B8 D, Z$ j
4.7.2      函数bsp_Init  P" x* ]6 @) ?: {( F/ X
硬件外设的初始化,这个函数在RTX5的启动任务里面调用。
. z$ m  {' J! ?- ]2 H4 i1 ~& U/ k) v
  1. /*
    7 L/ o' U) e$ Y$ F# ]! Q; j
  2. *********************************************************************************************************1 q7 j5 E) R. l) f; x$ l
  3. *    函 数 名: bsp_Init$ {0 r5 m; Q5 _# ^4 T
  4. *    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次0 w8 _: b' L- n
  5. *    形    参: 无
      X% }' E" s6 L7 H7 H- Z5 }! `
  6. *    返 回 值: 无: R9 x5 X7 E& F2 J3 b' q: }
  7. *********************************************************************************************************
    ) h# d. j; F7 z9 p0 ^
  8. */
    6 T7 z5 h: O  a5 s1 x% Y
  9. void bsp_Init(void)
    , S) `7 ^& F1 S+ ~0 K
  10. {. s8 {  X& X7 g6 P% U" P
  11.     bsp_InitDWT();     /* 初始化DWT时钟周期计数器 */       7 s( h$ l) n7 K* n- _
  12.     bsp_InitKey();        /* 按键初始化,要放在滴答定时器之前,因为按钮检测是通过滴答定时器扫描 */5 q1 e* y2 y- m8 D
  13.     bsp_InitUart();    /* 初始化串口 */5 v4 C, Y1 k/ ]
  14.     bsp_InitExtIO();    /* 初始化FMC总线74HC574扩展IO. 必须在 bsp_InitLed()前执行 */   
    ! _) o- h! U9 W/ J& R
  15.     bsp_InitLed();        /* 初始化LED */    $ `7 z$ W9 Q: o% r6 r
  16.     bsp_InitTimer();      /* 初始化滴答定时器 */
    2 e0 J5 x% @+ R; A5 ]$ P% g
  17. }
复制代码
1 m4 p  l7 t5 ?# Q( _
4.7.3      函数SystemClock_Config5 k! q, N0 O2 q8 |
这个函数主要是完成系统时钟配置。; v, U: z/ u$ I$ O
0 {3 e; p2 r! n# o
  1. /*
    ' O, U5 X3 i' s7 q1 U0 W' K
  2. *********************************************************************************************************
    & P4 N0 F* n" Q/ e
  3. *    函 数 名: SystemClock_Config
      N* D/ d5 `& c6 z7 _2 v
  4. *    功能说明: 初始化系统时钟8 k  `) o' O. j( d8 ^1 `, I
  5. *                System Clock source            = PLL (HSE)) F9 a4 c( _$ D5 G) g* t. L- m- ]
  6. *                SYSCLK(Hz)                     = 400000000 (CPU Clock)7 q' D. B  k" v  n, ]
  7. *               HCLK(Hz)                       = 200000000 (AXI and AHBs Clock)8 \3 U+ Y, o7 {  f' g3 B
  8. *                AHB Prescaler                  = 2
    ) I; S4 V5 ~) j+ e
  9. *                D1 APB3 Prescaler              = 2 (APB3 Clock  100MHz)
    ! @3 P- D9 s; [
  10. *                D2 APB1 Prescaler              = 2 (APB1 Clock  100MHz)
    ! c/ m& f; l' Q2 f6 }4 r
  11. *                D2 APB2 Prescaler              = 2 (APB2 Clock  100MHz)* \* G) X, i6 Y$ |; V( w; I3 H- |3 D
  12. *                D3 APB4 Prescaler              = 2 (APB4 Clock  100MHz)
    ( |: a- l7 @2 F4 h4 J) Q
  13. *                HSE Frequency(Hz)              = 25000000# z3 B& i- ^$ d( s
  14. *               PLL_M                          = 5% V) G* C1 |" V# Z* r. A$ c/ K
  15. *                PLL_N                          = 160
    ( r$ k! `7 o0 d) Q4 Z5 ~5 j/ F
  16. *                PLL_P                          = 2
    . G$ l0 _. g; D- u- f* w9 d
  17. *                PLL_Q                          = 4
    1 E4 R4 s/ n; x7 J) l" L
  18. *                PLL_R                          = 2  M- B1 Q: ~4 [0 I# x: X1 E
  19. *                VDD(V)                         = 3.3; U7 r9 {. V' d& ^9 ?
  20. *                Flash Latency(WS)              = 4
    4 b$ Q& n6 s3 y8 x
  21. *    形    参: 无: F$ U3 o; a) o- c' v) n
  22. *    返 回 值: 无: g! w8 A% W7 N( H) e
  23. *********************************************************************************************************8 X/ J. b9 P7 N! L
  24. */0 E5 V. g3 P6 f+ b6 r9 b
  25. static void SystemClock_Config(void)
    & e! J. a  C( o3 u0 m0 r
  26. {3 w9 |! q7 K2 Z+ ]1 Y
  27.    省略未写
    ; Z9 y6 f9 p3 R( ]# J/ \% X
  28. + I$ ^6 k2 }8 F- T+ k  B; K
  29.    /* AXI SRAM的时钟是上电自动使能的,而D2域的SRAM1,SRAM2和SRAM3要单独使能 */    ( r" ^! u0 O3 q8 v( s. b: U
  30. #if 1" K9 N: s7 q7 I4 b, ?, @: c
  31.     __HAL_RCC_D2SRAM1_CLK_ENABLE();
    ; c% r: J1 U9 |) x
  32.     __HAL_RCC_D2SRAM2_CLK_ENABLE();$ p9 s4 X. @* x8 a( L  x( t7 P
  33.     __HAL_RCC_D2SRAM3_CLK_ENABLE();
    8 }& @" |, w2 u/ u" G( B
  34. 6 y# I) k  j( p8 P- n( a% ]
  35.     __HAL_RCC_BKPRAM_CLKAM_ENABLE();       . C9 X2 v# ^1 Y' n; s
  36.     __HAL_RCC_D3SRAM1_CLKAM_ENABLE();4 `  h# L0 m8 C6 f
  37. #endif
    " @. M. {: v9 G% r5 Y/ L
  38. }
复制代码

( J5 N) O6 ^: p/ c这里的RAM时钟初始化比较重要,这几个RAM的时钟都要单独使能。7 c3 q0 @& Y) c; \) [

5 p; G& m. t" v, c5 }4.7.4      函数MPU_Config+ o1 y: e. J- C
RTX5例子默认采用AXI SRAM作为主RAM空间,因为空间比较大,方便我们后制作综合例子使用:
, K8 d) S, e2 U& }% C3 L4 G
  d6 v7 f4 ~( D8 i
  1. /*  ]4 J: k" m* M8 l+ O" E9 {4 i
  2. ********************************************************************************************************** Q9 T' L, s* P; I7 |
  3. *    函 数 名: MPU_Config
    ! Z9 M7 M2 [1 a' Y6 c7 R5 K$ v6 }
  4. *    功能说明: 配置MPU% w4 w3 ]$ e4 G4 H4 Y# l
  5. *    形    参: 无6 S1 v4 j" J# Z% ~. s
  6. *    返 回 值: 无
    6 }7 A4 s$ C# q2 R1 W9 l8 }
  7. *********************************************************************************************************3 x) [' D" S5 D4 o8 E! z
  8. */
      W; e/ Z3 s; x
  9. static void MPU_Config( void )( T2 c2 ?4 l: z( t8 q& W
  10. {
    * |% I0 L& \7 G, j. L# E
  11.     MPU_Region_InitTypeDef MPU_InitStruct;4 [) T' Z) b2 w1 \: R9 t( E7 K0 k
  12. 8 v1 }5 J. t) u& `  w3 c
  13.     /* 禁止 MPU */
    2 E/ a' v% p( z- O: U4 n
  14.     HAL_MPU_Disable();2 S: \3 `/ B6 c9 r) p

  15. 6 c1 `% J$ q2 S( t- \% W
  16. /* 最高性能,读Cache和写Cache都开启 */   
    + E8 X3 p% p) c( L- A) x
  17. #if 1
    6 C+ E7 C4 @0 S* r! |
  18.        /* 配置AXI SRAM的MPU属性为Write back, Read allocate,Write allocate */
    * K/ Y% M! J9 v% L2 m: \+ \
  19.     MPU_InitStruct.Enable           = MPU_REGION_ENABLE;! X% M- D5 {" C* b! P( a
  20.     MPU_InitStruct.BaseAddress      = 0x24000000;5 u! L' W$ y7 B" e. {
  21.     MPU_InitStruct.Size             = MPU_REGION_SIZE_512KB;
    . |, Z: E0 o* M% \4 p8 I! @
  22.     MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;# m' b9 a* Z  U( h6 q$ ]
  23.     MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;
    ; |4 s' e1 n  {" `3 F
  24.     MPU_InitStruct.IsCacheable      = MPU_ACCESS_CACHEABLE;
    + ^1 A& e' W1 A- t  Y
  25.     MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;* H& ^- _$ q8 p2 n
  26.     MPU_InitStruct.Number           = MPU_REGION_NUMBER0;: I8 P3 n7 e1 {
  27.     MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL1;
    ( V+ R" S& F% y! |, X3 ~/ u/ B+ ]
  28.     MPU_InitStruct.SubRegionDisable = 0x00;" m; B# p/ B' C
  29.     MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;
    ( ^  F/ q$ y7 I+ D/ [
  30. 2 M2 L+ S. h' D7 n# ~/ W
  31.     HAL_MPU_ConfigRegion(&MPU_InitStruct);
    # m' j2 U" F: H$ X  C2 o

  32. 4 F+ V- ~5 U5 R' g. C2 W
  33. /* 最低性能,读Cache和写Cache都关闭 */
    / }6 P, O: M' i
  34. #else$ @: t2 @2 ~0 p$ ]; [% i5 S
  35.     /* 配置AXI SRAM的MPU属性为NORMAL, NO Read allocate,NO Write allocate */  s; c, N" S. r5 d8 U
  36.     MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
    * b$ K: g( ]) Z) z! j: G; ^6 O
  37.     MPU_InitStruct.BaseAddress      = 0x24000000;8 o" B7 [; \& \# t0 L
  38.     MPU_InitStruct.Size             = MPU_REGION_SIZE_512KB;
    . P+ B; k" ?0 p+ V+ H+ \# o0 ~
  39.     MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
    " H+ L( N4 B% A0 }6 R: g
  40.     MPU_InitStruct.IsBufferable     = MPU_ACCESS_NOT_BUFFERABLE;
    ; f- L3 t" X. A# H' z7 m
  41.     MPU_InitStruct.IsCacheable      = MPU_ACCESS_NOT_CACHEABLE;
    $ c3 V; ~! l# \, Y7 c& j7 r5 L
  42.     MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;% t: X% O6 p, T" L; w: A! J, b
  43.     MPU_InitStruct.Number           = MPU_REGION_NUMBER0;
    ) x6 U6 s% s: G9 [: _- _% }
  44.     MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL1;2 M6 H& F, ^' L0 Y; b. }
  45.     MPU_InitStruct.SubRegionDisable = 0x00;
    2 i/ d( k: M% V. X7 |9 r) Q2 z9 k& t
  46.     MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;9 ]+ A- t* J. X# x9 F# A

  47. + r$ K. ]! B9 `
  48.     HAL_MPU_ConfigRegion(&MPU_InitStruct);
    ; v& V3 K# d5 \7 Z  r$ N# H- U
  49. #endif& U' ]' V: E6 F2 Q3 L1 s- Y7 L

  50. 7 V7 A3 A% I  n7 h4 r; o6 l+ m$ l
  51.     /* 配置FMC扩展IO的MPU属性为Device或者Strongly Ordered */
    ' A$ Y% s& \- _" B3 ^8 }: g
  52.     MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
    % j3 b5 R7 O. L. S
  53.     MPU_InitStruct.BaseAddress      = 0x60000000;; {! S3 i8 O. N! F
  54.     MPU_InitStruct.Size             = ARM_MPU_REGION_SIZE_64KB;    : e' J0 Z% R1 h$ W* p& k0 ~9 O4 p
  55.     MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
    8 G; N/ o" u2 l
  56.     MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;, y# X5 y: |/ e
  57.     MPU_InitStruct.IsCacheable      = MPU_ACCESS_NOT_CACHEABLE;    , o: \, \3 \$ e6 X' |6 n- s
  58.     MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;5 v! v1 |, k3 G& {3 e
  59.     MPU_InitStruct.Number           = MPU_REGION_NUMBER1;
    2 Y, V. }8 A7 b. H* r+ K( Z
  60.     MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL0;$ _  a+ V' X8 Q
  61.     MPU_InitStruct.SubRegionDisable = 0x00;
    , u( S8 Z0 q, ?
  62.     MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;9 J) [; G8 i2 E  P

  63. & _& _; Z& N) `; o+ E% M
  64.     HAL_MPU_ConfigRegion(&MPU_InitStruct);
    2 n/ Y) ^6 K( |$ r) X/ S' u* B

  65. 8 c& z  o; {1 Q# \& s. u
  66.     /* 使能 MPU */6 D2 a2 f2 H$ R3 J4 f; n( c$ `
  67.     HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);; @' [4 P* K8 }7 s5 r/ z
  68. }
复制代码
) h5 q; n- E5 R
4.7.5      函数bsp_RunPer10ms9 Y" Y6 [. b1 |" U# Y
这个函数里面默认有个按键扫描,如果大家移植的程序里面没有按键初始化,务必要把这个按键扫描函数注释掉。
$ ^+ o; I/ z7 R3 H' }8 ~, V% g- d8 F1 J
  1. /*1 T4 }. u8 s5 T; S* \! x
  2. *********************************************************************************************************" L# T: F& z" J" v$ I
  3. *    函 数 名: bsp_RunPer10ms) \$ w: B! j, W; e# {
  4. *    功能说明: 该函数每隔10ms被Systick中断调用1次。详见 bsp_timer.c的定时中断服务程序。一些处理时间要求
    ! q/ t/ g4 y! p/ m2 l- q9 ?& T
  5. *             不严格的任务可以放在此函数。比如:按键扫描、蜂鸣器鸣叫控制等。  v" S+ l6 c, P! [
  6. *    形    参: 无5 L7 e  ^/ e( ?! T: w
  7. *    返 回 值: 无
    8 @7 b  |0 v3 z
  8. *********************************************************************************************************
    ( o" S  ^8 K; c' V
  9. */
    , E' |2 W3 g; K( o- @
  10. void bsp_RunPer10ms(void)
    & y7 w$ o) t( Z6 n$ J( ]
  11. {8 ?" b. r. [5 A
  12.     bsp_KeyScan10ms();
    ' i4 P" ]. P, G6 I
  13. }
复制代码
; M3 m+ d9 R6 T# N+ m9 U9 U
4.8   第5步,更新bsp_timer.c和bsp.h文件, w( W$ Y2 ?- r
更新bsp_timer.c文件是因为此文件跟RTX5都要使用滴答定时器,有冲突。所以大家直接将我们工程模板里面此文件覆盖移植的这个文件即可。" X' B! ?/ z" \/ T$ A3 i- Y6 I

$ K; g0 C9 d  Bbsp.h文件里面要添加一个宏定义,因为bsp_timer.c文件里面做了些条件编译:
9 N: Q7 o0 r9 Q" ^4 P% s; Y, V8 I1 p+ B
8 P0 S& u" P0 o9 ^9 B# z#define  USE_RTX    1
( l$ H) G1 ?9 s
# o+ p; u2 c- [, x2 |另外,bsp.h文件将大部分头文件都添加进来了,大家可以根据需要,用到那些头文件,使能那些,用不到的,可以注释掉。当然,不注释也是没问题的:
- c2 M0 C6 f; x( O; g. l3 u- G
: w3 |. ~7 @! h' F6 H& U$ |
  1. /* 通过取消注释或者添加注释的方式控制是否包含底层驱动模块 */
    ( f- n! U' a- \1 M: q/ ~
  2. //#include "bsp_msg.h"
    + i$ R# Y) q1 `1 ]- Z+ [% A
  3. //#include "bsp_user_lib.h"$ `- Q' n% E: k+ D6 z. h/ ~$ `; K
  4. #include "bsp_timer.h"$ M9 S, c3 o; l
  5. #include "bsp_led.h"9 y9 w; E8 x/ P) X+ f
  6. #include "bsp_key.h"
    3 O( l6 `( \4 n8 M4 L
  7. #include "bsp_dwt.h"
    3 e. t  V' y6 K6 W8 d7 @0 T

  8. 2 H7 M: k5 n- U2 n& g% w
  9. //#include "bsp_cpu_rtc.h"
    ; L* C) {' A& v0 }) j
  10. //#include "bsp_cpu_adc.h"
    7 C% J/ h* F4 e6 A, ?& Q6 D# }* g
  11. //#include "bsp_cpu_dac.h"
    + T' g3 @; |2 f) ~0 P% w
  12. #include "bsp_uart_fifo.h"
    * z4 u* }% ?7 x2 M: u' i) f
  13. //#include "bsp_uart_gps.h"
    6 A7 c3 k& |6 A% X2 U$ ~
  14. //#include "bsp_uart_esp8266.h"  X9 W2 F8 e4 W$ U) Y
  15. //#include "bsp_uart_sim800.h"3 L4 S, ]$ O  X! w3 B

  16. : X% T) v$ ?9 o0 c1 |
  17. //#include "bsp_spi_bus.h"
    % q7 c8 w. E1 E3 N) h( M
  18. //#include "bsp_spi_ad9833.h"; r5 o2 s. \0 g# ?7 B7 ]3 Y
  19. //#include "bsp_spi_ads1256.h"
    . S3 `8 B: K) J8 n( C2 Z
  20. //#include "bsp_spi_dac8501.h"
    0 h/ |: ]/ o( v% Y# l
  21. //#include "bsp_spi_dac8562.h"$ i: _( V  ?2 j& Z# F; k
  22. //#include "bsp_spi_flash.h"* [5 {/ D: u6 ]) W) @3 B9 W5 d
  23. //#include "bsp_spi_tm7705.h"
    2 I; R; U2 _' p6 J$ w& u
  24. //#include "bsp_spi_vs1053b.h"$ {: G( R* h$ r' ^8 P9 o' R

  25. , }/ ~1 Y% B* D
  26. //#include "bsp_fmc_sdram.h"1 i) a0 d' w) Y& O8 }( d0 s
  27. //#include "bsp_fmc_nand_flash.h"
    % [" P7 s- Q& q4 u( t+ L4 _
  28. //#include "bsp_fmc_ad7606.h"
    5 u+ W# ?4 K/ b7 e8 [2 L5 o
  29. //#include "bsp_fmc_oled.h"
    4 a: ~0 v* L) i" A1 [# L
  30. #include "bsp_fmc_io.h"
    - T/ y7 R  `( j# j  A6 q

  31. - c  {+ i, L* N0 @  Z3 y, ^
  32. //#include "bsp_i2c_gpio.h"9 `! L1 c4 `4 }( p0 H! s3 }& C
  33. //#include "bsp_i2c_bh1750.h"
    0 H8 j4 C2 U. S9 l# c. C+ L! {
  34. //#include "bsp_i2c_bmp085.h"$ w! j! s  c( _" R# e2 c2 q! e2 V
  35. //#include "bsp_i2c_eeprom_24xx.h"
    5 n% o8 D  @" m; @% a( g
  36. //#include "bsp_i2c_hmc5883l.h". D# j5 y: n: s( N
  37. //#include "bsp_i2c_mpu6050.h"
    0 N$ [' Q# C- \7 g- s
  38. //#include "bsp_i2c_si4730.h"
    / w2 t0 u# _+ p5 R+ H1 M. k* b
  39. //#include "bsp_i2c_wm8978.h"$ T7 G& o- {% l! U
  40. $ b9 J) @1 A& n' e7 {: l3 |- t
  41. //#include "bsp_tft_h7.h"8 B# v# B& t; a  b
  42. //#include "bsp_tft_429.h"4 g! {/ r6 l- a6 ]1 u1 ^2 X
  43. //#include "bsp_tft_lcd.h"
    + ^, m9 R- l5 v: {6 E  o
  44. //#include "bsp_ts_touch.h"/ J+ i; \9 v/ k& G* O! R
  45. //#include "bsp_ts_ft5x06.h"- s" G3 q8 c! r
  46. //#include "bsp_ts_gt811.h"% \' o5 K2 X6 N6 z) H+ Y0 t' b+ ]
  47. //#include "bsp_ts_gt911.h". H) I( S& v; D! `# G9 e8 F+ _
  48. //#include "bsp_ts_stmpe811.h"
    $ W8 B) W# H6 p8 X: i! J3 N

  49. 5 c9 M& K6 T% u+ I6 z
  50. #include "bsp_beep.h"
    + ]" @% d3 a2 n6 x
  51. #include "bsp_tim_pwm.h"
    3 W+ v+ S' D  @* x
  52. //#include "bsp_sdio_sd.h"  n# e) ~, _/ h. M, |2 a
  53. //#include "bsp_dht11.h"
    % x4 J- L5 v, q5 D% L( f0 t5 v
  54. //#include "bsp_ds18b20.h"
    + ]5 j+ W2 t  a9 q6 e0 S
  55. //#include "bsp_ps2.h"
      v) F& u1 l2 P8 H. m& [$ n
  56. //#include "bsp_ir_decode.h"
    ( j, M2 j1 e( j3 g" \/ q
  57. //#include "bsp_camera.h"' U: i* e8 U3 y  \3 |7 K4 v- y
  58. //#include "bsp_rs485_led.h"
    + C% _- L& y  _7 x4 g+ ]/ Z
  59. //#include "bsp_can.h"
复制代码

+ _- C" v( Q) h, q: \4.9   第6步,修改文件stm32h7xx_it.c
$ F2 X* ~" P: ]9 R删除此文件里面带的如下函数,RTX5要使用,冲突了。
2 K& E( ^5 c) p' p
; J' l/ z# L- E# o) [- }: ]! w: x
  1. /**
    5 A, z$ Q2 _6 ?4 h1 F
  2.   * @brief  This function handles SVCall exception.
    / f( n3 T% x+ |. _9 _3 S8 x
  3.   * @param  None4 G3 s2 u( e$ K. r2 B. P1 P
  4.   * @retval None
    2 j: E& i* |8 C" b8 A& R" h) `- k
  5.   */
    ) j5 ]3 h( l; B- u2 j- t! X
  6. void SVC_Handler(void)
    ( `' Q. P  q5 r2 T5 Z
  7. {
    3 m( F/ T2 k) A6 Z! F9 T. s0 n1 n
  8. }  D" k1 x/ \" p) m5 k
  9. - E# s( S5 v  z: N* u; m3 W: C
  10. /**% ~- A1 x" F  M% R. m6 |
  11.   * @brief  This function handles PendSVC exception.
    4 [& @2 E8 B6 _! ~2 F
  12.   * @param  None
    ; R# B) Q; z7 s7 J  g' V& B) J" g
  13.   * @retval None# e7 E( O/ v+ G! H: w/ E1 c3 s
  14.   */
    9 V, x+ N2 ^8 N# Q3 W5 `
  15. void PendSV_Handler(void)
    & y, |" J( W% r1 ~' F# t; G# V. ?
  16. {
    4 g, S$ `+ _1 K- v. q4 `
  17. }
复制代码

9 B. v+ N3 \7 `0 S4.10 第7步,添加头文件的汇总文件includes.h
3 C6 ~" q, s: W; b! l& ?5 d在User文件夹下添加文件incudes.h,直接从本章节教程配套例子的User文件夹复制即可。此文件主要用于RTX5的各种头文件汇总。9 X' v1 U/ y; J: W
4 P$ t) Q" P2 D
63fafbc927e6b911f6f3b81c4acb6af1.png
* v* a& Z+ d8 w

: m) G( ?! q  k, j# {4.11 第8步,HAL库时间基准stm32h7xx_hal_timebase_tim.c
+ ^2 F' r% o( h, h/ A( N
由于RTX5和HAL库需要一个时间基准,而且默认都是用的滴答定时器,所有要有一个选用其它的时间基准。当前的处理方案是为HAL库提供一个时间基准文件stm32h7xx_hal_timbase_tim.c。此文件% e) p& B* `) U, F: k( U% h
8 A& B& I6 g1 Z2 v
里面做了两套方案,一个是使用TIM7做时间基准,另一个是使用RTX5的API做时间基准,通过条件编译做选择。默认是采用RTX5的API做时间基准。3 q( Q$ @" @. k

. b8 B1 q) Z: H4 A3 z) u3 }
  1. /*
    " i4 r. h+ ]$ }, |
  2. *********************************************************************************************************
    ( t7 _. h5 Q! K7 u4 ~% h
  3. *    函 数 名: HAL_Delay+ B1 D$ i2 w' [
  4. *    功能说明: 重定向毫秒延迟函数。替换HAL中的函数。因为HAL中的缺省函数依赖于Systick中断,如果在USB、SD
    : v! z- f4 G1 b- ]& f! ^
  5. *             卡中断中有延迟函数,则会锁死。也可以通过函数HAL_NVIC_SetPriority提升Systick中断; Q2 g0 ^2 w, ^
  6. *    形    参: 无
    7 J$ |* `# `0 E* k4 Y
  7. *    返 回 值: 无& {; h& [' j7 I
  8. *********************************************************************************************************
    6 J! [& j! g' [, s# O: D+ C3 V
  9. */
    . S: x' L& _- P1 _
  10. void HAL_Delay(uint32_t Delay)* x. P  I& [% U
  11. {$ M  B; f/ o% f( t9 _0 k
  12.     bsp_DelayMS(Delay);
    - a7 x8 S: u- g) ^1 e, Q
  13. }9 P7 m9 c7 X0 }! N
  14. / J' W" G4 H1 J2 F
  15. HAL_StatusTypeDef HAL_InitTick (uint32_t TickPriority)
    " J& i1 I) m' g1 i& k* h3 r/ J* G
  16. {
    2 M3 t5 _) I: E; n8 E$ l, L
  17.     return HAL_OK;
    , ?9 Z5 s4 ?" Q/ T4 }, ]
  18. }4 n# w# |* l% k

  19. 5 S7 o1 u# R' _5 d9 o( p
  20. uint32_t HAL_GetTick (void)
    5 d2 a' u* G$ X; f% ~# u% ?$ z# A
  21. {
    0 _4 p5 C' g( l5 b" U& s6 X: H
  22.     static uint32_t ticks = 0U;* u, |) P7 J: \; D9 _+ F0 ^
  23.     uint32_t i;" x1 X" V# x; K" ^4 n5 I( F3 v
  24. 9 z2 [! `0 N  \# H0 |: L- T
  25.     if (osKernelGetState () == osKernelRunning)# x) r. u2 L, Z9 z3 g* A" e8 D
  26.     {
    1 ~6 F* G/ {# v/ q+ ?
  27.         return ((uint32_t)osKernelGetTickCount ());2 n  p6 B1 r$ r
  28.     }+ [4 x$ H+ O$ o7 k/ }" {1 d

  29. - r# m0 ^7 @& S
  30.     /* 如果RTX5还没有运行,采用下面方式 */
    8 Z# n, F; E& l3 }/ Z- m
  31.     for (i = (SystemCoreClock >> 14U); i > 0U; i--)
    ' ~' {. i. Y% Y
  32.     {
    8 t, Z4 M# e) t+ h% ?$ G8 [
  33.         __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP();
      c, r# w4 f# {7 b
  34.         __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP();
    ! k4 a0 i8 J: K- {! E; t( n
  35.     }
    + ~6 Y5 r8 ^9 S: Y. o
  36. 5 B7 }4 U% [0 x) R0 K
  37.     return ++ticks;
    8 p9 W& N+ g. s2 T5 B* b4 i! Q
  38. }
复制代码

( P+ M1 G. B7 V6 @' p: h9 J/ l4.12 第9步,添加BSP驱动文件bsp_dwt.c
; A8 x5 s. R2 M9 E
添加bsp_dwt.c文件和bsp_dwt.h文件主要是因为第8步中的stm32h7xx_hal_timebase_tim.c文件里面的函数bsp_DelayMS要使用,此函数是基于DWT系统时钟周期计数器实现。; q1 ]. ^& B  ~7 t5 P

4 i: ~0 x3 u7 C" Z9 T
f0d85f2002a553fa31c8f67b30e2db76.png
7 _  P" ~; L& T

: F4 U+ p! u7 A5 @+ }4.13 第10步,创建应用任务(重要,注意启动任务)
5 B' p: d) ]: I8 A- ^+ Z
应用程序比较简单,大家可以直接复制本章教程配置例子的main.c文件中的内容到自己工程里面测试。主要创建了如下几个任务:* p2 v1 F1 l% X# G
/ Q- k/ w' C& m( ^
AppTaskUserIF任务   : 按键消息处理。
7 q$ X' H! _# g& C
5 m/ @8 T% y% E# LAppTaskLED任务      : LED闪烁。
+ y1 z1 f; f2 J. i5 q/ ?
3 j8 H: h& h& `AppTaskMsgPro任务   : 消息处理,暂未使用。. R* h( [* [! U

4 l- w1 i" `. X8 I3 O: _AppTaskStart任务    : 启动任务,也是最高优先级任务,这里实现按键扫描。
" s! @& n4 I/ B) `+ [4 Y1 L/ V& |# x8 B0 W. q
osRtxTimerThread任务: 定时器任务,暂未使用。
$ [: M; W6 N9 r3 D4 {  b9 ^9 Z1 f+ _3 {9 ?
任务栈大小和任务控制块定义如下:
) }% ~7 J: \! [" P5 _7 o$ y, v
% O6 U6 J+ d& x3 A$ i
  1. /*# n. `' N6 {9 f0 g/ U+ {
  2. **********************************************************************************************************; l% n4 p4 B9 [9 w) }$ [; X
  3.                                              变量
    8 {) e7 ^, F0 Y/ A
  4. **********************************************************************************************************
    - d* a$ \; y0 q2 d6 N
  5. */
    + m  ~0 g- B# H% }) Q1 k
  6. /* 任务的属性设置 */4 r0 E6 A7 j6 m5 `0 Y& r5 S+ d4 E
  7. const osThreadAttr_t ThreadStart_Attr =
    4 P: x  t, ]6 `" j2 }, h" L, i, j
  8. {
    % [- J  f8 A2 A8 E7 F3 S
  9.     /* 未使用 */9 x7 k0 o$ J' o$ g
  10. //    .cb_mem = &worker_thread_tcb_1,
    7 O. V# Y) ]8 g7 m
  11. //    .cb_size = sizeof(worker_thread_tcb_1),
    " T. V: L( \2 @6 N: Q
  12. //    .stack_mem = &worker_thread_stk_1[0],6 Z% Q7 C% h8 U
  13. //    .stack_size = sizeof(worker_thread_stk_1),* I# K4 y3 T% J. A7 R  Q$ H
  14. //    .priority = osPriorityAboveNormal,# z! v* r$ z' Z& f6 {
  15. //    .tz_module = 0' U  x  U2 }+ L# @0 w

  16. 7 |. w/ X( R1 A) F, @$ R
  17.     .name = "osRtxStartThread",% k3 Y  B% x% W; r
  18.     .attr_bits = osThreadDetached, 8 R9 z& {: Y! Q0 E5 L! L
  19.     .priority = osPriorityHigh4,5 _& [+ D2 j' R- a# X" N7 g
  20.     .stack_size = 2048,6 q* q; l8 t7 H* {5 N# O# r
  21. };
    # J  u9 V9 ?4 O' D

  22. 2 n6 s- n+ j8 B  H; Y) f
  23. const osThreadAttr_t ThreadMsgPro_Attr = % ?% b# D' D7 k
  24. {/ W1 ^4 w. R3 N" C$ v( r
  25.     .name = "osRtxMsgProThread",
    ! l1 H, P4 G; L& u3 a
  26.     .attr_bits = osThreadDetached, 0 D0 @& i2 m4 z) H3 h
  27.     .priority = osPriorityHigh3,
    3 \# y+ s# r2 C2 h, Z( y
  28.     .stack_size = 1024,
    , f% F$ m& x  w, Z% b: ^$ q3 O
  29. };
    4 M( @1 o* w) V1 S5 w
  30. ( M; U" E4 t2 A* V
  31. const osThreadAttr_t ThreadLED_Attr =
    * J- Z; o2 U$ l6 s# z  T
  32. {
    % x  D5 n4 h* X; R% ]: |9 u1 E6 f
  33.     .name = "osRtxLEDThread",
    7 v! w: m! {2 i" G
  34.     .attr_bits = osThreadDetached, * b4 V# [: P' L) ^! q
  35.     .priority = osPriorityHigh2,
    ! y% P( U4 [9 i8 B# x! h6 ~# K
  36.     .stack_size = 512,
    ) a$ y$ U  H2 v* \! @
  37. };
    7 ]; K6 s; }$ x0 m) D7 g* Q3 ?

  38. # }2 C# e' F" a5 A; ?9 ]- F; w$ j
  39. const osThreadAttr_t ThreadUserIF_Attr = 8 Z& `& ?& ?; y- ~& ~
  40. {
    " {# c7 l: r! b* v; W5 N) v
  41.     .name = "osRtxThreadUserIF",. @" F+ p6 R) P( L. c: W& }
  42.     .attr_bits = osThreadDetached,
    7 |: p; C, q+ [6 n5 z
  43.     .priority = osPriorityHigh1,) M1 |) k: A" @3 D7 ]( A3 B
  44.     .stack_size = 1024,
    7 {7 c- }6 q" w" J
  45. };
复制代码
6 F' z3 Z0 h+ _
任务创建:
/ b- p6 H% y! h3 a7 ?) [6 }# o/ S2 @% @) v( F) G& l4 |
  1. /*
    * C0 Y# k8 I" B3 V
  2. *********************************************************************************************************
    0 r3 [" F/ H9 J3 }2 E4 }7 T. G
  3. *    函 数 名: main
    3 I1 E- F# W) t# @1 {! X
  4. *    功能说明: 标准c程序入口。, C2 x6 W5 Z) U6 M! k# V& j
  5. *    形    参: 无
    % b& a; G- ^+ v# O5 Y6 |% ?0 c2 L
  6. *    返 回 值: 无0 m( w3 b8 F2 K; o
  7. *********************************************************************************************************1 N9 B4 _2 C0 f3 P( G) U- \
  8. */
    3 x; v+ C9 o" H+ Z9 ~5 L1 Z& y
  9. int main (void) - Z5 U- A( z$ v0 M
  10. {    5 z, e3 [! O$ I6 L
  11.     /* HAL库,MPU,Cache,时钟等系统初始化 */3 F* K2 i% P- h  q
  12.     System_Init();' F1 w* I* T$ P* o2 D" Z
  13. $ P* h' w' M- u9 r( v0 ^/ |/ m9 c) z
  14.     /* 内核开启前关闭HAL的时间基准 */
    # r& \5 N2 c; [4 {+ b
  15.     HAL_SuspendTick();4 }2 R* h% a8 E) J4 |

  16. 5 M2 I* K& }  w7 Q$ |7 W
  17.     /* 内核初始化 */
    & r: m% [' o0 y/ \" l! X! y$ w
  18.     osKernelInitialize();                                 
    ' G' W9 t3 O- B5 j0 p1 W

  19. , R& k" D; o( T2 ?4 M$ j/ e
  20.     /* 创建启动任务 */
    6 N9 v3 H" c  Q& }2 R
  21.     ThreadIdStart = osThreadNew(AppTaskStart, NULL, &ThreadStart_Attr);    v- u, y; g$ ~4 S2 _

  22. 6 h. |0 D, b# k" _
  23.     /* 开启多任务 */' K/ U0 |) t, I' W
  24.     osKernelStart();% S& y7 z* M" n+ J7 ~% d6 P: [

  25. 7 t9 E, E2 k6 ~' z0 A; w1 c. o
  26.     while(1);
    ( ^0 x1 U% D1 X3 B8 i& M7 ]& S
  27. }
    # o- }7 l+ z4 T& B2 ?) ^

  28. - ?0 e! x) g! `, U* j+ {0 G
  29. /*
    9 U2 F' O0 ]. i
  30. *********************************************************************************************************
    ) V. `9 X8 x7 {+ q9 n; o4 K
  31. *    函 数 名: AppTaskCreate
    ( r# {" d/ K9 a! o0 U. o. W/ C
  32. *    功能说明: 创建应用任务
    ; U( ?% x0 M2 L  V9 ?% m
  33. *    形    参: 无
    : R3 F* {9 |! S" n- w* N
  34. *    返 回 值: 无; s+ }- F2 L7 s
  35. *********************************************************************************************************
    ) k* l" z' ]1 j4 {. |2 {
  36. */
    3 C* O1 i& y8 f6 Q+ p2 z/ [
  37. static void AppTaskCreate (void)0 ]5 H+ h8 `- H& |
  38. {# \" y$ h) O! I1 o' Z) Z
  39.     ThreadIdTaskMsgPro = osThreadNew(AppTaskMsgPro, NULL, &ThreadMsgPro_Attr);  . ^) @. z$ w/ b% ]+ y: v7 ^% K( y
  40.     ThreadIdTaskLED = osThreadNew(AppTaskLED, NULL, &ThreadLED_Attr);  
    9 ?' Y1 X& K" u% O# N' ]
  41.     ThreadIdTaskUserIF = osThreadNew(AppTaskUserIF, NULL, &ThreadUserIF_Attr);  
    ( N! {  Z5 z/ h4 y# O4 f
  42. }
复制代码
3 l0 ]3 R- {. |  M7 u
这里我们重点看下启动任务,主要做了四个工作:
6 k2 O7 H* E" a) E+ |- y& @+ T! U2 p
& J( B/ D  S. e+ p  外设初始化bsp_Init。
* J( D2 N( T% p- X; f$ F  任务创建AppTaskCreate。
  S+ z( Q; D4 n9 y  需要周期性处理的程序bsp_ProPer1ms,对应裸机工程调用的SysTick_ISR。这个的实现非常重要,这样之前裸机里面使用的API,就可以直接在RTX5里面直接调用。4 _6 k# e- J$ q* w6 X3 E
  1. /*2 G4 g' E4 m  }
  2. *********************************************************************************************************$ j& u3 m4 [) }0 V6 c( j) i
  3. *    函 数 名: AppTaskStart
    " `. I: x0 u* l, g7 A8 `# L
  4. *    功能说明: 启动任务,这里用作BSP驱动包处理。2 E# c& A# y  O) M
  5. *    形    参: 无; U7 n5 l( C, A
  6. *    返 回 值: 无: w) E7 V9 u4 O2 ^& I+ g8 q3 v. Q
  7. *   优 先 级: osPriorityHigh4  ; M3 p' u+ R( o5 l6 p" i7 s9 H1 o
  8. *********************************************************************************************************
    : C+ y, C0 f  j' b: @* V
  9. */! }: T2 \/ W& k' P* R
  10. void AppTaskStart(void *argument). W2 ?# ^$ O4 t: o
  11. {7 X% X! |% b. v) U$ z: x9 a
  12.     const uint16_t usFrequency = 1; /* 延迟周期 */
    9 \; m8 P/ Q' W3 R
  13.     uint32_t tick;
    + u- v2 j2 d! q, e4 P% ?' l

  14. ; A7 `/ d9 f9 g8 n1 X
  15.     /* 初始化外设 */
    / g- v4 s8 A$ r2 Y" X1 c
  16.     HAL_ResumeTick();* J# p) j4 d4 n/ _5 S
  17.     bsp_Init();7 n) S1 ?% \; E1 v- _0 a
  18. * c* q% O7 @- U
  19.     /* 创建任务 */
    3 j! v$ s' e/ Q2 x5 V
  20.     AppTaskCreate();
      a# S, F$ Z: i; G2 ^

  21. 3 o* l5 U' J  M7 h5 W
  22.     /* 获取当前时间 */- f2 Y" A+ O: H8 n# z, S
  23.     tick = osKernelGetTickCount(); - v+ g: U, s- ?8 s

  24. 5 w* ]! `5 ?" _0 {) m( I6 G& f# u( _
  25.     while(1)
    0 @4 D2 v% p3 L' ]
  26.     {
    ( R$ |. `! B' T8 r  k9 @- A, L
  27.         /* 需要周期性处理的程序,对应裸机工程调用的SysTick_ISR */
    6 Z" o( _# ]$ I- u
  28.         bsp_ProPer1ms();! A% D, p( S2 V/ _

  29. / d. g; ~$ a; e; W) J: _
  30.         /* 相对延迟 */2 V. h5 t$ V+ c. b+ B
  31.         tick += usFrequency;                          
    . B1 }& |9 {  m: M3 b5 g6 m- j4 O
  32.         osDelayUntil(tick);+ l; U9 L- `- t9 j
  33.     }
    / L1 s9 i4 A( u  E% r/ f0 S+ e/ ^
  34. }
复制代码

' a, g. U$ c2 _2 E& J: h, U4.14 常见移植错误总结
/ |" |: `' z. S* o1 r3 E* H
常见的移植错误主要有下面几种情况:4 m. q6 ~" K- \- \  s8 \) U

- g% k; p3 a3 B1 K& U, G4 T  编译后提示如下两种错误:
- z3 x  z; N7 f4 g% d" GError: L6200E: Symbol PendSV_Handler multiply defined (by irq_cm4f.o and stm32h7xx_it.o).
" ~! ^3 q: m2 M3 _$ v
* O# ?; E! k4 E7 M4 lError: L6200E: Symbol SVC_Handler multiply defined (by irq_cm4f.o and stm32h7xx_it.o).
) d* M4 \4 P9 `2 D. E0 j) S" K
+ s1 M; C2 o0 k3 [8 n解决办法:这是函数重定义了,直接将stm32h7xx_it.c文件里面的PendSV_Handler和SVC_Handler删掉。
' C4 k7 v' l4 P* w1 C5 {, G* a. f* z  W4 R. X# s+ ~, Q
  提示如下错误
6 a: E" f+ O% g$ PError: L6218E: Undefined symbol bsp_DelayMS (referred from bsp_fmc_io.o).
7 h* f5 `7 U5 ~6 X: b* W: g2 {9 O5 T  a! ^6 G. r% |( l" K1 o7 \
解决办法:打开bsp_dwt.C文件中的条件编译。7 }5 m# T2 D% L3 P

0 U2 a6 ]0 K$ B, u0 ^! I8 Z8 V9 s4.15 实验例程
, O* c: D8 o* M9 S9 Q* X/ B! w本章节配套了如下几个例子供大家移植参考:* i" g6 q% B9 \4 _3 w
- z  q  F9 N0 [# _* r+ r# v
  V7-400_Base Template
& [1 O5 \- h- s裸机模板,方便大家添加RTX5内核源码。
% y. c; M. I5 q
1 h: i' J' g: a. a$ g( P9 B4 v  V7-401_Threadx Kernel Template
/ s; m; N7 q( p7 [
8 {$ b! A9 X/ v0 B+ S7 fThreadX内核模板。3 W. P/ }+ g3 T+ I3 W; b

" B2 B% B. w/ |" \MDK进入调试状态后,选择周期更新:
# t+ G4 A% k8 ^. ]+ R% {9 Y
* N' A  c7 w. `/ h% e
fdce9fac9944ad56faa0dd13307f6ebb.png
8 ~% x1 ]6 V  v3 B# A

) N! I, K( E6 v' ^3 r5 j. f然后打开调试组件,注意和RTX4的调试组件位置不同:
7 C. n4 @8 R% ^/ U4 ~% E; h3 f$ c$ t
; J9 C5 V2 w9 z. l9 s4 B6 N
9482ce7367ba4d7cf08c73a56db28f75.png

- H# k- y8 g  e6 H, G0 \# ^& Q% N
然后点击MDK的全速运行," C" t; p0 E: C0 Q" y

3 i, z) s; Y2 _
e3038a01781216611f96ae37d5bccb17.png

% c0 W1 r0 ]- {. b1 M/ r0 `
8 Y+ R6 _. K# k0 b8 L; N至此,就可以动态实时查看RTX5的运行状态:+ c- F8 G: o* Q
8 @9 Y4 B+ b2 x& i, [3 U
797f68ea76bd699fe11ce441076df4ec.png
2 c$ M+ ]8 h/ v( H6 K- F% B% h
3 z" I- j" J) v3 J! x6 t. a0 M
4.16 总结5 z% Q! T. j  n2 ?
本章节为大家讲解了RTX5 在MDK AC5上的移植方法,移植涉及到的知识点比较多,初学的话,建议实际动手操作一遍。
9 M! v' X0 N$ q  C3 Z0 q9 Y+ N: p2 s& b

/ p' [9 c. W% _
- A9 M' D/ ^; X8 _
收藏 评论1 发布时间:2021-12-30 14:32

举报

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

好好学习

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版