|
大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家分享的是在MDK开发环境下将关键函数重定向到RAM中执行的几种方法。+ B9 ]5 j X- w& `5 d
这个关键函数重定向到 RAM 中执行系列文章,痞子衡已经写过 《IAR篇》、《MCUXpresso IDE篇》,今天一鼓作气把 Keil MDK 篇也写了,做个全家桶。0 N3 I4 k% t% `* v# L
把 Keil MDK 放到最后来写,其实痞子衡是有用意的。第一篇写 IAR,我们基本上是要纯手工改链接文件。第二篇写 MCUXpresso IDE,我们除了手工改链接文件,也在利用它的链接文件配置自动生成功能。现在到了 Keil MDK,这个 IDE 其实跟 MCUXpresso IDE 一样也支持链接文件配置自动生成,但是具体功能设计上有各有千秋,今天我们就来了解下:0 i' V! N% A+ E" O2 N" F1 M% {
Note:本文使用的 Keil uVision 软件版本是 v5.31.0.0。一、准备工作为了便于描述后面的函数重定向方法实现,我们先做一些准备工作,选定的硬件平台是恩智浦 MIMXRT1170-EVK,主芯片内部有2MB RAM,外挂了 16MB Flash 和 2 片 32MB SDRAM。这些存储设备在芯片系统中映射地址空间如下:- X( O, f; G3 ]: {; n. e% _
NOR Flash: 0x30000000 - 0x30FFFFFF (16MB)" Q" Q5 R8 K9 \' b: M8 d
ITCM RAM: 0x00000000 - 0x0003FFFF (256KB)
7 f8 R0 }! x( N DDTCM RAM: 0x20000000 - 0x2003FFFF (256KB)
6 i8 C# p9 m; Z0 Q/ K7 ]OCRAM: 0x20200000 - 0x2037FFFF (1.5MB)* g) Z+ S9 D( _# `9 r5 S9 i. q
SDRAM: 0x80000000 - 0x83FFFFFF (64MB). M. S# ^& {6 q+ o
我们随便选择一个测试例程:\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 中)。链接文件精简如下:# A6 Q! [: `$ Z; Q E# Y: k" D
LR_m_text 0x30002000 0x00FFE000 {1 Q; S1 t* U$ e/ g: b5 }: f0 D, C
VECTOR_ROM 0x30002000 FIXED 0x00000400 {
+ A5 j, N) L: V. D+ S. K- Q7 R) B * (.isr_vector,+FIRST)
0 B! I Z: x. f }
) C8 p. E* r+ b. R" d& x) Y ER_m_text 0x30002400 FIXED 0x00FFDC00 {/ p, T5 Q% ?5 O; U7 [+ _
* (InRoot$$Sections), _4 I) H1 H& f
.ANY (+RO)
* w @- T7 i' l- W& S6 n }
5 N! G- A/ O! q$ ?, B0 X RW_m_data 0x20000000 0x0003F800 {* a5 x7 a& u, S: m/ `" I/ S5 q9 ?
.ANY (+RW +ZI)$ Z# y8 c3 a' q: O
}8 G8 p# v2 K8 Y9 m
ARM_LIB_HEAP +0 EMPTY 0x00000400 {
5 q$ I: y+ I. r" `' M0 b6 k( v }
# r7 f& V7 N ?! F+ Y ARM_LIB_STACK 0x20040000 EMPTY -0x00000400 {; |% E% I* ?; i" B0 ?+ y; J) @) X
}% |- k) i1 t1 l" z: i4 E& K
}' {, Y" b+ m+ e* L/ [5 {( Q ^) o' I
现在我们再创建一个新源文件 critical_code.c 用于示例关键函数,将这个源文件添加进 hello_world_demo_cm7.uvprojx 工程里,critical_code.c 文件中只有如下三个测试函数(它们在 main 函数里会被调用):
0 z [2 {6 }2 J: O6 F( a/ @. uvoid critical_func1(uint32_t n)6 s$ b7 D: ]( i3 K6 P0 M9 q2 |8 o
{. \. `. l: C( y8 J7 j4 ?$ N
PRINTF("Arg = %d .\r
" M" t8 `/ A( r", n);
' i5 b# b* L) r5 M9 s1 L% x& A' a}1 w( j" Y+ \' A7 x, W* E
void critical_func2(uint32_t n). v; y9 N, e+ ]( |) E1 u4 @
{9 |7 r/ s' w4 T$ b- N8 o
PRINTF("Arg * 2 = %d .\r( z% A- I' V: p; r( B8 f+ y
", 2 * n);& O3 m7 [# v2 ?( o# V
}
8 Z7 g) q5 X2 t- R: hvoid critical_func3(uint32_t n)2 H% |$ f* {. c) _+ M. P( I+ V7 p
{
1 L" ]% T$ S7 u& [ PRINTF("Arg * 3 = %d .\r8 O* s4 b0 e8 s. I- P8 y. D
", 3 * n);
! y8 J+ e' D6 E}! U) ^0 q/ A H' x
编译链接修改后的工程,然后查看其映射文件(hello_world_demo_cm7.map)找到跟 critical_code.c 文件相关的内容如下,显然 critical_code.c 中的三个函数都会被链在 Flash 空间里(均在 .text 段里)。. e2 ?1 c O$ b# M
===============================================================================
) _1 J- Z) O+ w, G% L( GImage Symbol Table
" M+ F6 C( O7 C- i _# `0 ~3 @ Global Symbols
' e8 k" \) Q* M" D Symbol Name Value Ov Type Size Object(Section)$ z# E G( ?) Z9 n
critical_func1 0x30005429 Thumb Code 28 critical_code.o(.text.critical_func1)2 } K K; N0 o! U" R
critical_func2 0x30005449 Thumb Code 32 critical_code.o(.text.critical_func2): ~5 V) b8 k2 y# c7 }) j
critical_func3 0x30005469 Thumb Code 36 critical_code.o(.text.critical_func3)
8 P$ {9 `! z4 E7 W# K===============================================================================3 U6 v' K8 w7 b+ B* P' S
Memory Map of the image
; @+ N0 E; H @0 Q k+ e7 o Execution Region ER_m_text (Exec base: 0x30002400, Load base: 0x30002400, Size: 0x00003b68, Max: 0x00fbdc00, ABSOLUTE, FIXED)# I y5 ?1 ]9 v. ~$ d
Exec Addr Load Addr Size Type Attr Idx E Section Name Object( {3 k3 O* F( |1 \& u4 y7 l% C
0x30005428 0x30005428 0x0000001c Code RO 17 .text.critical_func1 critical_code.o
$ r( J% c$ G$ }' K4 }# @$ B* K+ E$ c 0x30005444 0x30005444 0x00000004 PAD9 |+ t$ }6 C: g
0x30005448 0x30005448 0x00000020 Code RO 19 .text.critical_func2 critical_code.o' j- k. l( M; O- O1 ^4 m
0x30005468 0x30005468 0x00000024 Code RO 21 .text.critical_func3 critical_code.o
) z$ F& D1 x9 `3 C) n; N* p# w, ` 0x3000548c 0x3000548c 0x00000004 PAD7 x9 `. p4 i. J2 H
===============================================================================
: p* g0 F* W) N+ a0 ?- rImage component sizes4 \( i# }& ]$ ^/ g) E8 W' ^
Code (inc. data) RO Data RW Data ZI Data Debug Object Name
. B2 G3 ?8 r9 ~5 X& C2 H: m5 h 96 56 0 0 0 903 critical_code.o
) a5 {! p$ ^; B0 U3 N二、重定向到RAM中方法我们现在要做的事就是将 critical_code.c 文件中的函数重定向到 RAM 里执行,原链接文件 MIMXRT1176xxxxx_cm7_flexspi_nor.scf 中指定的是 DTCM 来存放 readwrite 段,那我们就尝试将关键函数放到 DTCM 里(如需改到 ITCM、OCRAM、SDRAM,方法类似)。( x, H( n$ g0 k" F7 U" e2 c4 p1 r
2.1 自定义section指定函数 - 针对单个函数第一种方法是用 __attribute__((section("UserSectionName"))) 语法来修饰函数定义,将其放到自定义程序段里。这种方法主要适用重定向单个关键函数,比如我们将 critical_func1() 函数放到名为 .criticalFunc 的自定义段里:
- d, ^3 \- t s$ E+ g) c. a/ s__attribute__((section(".criticalFunc"))) void critical_func1(uint32_t n)
& F. v/ H( |7 A* G$ L6 g7 H0 ?; m* E{
. D. e7 q6 K5 O PRINTF("Arg = %d .\r1 m Q [5 y P4 u
", n);
# j @' Y/ G$ ?, k# K* ]% \}
, Q7 m# n8 I% O" x: R% qvoid critical_func2(uint32_t n)
7 Q6 k! n+ I. K0 K! _. G( y5 X{
$ J- C4 l+ g' [" H6 K* R PRINTF("Arg * 2 = %d .\r
6 G$ V4 U2 J' B; o8 I( q2 X7 g", 2 * n);' N5 h! i" s/ c) `
}7 U1 T! ]$ k' r2 }
void critical_func3(uint32_t n)
' u; O! F$ o7 f{1 M( }; j8 ]6 a: K1 [: K. I4 f
PRINTF("Arg * 3 = %d .\r
0 S$ Q: |* |; q3 k1 F' d", 3 * n);2 l4 U' d3 o4 `
}
2 Y: W% I9 c# l然后在工程链接文件 MIMXRT1176xxxxx_cm7_flexspi_nor.scf 里将这个自定义的 section .criticalFunc 也放进 RW_m_data 执行域中:
& ~6 `* B8 O8 Y4 z' SLR_m_text 0x30002000 0x00FFE000 {
8 n& C- p4 ^( l0 z$ |4 O0 E8 W ; ...
$ I4 ^7 r8 B: N8 ]' Q+ w, j+ j7 y RW_m_data 0x20000000 0x0003F800 {
6 H+ {4 a* W# p3 B .ANY (+RW +ZI)* J3 b* X) m; I/ P$ N
* (.criticalFunc) ;添加 .criticalFunc 段
% U+ e; R! a2 }; L! [ ; 第二种写法:*.o (.criticalFunc)
9 t& V1 c2 X O; `! ^8 i }
) ?; D2 [# B0 b6 ] ; ...6 H) A( Z, s& p9 H2 ~6 W& g5 X% M4 l
}& I7 @, `+ @9 D& J1 \1 s6 ~' A
编译链接修改后的工程,然后查看其映射文件(hello_world_demo_cm7.map)找到跟 critical_code.c 文件相关的内容如下,此时 critical_func1() 已经被放到自定义段 .criticalFunc 里,并且这个段被 MDK 底层链接器链接到了 RAM 里(RW_m_data 执行域空间)。
0 G1 T/ x5 A$ b& l; s2 B===============================================================================) @0 G" j2 y1 K) a$ o
Image Symbol Table
7 h# N* ^& D! c Global Symbols
, e, ?) |$ Y% t8 I! a! l* I Symbol Name Value Ov Type Size Object(Section)
% ?. G9 A; e( p; x; S8 a critical_func1 0x20000001 Thumb Code 28 critical_code.o(.criticalFunc)
# x; F" p [- \, _' S/ h critical_func2 0x30005429 Thumb Code 32 critical_code.o(.text.critical_func2)
8 s, Y( U7 ?+ W* O/ _ critical_func3 0x30005449 Thumb Code 36 critical_code.o(.text.critical_func3)
; y+ t0 m0 M2 }2 o0 J& f; c7 H! `===============================================================================
+ q/ ]0 Q$ [4 i3 IMemory Map of the image& d5 \ R5 u0 q+ s
Execution Region RW_m_data (Exec base: 0x20000000, Load base: 0x30005f60, Size: 0x00000078, Max: 0x0003f800, ABSOLUTE)
+ y4 R* J/ I; e q Exec Addr Load Addr Size Type Attr Idx E Section Name Object
8 ^; G; ]+ s$ U1 L4 u$ A 0x20000000 0x30005f60 0x0000001c Code RO 17 .criticalFunc critical_code.o$ m4 W, t- d# H; @+ q4 r
Execution Region ER_m_text (Exec base: 0x30002400, Load base: 0x30002400, Size: 0x00003b60, Max: 0x00fbdc00, ABSOLUTE, FIXED)3 b8 l0 `: V, f0 L9 v
Exec Addr Load Addr Size Type Attr Idx E Section Name Object7 i7 r/ W- C& Z/ x9 x
0x30005428 0x30005428 0x00000020 Code RO 19 .text.critical_func2 critical_code.o
3 v* A$ O/ f6 f5 s% v* B6 X 0x30005448 0x30005448 0x00000024 Code RO 21 .text.critical_func3 critical_code.o. ?- _" K- ~4 d* A& E+ I
0x3000546c 0x3000546c 0x00000004 PAD' E- L, ?. U4 L$ A, K% B* ?! m5 [* W
===============================================================================
8 l1 [5 ^) J' M* n5 |2 IImage component sizes1 g: r7 R6 ]5 v/ ?6 a0 j# l# a1 J
Code (inc. data) RO Data RW Data ZI Data Debug Object Name! _! D! A( x/ K; ?
96 56 0 0 0 903 critical_code.o
0 n! X* B1 n4 i# s0 v: _: f2.2 自定义section指定函数 - 针对同一文件里的多个函数第二种方法是利用 #pragma 语法来修饰函数定义(注意 AC5 编译器 Armcc 和 AC6 编译器 Armclang 语法不太一样),将同一源文件里紧挨在一起的多个关键函数放到自定义段里。比如我们将 critical_func1() 和 critical_func2() 函数放到名为 .criticalFunc 的自定义段里:
: w5 e" Z5 v% A8 @9 l3 s* n) f5 hNote: 这种方法一般情况下不太推荐,代码可移植性较差。 |
|