電子產(chǎn)業(yè)一站式賦能平臺(tái)

PCB聯(lián)盟網(wǎng)

搜索
查看: 45|回復(fù): 0
收起左側(cè)

在MDK開發(fā)環(huán)境下將關(guān)鍵函數(shù)重定向到RAM中執(zhí)行的幾種方法

[復(fù)制鏈接]

394

主題

394

帖子

2197

積分

三級會(huì)員

Rank: 3Rank: 3

積分
2197
跳轉(zhuǎn)到指定樓層
樓主
發(fā)表于 2021-9-12 22:52:00 | 只看該作者 回帖獎(jiǎng)勵(lì) |倒序?yàn)g覽 |閱讀模式
大家好,我是痞子衡,是正經(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/ G
  • Note:本文使用的 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: 這種方法一般情況下不太推薦,代碼可移植性較差。
  • 發(fā)表回復(fù)

    您需要登錄后才可以回帖 登錄 | 立即注冊

    本版積分規(guī)則


    聯(lián)系客服 關(guān)注微信 下載APP 返回頂部 返回列表