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