|
大家好,我是痞子衡,是正經(jīng)搞技術(shù)的痞子。今天痞子衡給大家分享的是在MDK開(kāi)發(fā)環(huán)境下將關(guān)鍵函數(shù)重定向到RAM中執(zhí)行的幾種方法。
4 \6 [7 a: W6 G6 c. y% N這個(gè)關(guān)鍵函數(shù)重定向到 RAM 中執(zhí)行系列文章,痞子衡已經(jīng)寫(xiě)過(guò) 《IAR篇》、《MCUXpresso IDE篇》,今天一鼓作氣把 Keil MDK 篇也寫(xiě)了,做個(gè)全家桶。
3 H4 B5 b0 M. @8 n3 m把 Keil MDK 放到最后來(lái)寫(xiě),其實(shí)痞子衡是有用意的。第一篇寫(xiě) IAR,我們基本上是要純手工改鏈接文件。第二篇寫(xiě) MCUXpresso IDE,我們除了手工改鏈接文件,也在利用它的鏈接文件配置自動(dòng)生成功能,F(xiàn)在到了 Keil MDK,這個(gè) IDE 其實(shí)跟 MCUXpresso IDE 一樣也支持鏈接文件配置自動(dòng)生成,但是具體功能設(shè)計(jì)上有各有千秋,今天我們就來(lái)了解下:% a! @) e. ~: [8 S, w3 H
Note:本文使用的 Keil uVision 軟件版本是 v5.31.0.0。一、準(zhǔn)備工作為了便于描述后面的函數(shù)重定向方法實(shí)現(xiàn),我們先做一些準(zhǔn)備工作,選定的硬件平臺(tái)是恩智浦 MIMXRT1170-EVK,主芯片內(nèi)部有2MB RAM,外掛了 16MB Flash 和 2 片 32MB SDRAM。這些存儲(chǔ)設(shè)備在芯片系統(tǒng)中映射地址空間如下:# G3 h. {" `! e& H8 K; v1 Y1 x
NOR Flash: 0x30000000 - 0x30FFFFFF (16MB)
! X, w7 X: B( ]4 O! K) [ITCM RAM: 0x00000000 - 0x0003FFFF (256KB)
8 [' q( }3 a8 W. l1 g5 f- K5 NDTCM RAM: 0x20000000 - 0x2003FFFF (256KB)
; W- F/ a* T3 s( A! `1 `9 bOCRAM: 0x20200000 - 0x2037FFFF (1.5MB)
; o; z* y+ b* V) r' s! D9 hSDRAM: 0x80000000 - 0x83FFFFFF (64MB)
8 \! f2 n( G$ F# n3 C/ H9 P我們隨便選擇一個(gè)測(cè)試?yán)蹋篭SDK_2.10.0_EVK-MIMXRT1170\boards\evkmimxrt1170\demo_apps\hello_world\cm7\mdk,其中 flexspi_nor 工程是最典型的代碼鏈接場(chǎng)景(見(jiàn) MIMXRT1176xxxxx_cm7_flexspi_nor.scf 文件),全部的 readonly 段分配在 0x30000000 - 0x30FFFFFF 空間(在 Flash 中),全部的 readwrite 段分配在 0x20000000 - 0x2003FFFF 空間(在 DTCM 中)。鏈接文件精簡(jiǎn)如下:1 @9 d8 y, R2 F- y) ] a! h8 `* E
LR_m_text 0x30002000 0x00FFE000 {# M! c$ c8 S o7 K
VECTOR_ROM 0x30002000 FIXED 0x00000400 {3 e5 G# j- }& y. g. c+ F
* (.isr_vector,+FIRST)
& J3 ?8 R9 N+ P }
% m- \/ x; x3 e: [* W ER_m_text 0x30002400 FIXED 0x00FFDC00 {9 l8 T! K, c8 x/ V
* (InRoot$$Sections)
; G* B# X- n. ]* h .ANY (+RO)
3 T9 Z& H# M% @$ L }/ I2 w) M3 p) [0 `: W. q% ?
RW_m_data 0x20000000 0x0003F800 {4 S/ i# Q4 G; n* c- A( C
.ANY (+RW +ZI). f1 \1 J2 P; k' G- y' Q# O7 Z* y
}
* ?5 P% x) M) `$ T. T" _ ARM_LIB_HEAP +0 EMPTY 0x00000400 {! J: ]8 J5 k, z( N7 o) i5 c
}
* x1 o2 X% M( [1 w$ ~) U# j0 J ARM_LIB_STACK 0x20040000 EMPTY -0x00000400 {+ ?- f. A5 o: }0 i( s: p2 {
}2 X7 x0 U0 w9 E
}
6 Y( |/ q& v- d3 n8 ]現(xiàn)在我們?cè)賱?chuàng)建一個(gè)新源文件 critical_code.c 用于示例關(guān)鍵函數(shù),將這個(gè)源文件添加進(jìn) hello_world_demo_cm7.uvprojx 工程里,critical_code.c 文件中只有如下三個(gè)測(cè)試函數(shù)(它們?cè)?main 函數(shù)里會(huì)被調(diào)用):
: U& l7 y" v* \4 F; V% ]void critical_func1(uint32_t n)
) Q8 |8 F# J# }' H: X{
- {, @' d" ]2 g7 _4 g( D& ` PRINTF("Arg = %d .\r+ I5 i- H: B" G' o: l6 d
", n);$ _/ V( V% B1 r7 x0 u
}1 @7 A% Q7 w, N! U% X* f h2 H' D
void critical_func2(uint32_t n)- p9 m8 W, F& H$ L. w6 }
{# n+ p }2 U% R- V! k" m& }6 a5 H
PRINTF("Arg * 2 = %d .\r
% s$ y+ y% n" V+ c L* |/ O5 k", 2 * n);
1 p7 I4 Z; }' H: z* k1 U}
2 k7 O* h$ w& X! T$ f$ x) dvoid critical_func3(uint32_t n)
+ C c; j4 K5 l{
2 F3 G, |5 @1 ~% K+ {3 E1 q PRINTF("Arg * 3 = %d .\r
6 Y, w: t& M6 l7 y4 h5 P4 @! w", 3 * n);
; v, u. b1 v K; d* B( W. s! H}
+ G! f% ^+ {5 |: p3 I& B編譯鏈接修改后的工程,然后查看其映射文件(hello_world_demo_cm7.map)找到跟 critical_code.c 文件相關(guān)的內(nèi)容如下,顯然 critical_code.c 中的三個(gè)函數(shù)都會(huì)被鏈在 Flash 空間里(均在 .text 段里)。
# U* N) y+ V3 _+ j6 x; F. F; Q" p7 I===============================================================================/ C( n) R$ W- V) V5 B/ I+ E5 I# t
Image Symbol Table" K7 \$ ~) d2 d
Global Symbols
8 {4 v; h2 s, _+ _) _% F @+ G0 B Symbol Name Value Ov Type Size Object(Section)
, z& f' H2 ~$ V critical_func1 0x30005429 Thumb Code 28 critical_code.o(.text.critical_func1)% N2 U; w7 \. W. Q$ @: Z2 l& g
critical_func2 0x30005449 Thumb Code 32 critical_code.o(.text.critical_func2)
5 w) f' ~3 r$ W# d) i0 ?1 H4 t critical_func3 0x30005469 Thumb Code 36 critical_code.o(.text.critical_func3)
9 e: n7 N/ {, n& g5 p3 t9 R$ V===============================================================================
+ Q3 h2 I* _& I; M4 HMemory Map of the image$ i( @& }) G8 h5 J0 a! _
Execution Region ER_m_text (Exec base: 0x30002400, Load base: 0x30002400, Size: 0x00003b68, Max: 0x00fbdc00, ABSOLUTE, FIXED)
( }( U2 d5 O0 A! k6 ] Exec Addr Load Addr Size Type Attr Idx E Section Name Object
* X' B& Q+ N: _) o 0x30005428 0x30005428 0x0000001c Code RO 17 .text.critical_func1 critical_code.o7 X) l. T9 g, b7 E
0x30005444 0x30005444 0x00000004 PAD
. n( j- I+ L( y7 ~* E6 {# G 0x30005448 0x30005448 0x00000020 Code RO 19 .text.critical_func2 critical_code.o( w% q: x/ }/ R- [" V
0x30005468 0x30005468 0x00000024 Code RO 21 .text.critical_func3 critical_code.o
9 Q8 W) |0 K2 f7 S 0x3000548c 0x3000548c 0x00000004 PAD
. ?4 e) Z/ N& N3 E, G, d& c# g/ l) t===============================================================================
6 m1 M8 _+ ^; K/ \! @, ZImage component sizes
' l, V" I6 ?; p0 I/ G Code (inc. data) RO Data RW Data ZI Data Debug Object Name+ v4 @3 c! a4 L/ j8 e
96 56 0 0 0 903 critical_code.o
) e9 Z3 i8 b! \# _: g9 F% E0 d二、重定向到RAM中方法我們現(xiàn)在要做的事就是將 critical_code.c 文件中的函數(shù)重定向到 RAM 里執(zhí)行,原鏈接文件 MIMXRT1176xxxxx_cm7_flexspi_nor.scf 中指定的是 DTCM 來(lái)存放 readwrite 段,那我們就嘗試將關(guān)鍵函數(shù)放到 DTCM 里(如需改到 ITCM、OCRAM、SDRAM,方法類(lèi)似)。
$ n0 ?* e4 X( e+ C2 a- e2.1 自定義section指定函數(shù) - 針對(duì)單個(gè)函數(shù)第一種方法是用 __attribute__((section("UserSectionName"))) 語(yǔ)法來(lái)修飾函數(shù)定義,將其放到自定義程序段里。這種方法主要適用重定向單個(gè)關(guān)鍵函數(shù),比如我們將 critical_func1() 函數(shù)放到名為 .criticalFunc 的自定義段里:
& @. J+ x, v1 F f5 {__attribute__((section(".criticalFunc"))) void critical_func1(uint32_t n)' k L1 K) L# k
{
+ e: ?' @. a+ ?- g7 { PRINTF("Arg = %d .\r% D# k$ D# F8 @5 s7 C. P
", n);, W$ \7 d% K4 j3 ^! ]3 @+ u
}
2 t' d+ |1 G" {- q6 b; ^; M7 fvoid critical_func2(uint32_t n): t. r: @$ _4 r/ @
{$ Q8 O( Z! J3 i' v" U
PRINTF("Arg * 2 = %d .\r3 F1 q% Z. T9 u0 H
", 2 * n);
; c8 P u( D4 m! N}4 m8 d# h# d. C$ n8 L
void critical_func3(uint32_t n). s9 t0 `5 o0 ?9 {8 B, F' k4 Q
{) [5 k f, I( Z) S- k
PRINTF("Arg * 3 = %d .\r
8 ` H p2 g. T( J' S+ ?", 3 * n);
/ _* Z! |/ o+ k/ m1 n}
0 Y- Y! t6 ?- I然后在工程鏈接文件 MIMXRT1176xxxxx_cm7_flexspi_nor.scf 里將這個(gè)自定義的 section .criticalFunc 也放進(jìn) RW_m_data 執(zhí)行域中:
+ H9 I; N0 \6 t: q' M5 x; ~# j$ NLR_m_text 0x30002000 0x00FFE000 {! u9 G! ~' {+ w+ Z
; ...* F' W1 W7 @7 a. o% U, B+ e: e
RW_m_data 0x20000000 0x0003F800 {
: l# ?1 ~' l" \# v/ e: n2 n! k' C .ANY (+RW +ZI)
% ^6 J7 x, ]* Q" X! a * (.criticalFunc) ;添加 .criticalFunc 段
# P& R1 O9 P. j- g9 z ; 第二種寫(xiě)法:*.o (.criticalFunc)
" z7 \( O; U* J; ~ }, {. s$ @/ \ D3 H' k
; ...) M' G. V2 M3 E/ q$ V, r' b1 v
}
% z+ P! _ X# F$ M' i8 m編譯鏈接修改后的工程,然后查看其映射文件(hello_world_demo_cm7.map)找到跟 critical_code.c 文件相關(guān)的內(nèi)容如下,此時(shí) critical_func1() 已經(jīng)被放到自定義段 .criticalFunc 里,并且這個(gè)段被 MDK 底層鏈接器鏈接到了 RAM 里(RW_m_data 執(zhí)行域空間)。
7 l t0 X4 Q- P- P/ J r. N1 p9 f C$ T===============================================================================
8 O# Q! q1 |$ c7 m, bImage Symbol Table
. I* w4 ?0 n9 N4 Q# e, I Global Symbols, x/ H: w- Q3 ~7 a( L2 D
Symbol Name Value Ov Type Size Object(Section)7 g3 N) f" j% ~
critical_func1 0x20000001 Thumb Code 28 critical_code.o(.criticalFunc)$ W: b W" O1 B- R
critical_func2 0x30005429 Thumb Code 32 critical_code.o(.text.critical_func2)
7 O( n# ]6 T5 s0 o F4 z critical_func3 0x30005449 Thumb Code 36 critical_code.o(.text.critical_func3)
: |8 R# E% J9 m# |; I===============================================================================/ ^9 {# q& n# o! g3 b7 c3 {# o
Memory Map of the image
& B3 S% C* q' H- d Execution Region RW_m_data (Exec base: 0x20000000, Load base: 0x30005f60, Size: 0x00000078, Max: 0x0003f800, ABSOLUTE)9 T2 U' x" p& o& q4 p; G. }$ T6 q
Exec Addr Load Addr Size Type Attr Idx E Section Name Object
* W2 G$ S7 g8 f1 y/ Z9 T9 X 0x20000000 0x30005f60 0x0000001c Code RO 17 .criticalFunc critical_code.o
: B* e8 I- e8 N, j$ g% ~; P% K Execution Region ER_m_text (Exec base: 0x30002400, Load base: 0x30002400, Size: 0x00003b60, Max: 0x00fbdc00, ABSOLUTE, FIXED)
4 O# t" ~; t+ y1 |5 G Exec Addr Load Addr Size Type Attr Idx E Section Name Object
: I7 F' T% J/ I4 a 0x30005428 0x30005428 0x00000020 Code RO 19 .text.critical_func2 critical_code.o
8 r1 B/ @0 r h4 b: u3 X! ` 0x30005448 0x30005448 0x00000024 Code RO 21 .text.critical_func3 critical_code.o' Z# | R7 a$ B; |! b5 A
0x3000546c 0x3000546c 0x00000004 PAD
8 X& x% _+ ^8 T Y===============================================================================& w1 z+ h9 Y/ w+ G
Image component sizes4 D5 o4 B& T! ]
Code (inc. data) RO Data RW Data ZI Data Debug Object Name2 K: X7 }0 G, c( g- K" v( f
96 56 0 0 0 903 critical_code.o: [4 p. V8 Q( s4 l/ K, j
2.2 自定義section指定函數(shù) - 針對(duì)同一文件里的多個(gè)函數(shù)第二種方法是利用 #pragma 語(yǔ)法來(lái)修飾函數(shù)定義(注意 AC5 編譯器 Armcc 和 AC6 編譯器 Armclang 語(yǔ)法不太一樣),將同一源文件里緊挨在一起的多個(gè)關(guān)鍵函數(shù)放到自定義段里。比如我們將 critical_func1() 和 critical_func2() 函數(shù)放到名為 .criticalFunc 的自定義段里:
" e n0 ~( b$ K6 P0 f3 m- FNote: 這種方法一般情況下不太推薦,代碼可移植性較差。 |
|