|
大家好,我是痞子衡,是正經(jīng)搞技術(shù)的痞子。今天痞子衡給大家分享的是在MDK開發(fā)環(huán)境下將關(guān)鍵函數(shù)重定向到RAM中執(zhí)行的幾種方法。; M, T9 o6 X0 a' B
這個關(guān)鍵函數(shù)重定向到 RAM 中執(zhí)行系列文章,痞子衡已經(jīng)寫過 《IAR篇》、《MCUXpresso IDE篇》,今天一鼓作氣把 Keil MDK 篇也寫了,做個全家桶。" J7 h# K4 T! [- R7 j0 V
把 Keil MDK 放到最后來寫,其實(shí)痞子衡是有用意的。第一篇寫 IAR,我們基本上是要純手工改鏈接文件。第二篇寫 MCUXpresso IDE,我們除了手工改鏈接文件,也在利用它的鏈接文件配置自動生成功能,F(xiàn)在到了 Keil MDK,這個 IDE 其實(shí)跟 MCUXpresso IDE 一樣也支持鏈接文件配置自動生成,但是具體功能設(shè)計上有各有千秋,今天我們就來了解下:
; G7 ~2 O: E2 ]Note:本文使用的 Keil uVision 軟件版本是 v5.31.0.0。一、準(zhǔn)備工作為了便于描述后面的函數(shù)重定向方法實(shí)現(xiàn),我們先做一些準(zhǔn)備工作,選定的硬件平臺是恩智浦 MIMXRT1170-EVK,主芯片內(nèi)部有2MB RAM,外掛了 16MB Flash 和 2 片 32MB SDRAM。這些存儲設(shè)備在芯片系統(tǒng)中映射地址空間如下:# g) O' B5 @9 m2 K S4 ?
NOR Flash: 0x30000000 - 0x30FFFFFF (16MB)" J4 g% v- ?8 S6 H" ?! o+ ]
ITCM RAM: 0x00000000 - 0x0003FFFF (256KB)$ S4 a4 O: y: Y6 Y
DTCM RAM: 0x20000000 - 0x2003FFFF (256KB)& N0 v$ V( e/ B! @
OCRAM: 0x20200000 - 0x2037FFFF (1.5MB)6 I4 x) { p( }' {7 H( F
SDRAM: 0x80000000 - 0x83FFFFFF (64MB)8 c5 h0 V5 L' z0 I
我們隨便選擇一個測試?yán)蹋篭SDK_2.10.0_EVK-MIMXRT1170\boards\evkmimxrt1170\demo_apps\hello_world\cm7\mdk,其中 flexspi_nor 工程是最典型的代碼鏈接場景(見 MIMXRT1176xxxxx_cm7_flexspi_nor.scf 文件),全部的 readonly 段分配在 0x30000000 - 0x30FFFFFF 空間(在 Flash 中),全部的 readwrite 段分配在 0x20000000 - 0x2003FFFF 空間(在 DTCM 中)。鏈接文件精簡如下:
- Q3 e3 h( t9 s) k7 ?LR_m_text 0x30002000 0x00FFE000 {' M7 H7 `. O3 o! [; ^- t( H
VECTOR_ROM 0x30002000 FIXED 0x00000400 {# X1 v) G5 W( Y; b8 P0 v" [3 B6 O
* (.isr_vector,+FIRST)) e. |$ @/ v# \: c3 c) Q4 ^
}
0 B) Y* X5 p$ y/ Z: I ER_m_text 0x30002400 FIXED 0x00FFDC00 {& u0 E0 B; q+ r" \/ R" o
* (InRoot$$Sections)
8 w8 ?+ I" k+ W .ANY (+RO)$ x) G# v, H; X: C9 o7 f9 n
}
" ~0 r3 D) E1 r# g RW_m_data 0x20000000 0x0003F800 {, Q/ C) b# U3 c C! Z
.ANY (+RW +ZI). u+ f6 P2 Q+ |0 N
}" N; I4 U1 B8 V5 q# v4 F
ARM_LIB_HEAP +0 EMPTY 0x00000400 {! Z' o% U- [* ~" d9 l9 i9 y1 x z3 D
}
, y2 v/ Y; k, |+ Z4 } ARM_LIB_STACK 0x20040000 EMPTY -0x00000400 {
. }9 b3 f" C! y# } }8 x8 z; {6 E3 O; k9 r
}; c1 _) Y; \! U! z' |: o) [. V- Z
現(xiàn)在我們再創(chuàng)建一個新源文件 critical_code.c 用于示例關(guān)鍵函數(shù),將這個源文件添加進(jìn) hello_world_demo_cm7.uvprojx 工程里,critical_code.c 文件中只有如下三個測試函數(shù)(它們在 main 函數(shù)里會被調(diào)用):
8 e' z; r* H: A) E6 l. Cvoid critical_func1(uint32_t n)3 K: ~/ s* B* k) z4 U
{
0 ^2 I7 v* }1 _$ d Q PRINTF("Arg = %d .\r
; C/ S/ N$ x/ K6 L. z3 d* T9 z% ^", n);) J6 c; X. P: K: w9 Q- a c
}
# t5 h) s6 B. R; rvoid critical_func2(uint32_t n)- u, \1 K$ T) Z/ p4 B
{
, O% s) R5 D# g6 y1 N1 ^( S PRINTF("Arg * 2 = %d .\r
. X! r7 K: s( c0 Z" y; P- d", 2 * n);, H0 i" f, _& Z2 W" x, N
}" O' u+ i$ P% @, o% \
void critical_func3(uint32_t n)
. Z7 X; K/ ?2 h: b9 T5 U+ a{
( B' y2 U @; q& Q PRINTF("Arg * 3 = %d .\r
5 _+ z, Q' Q0 _0 K" Q", 3 * n);
7 P2 B3 Z7 k* ^! c* ^- ^}
6 ^! r" T; p# _5 U編譯鏈接修改后的工程,然后查看其映射文件(hello_world_demo_cm7.map)找到跟 critical_code.c 文件相關(guān)的內(nèi)容如下,顯然 critical_code.c 中的三個函數(shù)都會被鏈在 Flash 空間里(均在 .text 段里)。
$ I1 W: s- i8 q7 C===============================================================================
+ v8 q1 ]' a' G" `9 ?Image Symbol Table* @% H9 A4 O; I- S. f/ M) C
Global Symbols* R4 A. w# }+ i4 e" n1 u: z/ a
Symbol Name Value Ov Type Size Object(Section)% ^2 {" s6 w z3 I" w
critical_func1 0x30005429 Thumb Code 28 critical_code.o(.text.critical_func1)
" a( t0 T# g7 K( j. }) [# F% I critical_func2 0x30005449 Thumb Code 32 critical_code.o(.text.critical_func2)8 Z" d4 n) D' _ _
critical_func3 0x30005469 Thumb Code 36 critical_code.o(.text.critical_func3). {5 @! B8 \5 T5 ~
===============================================================================: W4 i) w1 B! L4 E
Memory Map of the image3 ^" i, `. z( Q
Execution Region ER_m_text (Exec base: 0x30002400, Load base: 0x30002400, Size: 0x00003b68, Max: 0x00fbdc00, ABSOLUTE, FIXED)# d& v! i+ |4 v# j" ~
Exec Addr Load Addr Size Type Attr Idx E Section Name Object! K8 r$ j. C7 p. f/ l
0x30005428 0x30005428 0x0000001c Code RO 17 .text.critical_func1 critical_code.o
& Q' b7 {/ B+ {5 |$ z 0x30005444 0x30005444 0x00000004 PAD; w) z% r, Z/ C2 B
0x30005448 0x30005448 0x00000020 Code RO 19 .text.critical_func2 critical_code.o* x0 D5 B7 {; m! R
0x30005468 0x30005468 0x00000024 Code RO 21 .text.critical_func3 critical_code.o
. r1 N8 ~6 I; Y$ m 0x3000548c 0x3000548c 0x00000004 PAD
. U/ w% \! d) D===============================================================================% G4 E* @+ y9 u: H+ {2 W: L% q f
Image component sizes
; I. E8 R# ~( x$ J; M) B6 C, d/ u% e Code (inc. data) RO Data RW Data ZI Data Debug Object Name
1 N: v9 B9 N% z 96 56 0 0 0 903 critical_code.o8 g$ u9 R: ~6 M* x
二、重定向到RAM中方法我們現(xiàn)在要做的事就是將 critical_code.c 文件中的函數(shù)重定向到 RAM 里執(zhí)行,原鏈接文件 MIMXRT1176xxxxx_cm7_flexspi_nor.scf 中指定的是 DTCM 來存放 readwrite 段,那我們就嘗試將關(guān)鍵函數(shù)放到 DTCM 里(如需改到 ITCM、OCRAM、SDRAM,方法類似)。
# y0 [2 D- j1 q2.1 自定義section指定函數(shù) - 針對單個函數(shù)第一種方法是用 __attribute__((section("UserSectionName"))) 語法來修飾函數(shù)定義,將其放到自定義程序段里。這種方法主要適用重定向單個關(guān)鍵函數(shù),比如我們將 critical_func1() 函數(shù)放到名為 .criticalFunc 的自定義段里:4 l% A$ j4 f8 w' e. ]- G: Q
__attribute__((section(".criticalFunc"))) void critical_func1(uint32_t n)$ |. k% J& j- n
{ m& X! e2 k: f* r
PRINTF("Arg = %d .\r
+ x3 g1 y4 X$ M", n);
2 ]$ Y+ e1 P' L* r2 R}
; N* A; y% {5 k0 evoid critical_func2(uint32_t n)/ [$ ~* C5 B( d' Q- W0 F+ O( g7 f0 D
{
+ l$ W @( R1 h3 b: ?- T+ H! g PRINTF("Arg * 2 = %d .\r
! |# d* L+ n C/ g/ a8 u4 W", 2 * n);7 S$ L1 a r( {2 j" T/ n
}
% `8 {0 O( a. a: S8 Nvoid critical_func3(uint32_t n)
' G. T; o2 {# p$ }9 g: l{4 g$ I F3 Z6 _" \3 I
PRINTF("Arg * 3 = %d .\r5 c9 M6 q: ]2 B& Y5 {* F
", 3 * n);* l+ y. p% q% M G9 r/ I- l
}2 p o7 n% d2 x2 M4 q0 g* T
然后在工程鏈接文件 MIMXRT1176xxxxx_cm7_flexspi_nor.scf 里將這個自定義的 section .criticalFunc 也放進(jìn) RW_m_data 執(zhí)行域中:3 `) x n; M7 p, w
LR_m_text 0x30002000 0x00FFE000 {
3 j; [1 ^# h+ l. k7 c- ]+ \ ; ...# [' w/ L7 u% u6 m) v
RW_m_data 0x20000000 0x0003F800 {, e! ?1 v5 N$ n* H
.ANY (+RW +ZI)
+ S- w( q* L- y4 V! Q: Q+ \% | * (.criticalFunc) ;添加 .criticalFunc 段
* N/ U0 x5 x& _/ C" H* ^ B ; 第二種寫法:*.o (.criticalFunc)
4 G9 P- |& u2 v3 P# h }
/ d! T1 u7 \) D: w ; ...
3 U* D9 J }, O, L: d}
1 d% `/ B) I# _$ C& j編譯鏈接修改后的工程,然后查看其映射文件(hello_world_demo_cm7.map)找到跟 critical_code.c 文件相關(guān)的內(nèi)容如下,此時 critical_func1() 已經(jīng)被放到自定義段 .criticalFunc 里,并且這個段被 MDK 底層鏈接器鏈接到了 RAM 里(RW_m_data 執(zhí)行域空間)。; N% A6 @, M3 X2 Q
===============================================================================
E+ a2 C* W, w. |4 iImage Symbol Table
7 H7 x8 b6 s9 z3 o Global Symbols
u5 n. `2 t+ a" [ Symbol Name Value Ov Type Size Object(Section)
( W. f8 l+ b' A" @4 h8 r) S critical_func1 0x20000001 Thumb Code 28 critical_code.o(.criticalFunc)- x8 |. ~7 \ F
critical_func2 0x30005429 Thumb Code 32 critical_code.o(.text.critical_func2)7 [2 K. y% y6 k4 A( l
critical_func3 0x30005449 Thumb Code 36 critical_code.o(.text.critical_func3)
: j; _6 R* Q) x1 W8 ?: g===============================================================================) S; y% X) Y( ?" A& t" M# _
Memory Map of the image
' v% D: N/ ?( Z V- s0 h Execution Region RW_m_data (Exec base: 0x20000000, Load base: 0x30005f60, Size: 0x00000078, Max: 0x0003f800, ABSOLUTE)0 v6 U: R- ~$ w% d) Z) a( g
Exec Addr Load Addr Size Type Attr Idx E Section Name Object
/ z k+ k7 J% p- O 0x20000000 0x30005f60 0x0000001c Code RO 17 .criticalFunc critical_code.o
/ S3 a# O& `7 x$ c% _. |% Y+ h Execution Region ER_m_text (Exec base: 0x30002400, Load base: 0x30002400, Size: 0x00003b60, Max: 0x00fbdc00, ABSOLUTE, FIXED)4 F4 o" _% S# S. A c4 U+ h8 N' Q
Exec Addr Load Addr Size Type Attr Idx E Section Name Object. Y1 Z' p# ~4 |
0x30005428 0x30005428 0x00000020 Code RO 19 .text.critical_func2 critical_code.o! m5 [6 h _: j! |8 v! J
0x30005448 0x30005448 0x00000024 Code RO 21 .text.critical_func3 critical_code.o
# K0 @: d/ Y2 N 0x3000546c 0x3000546c 0x00000004 PAD A( g% f7 W; w/ _
===============================================================================7 `! w7 J: Y T* J. R# x1 w& f
Image component sizes$ f& q" \/ R; [3 P
Code (inc. data) RO Data RW Data ZI Data Debug Object Name, w6 U4 @% r8 G
96 56 0 0 0 903 critical_code.o* F# D: i. F+ [( E/ P0 E% l, w" {
2.2 自定義section指定函數(shù) - 針對同一文件里的多個函數(shù)第二種方法是利用 #pragma 語法來修飾函數(shù)定義(注意 AC5 編譯器 Armcc 和 AC6 編譯器 Armclang 語法不太一樣),將同一源文件里緊挨在一起的多個關(guān)鍵函數(shù)放到自定義段里。比如我們將 critical_func1() 和 critical_func2() 函數(shù)放到名為 .criticalFunc 的自定義段里:; L& g" ]& R% w. y0 p2 j
Note: 這種方法一般情況下不太推薦,代碼可移植性較差。 |
|