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

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

[复制链接]
STMCU小助手 发布时间:2021-12-30 14:32
4.1   初学者重要提示
/ l0 m6 ?7 Z. K9 B( d% b3 o3 ]* Z  当前RTX5可以移植到GCC,MDK和IAR三大平台,考虑到仅MDK平台下有RTX5的调试组件,我们这里仅提供了MDK的移植说明。
0 D! e, Y/ b$ u) h9 [# A1 e: m  STM32H7使用MDK RTE环境添加RTX5,需要强制运行一次STM32CubeMX,因为H7已经没有配套RTE经典添加方式,而STM32F4是支持经典方式的,所以无需运行STM32CubeMX,详情可以看我们STM32F4开发板对应的RTX5教程。7 }5 \, j/ I2 @$ X. `4 L! r
4.2   移植RXT5内核整体说明, W! x5 b: K- H! W
移植之前,有必要对移植过程有个整体的认识:( p% o6 X8 q2 Y+ g! q1 K

  e2 {7 g( Q) C3 I0 [  第1步,准备一个工程模板。
1 T) U9 R* A! P) W* N  第2步,移植RTX5。
( v+ a7 r& f8 v3 {  移植RTX5是采用MDK的RTE环境直接添加。当前H7芯片使用RTX5强制运行STM32CubeMX,所以需要大家提前安装好STM32CubeMX V5.4或者以上版本。
6 P4 `9 j: J* L; r2 k3 R  i  第3步,处理HAL库时间基准,MPU配置等。7 j0 n! w8 `/ S/ v3 l- c: Z' y
  第4步,创建应用。
- N: [& d3 b% P8 b/ j4 X( p3 F$ z4 T  s1 U6 l
总的来说,这4步就可以完成移植, 下面将STM32H7的移植步骤和注意事项为大家做个说明。& w( c4 r- e1 a$ b' j: Q% B
" {9 ?- N: }- S* ]+ m2 q: J- g
4.3   了解RTX5内核模板框架设计2 R3 a5 y! @  k* I8 ?8 ~
移植RTX5前,我们优先了解下移植好的RTX5内核模板,方面大家后面移植:2 W: c  H7 g" v) `& H
( Q3 {! m3 G  R- ~
ebf7bed4831890980f518eaeb842a943.png
6 {7 p8 x. S/ v- h$ b

: c8 m; H8 ^& l' d2 v8 u框图如下:
  t4 i6 x- u6 K  L* U; I$ Y6 Q9 P# F" K5 L/ u. O
cc3f4f5af7e41dcb23a03a25e14d8ae7.png

3 }$ Q' k; s/ c. \2 E8 S) d  D% u5 Y/ J0 I9 b
4.4   第1步,安装指定的MDK软件包版本8 Q5 a" O8 u; ]  |
移植新版RTX5需要大家下载当前最新的MDK软件包版本(如果有最新版,推荐大家用最新版):- [& ?+ Q* Y% V4 T- u% ^4 u

& A. F% Z3 Q4 j- E9 }. W0 z7 F  CMSIS 软件包使用当前最新的:V5.7.0
" c* E, Y5 a# |  STM32H7使用当前最新的:V2.6.0: x/ V8 E9 ~( B/ I
  STM32F4使用当前最新的:V2.6.0" I: w; b( k# E; n1 F$ ]4 L% E
  STM32CubeMX使用当前最新的:V6.0.x8 K1 X# x) r+ I
  ARM_Compiler使用当前最新的:V1.6.1+ t1 e4 ~9 Q" }" }" X. c5 r
" O& Q: l" A' i& X+ B
不管以后MDK的软件包版本如何升级,当前的软件包版本和以后的新版是可以同时安装的,也就是说可以安装多个不同版本,在这里可以选择指定版本:6 @+ U1 }# u6 a3 l3 a8 e& T3 I4 F

. I% Q4 X& \1 @2 G- y3 t6 x4 l4 r7 f
bbb84b8c4b3275b1026d2c95b5012294.png
7 W% v' p; P5 Q; D5 n3 a
5 X$ }9 f( D- q0 t- j
4.5   第2步,准备一个工程模板- a% \" k* i: U, p( Z, T
首先准备好一个简单的裸机工程模板,已经为大家做好:V7-400_Base Template,准备好的工程模板如下图所示(大家也可以制作其它任意的工程模板,不限制):
& S0 P7 B4 d# G, I2 f; }4 o  V
" n& s0 V% E0 o
5618d5a487ef825c0a75ce19685c4821.png

( Z$ U9 A" H6 }# R5 @5 d1 `
1 U: @% c0 T5 i4.6   第3步,添加RTX5并配置
" P+ c. v" {7 MRTX5可以方便的通过MDK的RTE环境添加进来。对于H7版本,MDK会强制运行一次CubeMX,并添加很多H7的HAL库文件,这些库文件我们可以使用,也可以不使用。教程配套的工程文件是不使用这些,因为前面的工程模板里面已经添加了。所以要将这些文件全部隔离出来。$ U: V. f$ P& s5 t" {/ ]" o
! n2 L  j  R0 f
4.6.1      添加RTX5源码
5 i1 B) @/ m5 U" x$ X1 R' a
% J0 H9 M1 k; D3 @7 h
48f11b91f9fc45f3f04431047156434d.png
2 D) z2 q& Y6 Q! k3 k% I
3 a  Z  h: L  {9 O7 D
点击OK按钮后,弹出如下界面:; a1 O" k; R) y$ X# X
6 g. |$ T* R9 @( ]8 `7 w) k" [# }# U
b430f5f7b2e1a16de73553adb9dd1f89.png

& w3 @3 l- ~6 e; W7 w. K# K, h) U& o9 T: P$ ~$ Q
点击Start STM32CubeMX,这里需要大家电脑上已经安装了STM32CubeMX,并且为其安装了H7的软件包。
5 D* ^9 ?( [! I6 O1 N: b7 G, _; ~
+ y( Z" J1 S" v
af4f52889e56b18313faf6baa5ed1281.png
; J0 e9 w9 V. n4 ]( V' l
4 n3 g% W3 S2 b6 P; r% V
打开后,用户仅需配置如下地方即可:' M1 L6 a, o% j+ @  E" c) {7 w6 c

. L+ o  `$ b; ?$ l+ n
7c8a9271ba3d0ccb045c81921fd97d0f.png

7 |6 k( F4 @2 U, e, ?
) k: _) d& j& w8 U2 A% z- S7 y: s然后点击右上角的GENERATE CODE:2 ~1 C3 b/ h0 z

( E0 C! z/ H6 B& \* `* l
62747d5251f02d427c05caf48fc46d77.png
. I8 D: \( W  p8 \, Q. c9 T" E8 w
; P9 O& Q" m5 h
然后弹出如下对话框,点击Close即可,然后关闭STM32CubeMX。5 P% k0 S7 N' b
# P" w) X3 g% v' G- `3 N% s
1a4404327c06b66c217f46c74bd48db2.png

, z- j8 D' Y* r5 ~; Q( k* l) s6 s" M2 H
重新回到MDK,会有一个对话框,点击是即可:
/ F! t! R2 O/ h: `% e' [6 {0 m6 Z* p( ?- r8 M
cdfb3b29fdf8c8b60f0d85f8aaa161ff.png
, ^* H3 G4 d" r# ~: f" c" x6 g
" d! k1 N  e2 |( P3 k" p0 D8 j) Q; M
最后就可以看到RTX5源码已经添加到工程里面了:
- x* O7 m$ v$ r( H$ I& T- |; u: C: x' u) G9 G1 L% N- p
e49f340b4464ddd3afb5bf5082de0fdd.png
4 x8 K$ h6 w8 s# {% X

1 o4 b# b+ a" @- t+ n4 y" ^4.6.2      将自动添加的库文件隔离出来
' c$ k  [# L2 u6 B% v/ G  E+ X1 X* T添加的所有文件中,仅RTX5和文件stm32h7xx_hal_msp.c留下,其它文件全部隔离出来,隔离方法也比较简单,比如隔离生成的main.c函数,鼠标右击此文件选择Options for file ‘main.c’: m2 D5 t% y, ?2 o) L' M/ p# Z8 M/ R+ N
0 w- d8 s( E+ z: Q! o; Q$ i$ r
3b989ad148a2ec7c0522490cd84fcf3c.png

; P4 A% |. @% v0 e1 O1 ]
# d% o; @% b4 d5 b+ f% \! [; T' Y然后取消掉include Target Build前的对勾,点击OK:5 [" t# ]2 n. r5 S' W
% j) g0 c. f7 V: Z( Z: O
6652eec0f1078d33b6c1508049d0c922.png

8 I* W) O4 x1 p4 x4 h( u/ b
( v' m  j9 c9 g3 z看到main.c文件上有个红色横杠,就表示已经隔离出来了:
; T3 j0 J$ N; e( K; r
) w, N" W9 u- ?9 _
cafbe4a03ab78632d36b9cf1b050250c.png
+ h6 e9 @) z; I4 X! V; G" C

4 J! z, [! S3 B( H" Z" @/ m" t同样的方法,将stm32h7xx_it.c文件也隔离出来,文件stm32h7xx_it.h不用管。
8 u( E: t! M3 w0 g5 O) ~" ~5 f: W/ r! Q) [$ d
Device下面的这些文件也是同样的隔离方法:
  ^" ]/ H9 r/ n  P% B0 N5 `/ q/ u4 T, w1 N& C/ U, t8 W5 s
f46dbe6e1b27dd459e04cba9849d9ff9.png
& s! P6 S' V+ w* @' F

* ^+ @% |0 w3 S' [" f1 @6 Z只是鼠标右击弹出的界面有些不同:
0 |) y! d* j! L6 Q$ y5 B# g9 O8 `) G. n& M3 g; I; R" k
aeccd1d366ee4da23ceff332ae2f84e5.png

. W$ ^7 y1 Q  A4 z, Z+ E3 A; r' `8 E4 j0 C/ H/ F; l; H2 x
注意stm32h7xx_hal_msp.c无需隔离,其它所有的文件全部隔离,stm32h7xx_hal_msp.c对应的隔离配置是STM32CubeMX,如果也隔离了,编译会有问题:
, K/ ?: }* j) x4 W/ r* R
$ d, G7 Y/ X) W& x3 Y) {
59f0e5e7d43f7ac7e983147c132a42ce.png
; k7 Y, I# O: B8 X$ I, Q. I; ]
. \0 L7 q2 O  E0 A7 n$ ^+ }
隔离后的效果如下:
; U+ q. g; v! _5 P7 \3 S3 I& w8 f, s* i3 ?
573fb2c99aa8ef7ef6f577c106084913.png
, K8 k0 G  L9 \' Q* T

9 x  N* z2 s, }; X4.6.3      RTX5配置
$ G5 V" `" _2 ~  F8 `! k% T剩下就是配置RTX5,设置RTX_Config.h文件即可,移植阶段先按照如下设置配置好,后面章节会专门为大家讲解每个参数的配置含义:
: |3 o8 s$ ?' }) j
0 f4 r6 O% o! _3 W/ W' M/ M
576cda809f95be40653ff18b9682f906.png

+ E$ o1 a5 ~$ h/ e; u
% k5 j. V& a1 x& d7 k4.7   第4步,MPU和Cache配置文件bsp.c0 `& w4 ^* P( l
这个bsp.c文件也比较重要,移植阶段,直接将我们移植好的模板内容复制过去即可,这里把相关的内容为大家做个说明。( A7 g$ ]# ^/ W
0 x" v  f& W/ K1 |$ G
4.7.1      函数System_Init
- ^9 s  H7 _$ ~1 W
系统初始化,主要是MPU,Cache和系统时钟配置,需要在RTX5初始化之前调用。% w9 Q" q1 W) p9 m/ @$ g
* j2 a2 F; P; |* k8 o
  1. /*2 a; \) q. _4 w- t  h5 u
  2. *********************************************************************************************************# G' D. s' }% P- w: `2 Y
  3. *    函 数 名: System_Init: E0 F$ y- v) R6 {
  4. *    功能说明: 系统初始化,主要是MPU,Cache和系统时钟配置) V' x$ H9 z/ c/ q5 m5 }5 N/ [  L
  5. *    形    参:无
    / p% G! Q  `3 k1 h* X
  6. *    返 回 值: 无8 C5 K- ^! v3 E+ E: B$ O
  7. *********************************************************************************************************4 p: G! E) e$ G  X  z6 W! o
  8. */& R/ c; l0 {' ~2 j- ?
  9. void System_Init(void)
    & V- n( X, j! Q8 w
  10. {
    ( p8 \$ G! }" {8 a6 |7 D

  11.   M- `6 q+ }% ?4 v
  12.     /* 配置MPU */1 C$ d- K, @! j3 ^5 H+ C
  13.     MPU_Config();0 Q% ?1 B, s! I5 m: _0 t. n
  14. ! h- }" j# G8 V0 B5 [% X7 }
  15.     /* 使能L1 Cache */
    2 }$ b" p. x* _- P: G" o3 \! a
  16.     CPU_CACHE_Enable();
    ) P* y! X) F/ P7 s, A5 ?' b. j* t

  17. ' R: f% U! \& @; I, T) w+ U
  18.     /*
    & h' I7 X. z& I, P  ~* u8 [- z
  19.        STM32H7xx HAL 库初始化,此时系统用的还是H7自带的64MHz,HSI时钟:
    7 ?3 l, A$ D5 l  x% D2 o* w
  20.        - 调用函数HAL_InitTick,初始化滴答时钟中断1ms。
    4 ^: r8 K9 U4 B+ I7 J
  21.        - 设置NVIV优先级分组为4。
    ( R- \7 C, d8 M) {3 L! {1 ^
  22.      */
    - t+ Z8 Y" Q) v4 c  x  I8 t
  23.     HAL_Init();
    5 q# C1 O% W9 X8 S* ]6 x2 r

  24. 5 W* u3 \8 j- F
  25.     /* , d: p& |! I+ H4 c
  26.        配置系统时钟到400MHz
    # S* @% P: d. `5 N' l8 m7 B7 \3 |% J. X5 w
  27.        - 切换使用HSE。
    $ S5 f% C( s- \% o4 j8 B
  28.        - 此函数会更新全局变量SystemCoreClock,并重新配置HAL_InitTick。
    ; K( h, K$ r4 o: s4 l& u! O  a
  29.     */
    1 X3 [$ E' y# G5 U# u4 t: X
  30.     SystemClock_Config();0 Y, B/ B& b1 }
  31. % F3 z& s/ K& y0 C, S# R" {6 e
  32.     /* 8 n% _5 F$ T9 Y
  33.        Event Recorder:
    $ H, G- [  d2 Y5 _- X
  34.        - 可用于代码执行时间测量,MDK5.25及其以上版本才支持,IAR不支持。$ L% y( x0 X0 Q0 p7 x* ^4 l
  35.        - 默认不开启,如果要使能此选项,务必看V7开发板用户手册第8章; v' ^, e/ l2 S- \1 T7 Z% ^9 i
  36.     */    4 k, A9 t4 x& u) d' y
  37. #if Enable_EventRecorder == 1  
    ( z- X# ?0 C. f  {  e& X& q
  38.     /* 初始化EventRecorder并开启 */
    % f6 W. |) L' s3 H0 @! y3 d
  39.     EventRecorderInitialize(EventRecordAll, 1U);/ n/ U" W0 i  S- O' A
  40.     EventRecorderStart();
    + t% q+ c* w' z' A
  41. #endif
    $ j) g5 B2 h; S
  42. ' [' N5 x; I( j
  43. }
复制代码
  C' `: m/ {4 d4 M4 L
4.7.2      函数bsp_Init
8 \* w4 K( |& C5 W  x) ^6 s( \* n, j- T硬件外设的初始化,这个函数在RTX5的启动任务里面调用。
2 z5 ?* M5 |& i/ ^
2 }; h. o2 n! ?' l
  1. /*
    , h! t# Q* U; d% a3 ?
  2. *********************************************************************************************************2 R0 }8 v6 v$ ^  g, t! m. t
  3. *    函 数 名: bsp_Init0 @" ~) m1 u5 e- N" N; E1 b
  4. *    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次  ?& ^& k: s  D1 X
  5. *    形    参: 无6 G( j/ A9 ]7 S! G$ v2 z7 }
  6. *    返 回 值: 无& ]' i+ ]3 x0 y1 `5 \
  7. *********************************************************************************************************& j1 k9 ^( t: S
  8. */" P* v* [- J$ A4 F) o
  9. void bsp_Init(void)( L; |5 T! F- H9 o
  10. {* v  _0 M0 f5 S" @
  11.     bsp_InitDWT();     /* 初始化DWT时钟周期计数器 */      
    3 Q! Q$ N4 {9 \5 u, [
  12.     bsp_InitKey();        /* 按键初始化,要放在滴答定时器之前,因为按钮检测是通过滴答定时器扫描 */
    ) ?" _, d2 D4 A4 |/ d
  13.     bsp_InitUart();    /* 初始化串口 */* ]+ s8 R8 s' a6 y# `' B
  14.     bsp_InitExtIO();    /* 初始化FMC总线74HC574扩展IO. 必须在 bsp_InitLed()前执行 */   
    $ x* l; V9 ~1 `/ \$ a% F3 H
  15.     bsp_InitLed();        /* 初始化LED */   
    0 n$ k' l/ S5 _! K
  16.     bsp_InitTimer();      /* 初始化滴答定时器 */
    ) v* }4 w+ U3 t) o2 P
  17. }
复制代码

% }. |: ^1 g0 O) H* U1 L- Z# G4.7.3      函数SystemClock_Config
5 _& D! K1 y7 \+ r这个函数主要是完成系统时钟配置。( ^! p/ i2 x4 L5 Y- x3 g

) ]/ C1 }/ o) X( _
  1. /*- {9 ~; y8 L4 t( @% j
  2. *********************************************************************************************************; n$ l# p, o9 d3 [# w2 o: ^* F
  3. *    函 数 名: SystemClock_Config! ^# F% A" I: |
  4. *    功能说明: 初始化系统时钟
    1 e- A. X+ P8 Y
  5. *                System Clock source            = PLL (HSE)8 D1 C4 U2 D. Z0 ?4 v% L* ^
  6. *                SYSCLK(Hz)                     = 400000000 (CPU Clock)# D2 S& u3 ]& h
  7. *               HCLK(Hz)                       = 200000000 (AXI and AHBs Clock)
    + P5 L- y  W7 q0 v4 b
  8. *                AHB Prescaler                  = 2
    ! X$ S: T7 O# P" k, w( d
  9. *                D1 APB3 Prescaler              = 2 (APB3 Clock  100MHz)% M3 ^: i( e! v
  10. *                D2 APB1 Prescaler              = 2 (APB1 Clock  100MHz)
    + B1 x% N7 w/ G! w0 ~3 @3 a. ^, f
  11. *                D2 APB2 Prescaler              = 2 (APB2 Clock  100MHz)8 Y$ r2 I- F( s2 a
  12. *                D3 APB4 Prescaler              = 2 (APB4 Clock  100MHz)/ T" {/ x5 c! [7 U" V# b
  13. *                HSE Frequency(Hz)              = 25000000
    ; n8 H/ H. B! m
  14. *               PLL_M                          = 5
    + }4 O+ V/ n  Z  J/ p8 t( Z5 @
  15. *                PLL_N                          = 160
    5 n  h4 p9 P5 j4 c( Q7 E
  16. *                PLL_P                          = 2( H  y; v$ s1 Y
  17. *                PLL_Q                          = 4% W; _/ l6 T7 j! C
  18. *                PLL_R                          = 2
    9 v! g- z$ u, r0 I
  19. *                VDD(V)                         = 3.3
      {8 @. ^4 @8 r! W0 e5 @* L7 m
  20. *                Flash Latency(WS)              = 41 Z" G6 C3 h/ {8 ^" s
  21. *    形    参: 无
    ( a* y( L& a2 \7 i8 T' t
  22. *    返 回 值: 无6 g. M1 M+ q! Y3 K. A
  23. ********************************************************************************************************** L' Y0 c) r5 w( w) E
  24. */& K( V, M+ Z6 z" [( y1 G
  25. static void SystemClock_Config(void): n3 G' P+ a8 ?) j7 p
  26. {
    % b: b  K* i# S% b
  27.    省略未写* [0 u* H* O* [' U
  28. ) e4 ~: w  K: t7 o8 M6 ]( \% a
  29.    /* AXI SRAM的时钟是上电自动使能的,而D2域的SRAM1,SRAM2和SRAM3要单独使能 */   
    2 L3 X* E2 {! q$ g
  30. #if 18 c1 ?  ?4 B$ |
  31.     __HAL_RCC_D2SRAM1_CLK_ENABLE();
    $ Y7 }4 }% y6 Y
  32.     __HAL_RCC_D2SRAM2_CLK_ENABLE();3 _8 F, c! i4 q# p
  33.     __HAL_RCC_D2SRAM3_CLK_ENABLE();
    4 {, d" P0 C* T& e  G6 a9 k! M) W$ y# ^
  34. ' [$ `' s7 b: K$ O' [+ W0 {
  35.     __HAL_RCC_BKPRAM_CLKAM_ENABLE();      
      c) ^* W- |, ?& }, e6 b: o
  36.     __HAL_RCC_D3SRAM1_CLKAM_ENABLE();
    , l" ~4 F- p$ ^
  37. #endif+ T0 O% s6 R: _0 w( H) `
  38. }
复制代码

6 W. a9 R  C+ D1 A. A这里的RAM时钟初始化比较重要,这几个RAM的时钟都要单独使能。
) ^. i  T4 p- ?% V) T" k) v$ K# J" S6 z! N: y; Z
4.7.4      函数MPU_Config
7 A( C+ e8 B: eRTX5例子默认采用AXI SRAM作为主RAM空间,因为空间比较大,方便我们后制作综合例子使用:6 N4 d8 |0 U2 F7 c2 r2 h
7 N  B$ l( U( f+ X+ K
  1. /*
    % Q& V2 g5 J: u& \0 g
  2. *********************************************************************************************************
    + [, ^& Y* k5 j! `
  3. *    函 数 名: MPU_Config4 R$ Y! ]3 a. N6 S
  4. *    功能说明: 配置MPU
    % C% T1 ~$ ^) l  C
  5. *    形    参: 无7 e5 m- f# r. X3 B* |
  6. *    返 回 值: 无% C; \: L  i  i, c
  7. *********************************************************************************************************
    4 F4 z& d8 \7 P  S- r
  8. */& _: U7 q5 @  m8 l% z
  9. static void MPU_Config( void )0 v' }4 S, e, f
  10. {3 R$ c4 L4 p- C4 g: v0 ]
  11.     MPU_Region_InitTypeDef MPU_InitStruct;2 k4 w$ V( d" k+ Q" G1 u
  12. 8 B; V2 @* P. a0 a7 V
  13.     /* 禁止 MPU */
    3 h: F# j8 c2 G6 N+ ^$ K: q
  14.     HAL_MPU_Disable();
    ' s' K. t) g; d  q% D

  15. $ z  V% H% i# h! c1 \: Y' N$ C
  16. /* 最高性能,读Cache和写Cache都开启 */   
    % c. Y0 g- Y, T
  17. #if 15 _7 }- ?# o% {/ b2 |7 H5 B
  18.        /* 配置AXI SRAM的MPU属性为Write back, Read allocate,Write allocate */  n- C* G& z! G5 N* A2 P# ?- k( P
  19.     MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
    4 j0 D2 m0 j' b+ g# ]# h
  20.     MPU_InitStruct.BaseAddress      = 0x24000000;% Y. E$ {8 \! D  i3 O' Q8 q$ n8 |
  21.     MPU_InitStruct.Size             = MPU_REGION_SIZE_512KB;
    ! w% v& z! W" ]
  22.     MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
      z- ?/ B1 E" _) y. G4 B
  23.     MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;* z  c$ O" }! c& ]9 Y3 ~8 j
  24.     MPU_InitStruct.IsCacheable      = MPU_ACCESS_CACHEABLE;% F' s4 H+ \+ J* K- w) o0 W3 E
  25.     MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;- |+ q6 D6 t; \( e; m
  26.     MPU_InitStruct.Number           = MPU_REGION_NUMBER0;
    ! C7 E* X# p' y/ O" l6 @7 _
  27.     MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL1;
    ! \- I0 X3 J/ b' _
  28.     MPU_InitStruct.SubRegionDisable = 0x00;
      j  ?/ b+ z" Y: C; x% x3 j
  29.     MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;% L7 R- b/ q; m4 {' N6 }5 d
  30. 2 v6 \  h4 ]) q6 @0 h
  31.     HAL_MPU_ConfigRegion(&MPU_InitStruct);
    - E. f+ J$ ]" Q7 a) Y, |) ~

  32. 9 j& y: [; U! [9 m. T5 g0 C
  33. /* 最低性能,读Cache和写Cache都关闭 */
    5 @# j: B0 C+ M
  34. #else' y. X8 B8 T" ~8 Z& u
  35.     /* 配置AXI SRAM的MPU属性为NORMAL, NO Read allocate,NO Write allocate */9 ]& A) M4 |3 ^- E" s9 h
  36.     MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
    9 P) _! b' w% M3 {6 |. x
  37.     MPU_InitStruct.BaseAddress      = 0x24000000;" v9 w5 ^  w7 O" I3 Z* L3 t4 A
  38.     MPU_InitStruct.Size             = MPU_REGION_SIZE_512KB;
    ! t- m' f  @4 `/ r
  39.     MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
    6 c/ F" X% y$ h, Q- }) c
  40.     MPU_InitStruct.IsBufferable     = MPU_ACCESS_NOT_BUFFERABLE;
    + z" p, }  u7 E
  41.     MPU_InitStruct.IsCacheable      = MPU_ACCESS_NOT_CACHEABLE;
    8 o( N, w  v% n) P  X& x
  42.     MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;! ^1 a9 L- Z3 o$ f: k* J$ R
  43.     MPU_InitStruct.Number           = MPU_REGION_NUMBER0;0 G6 R9 m" z8 I5 V
  44.     MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL1;
    % r( p+ O+ {% d! J4 b+ z% r
  45.     MPU_InitStruct.SubRegionDisable = 0x00;! u  F' T2 [8 |" e' S' o
  46.     MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;
    5 U7 C3 G0 |# W5 ?  }; q
  47. 4 g( o6 [+ R% q+ P8 {
  48.     HAL_MPU_ConfigRegion(&MPU_InitStruct);9 Z+ j5 \( S9 p0 F
  49. #endif- L" A& @0 n9 o
  50. % o0 X3 U% }) _" F" @3 E7 Z
  51.     /* 配置FMC扩展IO的MPU属性为Device或者Strongly Ordered */, E6 c* Z/ U" J7 k4 y: i7 I: y% z
  52.     MPU_InitStruct.Enable           = MPU_REGION_ENABLE;" |% y3 s" f' t. X3 q  r. p
  53.     MPU_InitStruct.BaseAddress      = 0x60000000;
    7 V! d3 a; y8 b8 y6 F: X' R
  54.     MPU_InitStruct.Size             = ARM_MPU_REGION_SIZE_64KB;   
    - J$ S) v, D. Y/ M
  55.     MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
    5 o! t$ x9 \2 P9 k* K
  56.     MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;
    * X  o4 I5 X7 T% f3 C
  57.     MPU_InitStruct.IsCacheable      = MPU_ACCESS_NOT_CACHEABLE;   
    + p' K( W' R0 X7 f
  58.     MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
    / R$ x5 {$ d5 u: i. c
  59.     MPU_InitStruct.Number           = MPU_REGION_NUMBER1;
    * y; v1 C' l! z# b+ }9 {, V* ]
  60.     MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL0;: a) K$ J" ^2 y, o/ C
  61.     MPU_InitStruct.SubRegionDisable = 0x00;/ y; w* u. ]' `9 h$ Q
  62.     MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;
    ' B) J9 d  ~- r. b
  63. / C! h! D; D: l) j9 U( w3 L
  64.     HAL_MPU_ConfigRegion(&MPU_InitStruct);7 y1 a$ K$ z/ c. c  G2 V, g1 q8 g

  65. 2 ?+ [- H- f8 k1 J+ V9 X8 |6 f
  66.     /* 使能 MPU */5 A% L: ], k, Z+ D: ?6 X
  67.     HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);7 j! C+ ^  o+ h: i
  68. }
复制代码

! |7 f2 \" g! X( t4.7.5      函数bsp_RunPer10ms
2 P9 d1 ^% W$ R, f9 r1 w) X这个函数里面默认有个按键扫描,如果大家移植的程序里面没有按键初始化,务必要把这个按键扫描函数注释掉。
% G# v4 s$ ~: Z" O. G0 w
) D* c# k1 [' W$ H4 n
  1. /*6 v9 e" ]2 |# J' m# f
  2. *********************************************************************************************************3 x: g* b" l  c5 P8 V
  3. *    函 数 名: bsp_RunPer10ms" |2 y5 X' L& v) o' r
  4. *    功能说明: 该函数每隔10ms被Systick中断调用1次。详见 bsp_timer.c的定时中断服务程序。一些处理时间要求
    3 l, H* T5 ^5 w+ T, x
  5. *             不严格的任务可以放在此函数。比如:按键扫描、蜂鸣器鸣叫控制等。
    9 Q6 G1 G2 e7 R6 C; O7 L
  6. *    形    参: 无
    4 D2 Z& T5 P( _4 Z  j
  7. *    返 回 值: 无. X( @' P6 g& _9 ^
  8. *********************************************************************************************************$ _& F% s+ K: R1 x
  9. */) _/ X; N3 C7 ~% B& ^0 z
  10. void bsp_RunPer10ms(void)7 i2 ^5 i2 F& u# h( k
  11. {0 ]% u; T- d& V" p- S
  12.     bsp_KeyScan10ms();+ n3 T# K: K( i
  13. }
复制代码

" X1 s& ^( M  S% }6 h* b& x) t4.8   第5步,更新bsp_timer.c和bsp.h文件: o: B. r% |9 _* y, g: a6 ]- p+ _' w
更新bsp_timer.c文件是因为此文件跟RTX5都要使用滴答定时器,有冲突。所以大家直接将我们工程模板里面此文件覆盖移植的这个文件即可。$ W0 Y5 U- M+ t0 r+ e6 }
* _5 t. @+ w$ k
bsp.h文件里面要添加一个宏定义,因为bsp_timer.c文件里面做了些条件编译:% y/ a2 R9 \5 ~; k4 w

7 C, j" ~# D* Q#define  USE_RTX    1
0 P7 ]6 k" R. ]! k' g' L9 r6 N. N9 A; ?4 T0 _9 ]1 t
另外,bsp.h文件将大部分头文件都添加进来了,大家可以根据需要,用到那些头文件,使能那些,用不到的,可以注释掉。当然,不注释也是没问题的:3 q( b* A. Q6 y/ b, i" E7 L

( M) Z8 F) ]6 }& M7 j& r% o
  1. /* 通过取消注释或者添加注释的方式控制是否包含底层驱动模块 */" H- z- u( e8 q- {. S
  2. //#include "bsp_msg.h"6 @+ q8 G) V* s
  3. //#include "bsp_user_lib.h"
    ) V, u" s" o7 \& U
  4. #include "bsp_timer.h"( _0 n: M5 v# y2 N- H
  5. #include "bsp_led.h". x/ V5 ^  d2 @% G
  6. #include "bsp_key.h"0 s7 A2 _! M) u6 d% `* h
  7. #include "bsp_dwt.h"
    " l: P: [+ T7 Z& [7 z, H

  8. - S4 y5 ]7 ~0 c4 z
  9. //#include "bsp_cpu_rtc.h"" G$ }- |6 @5 u/ E0 y" H  Y
  10. //#include "bsp_cpu_adc.h"
    . h' l! s1 B4 [. ?
  11. //#include "bsp_cpu_dac.h"
    + f  K$ {  T6 x% P9 M( u
  12. #include "bsp_uart_fifo.h"
    ! w1 z7 E9 S/ s) v  A. z7 U& Q/ b# h
  13. //#include "bsp_uart_gps.h"
    ' w) M' c; G* ]: T4 M; Y2 a
  14. //#include "bsp_uart_esp8266.h"
    + f7 b  J2 Y$ C9 g4 _9 X
  15. //#include "bsp_uart_sim800.h"
    8 r) g6 Y  b: r5 W5 u$ r; _- t

  16. ( z" ~3 \9 ]; H; E
  17. //#include "bsp_spi_bus.h"+ t5 U4 Z' g$ G& ~. i5 o' f+ M
  18. //#include "bsp_spi_ad9833.h"; \1 g% Q7 q8 W7 J+ ~0 ]- |# f1 G
  19. //#include "bsp_spi_ads1256.h"6 H( {+ {4 r* Z. m( ^- Y4 q
  20. //#include "bsp_spi_dac8501.h"
    3 j7 v' g+ f% [" ^/ i
  21. //#include "bsp_spi_dac8562.h"
    : s: g( \* {' H( p0 N3 c1 d
  22. //#include "bsp_spi_flash.h"9 v' Z" _1 @' f! d
  23. //#include "bsp_spi_tm7705.h"
    , @5 n: _# e  H/ ]' j
  24. //#include "bsp_spi_vs1053b.h"" Y2 A/ \2 R, I, A
  25. / b' l1 z% T8 u  G& r1 D1 o' l
  26. //#include "bsp_fmc_sdram.h"
    0 A+ R; @1 P/ H( W$ Q& X" p
  27. //#include "bsp_fmc_nand_flash.h"
    . W0 \$ @% _& r7 |( ~
  28. //#include "bsp_fmc_ad7606.h"
    & P1 b+ u5 w0 |' s2 E) p2 v
  29. //#include "bsp_fmc_oled.h"
    ) h- m) z9 b  K3 A9 s. h- n6 t* d
  30. #include "bsp_fmc_io.h"% O$ Q$ @( E4 C, d. G* E
  31. 3 _- n) f, j8 M3 z% ]3 `
  32. //#include "bsp_i2c_gpio.h"" T9 h- {! z! W
  33. //#include "bsp_i2c_bh1750.h"8 h+ o( @8 ~& F% y$ d
  34. //#include "bsp_i2c_bmp085.h"  w( k; e6 U6 Q/ Z' C9 ?6 M' O( [
  35. //#include "bsp_i2c_eeprom_24xx.h"
    6 e6 T2 o2 Y- p- h! P6 _
  36. //#include "bsp_i2c_hmc5883l.h"
    ; l' k" d$ w9 g* {
  37. //#include "bsp_i2c_mpu6050.h"7 f7 |0 G  y  V9 S0 K! i6 W7 @
  38. //#include "bsp_i2c_si4730.h"% W% N, a* m) W2 B4 V6 w' i
  39. //#include "bsp_i2c_wm8978.h"
    1 I) P" z8 O) O2 o
  40. - H1 {% b* T$ C% U  ^8 @5 t- ?/ E
  41. //#include "bsp_tft_h7.h". b$ r# W* I/ \' M' G- X) v
  42. //#include "bsp_tft_429.h"
    9 H5 s  K/ V% @! {; X, \3 F
  43. //#include "bsp_tft_lcd.h". l% E& ]! I7 F
  44. //#include "bsp_ts_touch.h"4 d8 z+ ?! p4 u6 r  G
  45. //#include "bsp_ts_ft5x06.h". o( }4 ~$ r: T. N) v8 Z' b
  46. //#include "bsp_ts_gt811.h"
    $ y* H, X/ ?# W8 _
  47. //#include "bsp_ts_gt911.h"
    # A* g+ x- _9 d: d1 W
  48. //#include "bsp_ts_stmpe811.h"
    " c. @9 M3 J# N0 Q5 v, e

  49. & n: X! T9 G  m* g; G9 }, x7 U
  50. #include "bsp_beep.h"
    * _6 j1 @) [) |( \6 ]
  51. #include "bsp_tim_pwm.h"& s. s1 r3 j) Y! r8 d; r
  52. //#include "bsp_sdio_sd.h"# E% ?9 p9 c! [
  53. //#include "bsp_dht11.h"9 s8 A  s8 Z1 N! S# }  ]
  54. //#include "bsp_ds18b20.h"
    , h0 G; v# O- q$ ~1 c
  55. //#include "bsp_ps2.h"( a% L% i% s% h5 _, Y! G0 E& X
  56. //#include "bsp_ir_decode.h"- r: W4 a, I) ?
  57. //#include "bsp_camera.h", U; R" J  j8 C" T9 J% d
  58. //#include "bsp_rs485_led.h"  a, p9 Q% \' R1 M
  59. //#include "bsp_can.h"
复制代码
4 I7 j" [, S& u
4.9   第6步,修改文件stm32h7xx_it.c7 z$ X0 m2 q2 B$ c- j
删除此文件里面带的如下函数,RTX5要使用,冲突了。
$ p" i" m  @- ]& @7 R& g0 m/ g! `! ?3 m  R, V, m  G! y! l7 R
  1. /**
    . h3 g# h9 C2 \9 [* E
  2.   * @brief  This function handles SVCall exception.* q1 ]! j6 G, Z  R* b" r$ |
  3.   * @param  None
    7 d7 K  E: m4 v
  4.   * @retval None- B$ U( I5 D( I" _3 U+ k
  5.   */
    + |1 `, s* m2 O7 M) y
  6. void SVC_Handler(void)
    " o& B; G' @! i! n
  7. {- m- t' @! K! s& R$ G$ x# y( Q2 K
  8. }3 a' r  K' {( O
  9. * E' Q/ N- K* D
  10. /**# K3 [+ t/ X% g! _* N5 I
  11.   * @brief  This function handles PendSVC exception.' U- `  j9 m9 F1 ~( q/ L
  12.   * @param  None' h( Y5 H2 s- G- L9 w  A2 X- B% t
  13.   * @retval None- N# \& X, G  N' q/ @$ s/ G/ Z7 ~
  14.   */5 `$ P1 p) R4 o$ P0 _9 N1 W, D$ X
  15. void PendSV_Handler(void)
    % V1 G) {% Q9 ?. z
  16. {
    * v4 k) l5 e! W, u: l
  17. }
复制代码
  Y4 E* D8 R$ W
4.10 第7步,添加头文件的汇总文件includes.h, l: s6 W6 c6 b5 ?0 [, n) l
在User文件夹下添加文件incudes.h,直接从本章节教程配套例子的User文件夹复制即可。此文件主要用于RTX5的各种头文件汇总。6 e8 L4 i) _6 C: m
6 U5 V: y0 e- R" q8 z: B2 ~  C
63fafbc927e6b911f6f3b81c4acb6af1.png

0 G" w# K1 w  H4 ^% v5 Q8 N
; M7 {3 [/ y( A" |% p+ F4.11 第8步,HAL库时间基准stm32h7xx_hal_timebase_tim.c
" W- t3 @2 a! G2 L, \
由于RTX5和HAL库需要一个时间基准,而且默认都是用的滴答定时器,所有要有一个选用其它的时间基准。当前的处理方案是为HAL库提供一个时间基准文件stm32h7xx_hal_timbase_tim.c。此文件
* I; Q% `  D/ f& q. d7 V# ]3 F/ S+ Z4 f8 _9 V3 \
里面做了两套方案,一个是使用TIM7做时间基准,另一个是使用RTX5的API做时间基准,通过条件编译做选择。默认是采用RTX5的API做时间基准。0 ?4 I. L1 v: p) |* D  p( w1 k* w  ]# K
; I6 P6 x9 j  o# W- \
  1. /*5 ?1 `2 V/ c& k$ I# e) C
  2. *********************************************************************************************************" P3 k( i) g6 R& ~
  3. *    函 数 名: HAL_Delay
    5 r( x/ @. f, ]; g
  4. *    功能说明: 重定向毫秒延迟函数。替换HAL中的函数。因为HAL中的缺省函数依赖于Systick中断,如果在USB、SD
    5 z! l  k6 o5 W- s& I
  5. *             卡中断中有延迟函数,则会锁死。也可以通过函数HAL_NVIC_SetPriority提升Systick中断
    7 |0 q& E; h7 h2 v5 U5 h
  6. *    形    参: 无
    ; z/ W" w: }# i& F/ b( H
  7. *    返 回 值: 无
    $ F8 d$ N( [* }$ \' h' P' B
  8. *********************************************************************************************************
    : C3 Q* f, M# Z- E" |
  9. */- f) P- A+ C% }3 _  m- I# D- O
  10. void HAL_Delay(uint32_t Delay)
    4 o* d% O- |2 ^7 M3 w
  11. {
    ! p9 f) {6 r  D9 b  ~# ~
  12.     bsp_DelayMS(Delay);$ e! G( d) c* V" A" S: r
  13. }; ~& {+ z& N- M0 `

  14. ! `6 s: q+ `7 u- z
  15. HAL_StatusTypeDef HAL_InitTick (uint32_t TickPriority)+ w4 r0 ]- h1 ?! z* O
  16. {
    * K( @2 G9 b. i! C
  17.     return HAL_OK;$ C2 `# o' }0 Q2 {! a
  18. }  E4 |) I9 ?3 B$ T, r5 _. ?+ t: [
  19. ! Z; d; t) M9 q( Q) ]& s
  20. uint32_t HAL_GetTick (void)
    2 m1 q. I, d9 o0 J
  21. {5 z7 |) f3 v, g( b8 r
  22.     static uint32_t ticks = 0U;
    ( ]( J0 U; u4 ^
  23.     uint32_t i;( o* |* O% m+ Y& o$ n
  24. 2 p5 i( H/ t0 M# e1 S/ p
  25.     if (osKernelGetState () == osKernelRunning)* c/ a! X1 x% d3 I& k
  26.     {( j+ y3 }6 {7 B0 @; E
  27.         return ((uint32_t)osKernelGetTickCount ());
    3 v# q, O9 Q/ W3 s
  28.     }) v8 E5 F* j( m& \
  29. $ }! U2 C( d  g& I% o1 T5 m+ A
  30.     /* 如果RTX5还没有运行,采用下面方式 */
    ' x& n& C. d. @2 M
  31.     for (i = (SystemCoreClock >> 14U); i > 0U; i--)
    ' _9 o+ Y/ H- L/ Z& l" @: Z
  32.     {1 N* e0 Q. {0 z2 J2 i' p
  33.         __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP();0 c+ i1 E6 q8 b
  34.         __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP();
    " @' l) {3 K, t, q8 r  E& r. w
  35.     }
    $ j) J2 }. o4 c% n0 m
  36. + C, [, z( g* U1 g. T. i9 I
  37.     return ++ticks;
    + I& P6 F2 U. I" V, |% _( R
  38. }
复制代码
. y  m. N$ I& q# \
4.12 第9步,添加BSP驱动文件bsp_dwt.c

9 E9 g3 z2 H+ u; c8 v添加bsp_dwt.c文件和bsp_dwt.h文件主要是因为第8步中的stm32h7xx_hal_timebase_tim.c文件里面的函数bsp_DelayMS要使用,此函数是基于DWT系统时钟周期计数器实现。/ d' s1 x' n) z' S( K
- g- d8 V5 Y: ]8 C% c& M3 n
f0d85f2002a553fa31c8f67b30e2db76.png

4 t: P* y1 G" X: a! j! P  ^+ @$ W( W. Q' m0 }) G* M
4.13 第10步,创建应用任务(重要,注意启动任务)
) R. e' R" s. f% T0 t/ i0 {
应用程序比较简单,大家可以直接复制本章教程配置例子的main.c文件中的内容到自己工程里面测试。主要创建了如下几个任务:
% d8 U1 N) C- F
, K* p& N; q+ B& D7 d/ Z6 `! y5 {AppTaskUserIF任务   : 按键消息处理。
$ _  a3 N) I% b' s
/ u# J7 v  |- I+ n8 F# ?; m2 t- CAppTaskLED任务      : LED闪烁。
; z9 [- }( C  t0 w" g; S# b4 n" k# T7 J7 G
AppTaskMsgPro任务   : 消息处理,暂未使用。' U. Y# E  `' g! B1 W: }) |

2 \* m( x% L% \$ {  `2 |! oAppTaskStart任务    : 启动任务,也是最高优先级任务,这里实现按键扫描。/ ~" H9 s6 W5 R8 H2 j

5 f( G; f& Z  P" qosRtxTimerThread任务: 定时器任务,暂未使用。
0 N3 c: x7 o/ |. T+ R& ~# M. R9 u. E# U7 B
任务栈大小和任务控制块定义如下:
& b- c+ [/ V6 S( v& I5 w# \
+ U% I) L4 A+ P
  1. /*6 E3 S" S  b1 N  Y: B
  2. **********************************************************************************************************  F' s2 e6 G% ~2 K1 N/ _9 a
  3.                                              变量
    - j- R9 j  J/ V! Y
  4. **********************************************************************************************************
    ; r6 J8 E- a2 e# t4 w- r
  5. */5 |; ~, v% R7 h8 Y8 ?. r4 K
  6. /* 任务的属性设置 */7 f1 K* ?- ?0 i# W
  7. const osThreadAttr_t ThreadStart_Attr = 0 ~3 L& n* b* s' ~3 ~, |; @, h
  8. {6 i8 y" L1 R8 q; Q* q
  9.     /* 未使用 */
    9 ]9 Q/ \( l# i2 }
  10. //    .cb_mem = &worker_thread_tcb_1,
    6 P' {. t" I  q
  11. //    .cb_size = sizeof(worker_thread_tcb_1),
    1 E1 `) F; v- z; \( V& m$ x6 l
  12. //    .stack_mem = &worker_thread_stk_1[0],
      G3 @: H0 n8 ~; U
  13. //    .stack_size = sizeof(worker_thread_stk_1),
    6 n5 i0 q$ v$ n8 ?; H6 v; c
  14. //    .priority = osPriorityAboveNormal,
    1 s( g* H  ~4 I- k% B
  15. //    .tz_module = 0+ ]  D9 T5 x: x0 s9 z4 f3 U

  16. 7 m/ U" r1 l* h6 k( Q
  17.     .name = "osRtxStartThread",
    , e( y/ t& W& H7 o) u9 q
  18.     .attr_bits = osThreadDetached,
    6 x& t2 E; b, f! Y* k8 B" _6 c, |
  19.     .priority = osPriorityHigh4,/ x* V* Y6 ^4 A- k, Y: u$ n" l% D
  20.     .stack_size = 2048,9 N: r7 x" r+ ^1 B  q' t; u
  21. };0 R) l5 G% o- \; Q$ f
  22. ( \! [9 x% J# ~- p2 k. X+ x
  23. const osThreadAttr_t ThreadMsgPro_Attr = , C, r5 o8 E4 \' a" Z
  24. {
    * k0 d3 X/ b3 _6 ~' h. G
  25.     .name = "osRtxMsgProThread",
    ( ~' R8 b+ L8 m% R, Z* `
  26.     .attr_bits = osThreadDetached, & a7 }9 Z4 Q$ ?# x" x, V, i
  27.     .priority = osPriorityHigh3,1 x6 p% V3 X$ `1 p' {
  28.     .stack_size = 1024,
    4 V- k  C& F) V
  29. };% |1 H7 h# ~% W/ k3 Y( s' E/ @
  30. 9 E+ ~/ W5 Z5 e. z: i8 r& t
  31. const osThreadAttr_t ThreadLED_Attr =
    # c4 h8 b$ ~( O
  32. {
    - g& Q1 P" o( Q% a+ s! _
  33.     .name = "osRtxLEDThread",
    ) M7 O8 b: [: q6 u+ W
  34.     .attr_bits = osThreadDetached,
    2 r+ o) o+ f/ A4 x  M
  35.     .priority = osPriorityHigh2,
    ) F4 v4 V* I! m$ p" V. R: Z* \
  36.     .stack_size = 512,4 y# }9 F- I$ f1 u8 O
  37. };% M% H& A( K$ j6 m4 Q5 m

  38. 1 n' L- @8 H2 s% J2 g* C  x! `
  39. const osThreadAttr_t ThreadUserIF_Attr =
    4 f( ?  _2 U5 y
  40. {
    # K7 v) y- S% u' g
  41.     .name = "osRtxThreadUserIF",
    , i9 x9 y" R5 m1 a" M
  42.     .attr_bits = osThreadDetached,
    7 [0 _# m  f1 }, `4 @8 ]. j
  43.     .priority = osPriorityHigh1,
    0 v& ^% ~) J- w7 {
  44.     .stack_size = 1024," Q+ h% |+ H7 |; C9 O  P# @
  45. };
复制代码
* V! ]  `& w4 q6 d: y/ E/ @' ~1 K% d7 b
任务创建:
* ]& c) z; h* \9 g/ N$ O) L% t& Y4 q! u) Q: {7 R- Q; f
  1. /*2 @7 [$ H* ~9 b* d' @" l3 j7 h( w
  2. *********************************************************************************************************
    ; T+ P; x" [2 S% ^/ Q+ |7 M
  3. *    函 数 名: main! |2 |% v' O$ e  E! b( o8 L4 I
  4. *    功能说明: 标准c程序入口。6 P) M  n. i5 L8 F% F% B9 b
  5. *    形    参: 无
    4 u9 \! t- X# d' T$ u: T. A5 {7 a
  6. *    返 回 值: 无
    9 |4 y. @- Y% H5 |
  7. *********************************************************************************************************4 @1 S$ c4 {+ G9 b/ W# j8 ^
  8. */
    1 ~' x2 D. t+ I0 e5 l. H
  9. int main (void) 6 j8 H( X" o4 v' \% u
  10. {   
    + ~! i9 ^; G' r
  11.     /* HAL库,MPU,Cache,时钟等系统初始化 */) P" w- L" K, {" w) Q; L6 c
  12.     System_Init();
    ) G  P, R; [. ~6 T' R$ T

  13. + Z. w$ [' I. \0 s2 p/ ?7 H! J
  14.     /* 内核开启前关闭HAL的时间基准 */
    - W7 z* m2 _: R
  15.     HAL_SuspendTick();
    : S; \+ h2 @* y8 b& P

  16. 7 ]0 |3 ]* ^7 ]* x
  17.     /* 内核初始化 */
    & T* K$ X9 `8 W" |, {( K
  18.     osKernelInitialize();                                 
    $ }" `% k# j9 Y; b. Y
  19. 9 l! Y8 F/ m, l( H2 D4 X4 F8 s8 x7 u2 F" @
  20.     /* 创建启动任务 */1 h% w. k# X* c2 C8 {+ k' h6 K
  21.     ThreadIdStart = osThreadNew(AppTaskStart, NULL, &ThreadStart_Attr);  
    ' l3 D- V* e8 _" B1 x" R' A& c
  22. 2 \9 C) J9 y( U! [
  23.     /* 开启多任务 */1 o' U2 `2 Y! }- l+ k
  24.     osKernelStart();: E1 X6 `. J- D4 q

  25. ! ^* \6 d: P$ A7 F% Z' J3 x
  26.     while(1);( Y+ b* L/ V3 [
  27. }, ?' i( D" C; @

  28. ; Y; z5 ^" p9 H/ n' ], ~( d
  29. /*
    # o% j$ z4 r2 V/ m' U
  30. *********************************************************************************************************
    7 D$ R9 F" a7 P" v/ I1 B
  31. *    函 数 名: AppTaskCreate7 m/ T  u' i6 J
  32. *    功能说明: 创建应用任务
    3 e) _4 K' U) s2 a$ ~& P
  33. *    形    参: 无# g+ u/ g. x( w$ z. V& D/ o1 j
  34. *    返 回 值: 无
    / p3 d2 x/ K/ U, R0 @
  35. *********************************************************************************************************
    # r# z5 r, K# ]/ f: {2 }: m" t
  36. */
    . l  Z6 J* R; g+ m) u7 _
  37. static void AppTaskCreate (void)" w1 K  b; e/ Y/ ^3 h) i- I3 V
  38. {! t. q3 v; v+ g8 U
  39.     ThreadIdTaskMsgPro = osThreadNew(AppTaskMsgPro, NULL, &ThreadMsgPro_Attr);  
    ' E( I# O4 r3 g; B# S1 d- M7 Y$ j
  40.     ThreadIdTaskLED = osThreadNew(AppTaskLED, NULL, &ThreadLED_Attr);  6 L/ |: z8 j8 F: E$ B6 J! c
  41.     ThreadIdTaskUserIF = osThreadNew(AppTaskUserIF, NULL, &ThreadUserIF_Attr);  
    " R) n2 ]9 g1 y" n4 \; t
  42. }
复制代码

# |/ P3 e8 x* j! J4 h. R: {这里我们重点看下启动任务,主要做了四个工作:# c( f, s$ X0 {! t8 u. H% O

# ~; f$ N1 S5 R1 B! N. W( W  外设初始化bsp_Init。3 M9 K8 W6 {, q" |$ }
  任务创建AppTaskCreate。, Z4 h  `: K8 C/ L/ Z$ ]
  需要周期性处理的程序bsp_ProPer1ms,对应裸机工程调用的SysTick_ISR。这个的实现非常重要,这样之前裸机里面使用的API,就可以直接在RTX5里面直接调用。
% z9 C- h  C! V( R7 S
  1. /*
    / l$ G5 K- X* e3 @. v* H
  2. *********************************************************************************************************$ w/ S1 F/ v5 L; j) X
  3. *    函 数 名: AppTaskStart8 S% T$ Q3 Q  J" p* {4 G
  4. *    功能说明: 启动任务,这里用作BSP驱动包处理。% f  s; Y) R& {3 l) ?* I1 g/ k
  5. *    形    参: 无
    $ a: V  `! g6 q4 s; ?& ]) R+ p! `
  6. *    返 回 值: 无
    5 t9 Q5 `! J7 k( }8 E7 U* r
  7. *   优 先 级: osPriorityHigh4  
    ! J/ U9 G- D+ u/ a4 y+ v9 v
  8. *********************************************************************************************************2 N' l) [! h8 W
  9. */' P" Z: w' b1 P5 S
  10. void AppTaskStart(void *argument)
    1 ]' U- q: ~0 Y. j: g* ?9 B2 V
  11. {6 W* ~6 t& o; C# s# ]- x# ?/ H: S
  12.     const uint16_t usFrequency = 1; /* 延迟周期 */  h0 g! `$ |' q$ v9 n
  13.     uint32_t tick;
    ' f- z9 A* [* X0 s0 w
  14. 2 d: R  Q+ E7 l: j! U! k
  15.     /* 初始化外设 */
    * X: N. l4 C" j. S) }
  16.     HAL_ResumeTick();8 u0 o6 u. B5 T6 g. n
  17.     bsp_Init();
    $ s2 T: I7 E  {& l* |
  18. 6 S; A, v7 ]# W, E
  19.     /* 创建任务 */* L. H, U; V$ o. L* h+ _
  20.     AppTaskCreate();7 [( k( ?7 L3 k, M
  21. 4 E" v" T0 B% f3 P$ |9 g$ G
  22.     /* 获取当前时间 */
    4 }- T. x; v$ N8 i% a
  23.     tick = osKernelGetTickCount(); 7 L/ n* t% K8 G" E7 s! K6 a

  24. 8 }9 E4 Q* l; E1 F5 c3 N$ R
  25.     while(1)" i, x3 `# @& @0 I
  26.     {
    * G' ?: O9 n9 H$ s( @( }# B5 R* g
  27.         /* 需要周期性处理的程序,对应裸机工程调用的SysTick_ISR */
    6 i  `. o- r) c  ~, u5 s
  28.         bsp_ProPer1ms();) `$ N* o4 t/ }) l4 O0 I

  29. 8 E; R! x  X5 Q0 U
  30.         /* 相对延迟 */6 f; i% u  W' q% E  u9 l
  31.         tick += usFrequency;                          
    ( r# B) b! s) c# N+ I/ U
  32.         osDelayUntil(tick);; `0 W6 c% B" S+ B. H
  33.     }
    / q* U+ J- A" e. _
  34. }
复制代码

' o5 A5 u* F; p2 M6 B9 a" _4.14 常见移植错误总结
/ u" v$ h) p# |+ ]7 c8 C' C* D
常见的移植错误主要有下面几种情况:! s7 L; m' f) S- B' h7 M" u, e
6 _9 q7 F1 b' T0 V
  编译后提示如下两种错误:/ P6 ~7 f+ K" D) v  [
Error: L6200E: Symbol PendSV_Handler multiply defined (by irq_cm4f.o and stm32h7xx_it.o).
; n  `# ^2 |5 d% B( |2 T6 @1 w
! }; O$ x( X0 }Error: L6200E: Symbol SVC_Handler multiply defined (by irq_cm4f.o and stm32h7xx_it.o).8 W1 A8 d1 G, i# ]' J5 Y
8 B$ w& d0 o+ ~7 h
解决办法:这是函数重定义了,直接将stm32h7xx_it.c文件里面的PendSV_Handler和SVC_Handler删掉。3 g$ @4 A* i; ~% @; \6 N+ c/ G( X
- \( R" r$ e/ q7 l/ S) R7 \5 m- @
  提示如下错误
6 `8 t* x0 }  W/ R* sError: L6218E: Undefined symbol bsp_DelayMS (referred from bsp_fmc_io.o).- R( n/ \3 d. C- v7 g7 y$ a& u

  |5 _1 k7 t' v& r3 F8 r解决办法:打开bsp_dwt.C文件中的条件编译。
& V9 v# _1 J  Y0 X1 ~
' a! y8 i- `3 u' R3 Z4.15 实验例程' r- N% f% W; `; m
本章节配套了如下几个例子供大家移植参考:4 A0 p! i; {/ E0 Q7 p

& S- L, q) S1 X' }$ A) H  p  V7-400_Base Template
$ |* P) j* Z$ E4 J7 f% y裸机模板,方便大家添加RTX5内核源码。
, J" L' ?# B) @; d3 \& ]& P' y0 c. Z0 e' }+ m
  V7-401_Threadx Kernel Template
1 \+ R$ o; c- ^& u8 O( `7 z" m9 @: f6 H% g5 S: I
ThreadX内核模板。
; @1 J" B+ K" k% V) K9 k: t% F  t8 e) Q/ T4 t5 h" V
MDK进入调试状态后,选择周期更新:0 `, {/ h6 q6 H( j* C4 [8 O6 p2 j

, w7 B8 h9 Y3 w2 U2 z+ D
fdce9fac9944ad56faa0dd13307f6ebb.png

' C/ Y7 l# S6 F0 ?3 W* U) O( V4 b6 T2 o6 P9 p& O
然后打开调试组件,注意和RTX4的调试组件位置不同:/ m/ I9 N' x9 N0 k2 P, R
( |$ i- V9 l4 G# |
9482ce7367ba4d7cf08c73a56db28f75.png
. M* H' K5 [+ H* {

7 f/ m6 h4 [& r8 F然后点击MDK的全速运行,
. J8 w1 s5 x% L; D  C7 e- ?" ~
/ w+ Q6 r3 Y% L# |' @
e3038a01781216611f96ae37d5bccb17.png

; n  f6 w: w# g" d6 a  L  o# c, H, Z) U8 r
至此,就可以动态实时查看RTX5的运行状态:" y) C( b9 l; E& C

1 q: V2 v9 f# L
797f68ea76bd699fe11ce441076df4ec.png

9 u: b- i+ h; |/ u9 j
, Y4 {: M' k6 E7 h4 a$ P5 d8 e4 O4.16 总结
5 i5 t  ?# g# D* I9 R本章节为大家讲解了RTX5 在MDK AC5上的移植方法,移植涉及到的知识点比较多,初学的话,建议实际动手操作一遍。* I/ x: X  e. |& D5 |2 v
% x+ Y7 n% P5 ^) `/ Q; C, `5 d7 j

$ t. a/ Y. s1 m7 T8 a9 a, L# V6 G% {% o* ]; h  {
收藏 评论1 发布时间:2021-12-30 14:32

举报

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

好好学习

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版