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