• 如何使用sct文件、icf文件来定位不同的内存存储变量(cortex-m3平台)keil+iar


    好久没写博客了,快到国庆了,经历了一些项目和坑,还是要保持记录的好习惯,好记性不如烂笔头嘛。
        目前使用了cortex-m3内核的两款单片机:stm32f1和lpc1768的,虽说是cm3内核,但是两个芯片添加的外设是有区别的,很多外设的使用方式也是各有千秋,st在国内比较火,全国研讨会如火如荼,每年都有。lpc1768是属于NXP半导体,前身是飞利浦半导体,也算是老牌的半导体公司,相比较stm32,国内入门的论坛没有stm32火爆,但我相信质量过得去。
        
        两款单片机都是比较老了,stm32f1是2007年发布的,lpc1768是估计2009年左右,具体不清楚,我是看标准库上是这个日期,因此猜测。
        虽然不是老的芯片,但是市场依然有供应。
        可以作为arm入门的基础芯片。
        
        stm32f103zet是512flash,64ksram,而且是连续的sram分布,那么程序上使用基本上不用过多考虑;而lpc1768也是有64ksram的,但是是分为3个区域的,32ksram作为普通的sram,和stm32f1类似,使用无区别,但是另外两个16kb的内存空间是在另外的地址空间,手册原文:
        The LPC17xx contain a total of 64 kB on-chip static RAM memory. This includes the main 32 kB SRAM, accessible by the CPU and DMA controller on a higher-speed bus, and two additional 16 kB each SRAM blocks situated on a separate slave port on the AHB multilayer matrix.
        
        LPC17xx总共包含64 kB片上静态RAM存储器。 其中包括可由高速总线上的CPU和DMA控制器访问的主32 kB SRAM,以及位于AHB多层矩阵上独立从端口上的两个附加16 kB SRAM块。
        总结起来就是,32ksram的起始地址0x1000 0000,大小0x8000=64kb
        两个附加16 kB SRAM块的起始地址0x2007C000,而且是连续的,下面的计算可见一斑。
    hex(0x2007C000+0x8000)= 0x20084000
    hex(0x2007C000+0x4000)= 0x20080000
    因此在keil设置中,可以设置两个32kb的内存空间,而且如果使用了分散加载文件,那么两个附加16 kB内存就可以完全利用起来了,lpc1768这个设计的原因是想两个内存空间可以再单片机运行的过程中,分别取数据,快加usb和ethernet数据的读写,和普通的变量区分开来————论坛大佬解释的。具体链接找不到了。。
        如何使用呢?sct文件的使用参考了硬汉论坛的pdf文档,H7系列的。

    这里首先使用stm32来演示下:
        ; *************************************************************
    ; *** Scatter-Loading Description File generated by uVision ***
    ; *************************************************************

    LR_IROM1 0x08000000 0x00080000  {    ; load region size_region
      ER_IROM1 0x08000000 0x00080000  {  ; load address = execution address
       *.o (RESET, +First)
       *(InRoot$$Sections)
       .ANY (+RO)
       .ANY (+XO)
      }
      RW_IRAM1 0x20000000 0x00008000  {  ; RW data
       .ANY (+RW +ZI)
      }
      ; RW data - 32KB SRAM
      RW_IRAM2 0x20008000 0x00008000 {
      *(.RAM_D1)
      }
    }

    我把64kb分成两个32kb的空间, keil需要设置linker界面,使用自定义的sct文件

    ac6.14编译器实例:

    定义全局变量:
        __attribute__((section (".RAM_D1"))) uint32_t AXISRAMBuf[10];
        __attribute__((section (".RAM_D1"))) uint32_t temp = 0;
    下面的语句也是合法的,
        uint8_t   UART_TX_BUF[10]  __attribute__((section(".ARM.__at_0x2000B00A")));    //就是将串口发送的数据定位到RAM中起始地址为0X2000b00A
        编译之后,可以在map文件看到这几个变量的具体地址
        temp                                     0x20008000   Data           4  main.o(.RAM_D1)
        AXISRAMBuf                               0x20008004   Data          40  main.o(.RAM_D1)
        UART_RX_BUF                              0x2000b000   Data          10  main.o(.ARM.__at_0x2000b000)
        UART_TX_BUF                              0x2000b00a   Data          10  main.o(.ARM.__at_0x2000B00A)

    那么就是成功的,如果使用AC5编译器

    __attribute__((section (".RAM_D1"))) uint32_t AXISRAMBuf[10];
    __attribute__((section (".RAM_D1"))) uint32_t temp = 0;

    AXISRAMBuf[0] = 11;
    temp= 11;

    优化等级-00
    AXISRAMBuf    0x20008000 Data 40 main.o(.RAM_D1)
    temp        0x20008028 Data 4 main.o(.RAM_D1)
    优化等级-03
    temp        0x20008000 Data 4 main.o(.RAM_D1)
    AXISRAMBuf    0x20008004 Data 40 main.o(.RAM_D1)

    优化等级-03
    temp只定义,代码中不试用
    AXISRAMBuf   0x20008000 Data 40 main.o(.RAM_D1)

    可见,编译会把代码中不适用的变量,在linker的时候就,不分配空间了,相当于删除了这个变量

    lpc1768的芯片小技巧:
    使用iar编译器,测试通过,也记录下:
    使用两个sram的方法参见博客链接:
    https://blog.csdn.net/liming0931/article/details/108887551

    定义变量,int val_addr @0x2007C000;
    编译后map文件如下:
    val_addr                0x2007'c000    0x4  Data  Gb  main.o [1]
    成功!

    keil平台下有两种方法可以将lpc1768的两个内存使用起来

    1、keil选项设置

     

    ac5编译器定义变量,uint32_t variable2 __attribute__((at(0x2007C42C)));  // Place at 0x2007C000(因为lpc1768的库文件core_cm3.h,不支持ac6,暂时使用ac5)

     0x2007C42C这个地址需要查看map文件后在自定义地址,否则就会出现linker警告,比如0x2007C004,

    linking...

    .KEIL5OUTcheck.axf: Warning: L6918W: Execution region RW_IRAM2 placed at 0x2007c000 needs padding to ensure alignment 4 of main.o(.ARM.__AT_0x2007C004).

    为啥呢?

     意思是0x2007c000 到0x2007c007的空间没有使用。定义到0x2007c000链接就没有警告了,因为uart_data_to_linux,uart_data_to_g0这两个变量占用的空间比较大,linker自动将该变量分配到0x2007c000之后的内存地址中了,但是如果不适用iram2,那么只能分配到iram1中。

    2、使用自定义的sct文件

    iram2 记得不要打钩。

      然后定义变量:

    uint32_t variable2 __attribute__((at(0x2007C050))); // Place at 0x2007C050 
    __attribute__((section(".RAM_D1"))) uint32_t AXISRAMBuf[10];
    __attribute__((section(".RAM_D1"))) uint32_t AXISRAMBuf2[10]

    map文件如下:具体负

    AXISRAMBuf     0x2007c000   Data   40 main.o(.RAM_D1)
    AXISRAMBuf2       0x2007c028  Data    40 main.o(.RAM_D1)
    variable2        0x2007c050    Data    4 main.o(.ARM.__AT_0x2007C050)

    keil的linker模式是优先分配__attribute__((section(".RAM_D1")))这种形式定义的变量,如果使用下面的方式:

    uint32_t variable2 __attribute__((at(0x2007C000))); // Place at 0x2007C000 
    __attribute__((section(".RAM_D1"))) uint32_t AXISRAMBuf[10];
    __attribute__((section(".RAM_D1"))) uint32_t AXISRAMBuf2[10]

    linker报错,也无法生产map文件

    .KEIL5OUTcheck.axf: Error: L6985E: Unable to automatically place AT section main.o(.ARM.__AT_0x2007C000) with required base address 0x2007c000. Please manually place in the scatter file using the --no_autoat option. 

    --no_autoat具体怎么使用,暂时不了解。

     具体的link而使用方法,可以参考arm linker参考文件

    总结:

    使用__attribute__((at(0x2007C004))); 这种方法需要自己计算内存的地址相对比较麻烦,__attribute__((section(".RAM_D1")))

    使用__attribute__((section(".RAM_D1"))) ,省去了手动计算地址的麻烦,相对简单。ac5,ac6通用的。

  • 相关阅读:
    android: LayoutInflater使用
    android:ListView bbs Demo
    android:制作 Nine-Patch 图片
    android:单位和尺寸
    android:提升 ListView 的运行效率
    android:定制 ListView 的界面
    android:ListView 的简单用法
    android:创建自定义控件
    android:四种基本布局
    android:ProgressDialog控件
  • 原文地址:https://www.cnblogs.com/CodeWorkerLiMing/p/13755436.html
Copyright © 2020-2023  润新知