电子产业一站式赋能平台

PCB联盟网

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

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

[复制链接]

397

主题

397

帖子

2463

积分

三级会员

Rank: 3Rank: 3

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

    使用道具 举报

    发表回复

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

    本版积分规则


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