电子产业一站式赋能平台

PCB联盟网

搜索
查看: 41|回复: 0
收起左侧

在MDK开发环境下将关键函数重定向到RAM中执行的几种方法

[复制链接]

394

主题

394

帖子

2195

积分

三级会员

Rank: 3Rank: 3

积分
2195
发表于 2021-9-12 22:52:00 | 显示全部楼层 |阅读模式
大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家分享的是在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 h
  • Note: 这种方法一般情况下不太推荐,代码可移植性较差。
  • 回复

    使用道具 举报

    发表回复

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则


    联系客服 关注微信 下载APP 返回顶部 返回列表