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