Запись массива в определенное место флэш-памяти в файле .hex

Для моего встроенного приложения на 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.

В моем приложении я попытался определить блок информации о прошивке с помощью атрибута section. WInfo, но я не могу найти данные в моем файле .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 или?

2

Решение

Из моего опыта работы в Atmel studio 6 и 8bit AVR core:

определить раздел .FWInfo (Я делаю это без makefile извините)
Конфигурация Flash
И делать

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

недостаточно, потому что только компилятор будет хранить переменную. Тогда компоновщик может отказаться от него, если он не используется. Конечно, для сохранения этого достаточно простой ссылки, но если она используется, например, только в загрузчике, вы можете определить флаг компоновщика.

Я снова сделал это графически (извините).

флаг компоновщика

0

Другие решения

От GCC документация по переменным атрибутам:

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 Утилита для исправления данных непосредственно в шестнадцатеричный файл в виде после сборки операция. Это имеет то преимущество, что является независимым от цепочки инструментов, но вам понадобится шаг, возможно, для генерации данных, которые будут исправлены, но написание генератора для этого, вероятно, тривиально.

0

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector