首页 > 新闻中心 > 应用笔记

新闻中心

gcc环境下定义变量到固定地址的flash区的方法

更新时间:2011-02-15

  先转载一段内容,作者:myorange http://www.ourdev.cn/bbs/bbs_content.jsp?bbs_sn=3237920&bbs_id=9999

  前段时间有如题的问题,在论坛找了不少贴子看,有些启发和参考价值,但是没找到个能看了就可以用的答案(可 能有但我没找到),经过2个晚上的研读(《GNU-ld链接脚本浅析》:http://blog.chinaunix.net/u/13991 /showart_177822.html ) 和实践,终于自己把问题解决掉. 现在整理下,贴在这里.

  可能大家都熟悉 "char a[] PROGMEM={1,2,3,4}; "的定义方式,但是这种方式定义出来的变量地址

  是由编译器和连接器分配的,不能确定. 那有什么办法没呢? 答案是有。

 

  在网上搜索到2种方法:

  实验方法1. 在makefile 中定义section,如下:

  LDFLAGS = -Wl,--section-start=.mydatasection=0x001000,-Map=$(TARGET).map,--cref  

  然后引用

  const unsigned char data[] __attribute__((section(".mydatasection")))={   
  0x10,0x20,0x30   
  };   

  2. 在连接脚本里修改设置.

  在实验方法1

  在makefile 中设置

  LDFLAGS += -Wl,--section-start=.mydatasection=0x001500 

  在main.c中引用 
  const unsigned char mydata[4] __attribute((section(".mydatasection"))) = {'9','1','2','3'}; 

  但是要注意,mydatasection 的定位地址,要是其它段没有用到的才可以,否则会报错,有地址重叠.

 

  实验方法2. (修改连接脚本),winavr20071221 版本,默认用的是avr4.x 脚本.

  先是研读了下)《GNU-ld链接脚本浅析》:http://blog.chinaunix.net/u/13991/showart_177822.html (惭愧啊,现在也还是没读太明白)。

  我修改后的脚本内容部分:

  .start :     /*原来这里是.text,我改成.start*/ 
  
  *(.vectors) 
  KEEP(*(.vectors)) 
  /* For data that needs to reside in the lower 64k of progmem.  */ 
  *(.progmem.gcc*) 
  *(.progmem*) /*呵呵,常用到的 "PROGMEM" 是在这里定义的啊 */ 
  . = ALIGN(2); 
   __trampolines_start = . ; 
  /* The jump trampolines for the 16-bit limited relocs will reside here.  */ 
  *(.trampolines) 
  *(.trampolines*) 
  __trampolines_end = . ; 
  /* For future tablejump instruction arrays for 3 byte pc devices. 
  We don't relax jump/call instructions within these sections.  */ 
  *(.jumptables) 
  *(.jumptables*) 
  /* For code that needs to reside in the lower 128k progmem.  */ 
  *(.lowtext) 
  *(.lowtext*) 
  __ctors_start = . ; 
  *(.ctors) 
  __ctors_end = . ; 
  __dtors_start = . ; 
  *(.dtors) 
  __dtors_end = . ; 
  KEEP(SORT(*)(.ctors)) 
  KEEP(SORT(*)(.dtors)) 
  /* From this point on, we don't bother about wether the insns are 
  below or above the 16 bits boundary.  */ 
  *(.init0)  /* Start here after reset.  */ 
  KEEP (*(.init0)) 
  *(.init1) 
  KEEP (*(.init1)) 
  *(.init2)  /* Clear __zero_reg__, set up stack pointer.  */ 
  KEEP (*(.init2)) 
  *(.init3) 
  KEEP (*(.init3)) 
  *(.init4)  /* Initialize data and BSS.  */ 
  KEEP (*(.init4)) 
  *(.init5) 
  KEEP (*(.init5)) 
  *(.init6)  /* C++ constructors.  */ 
  KEEP (*(.init6)) 
  *(.init7) 
  KEEP (*(.init7)) 
  *(.init8) 
  KEEP (*(.init8)) 
  *(.init9)  /* Call main().  */ 
  KEEP (*(.init9)) 
  }    
  
  .first_data 0x100 : AT(0x100)  /*这里开始定义第一个自己section,注意要 VMA 和LMA 都要设置,且 
                                                                    相同,否则编译会有错,可能是因为不支持VMA与LMA不同地址*/ 
  
  . = ALIGN(2); 
         *(.first_data) 
  *(.first_data*)                        /*注意这行哦,*(.first_data*) 表示用改section 定义的数据放在这里*/ 
  

  .second_data 0x180 : AT(0x180 ) /*这里第2个*/ 
  
  . = ALIGN(2); 
         *(.second_data)     
         *(.second_data*) 
  

  .text 0x200 :  AT(0x200)   /*这里第3个*/ 
  

  *(.text) 
  . = ALIGN(2); 
  *(.text.*) 
  . = ALIGN(2); 
  *(.fini9)  /* _exit() starts here.  */ 
  KEEP (*(.fini9)) 
  *(.fini8) 
  KEEP (*(.fini8)) 
  *(.fini7) 
  KEEP (*(.fini7)) 
  *(.fini6)  /* C++ destructors.  */ 
  KEEP (*(.fini6)) 
  *(.fini5) 
  KEEP (*(.fini5)) 
  *(.fini4) 
  KEEP (*(.fini4)) 
  *(.fini3) 
  KEEP (*(.fini3)) 
  *(.fini2) 
  KEEP (*(.fini2)) 
  *(.fini1) 
  KEEP (*(.fini1)) 
  *(.fini0)  /* Infinite loop after program termination.  */ 
  KEEP (*(.fini0)) 
  _etext = . ; 
 }  > text 

  .third_data 0x1400 : AT(0x1400)  /*这里第4个*/ 
  
        . = ALIGN(2); 
    *(.third_data) 
    *(.third_data*) 
  

  .data          : AT (ADDR (.third_data) + SIZEOF (.third_data)) 
  
     PROVIDE (__data_start = .) ; 
    *(.data) 
    *(.data*) 
    *(.rodata)  /* We need to include .rodata here if gcc is used */ 
    *(.rodata*) /* with -fdata-sections.  */ 
    *(.gnu.linkonce.d*) 
    . = ALIGN(2); 
     _edata = . ; 
     PROVIDE (__data_end = .) ; 
  }  > data 

  文件中引用:

  const unsigned char buff2[4] __attribute((section(".first_data"))) = {'9','1','2','3'};

  const unsigned char buff3[4] __attribute((section(".first_data"))) = {'9','1','2','3'};

  看编译后的map 
  first_data         0x00000100        0x8 load address 0x00000100 
                      0x00000100                . = ALIGN (0x2) 
   *(.first_data) 
   .first_data       0x00000100        0x8 main.o 
                      0x00000104                buff3 
                    0x00000100                buff2 
   *(.first_data*) 

  .second_data   0x00000180        0x0 load address 0x00000180 
                   0x00000180                . = ALIGN (0x2) 
  *(.second_data) 
  *(.second_data*)     
  
  third_data       0x00001400        0x0 load address 0x00001400 
                 0x00001400                . = ALIGN (0x2) 
   *(.third_data) 
   *(.third_data*) 

  .data             0x00800100        0x0 load address 0x00001400 
                      0x00800100                PROVIDE (__data_start, .) 

  读取函数还是跟 用 PROGMEM 定义的一样, PROGMEM,只是告诉编译器或连接器把该变量放到什么地方去.

  另外,该ld脚本是经过修改,可能就适合这个特定项目,可以在makefile 中指定该项目的特定的脚本,而不是用默认的

  方法: LDFLAGS += -Wl,-T ./avr4.x

  呵呵,这样就能做到开辟一个指定地址空间的flash,用来存储特定的数据,而不必担心被其它text 或data占用掉.

 

  自我体会:

  在LPC1111编程时的应用, LPCexpress GCC 指定变量到flash地址。

  在Project->Properties->setting->Miscellaneous 添加一条记录: --section-start=.mydatasection=0x001800

  

  static volatile unsigned char data[] __attribute__((section(".mydatasection")))={

  'a','b','c','d','e','f','g','g'

  };

  void main(void)

  {

  x= data[0];

  }

  

测试效果:

GCC 指定位置

测试效果:

发表评论

*为必须填写项
  • (您的个人信息将被保密)