|
大家好,我是痞子衡,是正經(jīng)搞技術(shù)的痞子。今天痞子衡給大家分享的是在MDK開發(fā)環(huán)境下將關(guān)鍵函數(shù)重定向到RAM中執(zhí)行的幾種方法。
' Y" P' ^- g' C) Z這個(gè)關(guān)鍵函數(shù)重定向到 RAM 中執(zhí)行系列文章,痞子衡已經(jīng)寫過 《IAR篇》、《MCUXpresso IDE篇》,今天一鼓作氣把 Keil MDK 篇也寫了,做個(gè)全家桶。9 X6 t: T. z7 v: T" M/ X
把 Keil MDK 放到最后來寫,其實(shí)痞子衡是有用意的。第一篇寫 IAR,我們基本上是要純手工改鏈接文件。第二篇寫 MCUXpresso IDE,我們除了手工改鏈接文件,也在利用它的鏈接文件配置自動(dòng)生成功能。現(xiàn)在到了 Keil MDK,這個(gè) IDE 其實(shí)跟 MCUXpresso IDE 一樣也支持鏈接文件配置自動(dòng)生成,但是具體功能設(shè)計(jì)上有各有千秋,今天我們就來了解下:
% i; H2 g" B0 D$ P1 i, U/ GNote:本文使用的 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)中映射地址空間如下:
2 S3 y, d9 [) ]+ N0 z! o3 {5 q8 ]NOR Flash: 0x30000000 - 0x30FFFFFF (16MB)) G$ a9 R; W! s, Q; e7 o
ITCM RAM: 0x00000000 - 0x0003FFFF (256KB) d/ D; t) c! _$ T3 g+ A4 K
DTCM RAM: 0x20000000 - 0x2003FFFF (256KB). [" @, c; R- V4 U4 ?. U
OCRAM: 0x20200000 - 0x2037FFFF (1.5MB)
) J1 R# `& j4 Y9 S' K2 ^SDRAM: 0x80000000 - 0x83FFFFFF (64MB)
, c" y! R+ {% F7 M我們隨便選擇一個(gè)測試?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 中)。鏈接文件精簡如下:3 l2 ]; ]4 F) B3 M$ r( @9 y" k
LR_m_text 0x30002000 0x00FFE000 {# e% a3 \) W& ?2 y/ A8 ] ~9 W$ m% ]
VECTOR_ROM 0x30002000 FIXED 0x00000400 {
$ q. w/ l& e, I4 v4 ?0 G% j * (.isr_vector,+FIRST)2 L. [" J# ?5 E
}
9 U+ m/ |3 q/ K, N) n# A4 o% ] ER_m_text 0x30002400 FIXED 0x00FFDC00 {
) e" o, \. |& i1 A' M * (InRoot$$Sections)2 t1 `/ q1 E* Y0 M! v. x3 O: k+ Y
.ANY (+RO)+ R9 U ~* T( {. }% m
}6 _' ?5 I6 ?" l/ I
RW_m_data 0x20000000 0x0003F800 {2 i3 ~( B% J' Z* D( m* V3 m
.ANY (+RW +ZI)3 f. |% A- h9 H# n
}; J v0 s! }+ S' C# }: @
ARM_LIB_HEAP +0 EMPTY 0x00000400 {
3 Q. o- K. A* p }
, V$ n/ K8 o% l7 i4 \ ARM_LIB_STACK 0x20040000 EMPTY -0x00000400 {2 t' y \ z1 F3 k; Y: U) D
}' k7 N5 N( W; B% d& t
}
7 ]: w0 K* ^0 c ?現(xiàn)在我們再創(chuàng)建一個(gè)新源文件 critical_code.c 用于示例關(guān)鍵函數(shù),將這個(gè)源文件添加進(jìn) hello_world_demo_cm7.uvprojx 工程里,critical_code.c 文件中只有如下三個(gè)測試函數(shù)(它們在 main 函數(shù)里會(huì)被調(diào)用):
# V' h/ x( n6 R. Kvoid critical_func1(uint32_t n)
$ W4 H+ N' i- o{7 s; z$ ?/ q1 x1 f
PRINTF("Arg = %d .\r' p$ e& Z+ O1 i8 \* A ]% ?
", n);* Z$ U- K: Q) l/ q: z* x. T( W; X
}0 y( _- W+ G: N8 \0 u. j. C
void critical_func2(uint32_t n)- I6 _6 S y1 B4 e: n
{4 E& n6 i8 |3 G; ]" D! U
PRINTF("Arg * 2 = %d .\r
5 J, @7 r+ c) k# O: M", 2 * n);
" O3 `3 h# v& a2 _5 W}8 h( p1 H) Z! G. ?. ~
void critical_func3(uint32_t n)# I' s) j$ H5 h p8 y
{) u9 T1 X7 F' B8 O
PRINTF("Arg * 3 = %d .\r8 ~$ e9 C R+ Y. ]# J
", 3 * n);
7 q2 N( `% c8 h% Z2 F# {% {, g}2 f1 p9 j5 r. z! @& b' G0 w# `; F
編譯鏈接修改后的工程,然后查看其映射文件(hello_world_demo_cm7.map)找到跟 critical_code.c 文件相關(guān)的內(nèi)容如下,顯然 critical_code.c 中的三個(gè)函數(shù)都會(huì)被鏈在 Flash 空間里(均在 .text 段里)。
" m( u X4 I% Y' ^# Y% d1 S4 p* R===============================================================================
. R2 {1 u7 C+ e ^2 \" _3 UImage Symbol Table
! Z6 F+ Z! C' y% f. | Global Symbols4 I: g; w& { V1 Z
Symbol Name Value Ov Type Size Object(Section)
, t9 | L$ V* K' Z; N2 I. e% x critical_func1 0x30005429 Thumb Code 28 critical_code.o(.text.critical_func1)0 G* N' P& a8 l- C
critical_func2 0x30005449 Thumb Code 32 critical_code.o(.text.critical_func2)9 p+ D. ?/ s. c( @. P
critical_func3 0x30005469 Thumb Code 36 critical_code.o(.text.critical_func3)9 H* X `1 Q( g
===============================================================================
2 J# E% @3 m* _ e+ K* QMemory Map of the image; I5 {+ j0 |1 {! t( f* C! s
Execution Region ER_m_text (Exec base: 0x30002400, Load base: 0x30002400, Size: 0x00003b68, Max: 0x00fbdc00, ABSOLUTE, FIXED)
+ \( B2 v3 d5 h% ^ Exec Addr Load Addr Size Type Attr Idx E Section Name Object
7 G% J) u2 i$ g$ _ 0x30005428 0x30005428 0x0000001c Code RO 17 .text.critical_func1 critical_code.o" h% q2 T4 @( u6 B- V: s) V
0x30005444 0x30005444 0x00000004 PAD
# C5 t% Y0 Q. j8 a7 |9 U 0x30005448 0x30005448 0x00000020 Code RO 19 .text.critical_func2 critical_code.o# V3 ^8 x$ M! I
0x30005468 0x30005468 0x00000024 Code RO 21 .text.critical_func3 critical_code.o
]! V q4 t2 f 0x3000548c 0x3000548c 0x00000004 PAD
+ b8 p6 q, y7 |5 F===============================================================================
1 @, G9 ?) a+ ?0 V' X& d3 r zImage component sizes
/ E: u* I) A! c Code (inc. data) RO Data RW Data ZI Data Debug Object Name4 d# f. j8 ?* q# p! e
96 56 0 0 0 903 critical_code.o
3 O) O. B5 o% S! X0 N) B二、重定向到RAM中方法我們現(xiàn)在要做的事就是將 critical_code.c 文件中的函數(shù)重定向到 RAM 里執(zhí)行,原鏈接文件 MIMXRT1176xxxxx_cm7_flexspi_nor.scf 中指定的是 DTCM 來存放 readwrite 段,那我們就嘗試將關(guān)鍵函數(shù)放到 DTCM 里(如需改到 ITCM、OCRAM、SDRAM,方法類似)。# R0 r. _) o8 W
2.1 自定義section指定函數(shù) - 針對單個(gè)函數(shù)第一種方法是用 __attribute__((section("UserSectionName"))) 語法來修飾函數(shù)定義,將其放到自定義程序段里。這種方法主要適用重定向單個(gè)關(guān)鍵函數(shù),比如我們將 critical_func1() 函數(shù)放到名為 .criticalFunc 的自定義段里:
) c9 W, f1 v4 N, B6 l7 D7 s; J__attribute__((section(".criticalFunc"))) void critical_func1(uint32_t n)
/ I2 g7 r3 p9 j. ]: G- M8 E{9 m, M* Q7 x3 e4 m
PRINTF("Arg = %d .\r5 e( @- O' C, ]; S0 Y. N# l
", n);
; i3 [8 U) K" I+ v2 t}, P- T: x# o% a# k! v# n4 K* [
void critical_func2(uint32_t n)4 m6 V# J% L" R4 ~. X3 ]
{
0 ~- @; B, a, z1 t y3 i0 T- \ PRINTF("Arg * 2 = %d .\r
' b# M. j) O/ T B6 s", 2 * n);
" A! m* n3 w3 p- I8 H2 g}& r! \. Q X& A- \& \
void critical_func3(uint32_t n): r9 g$ |+ m) R
{
U/ V, C% o, Y( S4 i7 D* c PRINTF("Arg * 3 = %d .\r
4 u4 T' K# h _) n' @* S", 3 * n);) m, l- E$ @# A$ _' X' S
}
" l" b0 V y: C: A: x2 x然后在工程鏈接文件 MIMXRT1176xxxxx_cm7_flexspi_nor.scf 里將這個(gè)自定義的 section .criticalFunc 也放進(jìn) RW_m_data 執(zhí)行域中:/ M/ Q! A8 [ E3 M+ H8 s
LR_m_text 0x30002000 0x00FFE000 {
6 d, ]: R) _% O- k3 k" d( m, j& V2 j* j ; ...; `' S$ j8 \) W4 s# Q
RW_m_data 0x20000000 0x0003F800 {
" K% S" F: G: Q, g) W .ANY (+RW +ZI)
& @; t. S; M& p * (.criticalFunc) ;添加 .criticalFunc 段
4 J) c+ m5 X5 q1 l* z7 [; |9 ^& P) b ; 第二種寫法:*.o (.criticalFunc)6 e& W9 c9 M3 ~1 A, v6 `
}
1 M. M' Q: j4 d8 y2 A4 u ; ...
& y/ g J6 _+ ^+ P7 o}
- A2 V0 f' y1 \8 i) n編譯鏈接修改后的工程,然后查看其映射文件(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í)行域空間)。
9 y0 z3 ?) A" T0 O===============================================================================# }0 o' W0 R8 J, |, a
Image Symbol Table7 B9 p8 N. S7 {" h( I3 X/ s
Global Symbols1 _3 V+ O8 @4 ?3 w. l: I" K
Symbol Name Value Ov Type Size Object(Section)
5 M; X/ Y! ]0 I2 J critical_func1 0x20000001 Thumb Code 28 critical_code.o(.criticalFunc)
" f/ D- B0 d% _! E critical_func2 0x30005429 Thumb Code 32 critical_code.o(.text.critical_func2)4 d% L# k0 E. Q3 x% H. O
critical_func3 0x30005449 Thumb Code 36 critical_code.o(.text.critical_func3)
5 P" k* o( M5 H& h===============================================================================
, p# r3 g' l( U! Y4 [Memory Map of the image
7 J/ u1 m* `7 A, E Execution Region RW_m_data (Exec base: 0x20000000, Load base: 0x30005f60, Size: 0x00000078, Max: 0x0003f800, ABSOLUTE)
3 J, }# B, t: T6 Y( ^! l Exec Addr Load Addr Size Type Attr Idx E Section Name Object( |2 W5 @ z+ N( f3 w
0x20000000 0x30005f60 0x0000001c Code RO 17 .criticalFunc critical_code.o
$ V- M) C5 H# a. C2 Y$ F/ K# n Execution Region ER_m_text (Exec base: 0x30002400, Load base: 0x30002400, Size: 0x00003b60, Max: 0x00fbdc00, ABSOLUTE, FIXED). [* ^1 u D# @: P" L6 f+ B- ]
Exec Addr Load Addr Size Type Attr Idx E Section Name Object
! y' O4 [" w/ s 0x30005428 0x30005428 0x00000020 Code RO 19 .text.critical_func2 critical_code.o1 j4 Q9 w8 z" v
0x30005448 0x30005448 0x00000024 Code RO 21 .text.critical_func3 critical_code.o
4 k; F3 t0 y1 [ 0x3000546c 0x3000546c 0x00000004 PAD1 X: [- l( l; w& m
===============================================================================% `7 K% }3 G0 I
Image component sizes. w3 a/ U3 U5 M
Code (inc. data) RO Data RW Data ZI Data Debug Object Name
% _; R. c# z9 Q/ b4 F3 K 96 56 0 0 0 903 critical_code.o7 A, `2 M8 w( K- {, n3 D
2.2 自定義section指定函數(shù) - 針對同一文件里的多個(gè)函數(shù)第二種方法是利用 #pragma 語法來修飾函數(shù)定義(注意 AC5 編譯器 Armcc 和 AC6 編譯器 Armclang 語法不太一樣),將同一源文件里緊挨在一起的多個(gè)關(guān)鍵函數(shù)放到自定義段里。比如我們將 critical_func1() 和 critical_func2() 函數(shù)放到名為 .criticalFunc 的自定義段里:
; n9 B" W6 e% v# u+ \Note: 這種方法一般情況下不太推薦,代碼可移植性較差。 |
|