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

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

[复制链接]
STMCU小助手 发布时间:2021-12-30 14:32
4.1   初学者重要提示; L. C7 T3 l; a- y
  当前RTX5可以移植到GCC,MDK和IAR三大平台,考虑到仅MDK平台下有RTX5的调试组件,我们这里仅提供了MDK的移植说明。  k( _8 p: d* o* {6 w: f8 ?
  STM32H7使用MDK RTE环境添加RTX5,需要强制运行一次STM32CubeMX,因为H7已经没有配套RTE经典添加方式,而STM32F4是支持经典方式的,所以无需运行STM32CubeMX,详情可以看我们STM32F4开发板对应的RTX5教程。* P# Y0 ?0 }4 }  a: n0 w% g
4.2   移植RXT5内核整体说明
: `; r% p# c9 Z, b! W/ i移植之前,有必要对移植过程有个整体的认识:
& T6 T5 @# m% c
) X5 p( x. j# T/ |  第1步,准备一个工程模板。: C& `- {  d: L* e; ^$ u8 h* E! f
  第2步,移植RTX5。7 a5 O8 K: N5 R! B; e9 s2 A
  移植RTX5是采用MDK的RTE环境直接添加。当前H7芯片使用RTX5强制运行STM32CubeMX,所以需要大家提前安装好STM32CubeMX V5.4或者以上版本。: C# N8 b3 q3 s3 `" N* s
  第3步,处理HAL库时间基准,MPU配置等。! u, s" ?) N( i2 X8 s
  第4步,创建应用。* ]. v4 m$ y7 u3 N; l

! J+ v4 q7 X! h/ @3 Y- y: ]  Y! b总的来说,这4步就可以完成移植, 下面将STM32H7的移植步骤和注意事项为大家做个说明。9 v; A5 |6 ]" x! }3 x7 e
' \+ e6 k# ^& Q: d% d
4.3   了解RTX5内核模板框架设计
$ x3 A* i" D) K. U% [9 H! v. _移植RTX5前,我们优先了解下移植好的RTX5内核模板,方面大家后面移植:! X# Y/ s" X. r  y' e
9 ^! k# S8 a/ G% P" Y
ebf7bed4831890980f518eaeb842a943.png

( E1 n( F1 ~9 Z+ P9 `- f" d# w, H# M/ y1 J" i, ^- Z
框图如下:4 ^  `8 @! n" _. z0 S6 a

/ |% I! E# S: u% C% p
cc3f4f5af7e41dcb23a03a25e14d8ae7.png

- n+ V$ A1 U) [7 m% X) [
+ U; G* C+ t/ y$ n3 f; {4.4   第1步,安装指定的MDK软件包版本/ [' f: h) `5 y% c
移植新版RTX5需要大家下载当前最新的MDK软件包版本(如果有最新版,推荐大家用最新版):
. w$ \0 {1 s9 }- D1 d. a& b' w# G8 H/ i$ U6 J
  CMSIS 软件包使用当前最新的:V5.7.0
# A! g, h! F) [) }& b( A  STM32H7使用当前最新的:V2.6.01 R) w2 f2 s( x, [2 X7 s
  STM32F4使用当前最新的:V2.6.0
* ^/ F% u0 h, i7 ]  STM32CubeMX使用当前最新的:V6.0.x
" Q( z- L$ q& ^: _* D; K  ARM_Compiler使用当前最新的:V1.6.1
; p" T7 D! G$ T2 ^, _4 A; |- f. v) i. D" f
不管以后MDK的软件包版本如何升级,当前的软件包版本和以后的新版是可以同时安装的,也就是说可以安装多个不同版本,在这里可以选择指定版本:
, N  W9 C! |. l7 N4 O5 P. T, \1 K+ u" |# B
bbb84b8c4b3275b1026d2c95b5012294.png

1 l+ |, L: ^- N+ B4 U8 h: K9 x5 N0 t/ U; g
4.5   第2步,准备一个工程模板! V+ e; C4 j2 }* a/ z$ n$ k
首先准备好一个简单的裸机工程模板,已经为大家做好:V7-400_Base Template,准备好的工程模板如下图所示(大家也可以制作其它任意的工程模板,不限制):
! p7 O$ Q6 u2 q0 Z1 p" z
4 K: V9 `" u3 u6 \* C) j
5618d5a487ef825c0a75ce19685c4821.png
8 J, a8 x, i0 j1 v3 B4 |8 o

. n- x! d5 Q" T$ E  b  {" n4.6   第3步,添加RTX5并配置: b- @3 |5 c1 L4 M" c! F
RTX5可以方便的通过MDK的RTE环境添加进来。对于H7版本,MDK会强制运行一次CubeMX,并添加很多H7的HAL库文件,这些库文件我们可以使用,也可以不使用。教程配套的工程文件是不使用这些,因为前面的工程模板里面已经添加了。所以要将这些文件全部隔离出来。. a, _; u: `) g/ {/ `5 I
+ D3 v$ t  m) o0 T0 h. j& v
4.6.1      添加RTX5源码
5 D% F1 e/ d  f/ x" q8 W/ `* v7 P% Y/ t4 K! h1 z0 y
48f11b91f9fc45f3f04431047156434d.png
, N1 R5 m+ a5 E& B9 ~6 W2 |5 _

$ L( u7 {) e# W; G- y# f% {点击OK按钮后,弹出如下界面:
3 o( \+ u3 Q; v4 A5 B! D; j% \1 r1 @+ \/ N* N
b430f5f7b2e1a16de73553adb9dd1f89.png
1 N( z. j4 d# x5 G8 z

; M) p8 u  g/ J! e5 J  x1 e- p点击Start STM32CubeMX,这里需要大家电脑上已经安装了STM32CubeMX,并且为其安装了H7的软件包。
& C, K$ q% B/ ]: V' J; \! N9 m4 R, A* k; p
af4f52889e56b18313faf6baa5ed1281.png
' C1 t- D2 P. J: A' M  {
- b- a8 x3 _; e7 n( k/ r: n
打开后,用户仅需配置如下地方即可:1 Q; ^" H) L' b2 u6 ?+ F
7 Z9 g# [! M8 Z! F  i
7c8a9271ba3d0ccb045c81921fd97d0f.png

& G% q5 d: C/ b3 v0 a0 I& p" z" ?& V( ^2 _/ _1 F
然后点击右上角的GENERATE CODE:
; f3 d( n7 s! f+ b0 G
9 k$ W5 f" @! j0 o
62747d5251f02d427c05caf48fc46d77.png
# Y3 |6 T3 f/ ~" q) w
+ K+ r" x3 P6 [4 p/ T
然后弹出如下对话框,点击Close即可,然后关闭STM32CubeMX。( j2 `% ]$ ^5 b  y2 n  `
7 n0 Z* k4 Q) N8 {0 G. Z  G# p
1a4404327c06b66c217f46c74bd48db2.png
' n1 s3 e8 d$ q7 G, `* r7 a

7 j& ?4 _0 E' v& h: C. g8 ^重新回到MDK,会有一个对话框,点击是即可:! _; ]5 ]$ l( F# F: q
  p. L6 C3 C+ @8 }! g- Y
cdfb3b29fdf8c8b60f0d85f8aaa161ff.png

5 F5 I4 Y- o: B
* H- J# c3 J! H) P; d' P% g最后就可以看到RTX5源码已经添加到工程里面了:& j" v7 T6 C3 P
1 o6 c6 q% P6 I8 L* O5 J
e49f340b4464ddd3afb5bf5082de0fdd.png
2 R2 o' d; O2 I* }
/ w8 V6 ~; g5 e/ w" h+ v" R7 s
4.6.2      将自动添加的库文件隔离出来/ W* w) c' x! g2 s
添加的所有文件中,仅RTX5和文件stm32h7xx_hal_msp.c留下,其它文件全部隔离出来,隔离方法也比较简单,比如隔离生成的main.c函数,鼠标右击此文件选择Options for file ‘main.c’
  f( x7 p) D7 A+ }0 n. Z/ G8 z; R7 K4 R4 k) |) \( t; e, Q. q/ _
3b989ad148a2ec7c0522490cd84fcf3c.png
$ }& y! X; q9 N7 d7 o
* X- M) H9 N# K
然后取消掉include Target Build前的对勾,点击OK:
7 J9 D, v+ [$ I4 L, H5 C
5 A) J6 {% F) ]. K
6652eec0f1078d33b6c1508049d0c922.png

+ A8 y: H5 `2 g/ _! q: F; {
4 L% @3 H/ [! j看到main.c文件上有个红色横杠,就表示已经隔离出来了:8 s3 ?  }7 ?( c5 O6 Y! L: \+ k
( O! U3 I5 n- I
cafbe4a03ab78632d36b9cf1b050250c.png
! b7 F; ~. h2 o8 I" l
; i9 w3 w! f* U8 ]
同样的方法,将stm32h7xx_it.c文件也隔离出来,文件stm32h7xx_it.h不用管。# A/ `; B' p0 x+ {& }
" L: }7 C. E& H% v9 J
Device下面的这些文件也是同样的隔离方法:, z& S% G" z( J

( m* W5 J4 O0 u* |: ~" m3 G) _
f46dbe6e1b27dd459e04cba9849d9ff9.png
2 c& G) ?5 _8 V* Y

7 n1 G+ n0 U/ `3 p5 L只是鼠标右击弹出的界面有些不同:
3 A, x6 ~" |* S! E! X
) [1 @7 h/ Q) s( K
aeccd1d366ee4da23ceff332ae2f84e5.png

  j' q' }/ O! N) o& B4 Z
" @) `9 y0 U2 W' J* r. J, J注意stm32h7xx_hal_msp.c无需隔离,其它所有的文件全部隔离,stm32h7xx_hal_msp.c对应的隔离配置是STM32CubeMX,如果也隔离了,编译会有问题:" C# a; X2 S+ G4 Z/ t- B

6 A/ k$ X# M) _9 P3 p
59f0e5e7d43f7ac7e983147c132a42ce.png
  s3 c$ T9 Y1 Z
8 N1 ?0 E2 A- s; ]" J* O. c
隔离后的效果如下:
4 I$ S( @5 }7 s- w+ l, W1 i
; V$ r( J% H4 E4 ?8 }# _
573fb2c99aa8ef7ef6f577c106084913.png

" W$ V% w: z9 E2 G  v* l# r
% U) Y  G5 t  r3 R4.6.3      RTX5配置/ _# D4 Q" c3 U9 `. W# t9 s7 U
剩下就是配置RTX5,设置RTX_Config.h文件即可,移植阶段先按照如下设置配置好,后面章节会专门为大家讲解每个参数的配置含义:7 H( j  O  r% V4 {& r0 a& y

/ K4 s9 I, n6 z2 Y9 t
576cda809f95be40653ff18b9682f906.png

: w" l: P( v  J1 H# A
9 a) G* T0 P, K5 U7 z4.7   第4步,MPU和Cache配置文件bsp.c0 C  F' \, K& K( Y3 w( k
这个bsp.c文件也比较重要,移植阶段,直接将我们移植好的模板内容复制过去即可,这里把相关的内容为大家做个说明。
5 ~$ }  x8 b3 I0 d& X
2 ~! b7 n6 g& w  W5 V- l5 x+ A4.7.1      函数System_Init

% m) b$ l4 I( h4 |! N7 M系统初始化,主要是MPU,Cache和系统时钟配置,需要在RTX5初始化之前调用。3 w0 J0 _5 ?2 _: r- [# O$ T4 ?
$ Q9 `4 l" v& h  ^- d3 F" w  m, y
  1. /*
    3 `8 L3 Y# W  ~! l
  2. *********************************************************************************************************
    ' i4 W/ m5 C, [$ R3 L
  3. *    函 数 名: System_Init
    " G) g. E( Z6 i
  4. *    功能说明: 系统初始化,主要是MPU,Cache和系统时钟配置
    - a2 t) Z7 B% U: U  j
  5. *    形    参:无
    : n; g9 f/ j7 s, f3 I6 z% L
  6. *    返 回 值: 无
    9 [  ^6 S/ l/ f4 l, Y
  7. *********************************************************************************************************
    4 K$ Z, B& Y- {$ F' D& s7 A6 r1 h
  8. */
    & e! ~4 S, W, d. z
  9. void System_Init(void)+ z/ o9 f  _! x0 c
  10. {
    8 y/ W, ^# @( p* K

  11.   g$ A% @; ^. L# l! h- i6 m
  12.     /* 配置MPU */" O: [% Y9 g/ j) x5 y- E& V5 G
  13.     MPU_Config();% k. h! K% o6 R  Z+ D

  14. + _. t5 b7 |8 E3 O5 ~0 L
  15.     /* 使能L1 Cache */7 c0 ^: u0 {- ?' ]
  16.     CPU_CACHE_Enable();  h: l* N( V, m4 F2 j" o
  17. 4 q/ Q8 @% J$ S5 \$ I! `' z
  18.     /* - ^. |4 @! _: o7 q8 S" R5 G
  19.        STM32H7xx HAL 库初始化,此时系统用的还是H7自带的64MHz,HSI时钟:
    ' P: {9 @' S( v! @& `# S
  20.        - 调用函数HAL_InitTick,初始化滴答时钟中断1ms。" e" J% n7 e  A; |+ r  }
  21.        - 设置NVIV优先级分组为4。3 @3 q8 @/ e1 g# v
  22.      */" B' d4 l0 J$ }; c3 M
  23.     HAL_Init();. v- \1 o: X6 A: M; u. {

  24. 9 ]  \9 q4 \$ c, s% d; ^* R
  25.     /* : K9 x. O/ D6 c- ?6 j
  26.        配置系统时钟到400MHz7 P1 B2 s& @# c% i7 J5 Z; i* d
  27.        - 切换使用HSE。
    % U4 ~* b, ~2 X9 @; v
  28.        - 此函数会更新全局变量SystemCoreClock,并重新配置HAL_InitTick。" G/ N: r0 Q$ z
  29.     */4 O$ T; R, C4 a( m
  30.     SystemClock_Config();
    ! m7 I  [' S4 z8 u$ F

  31. - D4 h% p% c4 i
  32.     /*
    - j/ [6 O% D- K" h  ~; E6 H6 F
  33.        Event Recorder:# w/ X) {$ Y* i7 K
  34.        - 可用于代码执行时间测量,MDK5.25及其以上版本才支持,IAR不支持。
    7 C+ g  i9 Y7 U8 r' j9 {2 A
  35.        - 默认不开启,如果要使能此选项,务必看V7开发板用户手册第8章
    * Z9 y" [1 S4 I$ Q5 P2 Z& ^
  36.     */      ]' V$ |! i3 q/ m5 ]& ~& _
  37. #if Enable_EventRecorder == 1  0 {8 O: O( h1 v
  38.     /* 初始化EventRecorder并开启 */5 }' _# R; V4 b/ I
  39.     EventRecorderInitialize(EventRecordAll, 1U);! s8 w$ L% E# n4 L* T
  40.     EventRecorderStart();
    3 ~* }1 n/ k& ~  q" L
  41. #endif3 g: p! h8 N# L8 I
  42. ; v; q  s; Z) H
  43. }
复制代码

5 c- O- \) {# ]1 q4.7.2      函数bsp_Init0 L# ^9 M4 q0 i& d" q2 x% }3 r
硬件外设的初始化,这个函数在RTX5的启动任务里面调用。
. f3 W- J0 i- m7 R( N& w6 _5 {: r1 ~% o3 n& i. L
  1. /*2 t+ G- R6 t. R% z3 `9 }4 c+ C/ h8 C
  2. *********************************************************************************************************
    1 F' \0 B9 ^3 p2 f
  3. *    函 数 名: bsp_Init1 X6 D6 ?8 M/ E7 E: O
  4. *    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
    # P& h$ T' t& U5 ?7 s6 S
  5. *    形    参: 无/ Q' c8 p- ?9 D  [" Q
  6. *    返 回 值: 无
    . a7 {+ m! ^1 ]  B+ h1 G: h+ g, O/ U
  7. *********************************************************************************************************2 }, G7 H2 J% E8 d0 d4 P9 I
  8. */" [9 K, [" T' p% o! e  \1 u
  9. void bsp_Init(void)1 ]; C' {3 ?  f1 ~1 O1 H* j
  10. {
    ! G2 N0 N& w$ S$ M! d
  11.     bsp_InitDWT();     /* 初始化DWT时钟周期计数器 */      
    $ P) R" m* e: `; G& |
  12.     bsp_InitKey();        /* 按键初始化,要放在滴答定时器之前,因为按钮检测是通过滴答定时器扫描 */
    ' l5 j. @- L. @
  13.     bsp_InitUart();    /* 初始化串口 */
    0 T! d4 f6 {  e+ q/ a
  14.     bsp_InitExtIO();    /* 初始化FMC总线74HC574扩展IO. 必须在 bsp_InitLed()前执行 */   
    ' @: I6 M3 q, H" G/ O0 r9 `, T0 }
  15.     bsp_InitLed();        /* 初始化LED */    3 @9 T* ~. @2 b: d( a' T
  16.     bsp_InitTimer();      /* 初始化滴答定时器 */
    % c- N) P+ c) g) y7 a
  17. }
复制代码
+ v. F6 |% F* y/ H
4.7.3      函数SystemClock_Config5 z+ Y8 S4 j2 Z" J% q% u
这个函数主要是完成系统时钟配置。$ ?/ l& R; b3 P' n

' u1 G' I  |. _! w( a  N" C
  1. /*
    " H( T$ Z/ m. M; u8 e, I
  2. *********************************************************************************************************1 K/ ~4 P' n0 y) P1 ]  y4 y
  3. *    函 数 名: SystemClock_Config8 W: h: y# ?- s( i
  4. *    功能说明: 初始化系统时钟
    # P' S# L2 @8 l7 {9 }6 h; E+ A$ r
  5. *                System Clock source            = PLL (HSE)
    " h- s! ?5 n; I3 D1 Q
  6. *                SYSCLK(Hz)                     = 400000000 (CPU Clock)9 ~! ?. S3 ~/ R, r* e* ]
  7. *               HCLK(Hz)                       = 200000000 (AXI and AHBs Clock)
    $ g- N- d- Q7 b& H5 i6 F9 O
  8. *                AHB Prescaler                  = 2
    ' D8 i1 v( r# \
  9. *                D1 APB3 Prescaler              = 2 (APB3 Clock  100MHz)
    . T& Q( h* O, ]+ r# ]; i* R
  10. *                D2 APB1 Prescaler              = 2 (APB1 Clock  100MHz)6 t, J2 A0 `8 g# T" }
  11. *                D2 APB2 Prescaler              = 2 (APB2 Clock  100MHz)
    / P$ W" x. }6 a2 S& z7 J" a# U% ~& y
  12. *                D3 APB4 Prescaler              = 2 (APB4 Clock  100MHz)5 y, _8 N# m# `3 B9 }' i
  13. *                HSE Frequency(Hz)              = 25000000( h& w5 L( C0 `0 f/ c# l3 ]6 ]
  14. *               PLL_M                          = 5
    & u! g( C# @, _/ Z; d: h- t( _* B, l
  15. *                PLL_N                          = 160! ^4 G* v/ n7 b
  16. *                PLL_P                          = 2
    7 T) y+ e( R% n6 g- y7 {& X
  17. *                PLL_Q                          = 4
    4 |' d) f7 E7 a  F0 W7 q
  18. *                PLL_R                          = 2
    3 e4 N# H6 k; c* n& t$ J. i
  19. *                VDD(V)                         = 3.37 L7 U0 B+ c; w* l0 I; K) f& J
  20. *                Flash Latency(WS)              = 4: y$ E2 R$ z3 |$ @/ ~) M
  21. *    形    参: 无0 N5 i% R* K6 D- U3 }
  22. *    返 回 值: 无
    0 G8 S7 g1 P5 D$ x1 f
  23. *********************************************************************************************************9 ^8 G* Y- x( }
  24. */
    0 W  N* h% V, s0 D% s& y) k
  25. static void SystemClock_Config(void)% r7 ^* ?  C' q  Q! L% `- p$ c
  26. {
    - v, H8 ~! [1 f% n6 L
  27.    省略未写
    1 N7 K: n) ^+ ~3 h; q3 \" v& x4 ~

  28. # P+ o$ f2 ?. h( G& s9 U/ w' u
  29.    /* AXI SRAM的时钟是上电自动使能的,而D2域的SRAM1,SRAM2和SRAM3要单独使能 */   
    4 |- l! X0 c. [1 G; }: i) v" J: k
  30. #if 1$ j$ s0 ~, C# c
  31.     __HAL_RCC_D2SRAM1_CLK_ENABLE();
    ) w/ J: {! l# [7 t: C4 {. F% r8 H
  32.     __HAL_RCC_D2SRAM2_CLK_ENABLE();
    " U5 ^, O: ^. p5 r) z5 w
  33.     __HAL_RCC_D2SRAM3_CLK_ENABLE();3 t2 P* u0 n/ i" d3 Q+ ?- `
  34. $ x9 l' e5 N' t( ]: R, K( f
  35.     __HAL_RCC_BKPRAM_CLKAM_ENABLE();       / m. q; q9 X) y+ W. w* Z
  36.     __HAL_RCC_D3SRAM1_CLKAM_ENABLE();3 r& H4 u' o! n. e  a' X# ~
  37. #endif* k4 b& Q) p8 z* D3 c
  38. }
复制代码

7 \. C" B) F' }: U/ J+ }1 u& t这里的RAM时钟初始化比较重要,这几个RAM的时钟都要单独使能。
7 O8 x* v8 Z) {, P* J1 U4 |. @/ f8 Y0 u  A
4.7.4      函数MPU_Config/ e0 D  \% a( _+ u! m
RTX5例子默认采用AXI SRAM作为主RAM空间,因为空间比较大,方便我们后制作综合例子使用:2 G5 w- D+ x- F+ f# ~) c
& B' o% V, y) Z5 \* i% Y% ^4 s
  1. /*6 O) X5 a! ]5 s$ d! f
  2. *********************************************************************************************************
    6 q) a& z# D9 v
  3. *    函 数 名: MPU_Config- x. M' `5 \: q( a" }" ]- C$ N5 n
  4. *    功能说明: 配置MPU- z# E2 r9 p; F3 V
  5. *    形    参: 无3 c6 l) _" _) R3 O, S; J, y
  6. *    返 回 值: 无
    / H+ b  Z, I6 T% M
  7. *********************************************************************************************************
    ( ~  I) O% a) V
  8. */
    1 R8 R6 L1 g* W* e, x' D
  9. static void MPU_Config( void )
    % @, e% b( `- m) C$ P0 ?" \
  10. {
    # C1 \! }( Z: b( }+ Q" D3 x9 S
  11.     MPU_Region_InitTypeDef MPU_InitStruct;
    8 [2 T) E1 @# C, p! p" \

  12. ; q+ m; w4 F( r3 x. N( z% Q- m
  13.     /* 禁止 MPU */
    ( c2 C. T9 C% `7 Q9 J+ ?9 ~
  14.     HAL_MPU_Disable();
    " _/ F2 q6 V0 }2 |! R; b. l% S
  15. . K- P# B, ~* r, [, S6 ?
  16. /* 最高性能,读Cache和写Cache都开启 */    # x  c' q8 C' B9 W' Z2 k8 o
  17. #if 1
    & A3 q6 `) E% X$ y7 |$ C
  18.        /* 配置AXI SRAM的MPU属性为Write back, Read allocate,Write allocate */
    8 j, z$ w$ s* W5 v  `; u
  19.     MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
    * a: q) L: y0 g$ `
  20.     MPU_InitStruct.BaseAddress      = 0x24000000;: z* g: X& X0 m+ H* H
  21.     MPU_InitStruct.Size             = MPU_REGION_SIZE_512KB;* F9 u0 q; P5 u0 u: O
  22.     MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
    & @9 d0 S( l, _' d9 B' `
  23.     MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;
      I7 J2 W: q2 a5 z8 `# X
  24.     MPU_InitStruct.IsCacheable      = MPU_ACCESS_CACHEABLE;/ m# X# P/ u; E$ ?! J% D; ]- o, q' {# i
  25.     MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;! q! ~: S+ X2 }- w" F- g2 n/ o
  26.     MPU_InitStruct.Number           = MPU_REGION_NUMBER0;
    7 P' S6 I* [% }! k' Y! [  s
  27.     MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL1;
    6 d! y' f: U; I  [' }6 r% }  x
  28.     MPU_InitStruct.SubRegionDisable = 0x00;
    & }" ]- u3 S8 G2 b* D& b( t
  29.     MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;% E( [# [' o& U' c: c! m5 {
  30. * a0 l, I1 q5 g; M
  31.     HAL_MPU_ConfigRegion(&MPU_InitStruct);
    % g  B  ^3 R8 ~/ w" b1 ^" Z

  32. . t9 _0 ]6 a  J! f3 H2 G. ?# z
  33. /* 最低性能,读Cache和写Cache都关闭 */
      X+ T6 [& Y* g# `
  34. #else7 c! `" W- c4 f8 w
  35.     /* 配置AXI SRAM的MPU属性为NORMAL, NO Read allocate,NO Write allocate */  f1 t2 z( }5 M3 u) d* q/ w
  36.     MPU_InitStruct.Enable           = MPU_REGION_ENABLE;; \3 n, b$ [; ^1 w
  37.     MPU_InitStruct.BaseAddress      = 0x24000000;
      ]$ V2 ?. d% D6 f- h. u
  38.     MPU_InitStruct.Size             = MPU_REGION_SIZE_512KB;
    5 a: \% F9 u" I7 @$ j! n
  39.     MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;$ Q' v# q) C& V8 s8 _& U- k
  40.     MPU_InitStruct.IsBufferable     = MPU_ACCESS_NOT_BUFFERABLE;
    2 j; |8 f9 e- ~" P
  41.     MPU_InitStruct.IsCacheable      = MPU_ACCESS_NOT_CACHEABLE;
    % c7 b9 L- e# U. s4 @
  42.     MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
    6 E$ f- A" [4 Z
  43.     MPU_InitStruct.Number           = MPU_REGION_NUMBER0;
    9 k( ?; e2 f2 C9 k1 \9 c
  44.     MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL1;
    9 z9 A# f+ F  T$ ?. z: O
  45.     MPU_InitStruct.SubRegionDisable = 0x00;
    ; A- Q) S# A9 c4 K4 W! v$ K' E
  46.     MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;
    ; @% h) R7 s; y

  47. ' h" S3 m' t6 B" M4 R3 c8 N4 I0 I
  48.     HAL_MPU_ConfigRegion(&MPU_InitStruct);- }# o/ F7 T$ I1 `' H& @- j; D/ H
  49. #endif
    , l3 }4 x- }' c9 K1 y

  50. 6 Z. f' H# T; G/ Z# v$ F
  51.     /* 配置FMC扩展IO的MPU属性为Device或者Strongly Ordered */
    ( @% f4 \. R* G3 l$ A9 Z
  52.     MPU_InitStruct.Enable           = MPU_REGION_ENABLE;! J: o+ H3 S3 u
  53.     MPU_InitStruct.BaseAddress      = 0x60000000;
    $ W* u1 |7 w) h2 g+ Z
  54.     MPU_InitStruct.Size             = ARM_MPU_REGION_SIZE_64KB;    1 ^5 o: X' O9 P: [
  55.     MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
    ' I3 M0 K1 i% t( m
  56.     MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;1 Z9 @6 d% U7 Z
  57.     MPU_InitStruct.IsCacheable      = MPU_ACCESS_NOT_CACHEABLE;    ( M" |4 S9 T3 l& I
  58.     MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
    5 j9 i9 g$ u6 G: v, ~! T2 p  b+ E/ \
  59.     MPU_InitStruct.Number           = MPU_REGION_NUMBER1;
    9 z9 w; e! V% R" o8 D# c
  60.     MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL0;
    $ K9 q8 l' D* U+ D; t$ s, {% G
  61.     MPU_InitStruct.SubRegionDisable = 0x00;3 P: V2 D" S" Y! ^; o) D" a( c- w
  62.     MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;
    + W& _: [1 G, o& x* o* V

  63. ' ?+ n) e- t8 I
  64.     HAL_MPU_ConfigRegion(&MPU_InitStruct);7 V& O) R7 k9 I! ~, O+ F) {
  65. " T$ W3 f6 J% h  L$ P' k) r/ l
  66.     /* 使能 MPU */2 w- _6 b& ~7 }& B, z: r6 r7 _
  67.     HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
    $ I  Y9 y  \" ~
  68. }
复制代码
- X+ i6 D0 f/ N3 D3 P5 C; ]5 f
4.7.5      函数bsp_RunPer10ms( h: H) J& f/ [% ]$ [% ]6 L
这个函数里面默认有个按键扫描,如果大家移植的程序里面没有按键初始化,务必要把这个按键扫描函数注释掉。
$ v. U6 d$ }6 w1 n2 J5 D( q" L  C# y
: k+ e/ Q. O5 _3 P& A( e
  1. /*5 X2 Q$ ?* Y; y
  2. *********************************************************************************************************
    : X5 ?) o. h7 n- C7 d0 \* c
  3. *    函 数 名: bsp_RunPer10ms
    7 H, T4 k/ L, a2 F; c& e
  4. *    功能说明: 该函数每隔10ms被Systick中断调用1次。详见 bsp_timer.c的定时中断服务程序。一些处理时间要求- t- Z% D) Y. j, y* r, T
  5. *             不严格的任务可以放在此函数。比如:按键扫描、蜂鸣器鸣叫控制等。. }; e: i7 T( ~
  6. *    形    参: 无
    . m; Y* S/ U( f" M3 C/ X6 [
  7. *    返 回 值: 无" \, {4 s9 ^5 @6 W# K
  8. *********************************************************************************************************
    , k8 T! U3 Q6 ?6 L4 C+ k9 T7 |" j
  9. */
    $ W4 J0 S/ a) Y" o9 V
  10. void bsp_RunPer10ms(void)0 P. z6 ~# X7 R( y4 R* Y5 B
  11. {) U9 [( ]  Z; `7 z+ _0 x
  12.     bsp_KeyScan10ms();
    # h% R! T/ w- C3 L0 ^
  13. }
复制代码

% z* [' J, R1 m# ~4.8   第5步,更新bsp_timer.c和bsp.h文件, x  W6 M/ B' `) Q( g% S$ p
更新bsp_timer.c文件是因为此文件跟RTX5都要使用滴答定时器,有冲突。所以大家直接将我们工程模板里面此文件覆盖移植的这个文件即可。% @) N1 Y& e  K6 }- s2 h

7 M0 L# D, |( v! U- l+ d/ [bsp.h文件里面要添加一个宏定义,因为bsp_timer.c文件里面做了些条件编译:& B' }# I  o3 e

' O* M6 o% q7 J1 c7 k# y9 d: N' |#define  USE_RTX    1
  k& b7 T+ M0 o, i; l( d) ~
; I) ?. h9 H" z' }; g另外,bsp.h文件将大部分头文件都添加进来了,大家可以根据需要,用到那些头文件,使能那些,用不到的,可以注释掉。当然,不注释也是没问题的:
  g0 D7 E- x) o: _& a$ u0 \4 H# X9 a7 ~+ k, H0 A9 |5 X
  1. /* 通过取消注释或者添加注释的方式控制是否包含底层驱动模块 */
    : ^7 K) e  X/ B  `7 g7 F# U( P
  2. //#include "bsp_msg.h"
    , O. j& q+ V$ z1 \% @
  3. //#include "bsp_user_lib.h"
    , n7 J+ U* l  z; T
  4. #include "bsp_timer.h"+ _* `  {# L( X2 {: x
  5. #include "bsp_led.h"
    3 }, D9 s1 K5 o2 i' S" f+ T
  6. #include "bsp_key.h"
    5 \( b7 u! F0 J
  7. #include "bsp_dwt.h"0 M; N6 \8 a( L& k! b

  8. 4 ]  {) Z  Z3 {8 x& M% C
  9. //#include "bsp_cpu_rtc.h") {, S( }) j3 F# ^
  10. //#include "bsp_cpu_adc.h"
    : T7 d; r1 g( M& G1 F& V( }5 a
  11. //#include "bsp_cpu_dac.h"& Z* M6 p2 |. x4 t' j
  12. #include "bsp_uart_fifo.h"
    - Q/ W! P" X% N% E; O  k( z
  13. //#include "bsp_uart_gps.h"
    : n5 E) {, s* t/ N# f
  14. //#include "bsp_uart_esp8266.h"9 |! G; i4 K$ H) P5 Z, j
  15. //#include "bsp_uart_sim800.h"4 b$ D4 k3 w. s" X
  16. # O& s$ r9 w" ~$ F
  17. //#include "bsp_spi_bus.h"3 z# d; }  n0 o; i) ^1 s# ?: M
  18. //#include "bsp_spi_ad9833.h") V+ `! B3 B+ v( I" R. \( }
  19. //#include "bsp_spi_ads1256.h"
    : x+ W/ Z' Y, e
  20. //#include "bsp_spi_dac8501.h"
    8 w" [# E0 ]1 ^* V9 U
  21. //#include "bsp_spi_dac8562.h"
    7 O8 A4 J" R) b( E
  22. //#include "bsp_spi_flash.h"
    $ b% K& m% j3 \: v9 e) }3 o
  23. //#include "bsp_spi_tm7705.h"
    " H5 x7 X: H* z1 A% F0 S% o
  24. //#include "bsp_spi_vs1053b.h"1 Q- N" Q4 H" J  G3 l. d( L

  25. 6 x" v) S3 ~; v! p5 O) g
  26. //#include "bsp_fmc_sdram.h"- z( f( r3 D$ T: r
  27. //#include "bsp_fmc_nand_flash.h"9 \! f9 @4 J: H% H, S& _7 U
  28. //#include "bsp_fmc_ad7606.h"
    8 h7 _' e0 A: D2 H' E0 F" m
  29. //#include "bsp_fmc_oled.h"
    - @8 H4 ]" ]. z+ u3 p
  30. #include "bsp_fmc_io.h"6 N( |  G3 l+ w# Q. W$ j+ b
  31. 6 J0 H% ^" T' [
  32. //#include "bsp_i2c_gpio.h"
      }. K0 a; B3 u+ t* ~1 e% s
  33. //#include "bsp_i2c_bh1750.h"
    ( }( N9 [1 m$ z
  34. //#include "bsp_i2c_bmp085.h"
    : m, @8 Z8 {" ]! w  d8 W0 X: m" Q
  35. //#include "bsp_i2c_eeprom_24xx.h"
    2 B0 x9 ?& `0 A& y- m) v+ ^
  36. //#include "bsp_i2c_hmc5883l.h") }! z1 F) z3 o1 D1 X! h
  37. //#include "bsp_i2c_mpu6050.h"
    2 e/ ^0 _: D' v0 `  u
  38. //#include "bsp_i2c_si4730.h"8 e- n$ f: L8 \; M: J& x! T) M
  39. //#include "bsp_i2c_wm8978.h"4 |" H( ?' g8 z5 L! }

  40. ( |' [; A+ B3 P% G
  41. //#include "bsp_tft_h7.h"0 p  r+ O5 Z; i( ~( H* T
  42. //#include "bsp_tft_429.h") K3 G# @" E- u1 E% m' L: U+ e
  43. //#include "bsp_tft_lcd.h"- [/ W9 Z' P1 o8 r1 @, b0 }8 m: j
  44. //#include "bsp_ts_touch.h"
    ( B% x  ^; p) \; l
  45. //#include "bsp_ts_ft5x06.h"
    ! p8 r. l' L0 h$ I) t
  46. //#include "bsp_ts_gt811.h"
    8 Q) c7 f1 J: `( b2 N  a6 G: M
  47. //#include "bsp_ts_gt911.h"
    + T2 i1 L- S8 n; f1 _
  48. //#include "bsp_ts_stmpe811.h"
    - [( }! k' {' m, z- U9 o% n
  49. 5 h4 Z# x6 I' H, |7 f
  50. #include "bsp_beep.h"4 v$ L3 e& p! s1 f4 Y% H" X' {4 g
  51. #include "bsp_tim_pwm.h": x6 X  c- L( |8 t  Q1 s0 x+ U" g/ k
  52. //#include "bsp_sdio_sd.h"1 A. t9 B% d$ o/ R! V
  53. //#include "bsp_dht11.h"4 D* ^' n2 @" L
  54. //#include "bsp_ds18b20.h"
    % m" q9 @% n3 h" q: T5 k  E" F: R
  55. //#include "bsp_ps2.h") l% w8 S; g0 J- z
  56. //#include "bsp_ir_decode.h"
    1 N4 Z( k. M8 x
  57. //#include "bsp_camera.h"
    & V+ w  ^5 u* W2 S
  58. //#include "bsp_rs485_led.h"7 b' m$ |1 r5 q: _1 M9 W/ y
  59. //#include "bsp_can.h"
复制代码

3 M; a+ o& x" c9 n  U( B7 Z4.9   第6步,修改文件stm32h7xx_it.c
8 j$ ?7 J# Q% U5 L( e# w7 {. @删除此文件里面带的如下函数,RTX5要使用,冲突了。) o$ V) i; u! {- t6 g
6 b- B0 X; W  D! W3 ^0 s$ f9 G
  1. /**
    ; j/ b6 z+ K3 R2 `
  2.   * @brief  This function handles SVCall exception.! n% S. ]# q, [1 ]9 m5 [
  3.   * @param  None
    0 k+ ?! F2 L; ^$ l2 e
  4.   * @retval None/ r  w7 ~# k, r/ L% A* a
  5.   */
    % c! K/ s  r/ c* U
  6. void SVC_Handler(void)
    3 |3 e: V' W7 e
  7. {- i6 Q: z: I, q1 D1 ^
  8. }
    $ Y; I- T4 H# B) m' [8 ~3 e# ?
  9. , y  b  `0 b6 O/ @! j( x, y) y
  10. /**
    " @8 \) F$ a1 S6 C* ^( K
  11.   * @brief  This function handles PendSVC exception.
    4 m$ Y5 ?3 P& b& z* p& U0 L8 x
  12.   * @param  None' {" s" J# H% i3 o7 t9 d
  13.   * @retval None
    + x# A9 y- b9 D( `
  14.   */5 P7 K1 I: _. I9 Z* l4 [
  15. void PendSV_Handler(void)+ t/ J3 z5 e( r$ e
  16. {  c) `+ K# ?/ o1 w( K
  17. }
复制代码
* j- O. P) ?0 F1 P: p5 }
4.10 第7步,添加头文件的汇总文件includes.h$ o# |, f" q  ]
在User文件夹下添加文件incudes.h,直接从本章节教程配套例子的User文件夹复制即可。此文件主要用于RTX5的各种头文件汇总。
9 o1 x6 i/ M1 {9 g) v! [3 A3 i, d! ?* u, z* M5 _+ j3 S2 T
63fafbc927e6b911f6f3b81c4acb6af1.png

5 E* t% A: @0 f" `2 G! ^2 U/ c& ~% f. P. p. h
4.11 第8步,HAL库时间基准stm32h7xx_hal_timebase_tim.c
0 k3 k5 e' R: E9 ^+ L
由于RTX5和HAL库需要一个时间基准,而且默认都是用的滴答定时器,所有要有一个选用其它的时间基准。当前的处理方案是为HAL库提供一个时间基准文件stm32h7xx_hal_timbase_tim.c。此文件
# N" g# r. Y- ^/ d4 }' j7 I# k% W9 N+ }$ n, `" g
里面做了两套方案,一个是使用TIM7做时间基准,另一个是使用RTX5的API做时间基准,通过条件编译做选择。默认是采用RTX5的API做时间基准。  T, x4 C& Z/ h

) z& O! C( w9 N* |
  1. /*
    5 U+ y+ i$ W! B0 A1 w+ K+ I3 h
  2. *********************************************************************************************************7 S: q- ]1 S& s! d# V
  3. *    函 数 名: HAL_Delay
    * i, T# Z3 W) `, _/ k; W% Z
  4. *    功能说明: 重定向毫秒延迟函数。替换HAL中的函数。因为HAL中的缺省函数依赖于Systick中断,如果在USB、SD6 t( q6 L  B, S3 t" f( W- a- ]& s
  5. *             卡中断中有延迟函数,则会锁死。也可以通过函数HAL_NVIC_SetPriority提升Systick中断
    , r1 E- T( Q- e: I; f# }+ ^
  6. *    形    参: 无7 o( b% o# Z: O) ~, N& T
  7. *    返 回 值: 无, _+ t; a7 _% h9 J8 H
  8. *********************************************************************************************************7 ~2 }, j% I# R/ \) g- F
  9. */: ~, L* ^/ ?# `0 T" @1 Z' S
  10. void HAL_Delay(uint32_t Delay)4 w: ?; Y9 G9 d/ D2 J) C1 e$ }
  11. {
    5 K2 Q) I% x; l6 P4 P. I) \
  12.     bsp_DelayMS(Delay);* }5 i0 p4 L, Q& ^
  13. }
    * T! h' z  D7 S& m: I( T. z
  14. 7 |8 A; w) h1 a2 B
  15. HAL_StatusTypeDef HAL_InitTick (uint32_t TickPriority)- L& @& y' ^0 \
  16. {8 c- i$ z: ?+ ~" ~8 w* D
  17.     return HAL_OK;; K" Q4 f5 a6 g( P) Z7 K0 Y: W
  18. }
    & o, o- L) ?+ G$ W- ?) }1 k
  19. ( u8 C+ \! |/ b, B# z& F9 {# a) b
  20. uint32_t HAL_GetTick (void) & J; p& r; v0 B1 ~* e3 ?% u6 _$ y0 u/ H
  21. {
    . S# A5 p. c3 r. t
  22.     static uint32_t ticks = 0U;
    - V2 O8 O3 k1 Q; X
  23.     uint32_t i;
    " }5 V$ L1 U6 r
  24. * W- P# }( E% }
  25.     if (osKernelGetState () == osKernelRunning)! m) e. {1 x6 n0 z& G9 c
  26.     {
      ]) W% @9 p% N& P7 L
  27.         return ((uint32_t)osKernelGetTickCount ());
    & s# ^# T, d' [* g$ Q4 p& @
  28.     }
    8 P: m% s9 S/ H/ S
  29. 4 A8 V$ U+ ]5 Z( A
  30.     /* 如果RTX5还没有运行,采用下面方式 */
    + \9 G; `+ V  ~! R, j
  31.     for (i = (SystemCoreClock >> 14U); i > 0U; i--)
    8 H& u) `) Q/ ~3 [! j: G2 ^5 M3 f/ G& b
  32.     {
    * p+ k( I8 R% W! s5 n$ z2 C0 ]
  33.         __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP();
      ?( k) Y2 M& j6 T" l+ n0 r3 R
  34.         __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP();1 E9 P/ b+ j5 A) ^3 ?
  35.     }
    & \7 g1 M6 ^4 G  t& ^! R5 u2 T4 K
  36. 4 Y: k+ u$ }1 b/ I+ Q
  37.     return ++ticks;
    ! e6 S1 l# n9 M5 a$ n4 ^
  38. }
复制代码
! t9 T( D+ S/ P/ `% X, y  m1 F% Z
4.12 第9步,添加BSP驱动文件bsp_dwt.c

/ f6 L& c1 S( W添加bsp_dwt.c文件和bsp_dwt.h文件主要是因为第8步中的stm32h7xx_hal_timebase_tim.c文件里面的函数bsp_DelayMS要使用,此函数是基于DWT系统时钟周期计数器实现。
' {5 j. x& m! k, y- p8 X( b% Y% p$ ~4 E
f0d85f2002a553fa31c8f67b30e2db76.png

! f/ M! J% x3 D& M5 D$ C5 E0 P1 ^
6 C! s, b6 V& V9 ?4.13 第10步,创建应用任务(重要,注意启动任务)
/ t( u1 g6 T! y9 @1 S
应用程序比较简单,大家可以直接复制本章教程配置例子的main.c文件中的内容到自己工程里面测试。主要创建了如下几个任务:
! K% l4 R- M6 m- y5 d# C
2 f& f, r8 ^: @1 r& [AppTaskUserIF任务   : 按键消息处理。, O4 c0 |* O4 q% R8 q; @; P
+ s) ]0 V+ p" b* H) ]
AppTaskLED任务      : LED闪烁。7 y" a: t$ y5 G% g. _! q
3 H' u3 d- f# E1 R+ ]% V
AppTaskMsgPro任务   : 消息处理,暂未使用。
3 _4 m) T% v) T5 ~& A5 h0 ^5 ]* N- q) l1 k4 G/ Y4 \2 ?4 {& F$ c1 s
AppTaskStart任务    : 启动任务,也是最高优先级任务,这里实现按键扫描。6 o$ C# G- s& k
! f9 g6 ^. o& Q8 q  u
osRtxTimerThread任务: 定时器任务,暂未使用。
' o3 _: j% M( K0 M/ a- y, b) }# s2 }  ~' }+ n# p7 v
任务栈大小和任务控制块定义如下:5 E3 b- D) o1 l
1 [7 G% s5 U$ N' l* n2 f
  1. /*( ?0 X; C# c! @. ?3 o2 e
  2. **********************************************************************************************************
    & ?# x4 k, m2 @: }6 [
  3.                                              变量) W, L1 `0 ]" _, h+ p6 a
  4. **********************************************************************************************************
    8 C& ?+ o# D- w0 @) |
  5. */
    % }3 x& x+ u- U/ Y+ c
  6. /* 任务的属性设置 */0 q6 b+ A2 O4 D* X( `3 z
  7. const osThreadAttr_t ThreadStart_Attr =
    1 n! q* z, T; q5 y
  8. {
    0 Q  p! f$ M( i* F  Y8 y, W: a
  9.     /* 未使用 */  ^0 p. q4 W7 k' k3 Z
  10. //    .cb_mem = &worker_thread_tcb_1,
    3 Q4 g+ K2 J9 o% b4 w1 C
  11. //    .cb_size = sizeof(worker_thread_tcb_1),$ Z& X  ?* p" T2 A5 ?. q
  12. //    .stack_mem = &worker_thread_stk_1[0],
    * X2 K" P% K7 o8 J& F7 s8 N
  13. //    .stack_size = sizeof(worker_thread_stk_1),# ~) W4 g0 d" H# Z; Q( b1 Z+ Y
  14. //    .priority = osPriorityAboveNormal,( T2 h; y! Z& B2 }- ?1 J/ _9 h' d0 t
  15. //    .tz_module = 0
    ; W, x' b: ^& b. s9 w

  16. 2 J# `# P, m+ J! Q
  17.     .name = "osRtxStartThread",
    ! f- }9 w/ ^5 F! S
  18.     .attr_bits = osThreadDetached,
    # k: K. j" E! F9 a$ T) h. F
  19.     .priority = osPriorityHigh4,
    * z8 z- X, U' u# a
  20.     .stack_size = 2048,2 ~3 Z, e) |0 a7 \! ]  G' w
  21. };
    1 i  u+ m$ |6 b# }

  22. 3 O1 m; }% K1 u5 c% F5 k
  23. const osThreadAttr_t ThreadMsgPro_Attr = : q: |- G0 W7 ]! l
  24. {8 U' S' n9 g) x  C
  25.     .name = "osRtxMsgProThread",' Q& R+ w& u* }
  26.     .attr_bits = osThreadDetached, ( u% J6 `; {0 W; u9 Q
  27.     .priority = osPriorityHigh3,
    - g) z7 W( d1 G9 T2 B
  28.     .stack_size = 1024,% z% P# @. N9 b. ~; b
  29. };
    ( ?8 s# w1 T6 @+ ~6 ~' k

  30. ( H$ m/ W: d# O% T
  31. const osThreadAttr_t ThreadLED_Attr =
    6 _0 i% f" S/ q
  32. {
    . U5 W9 ^3 C6 k4 r. }4 j
  33.     .name = "osRtxLEDThread",
    $ ], E/ N4 e! y; l  n% \5 J7 P
  34.     .attr_bits = osThreadDetached, 8 ]# M: A, D  c0 W. K3 ^
  35.     .priority = osPriorityHigh2,& W& I5 B. P6 N0 h
  36.     .stack_size = 512,
    ! Y( M/ N3 }9 k
  37. };
    $ W1 C/ n# N6 Z6 p, [! G$ R
  38. 4 ?2 i/ t' P4 A2 ~) ]
  39. const osThreadAttr_t ThreadUserIF_Attr = 5 I- a% I2 c& l! A
  40. {* |4 d/ I3 |* o. L
  41.     .name = "osRtxThreadUserIF",
    # a' m( O+ h8 k. y7 ^, F: P; I
  42.     .attr_bits = osThreadDetached, & F* E+ Q, W5 R7 C! k$ m; a
  43.     .priority = osPriorityHigh1,; [' t6 Y! k: O$ S7 m, k
  44.     .stack_size = 1024,
    , R* P* I# ^9 u# p: U8 ~. u
  45. };
复制代码

2 P) w7 G2 Y7 t' Z5 i- L& F0 @; X) E任务创建:
, G# G' C$ ]  G/ c) G$ E
1 c/ I1 j' _/ A
  1. /*
    4 T, n5 {2 ^6 B5 n- w7 Z# }
  2. *********************************************************************************************************
    # O5 M6 l/ Z- R. B% v' ^3 ?2 o$ _! J
  3. *    函 数 名: main( M# G8 b9 W1 M, y4 A# d
  4. *    功能说明: 标准c程序入口。
    6 ^" d  t% {0 z3 |
  5. *    形    参: 无6 T1 h* a3 P3 z8 g" x6 o
  6. *    返 回 值: 无* X; P9 `0 o7 R2 Z6 [% y; r
  7. *********************************************************************************************************
    * X1 k2 o7 P0 b0 T$ h: ?0 b% m
  8. */
    ! E; P" [/ _) P3 E
  9. int main (void) $ C" o1 ~3 Q8 R- V9 A
  10. {   
    4 r" @3 t. a* g0 i) `
  11.     /* HAL库,MPU,Cache,时钟等系统初始化 */* u# R6 Z$ \# y
  12.     System_Init();
    : |+ |/ Q' d! _- R) G) T

  13. 9 H2 \! e, G  L6 C) C/ ?
  14.     /* 内核开启前关闭HAL的时间基准 */+ q  m: m. l: d4 ^* P
  15.     HAL_SuspendTick();
    5 H' p6 \0 M$ k3 Y) X* p  c

  16. * |: A9 ?0 e+ }+ n- M! R! E) z
  17.     /* 内核初始化 */
    7 ?1 H6 Z3 o! Z# ~: J
  18.     osKernelInitialize();                                  / n2 ?1 a  N1 M8 [& Y1 Q$ Q

  19. * k7 U* S0 U' `) B$ g8 d: t
  20.     /* 创建启动任务 */0 d3 ^/ l* K6 ^7 K" I0 M
  21.     ThreadIdStart = osThreadNew(AppTaskStart, NULL, &ThreadStart_Attr);  
    & _, M7 z1 o4 K4 w/ m  l

  22.   L/ }' l2 }; D! c8 K9 b% x2 R8 X
  23.     /* 开启多任务 */
    6 Z7 p' i3 r1 S
  24.     osKernelStart();
    7 V( ^. d0 }/ H3 ~! A; A; O
  25. / e+ I/ j) x! q1 J
  26.     while(1);! `: V7 p" m4 K+ q8 L2 F% l/ I
  27. }
    . ~" g9 X6 @' r* X0 G) r, X
  28. # }8 K, a  J7 ]4 F
  29. /*
    ; C: e2 [0 A' i- u; Z
  30. ********************************************************************************************************** C8 U; m" u+ @9 l; B: e
  31. *    函 数 名: AppTaskCreate! i. A! Z2 y$ \
  32. *    功能说明: 创建应用任务0 O% ~4 U! X8 o6 o3 {& |* ^7 \  m) a- i
  33. *    形    参: 无
    % U7 ]9 [# X' p# N  H! Q
  34. *    返 回 值: 无/ ?! ^9 |3 I6 b1 Q3 g5 a
  35. *********************************************************************************************************
    1 _, c+ S& Q  E7 F
  36. */
    + S, s4 S, ~5 F0 y  j
  37. static void AppTaskCreate (void)
    , k, Y4 e% x4 D4 i
  38. {$ t7 z3 v* p: o' T7 T/ w1 `
  39.     ThreadIdTaskMsgPro = osThreadNew(AppTaskMsgPro, NULL, &ThreadMsgPro_Attr);  / L( e. D* {! h5 P' B0 W7 E* R
  40.     ThreadIdTaskLED = osThreadNew(AppTaskLED, NULL, &ThreadLED_Attr);  6 S* Y( p* x% E6 V
  41.     ThreadIdTaskUserIF = osThreadNew(AppTaskUserIF, NULL, &ThreadUserIF_Attr);  $ q: u0 t2 c5 }- G/ }
  42. }
复制代码
; {2 @: ]$ l* \
这里我们重点看下启动任务,主要做了四个工作:' `9 B4 W, u( e3 [7 Y8 W
" p% G$ d0 b8 e7 B6 A
  外设初始化bsp_Init。( w, P/ m$ u0 S. F5 U' ^
  任务创建AppTaskCreate。
6 D# t) t3 k8 ^1 T5 {& h3 K  需要周期性处理的程序bsp_ProPer1ms,对应裸机工程调用的SysTick_ISR。这个的实现非常重要,这样之前裸机里面使用的API,就可以直接在RTX5里面直接调用。% G8 a7 r1 b3 T' ~! Y
  1. /*
    , ?) U& M2 u: R" n+ x( i
  2. *********************************************************************************************************
    / q# ]) A" q% A( p5 y( m" {
  3. *    函 数 名: AppTaskStart( t8 ]8 p) z8 |& v7 M
  4. *    功能说明: 启动任务,这里用作BSP驱动包处理。+ a5 H3 X& M- X6 V
  5. *    形    参: 无
    5 a" ~0 g1 h+ M* c, |* d
  6. *    返 回 值: 无* P9 f/ ?2 x" [- K
  7. *   优 先 级: osPriorityHigh4  ; I# F5 F# Y- ^% h5 C% H, f3 M& Y* n
  8. *********************************************************************************************************" j  G; e7 I* B+ C( N; Y9 Q+ _: o, s' V; l
  9. */: |! s/ {5 J3 n. l, e- Q( |; [
  10. void AppTaskStart(void *argument)4 n  T  Z4 f# L% N
  11. {
    2 P0 p. o# E' D, d) T1 m
  12.     const uint16_t usFrequency = 1; /* 延迟周期 */, j5 T- K; R! \' L' y) {) X) Q2 G
  13.     uint32_t tick;
    " Q! a& ~6 G) b: c8 `6 D' Y

  14. 0 l& ?, S  r3 }% ?% u* Z
  15.     /* 初始化外设 */
      w6 s4 f+ K: ~; h* p
  16.     HAL_ResumeTick();: Y+ U, t3 o# @: \9 {
  17.     bsp_Init();+ D" }4 C6 ]+ g! i9 j- W
  18. ( b( U, d; s/ y2 v$ E* R
  19.     /* 创建任务 */. X* i/ D2 P$ z0 T- q
  20.     AppTaskCreate();# O3 s1 H! D$ Z

  21. 5 u! g3 g* D5 Z) K
  22.     /* 获取当前时间 */0 `5 F! a/ |" s# N2 t/ q& c; e% f
  23.     tick = osKernelGetTickCount(); 3 ^1 }# j9 r$ p5 N" U7 n: Z6 D
  24. ; r2 g. ]" A+ a1 l5 p3 X3 K
  25.     while(1), L7 }) M5 a: B7 i. _* m4 t3 E1 ^3 ~
  26.     {) [+ j& w3 P% z6 m
  27.         /* 需要周期性处理的程序,对应裸机工程调用的SysTick_ISR */
    7 }* K+ ^8 K0 O% r7 s
  28.         bsp_ProPer1ms();. Q# e9 P6 k' o5 P% ?
  29. ! J( g! X( t+ p5 ~% L4 A
  30.         /* 相对延迟 */* [( T% \- Z8 J9 e2 z$ s
  31.         tick += usFrequency;                          
    & J, P- N7 e- R% f% v$ P' P4 o9 E
  32.         osDelayUntil(tick);
    8 n  {0 N: u3 Q# t9 [: B
  33.     }
    ) Y$ }% Z/ l' w: M
  34. }
复制代码
2 \, G, }6 G0 T' F) J" Q
4.14 常见移植错误总结

. n# v) h  W& s! w常见的移植错误主要有下面几种情况:. T! q9 ?5 c7 t4 z% s$ n( v7 J9 ]
% d* q( }/ G4 \! x2 c  c& X5 Z: k
  编译后提示如下两种错误:
9 C7 L1 D# c" P6 _0 VError: L6200E: Symbol PendSV_Handler multiply defined (by irq_cm4f.o and stm32h7xx_it.o).
2 u& ^5 k3 s5 k+ k1 _
% _6 `" e" Q; D" I" a; I, n% {( bError: L6200E: Symbol SVC_Handler multiply defined (by irq_cm4f.o and stm32h7xx_it.o).
7 `$ K* d" @- c- B
/ S* h( ^4 F5 {6 i& R. o8 y! F解决办法:这是函数重定义了,直接将stm32h7xx_it.c文件里面的PendSV_Handler和SVC_Handler删掉。" n3 {' k  m+ P5 x$ _+ e* x
; e6 D  K6 |" t( K
  提示如下错误
( }& t* Q1 I) K7 e9 i" ?; ]! GError: L6218E: Undefined symbol bsp_DelayMS (referred from bsp_fmc_io.o).. o. u6 ?! h  U

+ C# i8 |' s( I3 M" Q, P# j# V解决办法:打开bsp_dwt.C文件中的条件编译。
  }3 _' v' w' P  \. Q- C% e4 r3 @
" J6 @3 I9 T, F  B" f  B7 M9 ^4.15 实验例程5 P- m4 e: [9 r: o4 k
本章节配套了如下几个例子供大家移植参考:" R, `- w' I5 X1 E# y8 [

. {9 a8 C$ D. n, n5 K7 U( M  V7-400_Base Template( Q1 ^$ s/ O- C* k
裸机模板,方便大家添加RTX5内核源码。
% V+ b1 o, |. F$ L& j7 |0 Y0 D- x: N# w
( j9 u9 b) L% ~  V7-401_Threadx Kernel Template
. r4 F9 m6 T7 k; P0 B* P
" }8 o2 {/ U, q9 BThreadX内核模板。2 m( f- r( ?6 Z& N

4 n4 V" `, Q5 n4 Q" nMDK进入调试状态后,选择周期更新:
. u  B9 u7 V3 h& V0 Y- N- d: ~! g2 h, c* w9 h7 m
fdce9fac9944ad56faa0dd13307f6ebb.png

- C1 N3 P+ E; ]3 D
- K2 n2 z+ T* `) [  ?  |然后打开调试组件,注意和RTX4的调试组件位置不同:
% V% R7 W  _9 B
$ q% `" H2 ]( C- @
9482ce7367ba4d7cf08c73a56db28f75.png
: a/ ]& y8 H9 A& e

" f3 L) f: p! S: y7 E& \, r/ `然后点击MDK的全速运行,0 i- d; D3 s, \5 `/ S3 }8 m
! v9 N0 V2 a4 F( ?. t! t$ p+ C
e3038a01781216611f96ae37d5bccb17.png

2 o4 O4 Q# y- Q" r5 L
, Q1 m: M/ T: ]2 z" b' x4 x至此,就可以动态实时查看RTX5的运行状态:& N% t* m& a) S  w9 C% _
8 G4 a/ @: @+ b7 F
797f68ea76bd699fe11ce441076df4ec.png

, X0 @) B" E8 J8 t; q
$ y5 l0 q/ _6 t! y0 B4.16 总结" p3 W4 F7 F$ G( r, y
本章节为大家讲解了RTX5 在MDK AC5上的移植方法,移植涉及到的知识点比较多,初学的话,建议实际动手操作一遍。: c. y+ n8 P$ |. W( q8 X- v

1 ?3 i+ `/ q# q; C* k9 i4 z+ N8 R, P0 c& V1 o# ?' Q% M- Y  t" m8 S
2 x7 }& q! i6 U& ?
收藏 评论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 手机版