4.1 初学者重要提示" p* { }9 ^2 J4 S# V7 p$ U( u
当前RTX5可以移植到GCC,MDK和IAR三大平台,考虑到仅MDK平台下有RTX5的调试组件,我们这里仅提供了MDK的移植说明。* f! J7 R/ L$ U
STM32H7使用MDK RTE环境添加RTX5,需要强制运行一次STM32CubeMX,因为H7已经没有配套RTE经典添加方式,而STM32F4是支持经典方式的,所以无需运行STM32CubeMX,详情可以看我们STM32F4开发板对应的RTX5教程。
' ]5 k8 t$ o" v9 t4.2 移植RXT5内核整体说明5 Z. w4 u- P2 x# i8 Q
移植之前,有必要对移植过程有个整体的认识:
8 q3 j: }# ^9 j) w3 [) R4 |9 a1 h0 v
2 T2 ^+ B% Z7 Q* l 第1步,准备一个工程模板。
4 f2 ^% s0 n9 y 第2步,移植RTX5。2 J7 c; Z% Z' g2 D
移植RTX5是采用MDK的RTE环境直接添加。当前H7芯片使用RTX5强制运行STM32CubeMX,所以需要大家提前安装好STM32CubeMX V5.4或者以上版本。1 U' B$ {1 E3 B# Z
第3步,处理HAL库时间基准,MPU配置等。
. h) \$ w2 a% I% } 第4步,创建应用。9 _- ?% B( ~' ~
& v4 ]2 P' \* N总的来说,这4步就可以完成移植, 下面将STM32H7的移植步骤和注意事项为大家做个说明。
- J" i' p! A- }; S4 k" V3 h/ }: E
4.3 了解RTX5内核模板框架设计4 J0 j5 [$ s" {7 d( N7 L
移植RTX5前,我们优先了解下移植好的RTX5内核模板,方面大家后面移植:
# H% y* V$ a2 `! c. L- n4 T8 ?! e* m0 E
: k; S! ]" g; W1 q- o/ V& q) O7 _( h. N9 K- ~ T
框图如下:( o7 c4 z2 I q7 X
- j0 L' K! P6 C" L4 i Q1 g
) q7 D7 {' s- ? B7 _9 H9 h `% W2 A
/ Z6 |5 j& G' e! y U% M; y4.4 第1步,安装指定的MDK软件包版本
4 a$ O6 Y0 c+ }2 D+ S5 r9 ^7 R7 \移植新版RTX5需要大家下载当前最新的MDK软件包版本(如果有最新版,推荐大家用最新版):
& g/ c: ?. `, N, Z1 w4 ^. r) y: V9 D. F- M% {9 u0 x, F
CMSIS 软件包使用当前最新的:V5.7.0+ r6 v& D. o3 {8 u. B
STM32H7使用当前最新的:V2.6.0
& c3 V6 l$ z7 v. P! R3 f STM32F4使用当前最新的:V2.6.0* L% [# |# _+ X; @8 L
STM32CubeMX使用当前最新的:V6.0.x
. s% B, @) n& e4 L! S8 v ARM_Compiler使用当前最新的:V1.6.1. O. j* g" Z$ b P( k) P
( H! L# W( A$ @. m不管以后MDK的软件包版本如何升级,当前的软件包版本和以后的新版是可以同时安装的,也就是说可以安装多个不同版本,在这里可以选择指定版本:
! I+ r9 n# F0 V% C) Q5 l
/ x* V) E6 \. h& k* P1 h1 Q& ~4 u2 f$ O
! \2 l% `7 P6 p6 t0 G( c4 t
4.5 第2步,准备一个工程模板
* u/ M7 P0 A9 L9 j首先准备好一个简单的裸机工程模板,已经为大家做好:V7-400_Base Template,准备好的工程模板如下图所示(大家也可以制作其它任意的工程模板,不限制):6 ]& D9 v/ { d, S4 o9 t
; _0 D4 X# m8 u6 v* c3 `0 g/ U, e6 C
! G" \2 L9 h9 d4.6 第3步,添加RTX5并配置
/ U* }$ f( L$ S" v; Z1 t) WRTX5可以方便的通过MDK的RTE环境添加进来。对于H7版本,MDK会强制运行一次CubeMX,并添加很多H7的HAL库文件,这些库文件我们可以使用,也可以不使用。教程配套的工程文件是不使用这些,因为前面的工程模板里面已经添加了。所以要将这些文件全部隔离出来。( }, R; I" z- ]5 b! Q& s& P" @
$ _% Q4 f7 r; ~3 g4.6.1 添加RTX5源码# }7 E# a) O6 Z/ \' j
( l4 Q, K2 q3 n3 l7 w' o: {5 r8 N! M6 I/ Q
5 p9 k1 }3 u7 e$ `# T4 d7 t- S5 t
点击OK按钮后,弹出如下界面:3 u2 h$ _9 A7 n
3 _4 E6 a+ e5 K# k% m0 a' h, Y& ~( ?, Y. t
1 ?. u: K$ U6 k+ H# O0 H, d
点击Start STM32CubeMX,这里需要大家电脑上已经安装了STM32CubeMX,并且为其安装了H7的软件包。
7 {8 J6 _+ \( q9 r k4 p. w6 Y+ J, I6 h. ^% i( Z3 y5 p2 D
% {. x/ K% S [( y5 F2 ]0 ^
# C8 I/ R. O* b# ?& _0 Q, l
打开后,用户仅需配置如下地方即可:
4 h( F- }# j3 k# P8 Q3 v6 V9 {4 @" c, a5 z9 x) o5 W
# W4 r: m% c! }4 i3 P/ G a0 O
& ~* k; D: `2 C( d7 k然后点击右上角的GENERATE CODE:
* M0 |0 J) v5 E( B2 g8 h7 \/ Z/ z. A+ l" c3 m6 q7 V% F
3 O) u4 Y$ H7 w2 }, `9 T6 J
) T5 z* p2 j0 J然后弹出如下对话框,点击Close即可,然后关闭STM32CubeMX。! f$ w& ^2 e7 J: G' T
% s" e4 h# H! n% [/ F+ X, L9 C" V
& U- m- b$ M* B: U X4 V2 d: M- c& z3 B% n! B- W3 E
重新回到MDK,会有一个对话框,点击是即可:
& m% h/ V& ]( }" K/ z# J" @* u0 D7 r. _* o m" y
[' h# j. y2 |$ Q6 S. @
" w7 T# |- V& `最后就可以看到RTX5源码已经添加到工程里面了:
s, T0 `6 N3 Y: Y& W; w) d; R
3 X- E6 f# n# J% P- T% q/ c) @7 N! w/ C! Q
" i3 r. O: G; e
4.6.2 将自动添加的库文件隔离出来
9 v0 e( j. T/ H2 o* k添加的所有文件中,仅RTX5和文件stm32h7xx_hal_msp.c留下,其它文件全部隔离出来,隔离方法也比较简单,比如隔离生成的main.c函数,鼠标右击此文件选择Options for file ‘main.c’9 L: C2 i# \2 `; `! v* I
$ L) H z) o; p5 \4 a
9 V" o6 ?# s" [- T
" ]# n2 K' ~( o2 h# K8 S然后取消掉include Target Build前的对勾,点击OK:. C+ |* {, J1 o5 X
7 h4 p* _9 y% e7 W0 x6 L* Y0 r( n6 |7 J; Y5 e0 W2 k7 d
* h" `+ O: h) e# x; ]$ Q
看到main.c文件上有个红色横杠,就表示已经隔离出来了:/ \4 v& `- J9 ? O7 w
5 D% ?6 ~% j: \8 U6 u( N/ `' c" b
5 M& ]* e% e$ H/ j# N+ [8 Y
8 y w. M5 T5 B; F同样的方法,将stm32h7xx_it.c文件也隔离出来,文件stm32h7xx_it.h不用管。
( `1 R' w4 i0 Z
4 A- u2 I$ Y: D, m' o5 @Device下面的这些文件也是同样的隔离方法:
* _0 Z$ [0 [2 X; W- u. ?1 E: t5 `/ u8 K' }
- U# y. p9 R X$ N
8 v. N: e3 M/ n* t; A3 f% {. I- `/ g
只是鼠标右击弹出的界面有些不同:
: N5 c+ D, y, _$ h( g$ t
5 A0 C8 A; h- h# `) s8 d; q8 c1 s2 N0 k0 i
. `( y h7 `' F0 w3 w4 S8 l) J注意stm32h7xx_hal_msp.c无需隔离,其它所有的文件全部隔离,stm32h7xx_hal_msp.c对应的隔离配置是STM32CubeMX,如果也隔离了,编译会有问题:
& ]5 |3 e) j/ B6 J, l' T5 f
" B4 b: J! h( ~2 c/ ` x; m' m) @2 D" v4 e6 A; w
1 |" `1 g1 B, B" B# ^! e- o
隔离后的效果如下:
/ {8 Q) z' B# ]6 `; ?$ A7 }/ q8 ]8 s! z
7 S4 }. k% P8 N6 G5 R( s: y: B" @
! ?% W% ?$ r" A& q& w4.6.3 RTX5配置
& X. y! F# h6 _剩下就是配置RTX5,设置RTX_Config.h文件即可,移植阶段先按照如下设置配置好,后面章节会专门为大家讲解每个参数的配置含义:9 j/ W# |4 ^- U3 g# b
, @5 F( C. K$ H' `0 \ Z
F, \" t9 ~8 S
& n- t0 V2 k- \1 M9 H4 ?; ]- \- W9 f% M
4.7 第4步,MPU和Cache配置文件bsp.c
) F0 _2 K# u7 _/ l. k这个bsp.c文件也比较重要,移植阶段,直接将我们移植好的模板内容复制过去即可,这里把相关的内容为大家做个说明。
+ y6 h' \' s1 h" v: F9 |2 j H& S" Y) M9 c* t. P8 X
4.7.1 函数System_Init
) h: d; Z: U9 j" b+ c/ ~$ @0 @系统初始化,主要是MPU,Cache和系统时钟配置,需要在RTX5初始化之前调用。0 w+ ]' |. i3 n
/ R9 [6 |3 _! p& G/ \; L# i+ D- /*
8 g, G" X# I. Q; t - *********************************************************************************************************
6 B5 H M# ]/ s, g, ^5 g - * 函 数 名: System_Init
0 r# j! g+ r& \- D - * 功能说明: 系统初始化,主要是MPU,Cache和系统时钟配置
% s' e2 `# I4 j. q J7 h3 Y$ r - * 形 参:无
+ K4 j/ U4 m8 u) U - * 返 回 值: 无
0 {! ?1 p8 E9 s( O) u - *********************************************************************************************************
/ ]% b& W) d( {# ~/ L - */6 k. u* k" H$ b- u, v7 i
- void System_Init(void)
: U2 ~+ k, `! `$ ]) k7 F+ G - {
2 {# I, Q8 F3 `) G- d3 ]
1 N% \" r6 t6 u- /* 配置MPU */
2 x; C0 Y, f7 \6 R5 H/ B# j - MPU_Config();
( E$ B; X+ h c: m# \( ?4 D: [ - & g8 Z% ?# V3 ?' N
- /* 使能L1 Cache */, H$ D9 w& i2 f N
- CPU_CACHE_Enable();
6 Y6 r' J W) |8 ~& m6 X( ?( U
: u4 C+ M9 O1 h, }+ M0 u& V- /*
: ?- r4 F# |# e5 l! L/ Q2 `* C - STM32H7xx HAL 库初始化,此时系统用的还是H7自带的64MHz,HSI时钟:
4 J2 N' `4 S- d8 n' }$ N8 F6 Y - - 调用函数HAL_InitTick,初始化滴答时钟中断1ms。: }1 t& X& A. I I* l0 _8 x+ S! ]) \
- - 设置NVIV优先级分组为4。7 G0 p* F5 v5 n/ U
- */
6 d* e- H! p9 r2 t, d - HAL_Init();
, ]9 n3 z0 L$ V8 Z - $ Z% L$ a! n. t8 e) p
- /* ! e0 |* }; U0 `$ g' c: G0 ?; z
- 配置系统时钟到400MHz
. v. u5 H t2 [9 u. g1 _$ Y6 Z1 x - - 切换使用HSE。* O+ ]& E0 l$ n% M+ K7 [
- - 此函数会更新全局变量SystemCoreClock,并重新配置HAL_InitTick。
. i) h8 u) q& j' v - */) t9 |+ j3 K4 t, p9 u8 s2 m* V9 [
- SystemClock_Config(); ^- b" i4 i& t
9 p4 n1 m5 p0 F: G7 ?- /* 3 R& y2 K8 D, Q( }4 x
- Event Recorder:; F8 ]5 e- s/ K/ ~# L6 r
- - 可用于代码执行时间测量,MDK5.25及其以上版本才支持,IAR不支持。
( y8 l1 J9 g5 y( s - - 默认不开启,如果要使能此选项,务必看V7开发板用户手册第8章
3 b) F% U- e% l) Q- [" T) p - */ / `; R2 N4 K( Y/ Z* h
- #if Enable_EventRecorder == 1
C2 B7 ?5 U" f! b- U X - /* 初始化EventRecorder并开启 */% ]1 u0 `; E M6 K
- EventRecorderInitialize(EventRecordAll, 1U);+ I& X/ X) h8 t+ }/ D5 {( c6 p8 A
- EventRecorderStart();
/ s8 p; f; a& M+ z5 x( O2 H - #endif
! T1 _4 V' `" T D$ K
$ ?; ^2 _1 O9 B8 D- }
复制代码 ( q& f x- z. X
4.7.2 函数bsp_Init
9 }# G, P+ `/ a f) G硬件外设的初始化,这个函数在RTX5的启动任务里面调用。
+ Z! [ J5 d; @. x' x* c1 _+ @' m: _/ p* S) u* W
- /* I0 f0 X$ ~+ p% n k- S K
- *********************************************************************************************************
* A1 k& F% H- T* a6 x3 H - * 函 数 名: bsp_Init
& E7 z7 w' g3 h! k$ C - * 功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
7 y4 {" L O7 k, ]5 E x - * 形 参: 无) l6 r6 i0 ~5 S* P) `( W
- * 返 回 值: 无* g( n2 H: t/ c! ]# \% u
- *********************************************************************************************************- ~' f1 v% W2 r, j
- */
. r& P1 S9 E3 H0 H- X7 h1 q - void bsp_Init(void). O& z- `5 T9 x
- {$ e# o) [ S+ G! }0 {/ t
- bsp_InitDWT(); /* 初始化DWT时钟周期计数器 */
1 t1 N9 ^. }' Z" k - bsp_InitKey(); /* 按键初始化,要放在滴答定时器之前,因为按钮检测是通过滴答定时器扫描 */* e- c0 B: o& Q' G9 S8 U
- bsp_InitUart(); /* 初始化串口 */
- _: {2 f0 _* p( I' h: B6 i# i - bsp_InitExtIO(); /* 初始化FMC总线74HC574扩展IO. 必须在 bsp_InitLed()前执行 */
4 d3 _# u! x8 {6 l- V* y1 C4 x - bsp_InitLed(); /* 初始化LED */
+ x" s( J6 v2 d. e' | - bsp_InitTimer(); /* 初始化滴答定时器 */ w3 c6 X% B+ b% z
- }
复制代码
& p' f. O( _. R2 v4.7.3 函数SystemClock_Config
0 Q6 a' _9 L( m. x0 r" v o这个函数主要是完成系统时钟配置。
8 f: I" ^+ A, t' B& j4 ~8 h3 M3 f& F2 T
- /*1 y: v- R) N4 ~
- *********************************************************************************************************% h, ^* H0 [: d h8 E
- * 函 数 名: SystemClock_Config) S) |- v5 C% |6 b8 G6 _8 Y
- * 功能说明: 初始化系统时钟/ ~& x; q5 W/ Y6 N" n
- * System Clock source = PLL (HSE)
+ @8 y1 j) j9 L2 P. { - * SYSCLK(Hz) = 400000000 (CPU Clock)
# k9 e1 y) k7 b - * HCLK(Hz) = 200000000 (AXI and AHBs Clock)1 h( s R2 }+ H* F' Z; J5 N# y' ~/ m
- * AHB Prescaler = 26 g4 V" `% j, ?- p7 }
- * D1 APB3 Prescaler = 2 (APB3 Clock 100MHz)
& Y- F& U$ w# k5 g" X) Z. E - * D2 APB1 Prescaler = 2 (APB1 Clock 100MHz)3 l7 `# o% G' {# {
- * D2 APB2 Prescaler = 2 (APB2 Clock 100MHz)
. A2 x( J: _2 j/ [' T1 _/ X8 {& F1 b - * D3 APB4 Prescaler = 2 (APB4 Clock 100MHz)2 d. K/ f8 I! i, v- s G) \
- * HSE Frequency(Hz) = 25000000
+ O; B4 P9 k$ i2 n - * PLL_M = 5
8 C0 l/ w7 s5 T2 g4 H7 v - * PLL_N = 1607 M2 I" {; a9 q
- * PLL_P = 2
* j7 j& ^% C' S0 C - * PLL_Q = 4' Q$ l; u1 Y, g6 C( G, K
- * PLL_R = 29 a W( k9 |. p; T: H, W/ m8 s4 @8 H' i
- * VDD(V) = 3.3
; z8 L) l$ d9 C% m5 c - * Flash Latency(WS) = 4" W' f' r- o" S3 Q- T& F- W! M: q, K
- * 形 参: 无
( w1 l" a( x: l. g( O2 R+ _7 j - * 返 回 值: 无
' ^% R: p8 B, T2 T* F - *********************************************************************************************************
/ b+ C% L9 _$ P" I1 B# i - */
y1 ?6 } E% g& E - static void SystemClock_Config(void)$ F8 ~9 x' }2 D3 Y
- { R8 ?5 f: O U$ @
- 省略未写) R8 _% d, F+ b+ f7 p
( t) ]) y) j/ B9 o5 I- /* AXI SRAM的时钟是上电自动使能的,而D2域的SRAM1,SRAM2和SRAM3要单独使能 */
$ y5 }1 o/ |0 c% ] - #if 1 ]7 y% n* M b* O. N
- __HAL_RCC_D2SRAM1_CLK_ENABLE();
; ~$ G2 A2 q* E. |! j" ` - __HAL_RCC_D2SRAM2_CLK_ENABLE();$ v& s4 O/ m# M# U& S
- __HAL_RCC_D2SRAM3_CLK_ENABLE();
* U0 ~8 _ o; k! ?( x# I; u - + C8 `9 j( n3 \# n j, G5 r
- __HAL_RCC_BKPRAM_CLKAM_ENABLE();
' S7 o4 m* t3 k" v D4 l* J - __HAL_RCC_D3SRAM1_CLKAM_ENABLE();
$ L( H/ E9 l* h1 v" W) h4 V - #endif% v3 A- U- \" w, q" n& W
- }
复制代码 # l$ @9 G' _3 v" A$ \
这里的RAM时钟初始化比较重要,这几个RAM的时钟都要单独使能。4 V6 H% a T/ R+ c7 O( U: u/ x
% q i1 o i1 i/ v" o% I" q8 Z% j4.7.4 函数MPU_Config. V* Y' o8 t. \* W/ M- e0 c
RTX5例子默认采用AXI SRAM作为主RAM空间,因为空间比较大,方便我们后制作综合例子使用:- n/ F. f& [: o7 W
}4 c8 E D. ?- /*
- I+ h" [4 A/ D* Q - *********************************************************************************************************: |2 b" Z- o1 b7 j/ [% d
- * 函 数 名: MPU_Config5 j, p2 \ G0 k7 |8 k# `& a* @
- * 功能说明: 配置MPU1 y4 W# j& R% D% z, x8 t
- * 形 参: 无2 n4 g! N/ f6 o0 r# n! U
- * 返 回 值: 无5 \, D& G9 {- W' _8 j6 O
- *********************************************************************************************************
8 d2 w: |! L* y1 ]8 E! E8 O7 G - */3 {/ \' x' ]' _4 Y
- static void MPU_Config( void )
1 H% T/ l1 b8 d( I- j! P5 r - {
9 w& L, {- E* H2 V7 n - MPU_Region_InitTypeDef MPU_InitStruct;5 L) }, H+ g2 e' l6 c
- 6 {6 ~8 a5 V9 a! X A& }
- /* 禁止 MPU */1 ~ a3 D' y$ g1 \' D
- HAL_MPU_Disable();& X! b5 o, r& w6 G/ v0 h5 P
8 i. Q7 d, U! o- /* 最高性能,读Cache和写Cache都开启 */
4 H2 d! Y( `( I* v& [: I% L/ D - #if 1' @- I9 i. n `( E
- /* 配置AXI SRAM的MPU属性为Write back, Read allocate,Write allocate */
& L7 x; X8 J! V/ o s - MPU_InitStruct.Enable = MPU_REGION_ENABLE;1 t6 s o) n" a
- MPU_InitStruct.BaseAddress = 0x24000000;
6 N. \+ C" m$ S1 Q; G - MPU_InitStruct.Size = MPU_REGION_SIZE_512KB;7 L( m" b6 Z9 {; I' I5 M/ s
- MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
& G2 k6 j ^; o$ F2 @1 X - MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;
+ }% |3 ~3 l: \# n7 n; R" T - MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;( Q7 V) Y- O. }
- MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;1 |) C+ A0 h2 G8 {6 i" A6 \, M8 Y
- MPU_InitStruct.Number = MPU_REGION_NUMBER0;
' t( L$ x3 F& P: {) K/ x - MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;5 U6 k- I" S8 d" w
- MPU_InitStruct.SubRegionDisable = 0x00;
, ^2 h: L, P+ x" O# s3 W - MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;& v3 T/ y/ F5 _0 A1 D, }! P( ]
- 7 u, q7 X5 s& {, ]0 A6 S
- HAL_MPU_ConfigRegion(&MPU_InitStruct);8 t! j4 q2 @ z5 E4 E6 K. x
- , k4 f& m' A( L9 w% o# ~1 u
- /* 最低性能,读Cache和写Cache都关闭 */5 V0 }. Y; p8 q2 d- q f
- #else
5 U: v$ k- k6 Q* a% J/ q! T - /* 配置AXI SRAM的MPU属性为NORMAL, NO Read allocate,NO Write allocate */* }, g- ?# x) c' `5 b/ t( {( U
- MPU_InitStruct.Enable = MPU_REGION_ENABLE;
8 q8 @# \, T( F0 t - MPU_InitStruct.BaseAddress = 0x24000000;
5 V4 Z; u: @- I T5 I) ? - MPU_InitStruct.Size = MPU_REGION_SIZE_512KB;1 k9 ]/ k6 A; F8 u$ d: r9 J
- MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
7 [$ r8 I9 q. g% C - MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;6 i9 C9 j% Z F2 f
- MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE; j6 e$ t) _: b/ i7 _; Q( D, y' C
- MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
6 O8 `. N- c1 g: r7 S - MPU_InitStruct.Number = MPU_REGION_NUMBER0;8 Q7 t5 |- I: }
- MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;: R# r( T- i( C$ }4 N' d: I3 p6 p; e
- MPU_InitStruct.SubRegionDisable = 0x00;
8 s! N: Y% v. V9 Y - MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
; O, @2 m9 T' |8 t
7 G/ B; _) I/ [# i! n8 I8 a- HAL_MPU_ConfigRegion(&MPU_InitStruct);! M4 [- f! K0 k* K$ W
- #endif9 n( U1 y7 M( c7 }. B' K; W1 G& g
- % c+ l/ m: l) [7 }! C/ W
- /* 配置FMC扩展IO的MPU属性为Device或者Strongly Ordered */
5 C! v7 \7 k6 R6 }' ^. e k - MPU_InitStruct.Enable = MPU_REGION_ENABLE;
. B1 k$ C9 C& Y" [6 t) V5 }2 { - MPU_InitStruct.BaseAddress = 0x60000000;# i: @. Q8 k6 X1 s6 s: \$ {4 t1 J6 k
- MPU_InitStruct.Size = ARM_MPU_REGION_SIZE_64KB; ( K# `% x$ N0 k) D9 S7 T
- MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;* ^/ Q4 j) Y8 s
- MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;& b* m: N5 [7 t5 ]
- MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
+ s9 D0 }) @7 Z - MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
+ c: F! g* u! d: K - MPU_InitStruct.Number = MPU_REGION_NUMBER1;
7 C" ^: }5 y6 a. O5 u8 O0 m8 a - MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
3 z; q7 o- v* e. i4 D0 c - MPU_InitStruct.SubRegionDisable = 0x00;
( T1 @ x, r2 C* Q0 B1 y - MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;, k1 E4 n0 a9 Q1 L S
- " ^9 h0 j" k9 J; T* y2 q+ A
- HAL_MPU_ConfigRegion(&MPU_InitStruct);+ {) V, b; ~$ p \ b. C7 a
1 y) O: J: ^+ }2 Q$ A- l( o- m- /* 使能 MPU */
8 z- }. q3 Y+ g5 e/ I7 O - HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
6 u2 u; _/ A2 z( u7 }% l3 i - }
复制代码 ( W" `$ m+ k9 P0 n
4.7.5 函数bsp_RunPer10ms
* W* T1 V b( R) G( {% P5 B( ~. D这个函数里面默认有个按键扫描,如果大家移植的程序里面没有按键初始化,务必要把这个按键扫描函数注释掉。
. l8 u6 i/ V' x$ T
) C0 I+ v) j6 M& g8 [* H9 o- /*
' g' v ]' ], _5 y - *********************************************************************************************************
7 w. u( G' R8 F3 J7 R: V* c - * 函 数 名: bsp_RunPer10ms, Y) y& \0 k! ]
- * 功能说明: 该函数每隔10ms被Systick中断调用1次。详见 bsp_timer.c的定时中断服务程序。一些处理时间要求2 Z) X* ~5 `1 f* F2 g4 N
- * 不严格的任务可以放在此函数。比如:按键扫描、蜂鸣器鸣叫控制等。
* {& X/ v/ g: S+ `( L" k1 W n! J - * 形 参: 无* k* w% W0 N7 ^6 i' l# R
- * 返 回 值: 无
y6 h9 i Y( M) C' ]: c$ B6 i" n* @) A - *********************************************************************************************************& A! z- d7 {3 v V9 c
- */2 x3 B- n3 o- ^- e
- void bsp_RunPer10ms(void)+ p2 c& d1 H- B' E7 B
- {5 I3 r* A9 X. x: h/ B
- bsp_KeyScan10ms();
$ o$ p- }. q- ?9 p8 n" u& U - }
复制代码
2 x6 v+ E5 I: f- k/ y4.8 第5步,更新bsp_timer.c和bsp.h文件& p# }5 J2 Q: a" U, D. B
更新bsp_timer.c文件是因为此文件跟RTX5都要使用滴答定时器,有冲突。所以大家直接将我们工程模板里面此文件覆盖移植的这个文件即可。( C+ s9 L8 V/ O* H$ p4 ?" o
2 W- }* ~9 o0 m' pbsp.h文件里面要添加一个宏定义,因为bsp_timer.c文件里面做了些条件编译:
W" D, w4 P, E0 `$ G( q
2 N$ C/ J5 Y+ a#define USE_RTX 1, f3 I0 E; b/ b( t! e+ g5 C; P) Q. q1 Z5 j
1 N: I: n8 o$ `+ i3 I5 v另外,bsp.h文件将大部分头文件都添加进来了,大家可以根据需要,用到那些头文件,使能那些,用不到的,可以注释掉。当然,不注释也是没问题的:
# r& m' A, X2 M( g! k3 p, `: d8 Y5 B6 L: h' F
- /* 通过取消注释或者添加注释的方式控制是否包含底层驱动模块 */. S8 G2 M+ g3 I8 |
- //#include "bsp_msg.h"" K% R( e D$ w8 E
- //#include "bsp_user_lib.h"- U) s0 T% A! P/ o; c5 M# y5 }3 F
- #include "bsp_timer.h"' ~* e2 \$ M4 | ~6 D
- #include "bsp_led.h"
* ~. K" X/ T+ D8 ]6 K: R; ` - #include "bsp_key.h"7 y# S1 Y4 X+ F
- #include "bsp_dwt.h"$ n& M/ v6 o; I2 ]$ I/ p, z. O
7 N+ Z; \& x( ?' a9 f/ N. n! H4 x- //#include "bsp_cpu_rtc.h"
/ \0 Y6 y( [3 G5 I - //#include "bsp_cpu_adc.h"
( Y. ?! c- D* K9 }1 w8 ?0 F Z - //#include "bsp_cpu_dac.h"
7 x. |( q3 u7 s& o - #include "bsp_uart_fifo.h" W8 \1 w. d$ o& Q+ k9 ~
- //#include "bsp_uart_gps.h"
3 j- T% `" Y3 _0 r - //#include "bsp_uart_esp8266.h"% t3 \2 T( j) E
- //#include "bsp_uart_sim800.h"
7 @) E# q8 \: j9 {4 @ ~
' _# ~( t+ Z) k! s+ B0 n) _) o- //#include "bsp_spi_bus.h"# k; p8 @4 S8 L8 w9 P) D- b
- //#include "bsp_spi_ad9833.h"
- R7 V/ O, V L" Z - //#include "bsp_spi_ads1256.h"
% r6 X8 P! R+ @0 @ b" x' Q5 Z - //#include "bsp_spi_dac8501.h"1 O3 _1 M" _+ X3 h, Z
- //#include "bsp_spi_dac8562.h"
7 P6 ^$ t" X! G2 x5 m: S4 _ - //#include "bsp_spi_flash.h"
N1 C' t. y* [6 F! g! k - //#include "bsp_spi_tm7705.h"! ~0 m4 w; `$ ^4 N& `
- //#include "bsp_spi_vs1053b.h"5 R# h# W# ?+ w; X
0 [' E- G6 U4 P/ m9 G7 s3 ]0 }- //#include "bsp_fmc_sdram.h"
8 @ X, R! i% V - //#include "bsp_fmc_nand_flash.h"
" P) p) ^$ S( Y4 }0 U: O - //#include "bsp_fmc_ad7606.h"/ X6 ^8 L) c6 N: w6 j5 r
- //#include "bsp_fmc_oled.h" ?& Q5 ~1 _# F" B
- #include "bsp_fmc_io.h"
4 X8 x2 z( _9 S8 Y7 U6 k. v
: T1 ~6 ]: ~) F' ?- //#include "bsp_i2c_gpio.h"
3 V6 `3 x, {+ h! Q! _ - //#include "bsp_i2c_bh1750.h": ^7 ^0 w& K, o! O
- //#include "bsp_i2c_bmp085.h"
) S) D, a+ W/ m0 O* n( c+ U6 e7 A; U2 p - //#include "bsp_i2c_eeprom_24xx.h"
) a/ `' Y% W4 u" G7 k$ N! D/ y - //#include "bsp_i2c_hmc5883l.h"- I4 k9 a, a; c% X$ }
- //#include "bsp_i2c_mpu6050.h"7 E- E6 K& s7 _$ A* i3 `1 D
- //#include "bsp_i2c_si4730.h"1 _7 i% @, ]- L6 z$ A9 s
- //#include "bsp_i2c_wm8978.h"
, j& ~6 O$ Z9 ]
8 [! H6 ]( e, C- //#include "bsp_tft_h7.h"
' Z3 M1 o% x8 k' e6 G2 P$ d6 ~ - //#include "bsp_tft_429.h"
$ A: G5 }- h5 t, r/ J3 P, O! t - //#include "bsp_tft_lcd.h"
& `$ B# f8 O' r) o' B1 m$ F2 C - //#include "bsp_ts_touch.h"
% M, H! i/ P9 u; V0 l5 B3 j: c - //#include "bsp_ts_ft5x06.h"
& B/ s$ a, x9 {, ^ - //#include "bsp_ts_gt811.h"2 P' f% h f/ e0 l* M, o) Y
- //#include "bsp_ts_gt911.h"; O* r' o! ]! D3 W! z9 I7 ]
- //#include "bsp_ts_stmpe811.h"
& z8 P2 B# Q2 y
% D4 ~; X& }2 K+ U, Z! K$ U' L- #include "bsp_beep.h"1 [3 c2 N' q$ s! N
- #include "bsp_tim_pwm.h"
- ^. A' n2 U* I9 L$ H - //#include "bsp_sdio_sd.h"* {. x/ `+ {4 k$ h
- //#include "bsp_dht11.h"' S7 L4 u- h- I* R2 c
- //#include "bsp_ds18b20.h"0 C5 o; W8 ^) Y+ D4 W# Q
- //#include "bsp_ps2.h"5 j1 f1 a A6 X ]+ `
- //#include "bsp_ir_decode.h"
# Z' p. D, e! m% t& l - //#include "bsp_camera.h"
) A: @8 h- s/ f6 h/ v - //#include "bsp_rs485_led.h"
* l2 V+ u _+ Y - //#include "bsp_can.h"
复制代码 - a% T! R. u7 r: X5 ]
4.9 第6步,修改文件stm32h7xx_it.c% F! H8 N1 U( O' r3 A
删除此文件里面带的如下函数,RTX5要使用,冲突了。8 [/ x, @& W: p _3 K* t
1 J" V4 f3 b5 l% R& p
- /**, `, g6 d1 }+ s. `& R5 D0 B
- * @brief This function handles SVCall exception.
/ t# C3 n6 a# D$ g - * @param None
( M' n1 F3 `5 V2 j, z; O - * @retval None
# k( W$ x2 j8 j3 X" t# [# _: e2 ]4 F - */
1 {* m$ Q9 j# A: K7 g8 F - void SVC_Handler(void)& d% U7 R3 \% ]
- {0 ?0 ~" F) i- s$ V1 S
- }# ~6 |6 Z1 b0 M7 r2 v/ R5 `
- . _* I* _5 O+ f' k7 I5 J) n
- /**
( F8 y9 V9 J9 X/ F! K. i - * @brief This function handles PendSVC exception.8 V" b8 M: P3 X/ m6 d5 W! E
- * @param None9 I0 R: r* X2 m( L% K3 z5 ]
- * @retval None
) ]" s% S+ `* a, Y) C9 `1 ?# f - */
0 r/ |4 X6 a/ P! o) n - void PendSV_Handler(void): c' n8 h' m# _' N- q
- {+ g0 W4 ~9 d) P! m/ K! S9 U% \
- }
复制代码
/ i3 Z2 m* l8 r" y; R0 M# l+ z N4.10 第7步,添加头文件的汇总文件includes.h/ ~* @6 [# B4 k. i4 }
在User文件夹下添加文件incudes.h,直接从本章节教程配套例子的User文件夹复制即可。此文件主要用于RTX5的各种头文件汇总。( k" d j0 t3 A: p4 ]8 i4 W
* B; U& a2 e6 o
" u% {$ L @/ t, T1 d* |. ^% q2 x" e, V% G I/ I2 w% R
4.11 第8步,HAL库时间基准stm32h7xx_hal_timebase_tim.c
: O( x! O8 d9 W# ~由于RTX5和HAL库需要一个时间基准,而且默认都是用的滴答定时器,所有要有一个选用其它的时间基准。当前的处理方案是为HAL库提供一个时间基准文件stm32h7xx_hal_timbase_tim.c。此文件+ ~$ Z P7 U' v7 x
! q ], O& [3 q: L) b里面做了两套方案,一个是使用TIM7做时间基准,另一个是使用RTX5的API做时间基准,通过条件编译做选择。默认是采用RTX5的API做时间基准。/ u, C# H, U9 H' ?( r
9 Q, B0 A1 ^6 L: c: W3 S
- /*
% H4 t8 _& \: T5 q+ Z9 a - *********************************************************************************************************, u3 e6 o1 l* T* M! r u, A! ?
- * 函 数 名: HAL_Delay
+ I8 [9 V! \/ l% d3 b - * 功能说明: 重定向毫秒延迟函数。替换HAL中的函数。因为HAL中的缺省函数依赖于Systick中断,如果在USB、SD# f( Q5 ]; q7 U% V( o# ]
- * 卡中断中有延迟函数,则会锁死。也可以通过函数HAL_NVIC_SetPriority提升Systick中断
- |8 m/ }" O9 \9 R - * 形 参: 无
: \! b5 N' q, j) ` - * 返 回 值: 无
/ t9 m1 Z2 t, A* s6 ^ - *********************************************************************************************************7 W( A- T! C( I. ^9 X: {8 O
- */: t* M: w" U4 V+ N8 `$ w
- void HAL_Delay(uint32_t Delay)
+ I2 d5 A# ?' e4 b; |, @0 }7 v - {; B4 p5 ?8 o& ^
- bsp_DelayMS(Delay);
# y* |3 Y! v% e4 v: F4 K - }* f6 c: G# \1 v; {, H
6 G+ b- d3 F; {0 i, O' n- Z- HAL_StatusTypeDef HAL_InitTick (uint32_t TickPriority)
, T$ U. j" j" Y+ Y, ]5 j3 C - { u3 a3 v/ B( o! A8 r/ y( j
- return HAL_OK;/ n$ a* ~! i, I# _
- }
: ?8 u) w8 f- q - * E& h/ `3 y, O$ z. b% ~( P; O
- uint32_t HAL_GetTick (void)
; P4 r" J6 S9 W7 w( j$ f9 ` - {8 g) C5 d3 @9 ?+ f8 {* S, ?7 l) E6 C* y
- static uint32_t ticks = 0U;
" A c/ Q; x' ~: N - uint32_t i;
, W% l! N0 T5 o) |6 f. H
' C! W) }# I+ n# f: |. y% {# b- if (osKernelGetState () == osKernelRunning)% Z, h9 e6 S. Q D( ? I& N
- { t& m5 H) c; \1 e' h6 ^: g
- return ((uint32_t)osKernelGetTickCount ());- \0 X' @; w3 C+ g8 O6 Y- \
- }% g3 S$ {2 u$ i# S6 k
+ s' @8 y% w! U" ^/ ?1 x6 c5 {- /* 如果RTX5还没有运行,采用下面方式 */4 l; h0 Y; }1 B b: y
- for (i = (SystemCoreClock >> 14U); i > 0U; i--) 7 g3 \% d# N% {
- {
8 w" k+ k) D5 b+ z' H% O - __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP();
$ Y7 H/ _ [* R2 d) a5 `6 H - __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP();
( w+ r) v: m2 o - }
, h e: A8 h9 P4 p/ x7 F. Z/ b% ] - ( M( v, {0 _ n% j6 y7 _
- return ++ticks;
- Q6 @2 i9 e; y( F% g+ r- B - }
复制代码 ! U( l5 D; ^' T: s$ A& m4 `$ ]' f9 d
4.12 第9步,添加BSP驱动文件bsp_dwt.c: C" u7 z/ Z- }: f0 \! S, Q
添加bsp_dwt.c文件和bsp_dwt.h文件主要是因为第8步中的stm32h7xx_hal_timebase_tim.c文件里面的函数bsp_DelayMS要使用,此函数是基于DWT系统时钟周期计数器实现。6 ]8 O) M0 [8 l$ a6 m: C3 p
! M, F, G9 m" U7 S# |+ G6 |. n
& V) m! M/ [5 H+ j, ]; V5 y7 I2 V8 Y) J0 `
4.13 第10步,创建应用任务(重要,注意启动任务)8 H7 f) T9 w) |9 k7 a
应用程序比较简单,大家可以直接复制本章教程配置例子的main.c文件中的内容到自己工程里面测试。主要创建了如下几个任务:0 m3 I2 s- c2 o' c/ L' |
: {8 D+ j( s# p& ]# j: I2 G- }! r4 `. ?AppTaskUserIF任务 : 按键消息处理。
% Z, h# Q$ \! D5 G* x( X: ^" a3 u" x7 `
AppTaskLED任务 : LED闪烁。) W: h% `5 _$ t& q8 n0 x
) ~6 j8 T0 W# o, O7 }AppTaskMsgPro任务 : 消息处理,暂未使用。5 T r& }' W5 v0 i! K6 T. D
: \9 l( P$ X' c
AppTaskStart任务 : 启动任务,也是最高优先级任务,这里实现按键扫描。
Z% A0 b x1 k/ B6 N* m% \ a% M& V. u. \4 s4 U
osRtxTimerThread任务: 定时器任务,暂未使用。
) l, T- v4 I1 O
0 m- y( \$ c6 a0 l任务栈大小和任务控制块定义如下:' o/ U! @9 r6 ^2 \3 |" N
9 ]# j$ z; z- {( o' V- `- /*4 j9 G. E& \( z
- **********************************************************************************************************! I% u: P. z3 Z% q4 `' V9 a2 B
- 变量
% A1 V$ n( d! t3 k$ o V - **********************************************************************************************************
5 F. z& x5 b5 S" L: T5 U, j; d% k+ P - */
( d8 ]5 X- n0 l( z - /* 任务的属性设置 */
; O0 o; w' J0 a, [3 l - const osThreadAttr_t ThreadStart_Attr = 0 O$ K7 A# n& ?% s% b
- {6 @* j4 w5 X) I. j; J
- /* 未使用 *// r8 M& S0 } ^. H1 `8 o" o/ u
- // .cb_mem = &worker_thread_tcb_1,
3 q# p! y! z8 E5 J& F, U1 c$ A0 C - // .cb_size = sizeof(worker_thread_tcb_1)," Z$ V+ C' F6 V& w. R; C3 q5 T3 b
- // .stack_mem = &worker_thread_stk_1[0],
4 L d( O7 T$ X7 _. W$ B - // .stack_size = sizeof(worker_thread_stk_1),
1 L j' ? O- i4 o: o5 F - // .priority = osPriorityAboveNormal,
: d3 a. H* R6 U- c - // .tz_module = 0
" m- ]/ A, S# z% M& J7 m$ R9 h. ~ - * O3 r" ^$ L1 |5 g( e
- .name = "osRtxStartThread",. q/ B" {4 Z c( j! b; Q
- .attr_bits = osThreadDetached,
/ S+ z& G; ~0 j - .priority = osPriorityHigh4,
3 z! f R/ J. X& o+ z - .stack_size = 2048,/ [& \; }- m; q5 R" p7 o* @
- };
% t9 e! X! S* S |! C$ Z0 u
5 ]/ j, |+ d- F; M) l- const osThreadAttr_t ThreadMsgPro_Attr = 5 D# a: j9 F7 K; g" q. E
- {
7 q: x& {7 s" i; p - .name = "osRtxMsgProThread",. i2 K8 A- V$ t5 G! j% Q8 _! E1 N
- .attr_bits = osThreadDetached,
( v# y) P1 x6 z& A+ K" V6 x - .priority = osPriorityHigh3,
* d# F& k5 }' ~( |$ }5 o3 ` - .stack_size = 1024,6 y% J5 n$ p" v) Z" h6 Q P
- };
T, N* h7 v* M. s: T$ L' G, P
, s, A8 _0 X% T9 n1 @- Y/ D- const osThreadAttr_t ThreadLED_Attr =
2 A9 l4 \# N Z2 c& n+ \& l - {( w9 K; G$ K& b
- .name = "osRtxLEDThread",. u! s: z, B7 l3 [& | ^, _
- .attr_bits = osThreadDetached,
; p- d( @! [+ c1 J! e9 P - .priority = osPriorityHigh2,
( H l* W( Z; j7 d - .stack_size = 512,% T6 `& X9 z2 m* y
- };% ^% ^+ n; k% Q) a4 j4 e2 D
- 1 f" \. c; B L
- const osThreadAttr_t ThreadUserIF_Attr = - f- i, g" y8 V0 [
- {/ [; [) r# }% Y4 I2 e
- .name = "osRtxThreadUserIF",. j; e/ V. H' Z6 o2 D6 D
- .attr_bits = osThreadDetached,
' [7 u/ L' B: _. S - .priority = osPriorityHigh1,* X0 _( D6 {- l3 h& s
- .stack_size = 1024,
7 A8 b* |! q& N: W8 g7 Z! g - };
复制代码 ) V% _1 l' E" ?3 t* R, S/ Q7 ~7 D; M% Y
任务创建:
! L4 O; R: n; Y; X
F4 _# d- u! J/ a& e" j7 w- /*
* }0 @' }, a% y" w$ _ - *********************************************************************************************************+ T8 ~0 W! _8 `3 n
- * 函 数 名: main
; x* n- K5 E+ q/ M& A/ i( Y - * 功能说明: 标准c程序入口。
/ S" P5 c! ?9 n5 n& i - * 形 参: 无
1 r- X0 a s; |! H# p - * 返 回 值: 无
) z/ K/ F6 l6 z# _& t' { - *********************************************************************************************************
2 C- a* Q' y6 W! N% P$ p - */
' I# p6 h) k# ?% G- J! b! w - int main (void)
2 Q3 ?& U# h& D/ g# f% p3 g9 \ - { ; Z3 @6 o. G# l' h; E
- /* HAL库,MPU,Cache,时钟等系统初始化 */* U/ [0 M/ Y) \& F1 e
- System_Init();- t1 `3 M# {/ X- k6 f6 B
- & t( U; r( }+ S O% m0 ^* u+ S2 ]
- /* 内核开启前关闭HAL的时间基准 */+ i4 N% ]+ Y4 K8 G% i
- HAL_SuspendTick();( P5 c9 K( l( ^: b6 G8 i: p
- 9 [8 l6 r8 T. L: x
- /* 内核初始化 */8 V ~% K7 X: F/ q( k
- osKernelInitialize();
5 J5 N {/ J# Q6 L
4 |- Z3 w9 W; m* `% q& h- /* 创建启动任务 */
5 ~$ W6 Z) P3 J$ n7 n - ThreadIdStart = osThreadNew(AppTaskStart, NULL, &ThreadStart_Attr); " S% R& {0 o( P+ m; m
! @ m# O, u( a* p8 C3 c- /* 开启多任务 */( p) m6 k4 |8 S; Y+ p* s9 S! a
- osKernelStart();
# K* k" Z$ @( g% k3 k1 y6 ~ - ! S4 U& A3 X8 S" o3 K- m! H8 p
- while(1);
Y- f8 o" O$ ^% p4 e - }
4 v( C- I: l; v( D
4 f- F' }6 e, n1 u) F- /*& a h. S) i' I: }! ~7 ?
- *********************************************************************************************************/ L4 J) Y+ P/ K: t
- * 函 数 名: AppTaskCreate
, r r5 C/ ?+ k - * 功能说明: 创建应用任务
J2 \6 K3 l& |! w' \# E3 p - * 形 参: 无5 H3 n+ ]% s H# I- s5 z& q" I
- * 返 回 值: 无/ q0 m1 j4 H$ `5 a: d C5 P
- *********************************************************************************************************! Z" q# d% D. b6 C* ]) }$ x8 `
- */6 [' X1 H J8 S4 M
- static void AppTaskCreate (void)5 i7 y5 o! k; u9 }$ a$ [+ |8 O
- {) B) p; i: x# o- n- |% ^9 K
- ThreadIdTaskMsgPro = osThreadNew(AppTaskMsgPro, NULL, &ThreadMsgPro_Attr);
% \$ P. ]7 |, ] i. f! I: h - ThreadIdTaskLED = osThreadNew(AppTaskLED, NULL, &ThreadLED_Attr); 0 C0 w0 x% O" @8 d% \3 L
- ThreadIdTaskUserIF = osThreadNew(AppTaskUserIF, NULL, &ThreadUserIF_Attr); 6 |: Z5 c" b" r2 |4 H- _% u* W3 [
- }
复制代码 1 d! y6 M" ^! ~8 J! ]
这里我们重点看下启动任务,主要做了四个工作:6 O( ` x' ?# V6 {7 u8 @) q
+ L+ }. @2 j( ~' _
外设初始化bsp_Init。
G+ o' E$ ]8 p7 x 任务创建AppTaskCreate。
9 k% N/ R* V; d9 e3 C 需要周期性处理的程序bsp_ProPer1ms,对应裸机工程调用的SysTick_ISR。这个的实现非常重要,这样之前裸机里面使用的API,就可以直接在RTX5里面直接调用。1 x! }' I# J/ k3 m5 h6 I, c6 Z3 x
- /*
~5 B5 e; C# A l! S- k, E - *********************************************************************************************************+ z1 J" m2 [7 i8 H+ ?
- * 函 数 名: AppTaskStart
a0 P w: f# g p - * 功能说明: 启动任务,这里用作BSP驱动包处理。
" o w& V# D! b$ ^3 c, v& o z8 G - * 形 参: 无3 B7 L' ^+ S* A7 n% ^. _/ R
- * 返 回 值: 无9 o! F9 R' d! Q' ?
- * 优 先 级: osPriorityHigh4 # m' W8 h( A" y/ F8 G
- *********************************************************************************************************
0 O# t# t v2 p7 ? - */
: f& b% [3 Z8 X7 k& R - void AppTaskStart(void *argument)
& z) b: e( p2 A* `) r$ v a' \& z; L - {
3 t |; H) P; k0 M( l6 B, n - const uint16_t usFrequency = 1; /* 延迟周期 */
* m. I) g( F7 D I - uint32_t tick;% _+ C* W& L: M' ` D. Y+ M
9 ]- [( u" _0 M/ e- /* 初始化外设 */! J) \' C% k+ W# e! C
- HAL_ResumeTick();
/ P" f& n; j4 v - bsp_Init();
5 `7 H4 X& `2 O# ]6 w7 [- _ - 8 C7 O- l: |& \) j
- /* 创建任务 */
, }! h; H9 J! O( h. N- Q* G4 t2 A" J+ X - AppTaskCreate();$ b5 j8 W, U' K& X1 {
- 4 f: L7 I$ z o
- /* 获取当前时间 */
7 z: J( C% |/ H5 |( B - tick = osKernelGetTickCount(); $ q6 W3 s/ O- v" ]7 z
$ q9 B/ `. j7 Q- while(1)2 C! u9 D# U6 Z6 {; T- O
- {
r6 p0 Z- G/ m - /* 需要周期性处理的程序,对应裸机工程调用的SysTick_ISR */! F9 X/ `# G2 `. O# ^3 F: x& V
- bsp_ProPer1ms();
) O$ S8 O* x; |7 K& Z) X* S; l+ s2 i
) a9 Q% S3 O9 Z$ Y) v- f. A- /* 相对延迟 */
8 f+ ]4 k: q( S/ `& g - tick += usFrequency; - A. N/ @4 ^8 |0 _& R# G
- osDelayUntil(tick);
O. P, c( `1 v# I3 t" D - }; l. x8 M* g6 K0 c; `1 q
- }
复制代码
4 c! a% \5 F! y9 R4 Q4.14 常见移植错误总结3 E$ v2 G* n9 u! e B- d
常见的移植错误主要有下面几种情况:
' E4 i- t3 C$ o1 R! ?4 @- ~9 Y
! S H. U9 Q2 P. W6 N 编译后提示如下两种错误:- Z& n5 J5 }" G# y+ A; V+ }
Error: L6200E: Symbol PendSV_Handler multiply defined (by irq_cm4f.o and stm32h7xx_it.o).8 m) T! M# t* z2 M( t
& L8 M0 K' i' C9 s- ]Error: L6200E: Symbol SVC_Handler multiply defined (by irq_cm4f.o and stm32h7xx_it.o).
/ D' m) M/ [& F$ u4 s1 V7 ~7 M
z' ?5 A. ~* h; ~5 B+ Y# s解决办法:这是函数重定义了,直接将stm32h7xx_it.c文件里面的PendSV_Handler和SVC_Handler删掉。& r" ~+ X& o& Z7 D
0 d+ N2 i& J0 y1 w+ {0 J
提示如下错误& e; b+ K( p/ ?
Error: L6218E: Undefined symbol bsp_DelayMS (referred from bsp_fmc_io.o).0 O; X4 Z5 i+ K
2 v6 g n! g; D+ Z
解决办法:打开bsp_dwt.C文件中的条件编译。* K8 l7 z A/ S; j/ T7 t
* l5 f. y# U8 f& o) a4.15 实验例程
8 R( k/ W% N7 I Z r) Q本章节配套了如下几个例子供大家移植参考:$ U- M* c: K+ r( L
5 t+ M' l$ b, `6 B: Z. E! j
V7-400_Base Template; D ?8 @# j5 k: u9 J/ L
裸机模板,方便大家添加RTX5内核源码。+ c* ?! \6 W, X& y; U
F9 w+ z" [5 ?+ m# V V7-401_Threadx Kernel Template
- |% O* p; h7 x3 z X, G
0 W! `! I/ {. d' r$ {ThreadX内核模板。$ Q% `2 L& l3 d6 g
( @$ x% d: G5 k: E0 {- ^
MDK进入调试状态后,选择周期更新:
) _7 K/ H. X, t1 h' a% T
0 u# t" v& k7 q! f: ^, |) z e$ P6 r" ?, i
7 I3 v; R% c! Q* r# U$ A然后打开调试组件,注意和RTX4的调试组件位置不同:# `3 o4 p2 a& l3 ^: f
% D. _& H, q) x) i
7 y5 F7 z5 R: ?0 T' |
0 V# S& J N! h c0 S' }* L- _然后点击MDK的全速运行,
% X& Z+ Z" B9 s/ V) A! f, e: Y8 \2 p+ E5 X s4 v( W
( a. m! ]# S3 F5 y# W
1 h0 W) J# s/ i; l2 C/ m t
至此,就可以动态实时查看RTX5的运行状态:
: p1 k; l& U B$ I/ ~2 n' [0 X2 o2 N
) B, }3 Q7 b# e2 x0 Y
3 K/ B% ?/ j0 L9 B R5 q, ~
4.16 总结
; Y2 M0 m+ e3 L4 \! W y$ D ?5 J( G2 I本章节为大家讲解了RTX5 在MDK AC5上的移植方法,移植涉及到的知识点比较多,初学的话,建议实际动手操作一遍。1 o9 U, n( q' P5 e' f4 ^: j
# Q. b' V8 w( ]3 F' l0 M( s+ q5 f
5 V7 M: o/ n; Q! G$ r4 E, N
j+ g& [0 |/ l2 J |
好好学习