myorange 发表于 2009-3-11 14:12:21

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

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

可能大家都熟悉 "chara[] 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 __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 __attribute((section(".first_data"))) = {'9','1','2','3'};
const unsigned char buff3 __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
占用掉.

snark 发表于 2009-3-17 17:28:57

谢谢分享!学习了。

252177861 发表于 2009-3-17 17:58:57

这个得顶,谢谢楼主的分享。

lengqing1309 发表于 2009-3-27 09:17:22

支持,MARK

Adrian 发表于 2009-4-18 22:28:08

O(∩_∩)O谢谢

kidcao1987 发表于 2009-6-23 10:58:03

MARK

krdzw 发表于 2009-7-5 14:02:00

MARK

xcodes 发表于 2010-6-19 10:49:03

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

wc171170 发表于 2011-3-31 11:29:52

mark

wsygb 发表于 2011-4-9 17:36:12

mark

tangkechen 发表于 2011-7-27 13:06:23

受教了~尝试中~~~~~~~~·

yat 发表于 2012-4-3 14:07:58

研究学习中

cqv 发表于 2012-9-11 21:40:31

这个mark不犯法吧
页: [1]
查看完整版本: 在winavr gcc环境下定义变量到固定地址的flash区的方法.