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