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
( 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
- 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
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) j8 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
, 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
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
' 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
& 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# 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
' 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
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
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/ _
$ }& 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
+ 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
! 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) _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
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 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 }# _
" 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
: 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
- /*
3 `8 L3 Y# W ~! l - *********************************************************************************************************
' i4 W/ m5 C, [$ R3 L - * 函 数 名: System_Init
" G) g. E( Z6 i - * 功能说明: 系统初始化,主要是MPU,Cache和系统时钟配置
- a2 t) Z7 B% U: U j - * 形 参:无
: n; g9 f/ j7 s, f3 I6 z% L - * 返 回 值: 无
9 [ ^6 S/ l/ f4 l, Y - *********************************************************************************************************
4 K$ Z, B& Y- {$ F' D& s7 A6 r1 h - */
& e! ~4 S, W, d. z - void System_Init(void)+ z/ o9 f _! x0 c
- {
8 y/ W, ^# @( p* K
g$ A% @; ^. L# l! h- i6 m- /* 配置MPU */" O: [% Y9 g/ j) x5 y- E& V5 G
- MPU_Config();% k. h! K% o6 R Z+ D
+ _. t5 b7 |8 E3 O5 ~0 L- /* 使能L1 Cache */7 c0 ^: u0 {- ?' ]
- CPU_CACHE_Enable(); h: l* N( V, m4 F2 j" o
- 4 q/ Q8 @% J$ S5 \$ I! `' z
- /* - ^. |4 @! _: o7 q8 S" R5 G
- STM32H7xx HAL 库初始化,此时系统用的还是H7自带的64MHz,HSI时钟:
' P: {9 @' S( v! @& `# S - - 调用函数HAL_InitTick,初始化滴答时钟中断1ms。" e" J% n7 e A; |+ r }
- - 设置NVIV优先级分组为4。3 @3 q8 @/ e1 g# v
- */" B' d4 l0 J$ }; c3 M
- HAL_Init();. v- \1 o: X6 A: M; u. {
9 ] \9 q4 \$ c, s% d; ^* R- /* : K9 x. O/ D6 c- ?6 j
- 配置系统时钟到400MHz7 P1 B2 s& @# c% i7 J5 Z; i* d
- - 切换使用HSE。
% U4 ~* b, ~2 X9 @; v - - 此函数会更新全局变量SystemCoreClock,并重新配置HAL_InitTick。" G/ N: r0 Q$ z
- */4 O$ T; R, C4 a( m
- SystemClock_Config();
! m7 I [' S4 z8 u$ F
- D4 h% p% c4 i- /*
- j/ [6 O% D- K" h ~; E6 H6 F - Event Recorder:# w/ X) {$ Y* i7 K
- - 可用于代码执行时间测量,MDK5.25及其以上版本才支持,IAR不支持。
7 C+ g i9 Y7 U8 r' j9 {2 A - - 默认不开启,如果要使能此选项,务必看V7开发板用户手册第8章
* Z9 y" [1 S4 I$ Q5 P2 Z& ^ - */ ]' V$ |! i3 q/ m5 ]& ~& _
- #if Enable_EventRecorder == 1 0 {8 O: O( h1 v
- /* 初始化EventRecorder并开启 */5 }' _# R; V4 b/ I
- EventRecorderInitialize(EventRecordAll, 1U);! s8 w$ L% E# n4 L* T
- EventRecorderStart();
3 ~* }1 n/ k& ~ q" L - #endif3 g: p! h8 N# L8 I
- ; v; q s; Z) H
- }
复制代码
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
- /*2 t+ G- R6 t. R% z3 `9 }4 c+ C/ h8 C
- *********************************************************************************************************
1 F' \0 B9 ^3 p2 f - * 函 数 名: bsp_Init1 X6 D6 ?8 M/ E7 E: O
- * 功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
# P& h$ T' t& U5 ?7 s6 S - * 形 参: 无/ Q' c8 p- ?9 D [" Q
- * 返 回 值: 无
. a7 {+ m! ^1 ] B+ h1 G: h+ g, O/ U - *********************************************************************************************************2 }, G7 H2 J% E8 d0 d4 P9 I
- */" [9 K, [" T' p% o! e \1 u
- void bsp_Init(void)1 ]; C' {3 ? f1 ~1 O1 H* j
- {
! G2 N0 N& w$ S$ M! d - bsp_InitDWT(); /* 初始化DWT时钟周期计数器 */
$ P) R" m* e: `; G& | - bsp_InitKey(); /* 按键初始化,要放在滴答定时器之前,因为按钮检测是通过滴答定时器扫描 */
' l5 j. @- L. @ - bsp_InitUart(); /* 初始化串口 */
0 T! d4 f6 { e+ q/ a - bsp_InitExtIO(); /* 初始化FMC总线74HC574扩展IO. 必须在 bsp_InitLed()前执行 */
' @: I6 M3 q, H" G/ O0 r9 `, T0 } - bsp_InitLed(); /* 初始化LED */ 3 @9 T* ~. @2 b: d( a' T
- bsp_InitTimer(); /* 初始化滴答定时器 */
% c- N) P+ c) g) y7 a - }
复制代码 + 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- /*
" H( T$ Z/ m. M; u8 e, I - *********************************************************************************************************1 K/ ~4 P' n0 y) P1 ] y4 y
- * 函 数 名: SystemClock_Config8 W: h: y# ?- s( i
- * 功能说明: 初始化系统时钟
# P' S# L2 @8 l7 {9 }6 h; E+ A$ r - * System Clock source = PLL (HSE)
" h- s! ?5 n; I3 D1 Q - * SYSCLK(Hz) = 400000000 (CPU Clock)9 ~! ?. S3 ~/ R, r* e* ]
- * HCLK(Hz) = 200000000 (AXI and AHBs Clock)
$ g- N- d- Q7 b& H5 i6 F9 O - * AHB Prescaler = 2
' D8 i1 v( r# \ - * D1 APB3 Prescaler = 2 (APB3 Clock 100MHz)
. T& Q( h* O, ]+ r# ]; i* R - * D2 APB1 Prescaler = 2 (APB1 Clock 100MHz)6 t, J2 A0 `8 g# T" }
- * D2 APB2 Prescaler = 2 (APB2 Clock 100MHz)
/ P$ W" x. }6 a2 S& z7 J" a# U% ~& y - * D3 APB4 Prescaler = 2 (APB4 Clock 100MHz)5 y, _8 N# m# `3 B9 }' i
- * HSE Frequency(Hz) = 25000000( h& w5 L( C0 `0 f/ c# l3 ]6 ]
- * PLL_M = 5
& u! g( C# @, _/ Z; d: h- t( _* B, l - * PLL_N = 160! ^4 G* v/ n7 b
- * PLL_P = 2
7 T) y+ e( R% n6 g- y7 {& X - * PLL_Q = 4
4 |' d) f7 E7 a F0 W7 q - * PLL_R = 2
3 e4 N# H6 k; c* n& t$ J. i - * VDD(V) = 3.37 L7 U0 B+ c; w* l0 I; K) f& J
- * Flash Latency(WS) = 4: y$ E2 R$ z3 |$ @/ ~) M
- * 形 参: 无0 N5 i% R* K6 D- U3 }
- * 返 回 值: 无
0 G8 S7 g1 P5 D$ x1 f - *********************************************************************************************************9 ^8 G* Y- x( }
- */
0 W N* h% V, s0 D% s& y) k - static void SystemClock_Config(void)% r7 ^* ? C' q Q! L% `- p$ c
- {
- v, H8 ~! [1 f% n6 L - 省略未写
1 N7 K: n) ^+ ~3 h; q3 \" v& x4 ~
# P+ o$ f2 ?. h( G& s9 U/ w' u- /* AXI SRAM的时钟是上电自动使能的,而D2域的SRAM1,SRAM2和SRAM3要单独使能 */
4 |- l! X0 c. [1 G; }: i) v" J: k - #if 1$ j$ s0 ~, C# c
- __HAL_RCC_D2SRAM1_CLK_ENABLE();
) w/ J: {! l# [7 t: C4 {. F% r8 H - __HAL_RCC_D2SRAM2_CLK_ENABLE();
" U5 ^, O: ^. p5 r) z5 w - __HAL_RCC_D2SRAM3_CLK_ENABLE();3 t2 P* u0 n/ i" d3 Q+ ?- `
- $ x9 l' e5 N' t( ]: R, K( f
- __HAL_RCC_BKPRAM_CLKAM_ENABLE(); / m. q; q9 X) y+ W. w* Z
- __HAL_RCC_D3SRAM1_CLKAM_ENABLE();3 r& H4 u' o! n. e a' X# ~
- #endif* k4 b& Q) p8 z* D3 c
- }
复制代码
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
- /*6 O) X5 a! ]5 s$ d! f
- *********************************************************************************************************
6 q) a& z# D9 v - * 函 数 名: MPU_Config- x. M' `5 \: q( a" }" ]- C$ N5 n
- * 功能说明: 配置MPU- z# E2 r9 p; F3 V
- * 形 参: 无3 c6 l) _" _) R3 O, S; J, y
- * 返 回 值: 无
/ H+ b Z, I6 T% M - *********************************************************************************************************
( ~ I) O% a) V - */
1 R8 R6 L1 g* W* e, x' D - static void MPU_Config( void )
% @, e% b( `- m) C$ P0 ?" \ - {
# C1 \! }( Z: b( }+ Q" D3 x9 S - MPU_Region_InitTypeDef MPU_InitStruct;
8 [2 T) E1 @# C, p! p" \
; q+ m; w4 F( r3 x. N( z% Q- m- /* 禁止 MPU */
( c2 C. T9 C% `7 Q9 J+ ?9 ~ - HAL_MPU_Disable();
" _/ F2 q6 V0 }2 |! R; b. l% S - . K- P# B, ~* r, [, S6 ?
- /* 最高性能,读Cache和写Cache都开启 */ # x c' q8 C' B9 W' Z2 k8 o
- #if 1
& A3 q6 `) E% X$ y7 |$ C - /* 配置AXI SRAM的MPU属性为Write back, Read allocate,Write allocate */
8 j, z$ w$ s* W5 v `; u - MPU_InitStruct.Enable = MPU_REGION_ENABLE;
* a: q) L: y0 g$ ` - MPU_InitStruct.BaseAddress = 0x24000000;: z* g: X& X0 m+ H* H
- MPU_InitStruct.Size = MPU_REGION_SIZE_512KB;* F9 u0 q; P5 u0 u: O
- MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
& @9 d0 S( l, _' d9 B' ` - MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;
I7 J2 W: q2 a5 z8 `# X - MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;/ m# X# P/ u; E$ ?! J% D; ]- o, q' {# i
- MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;! q! ~: S+ X2 }- w" F- g2 n/ o
- MPU_InitStruct.Number = MPU_REGION_NUMBER0;
7 P' S6 I* [% }! k' Y! [ s - MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;
6 d! y' f: U; I [' }6 r% } x - MPU_InitStruct.SubRegionDisable = 0x00;
& }" ]- u3 S8 G2 b* D& b( t - MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;% E( [# [' o& U' c: c! m5 {
- * a0 l, I1 q5 g; M
- HAL_MPU_ConfigRegion(&MPU_InitStruct);
% g B ^3 R8 ~/ w" b1 ^" Z
. t9 _0 ]6 a J! f3 H2 G. ?# z- /* 最低性能,读Cache和写Cache都关闭 */
X+ T6 [& Y* g# ` - #else7 c! `" W- c4 f8 w
- /* 配置AXI SRAM的MPU属性为NORMAL, NO Read allocate,NO Write allocate */ f1 t2 z( }5 M3 u) d* q/ w
- MPU_InitStruct.Enable = MPU_REGION_ENABLE;; \3 n, b$ [; ^1 w
- MPU_InitStruct.BaseAddress = 0x24000000;
]$ V2 ?. d% D6 f- h. u - MPU_InitStruct.Size = MPU_REGION_SIZE_512KB;
5 a: \% F9 u" I7 @$ j! n - MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;$ Q' v# q) C& V8 s8 _& U- k
- MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
2 j; |8 f9 e- ~" P - MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
% c7 b9 L- e# U. s4 @ - MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
6 E$ f- A" [4 Z - MPU_InitStruct.Number = MPU_REGION_NUMBER0;
9 k( ?; e2 f2 C9 k1 \9 c - MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;
9 z9 A# f+ F T$ ?. z: O - MPU_InitStruct.SubRegionDisable = 0x00;
; A- Q) S# A9 c4 K4 W! v$ K' E - MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
; @% h) R7 s; y
' h" S3 m' t6 B" M4 R3 c8 N4 I0 I- HAL_MPU_ConfigRegion(&MPU_InitStruct);- }# o/ F7 T$ I1 `' H& @- j; D/ H
- #endif
, l3 }4 x- }' c9 K1 y
6 Z. f' H# T; G/ Z# v$ F- /* 配置FMC扩展IO的MPU属性为Device或者Strongly Ordered */
( @% f4 \. R* G3 l$ A9 Z - MPU_InitStruct.Enable = MPU_REGION_ENABLE;! J: o+ H3 S3 u
- MPU_InitStruct.BaseAddress = 0x60000000;
$ W* u1 |7 w) h2 g+ Z - MPU_InitStruct.Size = ARM_MPU_REGION_SIZE_64KB; 1 ^5 o: X' O9 P: [
- MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
' I3 M0 K1 i% t( m - MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;1 Z9 @6 d% U7 Z
- MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE; ( M" |4 S9 T3 l& I
- MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
5 j9 i9 g$ u6 G: v, ~! T2 p b+ E/ \ - MPU_InitStruct.Number = MPU_REGION_NUMBER1;
9 z9 w; e! V% R" o8 D# c - MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
$ K9 q8 l' D* U+ D; t$ s, {% G - MPU_InitStruct.SubRegionDisable = 0x00;3 P: V2 D" S" Y! ^; o) D" a( c- w
- MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
+ W& _: [1 G, o& x* o* V
' ?+ n) e- t8 I- HAL_MPU_ConfigRegion(&MPU_InitStruct);7 V& O) R7 k9 I! ~, O+ F) {
- " T$ W3 f6 J% h L$ P' k) r/ l
- /* 使能 MPU */2 w- _6 b& ~7 }& B, z: r6 r7 _
- HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
$ I Y9 y \" ~ - }
复制代码 - 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- /*5 X2 Q$ ?* Y; y
- *********************************************************************************************************
: X5 ?) o. h7 n- C7 d0 \* c - * 函 数 名: bsp_RunPer10ms
7 H, T4 k/ L, a2 F; c& e - * 功能说明: 该函数每隔10ms被Systick中断调用1次。详见 bsp_timer.c的定时中断服务程序。一些处理时间要求- t- Z% D) Y. j, y* r, T
- * 不严格的任务可以放在此函数。比如:按键扫描、蜂鸣器鸣叫控制等。. }; e: i7 T( ~
- * 形 参: 无
. m; Y* S/ U( f" M3 C/ X6 [ - * 返 回 值: 无" \, {4 s9 ^5 @6 W# K
- *********************************************************************************************************
, k8 T! U3 Q6 ?6 L4 C+ k9 T7 |" j - */
$ W4 J0 S/ a) Y" o9 V - void bsp_RunPer10ms(void)0 P. z6 ~# X7 R( y4 R* Y5 B
- {) U9 [( ] Z; `7 z+ _0 x
- bsp_KeyScan10ms();
# h% R! T/ w- C3 L0 ^ - }
复制代码
% 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
- /* 通过取消注释或者添加注释的方式控制是否包含底层驱动模块 */
: ^7 K) e X/ B `7 g7 F# U( P - //#include "bsp_msg.h"
, O. j& q+ V$ z1 \% @ - //#include "bsp_user_lib.h"
, n7 J+ U* l z; T - #include "bsp_timer.h"+ _* ` {# L( X2 {: x
- #include "bsp_led.h"
3 }, D9 s1 K5 o2 i' S" f+ T - #include "bsp_key.h"
5 \( b7 u! F0 J - #include "bsp_dwt.h"0 M; N6 \8 a( L& k! b
4 ] {) Z Z3 {8 x& M% C- //#include "bsp_cpu_rtc.h") {, S( }) j3 F# ^
- //#include "bsp_cpu_adc.h"
: T7 d; r1 g( M& G1 F& V( }5 a - //#include "bsp_cpu_dac.h"& Z* M6 p2 |. x4 t' j
- #include "bsp_uart_fifo.h"
- Q/ W! P" X% N% E; O k( z - //#include "bsp_uart_gps.h"
: n5 E) {, s* t/ N# f - //#include "bsp_uart_esp8266.h"9 |! G; i4 K$ H) P5 Z, j
- //#include "bsp_uart_sim800.h"4 b$ D4 k3 w. s" X
- # O& s$ r9 w" ~$ F
- //#include "bsp_spi_bus.h"3 z# d; } n0 o; i) ^1 s# ?: M
- //#include "bsp_spi_ad9833.h") V+ `! B3 B+ v( I" R. \( }
- //#include "bsp_spi_ads1256.h"
: x+ W/ Z' Y, e - //#include "bsp_spi_dac8501.h"
8 w" [# E0 ]1 ^* V9 U - //#include "bsp_spi_dac8562.h"
7 O8 A4 J" R) b( E - //#include "bsp_spi_flash.h"
$ b% K& m% j3 \: v9 e) }3 o - //#include "bsp_spi_tm7705.h"
" H5 x7 X: H* z1 A% F0 S% o - //#include "bsp_spi_vs1053b.h"1 Q- N" Q4 H" J G3 l. d( L
6 x" v) S3 ~; v! p5 O) g- //#include "bsp_fmc_sdram.h"- z( f( r3 D$ T: r
- //#include "bsp_fmc_nand_flash.h"9 \! f9 @4 J: H% H, S& _7 U
- //#include "bsp_fmc_ad7606.h"
8 h7 _' e0 A: D2 H' E0 F" m - //#include "bsp_fmc_oled.h"
- @8 H4 ]" ]. z+ u3 p - #include "bsp_fmc_io.h"6 N( | G3 l+ w# Q. W$ j+ b
- 6 J0 H% ^" T' [
- //#include "bsp_i2c_gpio.h"
}. K0 a; B3 u+ t* ~1 e% s - //#include "bsp_i2c_bh1750.h"
( }( N9 [1 m$ z - //#include "bsp_i2c_bmp085.h"
: m, @8 Z8 {" ]! w d8 W0 X: m" Q - //#include "bsp_i2c_eeprom_24xx.h"
2 B0 x9 ?& `0 A& y- m) v+ ^ - //#include "bsp_i2c_hmc5883l.h") }! z1 F) z3 o1 D1 X! h
- //#include "bsp_i2c_mpu6050.h"
2 e/ ^0 _: D' v0 ` u - //#include "bsp_i2c_si4730.h"8 e- n$ f: L8 \; M: J& x! T) M
- //#include "bsp_i2c_wm8978.h"4 |" H( ?' g8 z5 L! }
( |' [; A+ B3 P% G- //#include "bsp_tft_h7.h"0 p r+ O5 Z; i( ~( H* T
- //#include "bsp_tft_429.h") K3 G# @" E- u1 E% m' L: U+ e
- //#include "bsp_tft_lcd.h"- [/ W9 Z' P1 o8 r1 @, b0 }8 m: j
- //#include "bsp_ts_touch.h"
( B% x ^; p) \; l - //#include "bsp_ts_ft5x06.h"
! p8 r. l' L0 h$ I) t - //#include "bsp_ts_gt811.h"
8 Q) c7 f1 J: `( b2 N a6 G: M - //#include "bsp_ts_gt911.h"
+ T2 i1 L- S8 n; f1 _ - //#include "bsp_ts_stmpe811.h"
- [( }! k' {' m, z- U9 o% n - 5 h4 Z# x6 I' H, |7 f
- #include "bsp_beep.h"4 v$ L3 e& p! s1 f4 Y% H" X' {4 g
- #include "bsp_tim_pwm.h": x6 X c- L( |8 t Q1 s0 x+ U" g/ k
- //#include "bsp_sdio_sd.h"1 A. t9 B% d$ o/ R! V
- //#include "bsp_dht11.h"4 D* ^' n2 @" L
- //#include "bsp_ds18b20.h"
% m" q9 @% n3 h" q: T5 k E" F: R - //#include "bsp_ps2.h") l% w8 S; g0 J- z
- //#include "bsp_ir_decode.h"
1 N4 Z( k. M8 x - //#include "bsp_camera.h"
& V+ w ^5 u* W2 S - //#include "bsp_rs485_led.h"7 b' m$ |1 r5 q: _1 M9 W/ y
- //#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
- /**
; j/ b6 z+ K3 R2 ` - * @brief This function handles SVCall exception.! n% S. ]# q, [1 ]9 m5 [
- * @param None
0 k+ ?! F2 L; ^$ l2 e - * @retval None/ r w7 ~# k, r/ L% A* a
- */
% c! K/ s r/ c* U - void SVC_Handler(void)
3 |3 e: V' W7 e - {- i6 Q: z: I, q1 D1 ^
- }
$ Y; I- T4 H# B) m' [8 ~3 e# ? - , y b `0 b6 O/ @! j( x, y) y
- /**
" @8 \) F$ a1 S6 C* ^( K - * @brief This function handles PendSVC exception.
4 m$ Y5 ?3 P& b& z* p& U0 L8 x - * @param None' {" s" J# H% i3 o7 t9 d
- * @retval None
+ x# A9 y- b9 D( ` - */5 P7 K1 I: _. I9 Z* l4 [
- void PendSV_Handler(void)+ t/ J3 z5 e( r$ e
- { c) `+ K# ?/ o1 w( K
- }
复制代码 * 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
5 E* t% A: @0 f" `2 G! ^2 U/ c& ~% f. P. p. h
4.11 第8步,HAL库时间基准stm32h7xx_hal_timebase_tim.c0 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* |- /*
5 U+ y+ i$ W! B0 A1 w+ K+ I3 h - *********************************************************************************************************7 S: q- ]1 S& s! d# V
- * 函 数 名: HAL_Delay
* i, T# Z3 W) `, _/ k; W% Z - * 功能说明: 重定向毫秒延迟函数。替换HAL中的函数。因为HAL中的缺省函数依赖于Systick中断,如果在USB、SD6 t( q6 L B, S3 t" f( W- a- ]& s
- * 卡中断中有延迟函数,则会锁死。也可以通过函数HAL_NVIC_SetPriority提升Systick中断
, r1 E- T( Q- e: I; f# }+ ^ - * 形 参: 无7 o( b% o# Z: O) ~, N& T
- * 返 回 值: 无, _+ t; a7 _% h9 J8 H
- *********************************************************************************************************7 ~2 }, j% I# R/ \) g- F
- */: ~, L* ^/ ?# `0 T" @1 Z' S
- void HAL_Delay(uint32_t Delay)4 w: ?; Y9 G9 d/ D2 J) C1 e$ }
- {
5 K2 Q) I% x; l6 P4 P. I) \ - bsp_DelayMS(Delay);* }5 i0 p4 L, Q& ^
- }
* T! h' z D7 S& m: I( T. z - 7 |8 A; w) h1 a2 B
- HAL_StatusTypeDef HAL_InitTick (uint32_t TickPriority)- L& @& y' ^0 \
- {8 c- i$ z: ?+ ~" ~8 w* D
- return HAL_OK;; K" Q4 f5 a6 g( P) Z7 K0 Y: W
- }
& o, o- L) ?+ G$ W- ?) }1 k - ( u8 C+ \! |/ b, B# z& F9 {# a) b
- uint32_t HAL_GetTick (void) & J; p& r; v0 B1 ~* e3 ?% u6 _$ y0 u/ H
- {
. S# A5 p. c3 r. t - static uint32_t ticks = 0U;
- V2 O8 O3 k1 Q; X - uint32_t i;
" }5 V$ L1 U6 r - * W- P# }( E% }
- if (osKernelGetState () == osKernelRunning)! m) e. {1 x6 n0 z& G9 c
- {
]) W% @9 p% N& P7 L - return ((uint32_t)osKernelGetTickCount ());
& s# ^# T, d' [* g$ Q4 p& @ - }
8 P: m% s9 S/ H/ S - 4 A8 V$ U+ ]5 Z( A
- /* 如果RTX5还没有运行,采用下面方式 */
+ \9 G; `+ V ~! R, j - for (i = (SystemCoreClock >> 14U); i > 0U; i--)
8 H& u) `) Q/ ~3 [! j: G2 ^5 M3 f/ G& b - {
* p+ k( I8 R% W! s5 n$ z2 C0 ] - __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP();
?( k) Y2 M& j6 T" l+ n0 r3 R - __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP();1 E9 P/ b+ j5 A) ^3 ?
- }
& \7 g1 M6 ^4 G t& ^! R5 u2 T4 K - 4 Y: k+ u$ }1 b/ I+ Q
- return ++ticks;
! e6 S1 l# n9 M5 a$ n4 ^ - }
复制代码 ! 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
! 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
- /*( ?0 X; C# c! @. ?3 o2 e
- **********************************************************************************************************
& ?# x4 k, m2 @: }6 [ - 变量) W, L1 `0 ]" _, h+ p6 a
- **********************************************************************************************************
8 C& ?+ o# D- w0 @) | - */
% }3 x& x+ u- U/ Y+ c - /* 任务的属性设置 */0 q6 b+ A2 O4 D* X( `3 z
- const osThreadAttr_t ThreadStart_Attr =
1 n! q* z, T; q5 y - {
0 Q p! f$ M( i* F Y8 y, W: a - /* 未使用 */ ^0 p. q4 W7 k' k3 Z
- // .cb_mem = &worker_thread_tcb_1,
3 Q4 g+ K2 J9 o% b4 w1 C - // .cb_size = sizeof(worker_thread_tcb_1),$ Z& X ?* p" T2 A5 ?. q
- // .stack_mem = &worker_thread_stk_1[0],
* X2 K" P% K7 o8 J& F7 s8 N - // .stack_size = sizeof(worker_thread_stk_1),# ~) W4 g0 d" H# Z; Q( b1 Z+ Y
- // .priority = osPriorityAboveNormal,( T2 h; y! Z& B2 }- ?1 J/ _9 h' d0 t
- // .tz_module = 0
; W, x' b: ^& b. s9 w
2 J# `# P, m+ J! Q- .name = "osRtxStartThread",
! f- }9 w/ ^5 F! S - .attr_bits = osThreadDetached,
# k: K. j" E! F9 a$ T) h. F - .priority = osPriorityHigh4,
* z8 z- X, U' u# a - .stack_size = 2048,2 ~3 Z, e) |0 a7 \! ] G' w
- };
1 i u+ m$ |6 b# }
3 O1 m; }% K1 u5 c% F5 k- const osThreadAttr_t ThreadMsgPro_Attr = : q: |- G0 W7 ]! l
- {8 U' S' n9 g) x C
- .name = "osRtxMsgProThread",' Q& R+ w& u* }
- .attr_bits = osThreadDetached, ( u% J6 `; {0 W; u9 Q
- .priority = osPriorityHigh3,
- g) z7 W( d1 G9 T2 B - .stack_size = 1024,% z% P# @. N9 b. ~; b
- };
( ?8 s# w1 T6 @+ ~6 ~' k
( H$ m/ W: d# O% T- const osThreadAttr_t ThreadLED_Attr =
6 _0 i% f" S/ q - {
. U5 W9 ^3 C6 k4 r. }4 j - .name = "osRtxLEDThread",
$ ], E/ N4 e! y; l n% \5 J7 P - .attr_bits = osThreadDetached, 8 ]# M: A, D c0 W. K3 ^
- .priority = osPriorityHigh2,& W& I5 B. P6 N0 h
- .stack_size = 512,
! Y( M/ N3 }9 k - };
$ W1 C/ n# N6 Z6 p, [! G$ R - 4 ?2 i/ t' P4 A2 ~) ]
- const osThreadAttr_t ThreadUserIF_Attr = 5 I- a% I2 c& l! A
- {* |4 d/ I3 |* o. L
- .name = "osRtxThreadUserIF",
# a' m( O+ h8 k. y7 ^, F: P; I - .attr_bits = osThreadDetached, & F* E+ Q, W5 R7 C! k$ m; a
- .priority = osPriorityHigh1,; [' t6 Y! k: O$ S7 m, k
- .stack_size = 1024,
, R* P* I# ^9 u# p: U8 ~. u - };
复制代码
2 P) w7 G2 Y7 t' Z5 i- L& F0 @; X) E任务创建:
, G# G' C$ ] G/ c) G$ E
1 c/ I1 j' _/ A- /*
4 T, n5 {2 ^6 B5 n- w7 Z# } - *********************************************************************************************************
# O5 M6 l/ Z- R. B% v' ^3 ?2 o$ _! J - * 函 数 名: main( M# G8 b9 W1 M, y4 A# d
- * 功能说明: 标准c程序入口。
6 ^" d t% {0 z3 | - * 形 参: 无6 T1 h* a3 P3 z8 g" x6 o
- * 返 回 值: 无* X; P9 `0 o7 R2 Z6 [% y; r
- *********************************************************************************************************
* X1 k2 o7 P0 b0 T$ h: ?0 b% m - */
! E; P" [/ _) P3 E - int main (void) $ C" o1 ~3 Q8 R- V9 A
- {
4 r" @3 t. a* g0 i) ` - /* HAL库,MPU,Cache,时钟等系统初始化 */* u# R6 Z$ \# y
- System_Init();
: |+ |/ Q' d! _- R) G) T
9 H2 \! e, G L6 C) C/ ?- /* 内核开启前关闭HAL的时间基准 */+ q m: m. l: d4 ^* P
- HAL_SuspendTick();
5 H' p6 \0 M$ k3 Y) X* p c
* |: A9 ?0 e+ }+ n- M! R! E) z- /* 内核初始化 */
7 ?1 H6 Z3 o! Z# ~: J - osKernelInitialize(); / n2 ?1 a N1 M8 [& Y1 Q$ Q
* k7 U* S0 U' `) B$ g8 d: t- /* 创建启动任务 */0 d3 ^/ l* K6 ^7 K" I0 M
- ThreadIdStart = osThreadNew(AppTaskStart, NULL, &ThreadStart_Attr);
& _, M7 z1 o4 K4 w/ m l
L/ }' l2 }; D! c8 K9 b% x2 R8 X- /* 开启多任务 */
6 Z7 p' i3 r1 S - osKernelStart();
7 V( ^. d0 }/ H3 ~! A; A; O - / e+ I/ j) x! q1 J
- while(1);! `: V7 p" m4 K+ q8 L2 F% l/ I
- }
. ~" g9 X6 @' r* X0 G) r, X - # }8 K, a J7 ]4 F
- /*
; C: e2 [0 A' i- u; Z - ********************************************************************************************************** C8 U; m" u+ @9 l; B: e
- * 函 数 名: AppTaskCreate! i. A! Z2 y$ \
- * 功能说明: 创建应用任务0 O% ~4 U! X8 o6 o3 {& |* ^7 \ m) a- i
- * 形 参: 无
% U7 ]9 [# X' p# N H! Q - * 返 回 值: 无/ ?! ^9 |3 I6 b1 Q3 g5 a
- *********************************************************************************************************
1 _, c+ S& Q E7 F - */
+ S, s4 S, ~5 F0 y j - static void AppTaskCreate (void)
, k, Y4 e% x4 D4 i - {$ t7 z3 v* p: o' T7 T/ w1 `
- ThreadIdTaskMsgPro = osThreadNew(AppTaskMsgPro, NULL, &ThreadMsgPro_Attr); / L( e. D* {! h5 P' B0 W7 E* R
- ThreadIdTaskLED = osThreadNew(AppTaskLED, NULL, &ThreadLED_Attr); 6 S* Y( p* x% E6 V
- ThreadIdTaskUserIF = osThreadNew(AppTaskUserIF, NULL, &ThreadUserIF_Attr); $ q: u0 t2 c5 }- G/ }
- }
复制代码 ; {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
- /*
, ?) U& M2 u: R" n+ x( i - *********************************************************************************************************
/ q# ]) A" q% A( p5 y( m" { - * 函 数 名: AppTaskStart( t8 ]8 p) z8 |& v7 M
- * 功能说明: 启动任务,这里用作BSP驱动包处理。+ a5 H3 X& M- X6 V
- * 形 参: 无
5 a" ~0 g1 h+ M* c, |* d - * 返 回 值: 无* P9 f/ ?2 x" [- K
- * 优 先 级: osPriorityHigh4 ; I# F5 F# Y- ^% h5 C% H, f3 M& Y* n
- *********************************************************************************************************" j G; e7 I* B+ C( N; Y9 Q+ _: o, s' V; l
- */: |! s/ {5 J3 n. l, e- Q( |; [
- void AppTaskStart(void *argument)4 n T Z4 f# L% N
- {
2 P0 p. o# E' D, d) T1 m - const uint16_t usFrequency = 1; /* 延迟周期 */, j5 T- K; R! \' L' y) {) X) Q2 G
- uint32_t tick;
" Q! a& ~6 G) b: c8 `6 D' Y
0 l& ?, S r3 }% ?% u* Z- /* 初始化外设 */
w6 s4 f+ K: ~; h* p - HAL_ResumeTick();: Y+ U, t3 o# @: \9 {
- bsp_Init();+ D" }4 C6 ]+ g! i9 j- W
- ( b( U, d; s/ y2 v$ E* R
- /* 创建任务 */. X* i/ D2 P$ z0 T- q
- AppTaskCreate();# O3 s1 H! D$ Z
5 u! g3 g* D5 Z) K- /* 获取当前时间 */0 `5 F! a/ |" s# N2 t/ q& c; e% f
- tick = osKernelGetTickCount(); 3 ^1 }# j9 r$ p5 N" U7 n: Z6 D
- ; r2 g. ]" A+ a1 l5 p3 X3 K
- while(1), L7 }) M5 a: B7 i. _* m4 t3 E1 ^3 ~
- {) [+ j& w3 P% z6 m
- /* 需要周期性处理的程序,对应裸机工程调用的SysTick_ISR */
7 }* K+ ^8 K0 O% r7 s - bsp_ProPer1ms();. Q# e9 P6 k' o5 P% ?
- ! J( g! X( t+ p5 ~% L4 A
- /* 相对延迟 */* [( T% \- Z8 J9 e2 z$ s
- tick += usFrequency;
& J, P- N7 e- R% f% v$ P' P4 o9 E - osDelayUntil(tick);
8 n {0 N: u3 Q# t9 [: B - }
) Y$ }% Z/ l' w: M - }
复制代码 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
- C1 N3 P+ E; ]3 D
- K2 n2 z+ T* `) [ ? |然后打开调试组件,注意和RTX4的调试组件位置不同:
% V% R7 W _9 B
$ q% `" H2 ]( C- @: 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
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
, 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& ?
|
好好学习