|

大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家分享的是在MDK开发环境下将关键函数重定向到RAM中执行的几种方法。
4 G {, I# f" K/ c6 u( c这个关键函数重定向到 RAM 中执行系列文章,痞子衡已经写过 《IAR篇》、《MCUXpresso IDE篇》,今天一鼓作气把 Keil MDK 篇也写了,做个全家桶。9 ?6 f0 C& u0 {2 i
把 Keil MDK 放到最后来写,其实痞子衡是有用意的。第一篇写 IAR,我们基本上是要纯手工改链接文件。第二篇写 MCUXpresso IDE,我们除了手工改链接文件,也在利用它的链接文件配置自动生成功能。现在到了 Keil MDK,这个 IDE 其实跟 MCUXpresso IDE 一样也支持链接文件配置自动生成,但是具体功能设计上有各有千秋,今天我们就来了解下:# o+ [+ ^7 W+ p$ T' m7 D
Note:本文使用的 Keil uVision 软件版本是 v5.31.0.0。一、准备工作为了便于描述后面的函数重定向方法实现,我们先做一些准备工作,选定的硬件平台是恩智浦 MIMXRT1170-EVK,主芯片内部有2MB RAM,外挂了 16MB Flash 和 2 片 32MB SDRAM。这些存储设备在芯片系统中映射地址空间如下:# |$ }8 v* n/ g3 L+ F4 o
NOR Flash: 0x30000000 - 0x30FFFFFF (16MB)
2 z2 l% i, c. y1 h" F# S/ AITCM RAM: 0x00000000 - 0x0003FFFF (256KB). s' N( \5 J* u' i: Q; q2 C3 J: h
DTCM RAM: 0x20000000 - 0x2003FFFF (256KB)
" u! g. h% J, W" x4 H, B. P, uOCRAM: 0x20200000 - 0x2037FFFF (1.5MB)
4 k! H/ i2 t' nSDRAM: 0x80000000 - 0x83FFFFFF (64MB)5 k$ a# D' ~# C! H& u; K/ s
我们随便选择一个测试例程:\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 中)。链接文件精简如下: a# u) w1 R& N; t& ~
LR_m_text 0x30002000 0x00FFE000 {4 n& ]% ^9 j9 ^1 _9 ?3 |
VECTOR_ROM 0x30002000 FIXED 0x00000400 {
. q1 Z: B" |% y8 {: O# ? * (.isr_vector,+FIRST)
. a! c; Q8 z% x# D" E }
! b2 j2 `( I( J$ t' n ER_m_text 0x30002400 FIXED 0x00FFDC00 {
: S# i" T/ Y0 p: T1 }3 o. O& i * (InRoot$$Sections)
. | f% M( [' G9 ^ x0 z2 z4 o .ANY (+RO)
X7 _6 k- z$ p& v3 I9 m& a7 J }- \. w& X3 l" u0 D3 y3 a/ g2 _1 K, N# B
RW_m_data 0x20000000 0x0003F800 {* x5 a. P1 I0 L7 V( f
.ANY (+RW +ZI)
L7 Z* ^3 ]% R8 r+ M }: u2 M7 L- i. x' `
ARM_LIB_HEAP +0 EMPTY 0x00000400 {) a' z1 s6 A$ y" q6 g! K
}6 K, `+ {2 y7 m- c
ARM_LIB_STACK 0x20040000 EMPTY -0x00000400 {
. ]( R% _. c1 s- I5 J* y) T }
0 l. {' c3 v5 j0 P, q/ z}
5 L' c$ f% [6 \; F- S* i+ l现在我们再创建一个新源文件 critical_code.c 用于示例关键函数,将这个源文件添加进 hello_world_demo_cm7.uvprojx 工程里,critical_code.c 文件中只有如下三个测试函数(它们在 main 函数里会被调用):. b) B2 m5 y3 i4 E* ~
void critical_func1(uint32_t n)
- G3 ~+ w3 X1 w( }{
+ F; e B3 a" p! `" t PRINTF("Arg = %d .\r
8 {. ]" }- J1 R, K3 `4 |", n);5 S. _- E* q3 ^9 I( A
}
0 x6 W1 \# x1 c- Q( ^! bvoid critical_func2(uint32_t n)% T/ |2 M g0 e; z0 ~! B
{$ P! t/ T9 B: Y4 _8 u h
PRINTF("Arg * 2 = %d .\r
' C @. P9 s+ d- l4 [", 2 * n);
% z3 L9 c6 X, \0 S- S}7 N% N. }8 F4 B r1 j
void critical_func3(uint32_t n)! ]% d. i7 K7 V, V: G8 F
{
# F& O3 E& `; b* Y) B& s PRINTF("Arg * 3 = %d .\r
6 r4 r _8 Q, g+ O", 3 * n);
) e) C- O) F% ^, q}5 ?# z$ V, h7 `. V$ O" Y
编译链接修改后的工程,然后查看其映射文件(hello_world_demo_cm7.map)找到跟 critical_code.c 文件相关的内容如下,显然 critical_code.c 中的三个函数都会被链在 Flash 空间里(均在 .text 段里)。
x; q3 y0 X) W2 j4 Z% V% N0 D===============================================================================
0 c, t4 @3 y( O9 o- f" @Image Symbol Table3 P! S, g+ @0 B% q% T
Global Symbols
[0 t6 k8 {; I9 O: m Symbol Name Value Ov Type Size Object(Section)
$ }! n2 G) w3 S2 b# Y; b' {* ~, | critical_func1 0x30005429 Thumb Code 28 critical_code.o(.text.critical_func1)
% u- Z0 O! ] [. l3 n+ S3 M% Y8 l critical_func2 0x30005449 Thumb Code 32 critical_code.o(.text.critical_func2)
, ?% L, p: k& l: L, N$ a critical_func3 0x30005469 Thumb Code 36 critical_code.o(.text.critical_func3)$ `8 O" @) a* ~2 b: S& | y
===============================================================================
6 B8 F- q6 q+ kMemory Map of the image
) K9 x% d! Y6 P* t9 e0 } Execution Region ER_m_text (Exec base: 0x30002400, Load base: 0x30002400, Size: 0x00003b68, Max: 0x00fbdc00, ABSOLUTE, FIXED)
5 G8 B7 }7 q+ w: }0 k! B Exec Addr Load Addr Size Type Attr Idx E Section Name Object
1 G+ A6 ]1 b8 w$ G8 j 0x30005428 0x30005428 0x0000001c Code RO 17 .text.critical_func1 critical_code.o, f H% k& n& {
0x30005444 0x30005444 0x00000004 PAD
$ u5 Z5 N, ]# J7 t. O- g }+ T! { 0x30005448 0x30005448 0x00000020 Code RO 19 .text.critical_func2 critical_code.o
& b) C3 e. T4 k! H 0x30005468 0x30005468 0x00000024 Code RO 21 .text.critical_func3 critical_code.o
1 m; p5 u9 s% z/ S 0x3000548c 0x3000548c 0x00000004 PAD
$ {) y$ {0 D! o6 p% e' Y===============================================================================
& Z! A% i' Q7 q" c$ KImage component sizes" v: H9 v2 {' V5 E$ q
Code (inc. data) RO Data RW Data ZI Data Debug Object Name
7 |1 d7 }$ c. J0 Y2 ^- B3 i 96 56 0 0 0 903 critical_code.o- H4 R; ] T9 c$ v5 J3 ~, h' k
二、重定向到RAM中方法我们现在要做的事就是将 critical_code.c 文件中的函数重定向到 RAM 里执行,原链接文件 MIMXRT1176xxxxx_cm7_flexspi_nor.scf 中指定的是 DTCM 来存放 readwrite 段,那我们就尝试将关键函数放到 DTCM 里(如需改到 ITCM、OCRAM、SDRAM,方法类似)。
; d; H& X" T$ t% _. |0 t2.1 自定义section指定函数 - 针对单个函数第一种方法是用 __attribute__((section("UserSectionName"))) 语法来修饰函数定义,将其放到自定义程序段里。这种方法主要适用重定向单个关键函数,比如我们将 critical_func1() 函数放到名为 .criticalFunc 的自定义段里:7 v8 i1 w9 S$ q* Z8 H( M- j2 @0 X
__attribute__((section(".criticalFunc"))) void critical_func1(uint32_t n)
( ^- h2 p( l' o: }* a! _8 z6 G{
* }- V; ~6 f. \/ o: { PRINTF("Arg = %d .\r
( u1 i! }0 c9 M f2 V5 U", n);
; u% M: N% Z: C% N/ F, b4 a}
( t% N3 a- D; Avoid critical_func2(uint32_t n)' O" E! j5 \( m' h
{
. k3 Y2 v9 M( U, Z5 M. A% R/ x PRINTF("Arg * 2 = %d .\r0 s: U4 Q$ Y n/ c
", 2 * n);! j0 R8 t: Q3 g+ s* P, h
}
& O# C7 R7 f% I4 X$ x# U2 Xvoid critical_func3(uint32_t n)
5 z4 M. f# L6 T{
: C3 f3 u8 i6 j( e PRINTF("Arg * 3 = %d .\r+ v4 S& y8 ^" a* D9 n% j# M
", 3 * n);, E; Y! g1 a: N3 H5 N" F3 D
}
* z; x. b- n- ~9 R' D. m2 o" E& Z然后在工程链接文件 MIMXRT1176xxxxx_cm7_flexspi_nor.scf 里将这个自定义的 section .criticalFunc 也放进 RW_m_data 执行域中:$ D! t4 |* J8 {) o! G$ d
LR_m_text 0x30002000 0x00FFE000 {+ H/ i: l6 M7 Q5 t
; ...6 N1 _/ x8 I4 {- e7 {+ L# x% V# w
RW_m_data 0x20000000 0x0003F800 {
( m' c) D5 ]7 s% n .ANY (+RW +ZI)9 k) |0 ^+ v0 d' L" x) }
* (.criticalFunc) ;添加 .criticalFunc 段
& |# _1 D/ W* O8 _2 S9 M, w ; 第二种写法:*.o (.criticalFunc)
3 y6 X. E' A4 S& \, @ }9 d$ o8 A b j/ A9 c- \; ]( [
; ...
5 d. l8 l1 G! l' J: V& v9 Q; [, K}
3 {7 L4 F$ B% A1 e编译链接修改后的工程,然后查看其映射文件(hello_world_demo_cm7.map)找到跟 critical_code.c 文件相关的内容如下,此时 critical_func1() 已经被放到自定义段 .criticalFunc 里,并且这个段被 MDK 底层链接器链接到了 RAM 里(RW_m_data 执行域空间)。
" T% D: u* V1 M( g6 b=============================================================================== Z) h/ Q( V q; ~; E
Image Symbol Table
/ a& [, t, K1 O1 K Global Symbols: }; [0 |+ `/ k7 Q
Symbol Name Value Ov Type Size Object(Section)
# v, C! s% }' O/ U% { critical_func1 0x20000001 Thumb Code 28 critical_code.o(.criticalFunc)! Y) e+ u+ G+ L7 K; X
critical_func2 0x30005429 Thumb Code 32 critical_code.o(.text.critical_func2)
6 F& {/ s$ v, v3 K: C8 @/ P8 z/ { critical_func3 0x30005449 Thumb Code 36 critical_code.o(.text.critical_func3)" E# L; O/ R* n. h; h- H0 h% r+ X% L9 T8 e
===============================================================================- D0 `# S0 a8 J, `& z |; x( F" E
Memory Map of the image
; o+ v$ q- ^5 j$ O# O8 N/ B! H Execution Region RW_m_data (Exec base: 0x20000000, Load base: 0x30005f60, Size: 0x00000078, Max: 0x0003f800, ABSOLUTE)
( a, j" X. y' ^& R! s Exec Addr Load Addr Size Type Attr Idx E Section Name Object
4 O, Q' p0 D" o M7 o 0x20000000 0x30005f60 0x0000001c Code RO 17 .criticalFunc critical_code.o
0 d+ m/ `4 u- Q1 ] Execution Region ER_m_text (Exec base: 0x30002400, Load base: 0x30002400, Size: 0x00003b60, Max: 0x00fbdc00, ABSOLUTE, FIXED)
0 R/ ^1 B& B$ V* E1 ~4 ^$ ] Exec Addr Load Addr Size Type Attr Idx E Section Name Object
2 j# P( v/ P: X$ e 0x30005428 0x30005428 0x00000020 Code RO 19 .text.critical_func2 critical_code.o" A" b4 A; c! ?4 r
0x30005448 0x30005448 0x00000024 Code RO 21 .text.critical_func3 critical_code.o5 g. |2 L. a6 f9 P
0x3000546c 0x3000546c 0x00000004 PAD% e7 B& G- O5 g/ V A/ j
===============================================================================
/ }- h. \- f/ `$ K' X. j7 ~/ V" AImage component sizes" T5 r* P2 V- l( W4 C& T6 b
Code (inc. data) RO Data RW Data ZI Data Debug Object Name. L e$ d% p H! G) G+ Q
96 56 0 0 0 903 critical_code.o
- p1 R: F2 M9 W& K% }; ?5 { c+ V2 N" R2.2 自定义section指定函数 - 针对同一文件里的多个函数第二种方法是利用 #pragma 语法来修饰函数定义(注意 AC5 编译器 Armcc 和 AC6 编译器 Armclang 语法不太一样),将同一源文件里紧挨在一起的多个关键函数放到自定义段里。比如我们将 critical_func1() 和 critical_func2() 函数放到名为 .criticalFunc 的自定义段里:
4 \% m0 {; L' C- iNote: 这种方法一般情况下不太推荐,代码可移植性较差。 |
|