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