|
大家好,我是痞子衡,是正經(jīng)搞技術(shù)的痞子。今天痞子衡給大家分享的是在MDK開發(fā)環(huán)境下將關(guān)鍵函數(shù)重定向到RAM中執(zhí)行的幾種方法。9 S6 Y$ @# [7 {/ g, `* d
這個(gè)關(guān)鍵函數(shù)重定向到 RAM 中執(zhí)行系列文章,痞子衡已經(jīng)寫過(guò) 《IAR篇》、《MCUXpresso IDE篇》,今天一鼓作氣把 Keil MDK 篇也寫了,做個(gè)全家桶。
' I- V2 _& e+ ]( X把 Keil MDK 放到最后來(lái)寫,其實(shí)痞子衡是有用意的。第一篇寫 IAR,我們基本上是要純手工改鏈接文件。第二篇寫 MCUXpresso IDE,我們除了手工改鏈接文件,也在利用它的鏈接文件配置自動(dòng)生成功能,F(xiàn)在到了 Keil MDK,這個(gè) IDE 其實(shí)跟 MCUXpresso IDE 一樣也支持鏈接文件配置自動(dòng)生成,但是具體功能設(shè)計(jì)上有各有千秋,今天我們就來(lái)了解下:
. p/ I8 T9 @0 A. N, D6 K R( zNote:本文使用的 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)中映射地址空間如下:# k( M( Y2 p* c/ \% k) n, d+ s
NOR Flash: 0x30000000 - 0x30FFFFFF (16MB)
' o! G s* T7 A9 e( M( NITCM RAM: 0x00000000 - 0x0003FFFF (256KB)
x' q' H& g, t* q5 UDTCM RAM: 0x20000000 - 0x2003FFFF (256KB)% [! g& L8 V% p% Q
OCRAM: 0x20200000 - 0x2037FFFF (1.5MB)) a. \" \6 [ r
SDRAM: 0x80000000 - 0x83FFFFFF (64MB)+ Z1 Z, A$ Q5 d! v7 l( U
我們隨便選擇一個(gè)測(cè)試?yán)蹋篭SDK_2.10.0_EVK-MIMXRT1170\boards\evkmimxrt1170\demo_apps\hello_world\cm7\mdk,其中 flexspi_nor 工程是最典型的代碼鏈接場(chǎng)景(見 MIMXRT1176xxxxx_cm7_flexspi_nor.scf 文件),全部的 readonly 段分配在 0x30000000 - 0x30FFFFFF 空間(在 Flash 中),全部的 readwrite 段分配在 0x20000000 - 0x2003FFFF 空間(在 DTCM 中)。鏈接文件精簡(jiǎn)如下:3 T$ y( d/ \% q9 y3 b7 D# ?
LR_m_text 0x30002000 0x00FFE000 {, p' m# D9 N" G; w; w
VECTOR_ROM 0x30002000 FIXED 0x00000400 {
: X- Z3 x: h- w! U) ^ * (.isr_vector,+FIRST)
& d! A/ y s [4 \9 }3 N8 Z }
' U/ ?) I9 t7 q4 ^ ER_m_text 0x30002400 FIXED 0x00FFDC00 {3 U2 |+ y% W& t/ g8 t2 }) _$ f
* (InRoot$$Sections)
9 \% E7 S9 w. b0 ?4 H& m7 R .ANY (+RO)
; F& O; ^7 U D' b6 M }
9 t! D. P7 u2 e( Q4 k; c/ Q RW_m_data 0x20000000 0x0003F800 {& _* Q" o }. a I
.ANY (+RW +ZI)
( s7 C& t9 P9 O" q3 i. ]( ^. X }& l1 u" W$ V8 Z6 T
ARM_LIB_HEAP +0 EMPTY 0x00000400 {
2 G; D# `. E4 y5 j/ b# V, e1 n, x3 \6 s }
; p! |5 F/ N+ m9 D7 \5 \ ARM_LIB_STACK 0x20040000 EMPTY -0x00000400 {
0 Z1 c; y: _7 M4 z0 H }
3 j1 Y! {% v. c1 v* P}
, w& T0 V2 h, |; o2 ~) M現(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)用):
) Y- B/ s0 g8 Q# Z$ N: f, s) @/ Ivoid critical_func1(uint32_t n)& H# f& A0 C/ k: Q w% F' c
{ z, h7 L# n- q8 x& f: [1 h F/ Y4 E
PRINTF("Arg = %d .\r
/ ]8 ]6 t+ x# _6 u! h5 ^) z9 K", n);
* D5 H; M+ U$ n}* K3 r6 ]% a2 q) [
void critical_func2(uint32_t n)* a! T. }" h$ l" S! x' K2 z
{9 C, x7 L: i5 _
PRINTF("Arg * 2 = %d .\r
: H+ P: r/ A S5 }4 R", 2 * n);5 o8 E6 h) ?7 h$ I2 @
}
+ t5 }% X3 S: E P p% ]void critical_func3(uint32_t n)
! O1 k; c0 B6 n{
# m& R: B+ A/ |7 D( e: o3 m8 b PRINTF("Arg * 3 = %d .\r% J: k& E8 v. X4 t: [5 E8 S
", 3 * n);. u, k/ _$ y6 S( _$ Q9 q
}2 _# \' V2 v' u: p& H9 u
編譯鏈接修改后的工程,然后查看其映射文件(hello_world_demo_cm7.map)找到跟 critical_code.c 文件相關(guān)的內(nèi)容如下,顯然 critical_code.c 中的三個(gè)函數(shù)都會(huì)被鏈在 Flash 空間里(均在 .text 段里)。
/ [, P7 Y2 O- N: ?; |===============================================================================7 \9 D* U5 C! O& r9 R; y; E
Image Symbol Table
9 q5 s5 y3 C/ D* y. U- F4 k* i% C1 x( S Global Symbols* ^0 f* k1 t; _' d" r( c% i( F) a8 N
Symbol Name Value Ov Type Size Object(Section). r" Z* v2 b0 Q4 v D1 p4 M
critical_func1 0x30005429 Thumb Code 28 critical_code.o(.text.critical_func1)
5 V8 C8 e: O. z* X( U7 p# ? critical_func2 0x30005449 Thumb Code 32 critical_code.o(.text.critical_func2)0 k' ?) C$ H6 J1 a9 z! O! ~( x2 z2 D; V
critical_func3 0x30005469 Thumb Code 36 critical_code.o(.text.critical_func3)
7 y3 j; U/ i" `5 S6 t" D===============================================================================' Z4 L' D I" o5 ]1 b ^. I. Z
Memory Map of the image
* H$ _+ a3 `2 S% F& h0 j Execution Region ER_m_text (Exec base: 0x30002400, Load base: 0x30002400, Size: 0x00003b68, Max: 0x00fbdc00, ABSOLUTE, FIXED)) H/ [7 a, X7 |" i: }. D9 |
Exec Addr Load Addr Size Type Attr Idx E Section Name Object6 i. U$ Z2 m5 l; ~) j# X* k
0x30005428 0x30005428 0x0000001c Code RO 17 .text.critical_func1 critical_code.o
- n. W( O J$ A, { 0x30005444 0x30005444 0x00000004 PAD
$ a: m: x4 m- J; F4 Z+ m [0 P 0x30005448 0x30005448 0x00000020 Code RO 19 .text.critical_func2 critical_code.o
, @2 x( {2 ], Y. O( | 0x30005468 0x30005468 0x00000024 Code RO 21 .text.critical_func3 critical_code.o; O/ r) \$ z# V3 j3 ~
0x3000548c 0x3000548c 0x00000004 PAD
5 A$ \ A I. y6 _" M===============================================================================
0 F/ I1 b _& j% F DImage component sizes/ q: q; p" Y% b; H, G
Code (inc. data) RO Data RW Data ZI Data Debug Object Name
. X7 {$ J6 i: o' U7 E 96 56 0 0 0 903 critical_code.o
) I. Q" j* y1 N m二、重定向到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,方法類似)。& W1 r1 C6 m9 Z: M% i b# e
2.1 自定義section指定函數(shù) - 針對(duì)單個(gè)函數(shù)第一種方法是用 __attribute__((section("UserSectionName"))) 語(yǔ)法來(lái)修飾函數(shù)定義,將其放到自定義程序段里。這種方法主要適用重定向單個(gè)關(guān)鍵函數(shù),比如我們將 critical_func1() 函數(shù)放到名為 .criticalFunc 的自定義段里:) U D. U3 E3 p: m$ R6 o. g
__attribute__((section(".criticalFunc"))) void critical_func1(uint32_t n). z! Q1 @- n% o- {( T! z1 z
{
: i5 E0 S8 S0 u$ t1 G PRINTF("Arg = %d .\r. _2 C2 [+ @) l3 p$ Z. H
", n); ^- Q" V( m) l0 O6 D& |" `
}8 ?. Z# K9 B, `
void critical_func2(uint32_t n)$ J9 h6 T0 T* ]9 s$ Z
{
# Q# U6 E8 k) M/ N% G. K& S5 m PRINTF("Arg * 2 = %d .\r
+ {! m1 v$ J0 x2 g. M", 2 * n);6 Y, L' p; \; K7 b" h6 b8 Y7 P
}0 H) v4 l" m0 V' H. q3 N/ N" X
void critical_func3(uint32_t n)
! O6 ^, B3 m$ W) n9 Y+ Q- C{
: r4 ~ o" V" z) C5 H, F0 E PRINTF("Arg * 3 = %d .\r
/ |- x3 ` p) b- N. ]# v5 T", 3 * n);0 e% P! E: w2 E1 L( _) {
}
3 ?, r% @6 G: E5 P然后在工程鏈接文件 MIMXRT1176xxxxx_cm7_flexspi_nor.scf 里將這個(gè)自定義的 section .criticalFunc 也放進(jìn) RW_m_data 執(zhí)行域中:# ?; p! J6 t- j7 N
LR_m_text 0x30002000 0x00FFE000 {" y3 w5 @7 @) p( i
; ...% [0 C. d. @' y( \+ S/ k5 P0 [& A
RW_m_data 0x20000000 0x0003F800 {4 ?4 ?; l/ g/ P, B) O
.ANY (+RW +ZI)) n' [( Y# @9 u/ _
* (.criticalFunc) ;添加 .criticalFunc 段
5 y' F3 Q. T) z ; 第二種寫法:*.o (.criticalFunc)" {' v$ }# z9 c
}
8 K5 d! A) W. f$ h3 A8 L ; ..." ~/ B& ~0 t; G
}
, \5 J8 K; K- ?$ D K: ^, ~" ~編譯鏈接修改后的工程,然后查看其映射文件(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í)行域空間)。6 }/ n+ L( b8 x0 R. {, c- J
===============================================================================/ E; j: Q6 Y/ _2 m
Image Symbol Table
2 N1 E4 p- H' e( V1 Q: e. Y# C( x4 Y Global Symbols! L/ \( r: o x0 L) N0 D3 i& u
Symbol Name Value Ov Type Size Object(Section)
% D! p4 M( G* s: p1 R critical_func1 0x20000001 Thumb Code 28 critical_code.o(.criticalFunc)
# w3 b: A3 s5 w! O! _8 C critical_func2 0x30005429 Thumb Code 32 critical_code.o(.text.critical_func2)- t: t# ?$ l0 v: s( {3 q
critical_func3 0x30005449 Thumb Code 36 critical_code.o(.text.critical_func3)0 z' k6 H2 L) k1 b& N8 ?' i) z% Q
===============================================================================# Q" L, x# w f: V4 A0 ?/ t! v, g+ Q
Memory Map of the image' d4 ]" Q7 X7 \5 L8 `' [8 ^2 k
Execution Region RW_m_data (Exec base: 0x20000000, Load base: 0x30005f60, Size: 0x00000078, Max: 0x0003f800, ABSOLUTE)
; s& K: A( G( q; e5 O# q9 l1 f Exec Addr Load Addr Size Type Attr Idx E Section Name Object2 C* B, J2 N n0 z' V4 o
0x20000000 0x30005f60 0x0000001c Code RO 17 .criticalFunc critical_code.o
. x4 V/ G' `% O6 m& w7 P' I1 o7 I Execution Region ER_m_text (Exec base: 0x30002400, Load base: 0x30002400, Size: 0x00003b60, Max: 0x00fbdc00, ABSOLUTE, FIXED)
$ t' K6 u8 y# E! Y5 e! r) f Exec Addr Load Addr Size Type Attr Idx E Section Name Object
6 |9 l. X1 P* b 0x30005428 0x30005428 0x00000020 Code RO 19 .text.critical_func2 critical_code.o
3 s7 l: _0 e, i g0 `8 L% [ 0x30005448 0x30005448 0x00000024 Code RO 21 .text.critical_func3 critical_code.o1 ?( V% J2 p' |+ @5 Y4 K
0x3000546c 0x3000546c 0x00000004 PAD6 Z! u# y5 W( X; ?
===============================================================================
* i7 E" M1 M8 n5 FImage component sizes/ D9 D( v' b i$ p& A% U: j
Code (inc. data) RO Data RW Data ZI Data Debug Object Name
, S1 ~' _: t3 T3 M 96 56 0 0 0 903 critical_code.o
$ t3 e4 h. L& B( p2.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 的自定義段里:7 }6 @8 q P9 T9 D$ q$ D
Note: 這種方法一般情況下不太推薦,代碼可移植性較差。 |
|