将数组写入.hex文件中的特定闪存位置

时间:2016-11-23 15:56:54

标签: c++ linker embedded microcontroller atmel

对于我在Atmel SAM4E16C上的嵌入式应用程序,我需要在.hex文件的末尾放置一个包含固件信息的数组。我正在使用Atmel Studio 7和GCC。

我已经为Atmega168PB做过这个,但不知怎的,它对这个项目并不起作用。

OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
SEARCH_DIR(.)

/* Memory Spaces Definitions */
MEMORY
{
  rom (rx)  : ORIGIN = 0x00420000, LENGTH = 0x000E0000 /* changed to leave space for 128KB Bootloader -> was ORIGIN = 0x00400000, LENGTH = 0x00100000 */
  ram (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00020000
}

/* The stack size used by the application. NOTE: you need to adjust according to your application. */
__stack_size__ = DEFINED(__stack_size__) ? __stack_size__ : 0x3000;
__ram_end__ = ORIGIN(ram) + LENGTH(ram) - 4;
/* Firmware Info - 8 Bytes long at the end of ROM */
__FWInfo_start__ = ORIGIN(rom) + LENGTH(rom) - 8;
SECTIONS
{
.text :
{
    . = ALIGN(4);
    _sfixed = .;
    KEEP(*(.vectors .vectors.*))
    *(.text .text.* .gnu.linkonce.t.*)
    *(.glue_7t) *(.glue_7)
    *(.rodata .rodata* .gnu.linkonce.r.*)
    *(.ARM.extab* .gnu.linkonce.armextab.*)

    /* Support C constructors, and C destructors in both user code
       and the C library. This also provides support for C++ code. */
    . = ALIGN(4);
    KEEP(*(.init))
    . = ALIGN(4);
    __preinit_array_start = .;
    KEEP (*(.preinit_array))
    __preinit_array_end = .;

    . = ALIGN(4);
    __init_array_start = .;
    KEEP (*(SORT(.init_array.*)))
    KEEP (*(.init_array))
    __init_array_end = .;

    . = ALIGN(0x4);
    KEEP (*crtbegin.o(.ctors))
    KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
    KEEP (*(SORT(.ctors.*)))
    KEEP (*crtend.o(.ctors))

    . = ALIGN(4);
    KEEP(*(.fini))

    . = ALIGN(4);
    __fini_array_start = .;
    KEEP (*(.fini_array))
    KEEP (*(SORT(.fini_array.*)))
    __fini_array_end = .;

    KEEP (*crtbegin.o(.dtors))
    KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
    KEEP (*(SORT(.dtors.*)))
    KEEP (*crtend.o(.dtors))

    . = ALIGN(4);
    _efixed = .;            /* End of text section */
} > rom

/* .ARM.exidx is sorted, so has to go in its own output section.  */
PROVIDE_HIDDEN (__exidx_start = .);
.ARM.exidx :
{
  *(.ARM.exidx* .gnu.linkonce.armexidx.*)
} > rom
PROVIDE_HIDDEN (__exidx_end = .);

. = ALIGN(4);
_etext = .;

.relocate : AT (_etext)
{
    . = ALIGN(4);
    _srelocate = .;
    *(.ramfunc .ramfunc.*);
    *(.data .data.*);
    . = ALIGN(4);
    _erelocate = .;
} > ram

/* .bss section which is used for uninitialized data */
.bss (NOLOAD) :
{
    . = ALIGN(4);
    _sbss = . ;
    _szero = .;
    *(.bss .bss.*)
    *(COMMON)
    . = ALIGN(4);
    _ebss = . ;
    _ezero = .;
} > ram

/* stack section */
.stack (NOLOAD):
{
    . = ALIGN(8);
    _sstack = .;
    . = . + __stack_size__;
    . = ALIGN(8);
    _estack = .;
} > ram

. = ALIGN(4);
_end = . ;


/* 8 Byte Firmware Info Section */

.FWInfo : AT (__FWInfo_start__)
{
    *(.FWInfo)
} > rom
}

这是我正在使用的链接描述文件。我添加了__FWInfo_start__和.FWInfo部分。

在我的应用程序中,我尝试使用属性部分.FWInfo定义固件信息块,但我无法在.hex文件中找到数据。

#define SIZE_OF_FWINFO  8
const uint8_t nFirmwareInfoBlock[SIZE_OF_FWINFO] __attribute__((section(".FWInfo"))) = {
    0xff,   // reserved for future
    0xff,   // reserved for future
    DEVICE_TYPE,    // DeviceType
    BUILD_NR,       // BuildNr of Firmware
    VERSION_MINOR,  // VersionMinor of Firmware
    VERSION_MAJOR,  // VersionMajor of Firmware
    0xFF,           // Checksum
    0xFF            // Checksum
};  

我希望有人可以帮助我,为什么这不起作用。提前谢谢。

编辑:以下是.map文件中的条目:

.data          0x00000000        0x0 src/main.o
.FWInfo        0x00000000        0x8 src/main.o
.debug_macro   0x00000000      0x8b0 src/main.o

和..

 *fill*         0x200133b0     0x3000 
                0x200163b0                . = ALIGN (0x8)
                0x200163b0                _estack = .
                0x200163b0                . = ALIGN (0x4)
                0x200163b0                _end = .

.FWInfo
 *(.FWInfo)
OUTPUT(Dali4Net.elf elf32-littlearm)

据我可以从第二个块的上下文中读取,应该有一个在.FWInfo之后写的地址或?

3 个答案:

答案 0 :(得分:0)

来自GCC variable attribute documentation

  

used

     

此属性附加到具有静态存储的变量,意味着即使看起来未引用该变量,也必须发出该变量。

因此,为了防止链接器删除未使用的数据,请使用:

const uint8_t nFirmwareInfoBlock[SIZE_OF_FWINFO]
              __attribute__((used,section(".FWInfo"))) = 
{ ... } ;

另一种可能不太吸引人的解决方案是声明数组volatile,然后执行虚拟读取,即:

const uint8_t nFirmwareInfoBlock[SIZE_OF_FWINFO]
              __attribute__((section(".FWInfo"))) = 
{ ... } ;

int main()
{
    uint8_t dummy = nFirmwareInfoBlock[0] ; 
    ...
}

第三种方法是完全避免工具链依赖,并使用优秀的(如果有点神秘的SRecord实用程序将数据作为 post-build 操作直接修补到hex文件。这具有独立于工具链的优点,但是您可能需要一个步骤来生成要修补的数据,但为此编写生成器可能是微不足道的。

答案 1 :(得分:0)

根据我在Atmel studio 6和8bit AVR核心的经验:

定义部分.FWInfo(我这样做没有makefile抱歉) Flash config 并且正在做

const uint8_t nFirmwareInfoBlock[SIZE_OF_FWINFO]
              __attribute__((used,section(".FWInfo"))) = 
{ ... } ;

是不够的,因为只有编译器才会保留变量。如果未使用链接器,链接器可能会将其丢弃。当然,一个简单的引用足以保留它,但如果它只在引导加载程序中使用,例如你可以定义一个链接器标志。

我再次以图形方式做到了(抱歉)。

linker flag

答案 2 :(得分:0)

我知道这篇文章很老,但是无论如何...

如上所述,可能需要使用KEEP指令来保留该节,即使未使用该节也是如此,或者只是确保无论如何都将始终保留该节。

除此之外,我还想为STM32做类似的事情。 似乎各节的顺序也很重要(即使明确指定了地址也是如此)。 我必须将多余的部分放在RAM部分的开始之前。

在这里,您可以找到ROM url/wp-admin/admin-ajax.php和RAM class Wps_Wc_Sync { public function get_wc_products() { add_action( 'wp_ajax_nopriv_parseCsvAjax', array($this, 'wps_ajax_parseCsvAjax') ); add_action( 'wp_ajax_parseCsvAjax', array($this, 'wps_ajax_parseCsvAjax') ); ?> <script> jQuery( document ).ready(function($) { console.log('ajax'); parseCsvAjax(0); function parseCsvAjax(lastfile = 0) { $.ajax({ type: "POST", dataType: 'json', url: '/wp-admin/admin-ajax.php', data: { action: 'parseCsvAjax', lastfile: lastfile, }, success: function (data) { console.log(data); }, error: function (jqXHT, textStatus, errorThrown) {console.log('Error');} }); } }); </script> <?php public function wps_ajax_parseCsvAjax($lastfile = 0) { echo 'testAJAX1'; exit(); return true; } } } 的各个部分。您可能还会有其他部分的初始化数据,它们表示为> rom(对于STM32 gcc)。在此示例中,它似乎表示为> ram

无论如何,如果以相同的方式工作,则应在>RAM AT> FLASH之前放置自己的部分,该部分是未初始化数据的开始(仅与RAM相关的第一部分):

.relocate : AT (_etext)

如果仍然无法正常工作,则可以尝试将此部分放在.bss部分的前面;它位于最新提到的rom部分之后,但是由于该部分从ROM重定位到RAM,即使在符号上有歧义,我也认为第一个猜测应该可行。