Программирование ARM: решение проблем, FAQ IAR EWB for ARM: учимся управлять сегментами на примере добавления версии по фиксированному адресу Thu, March 28 2024  

Поделиться

Нашли опечатку?

Пожалуйста, сообщите об этом - просто выделите ошибочное слово или фразу и нажмите Shift Enter.

IAR EWB for ARM: учимся управлять сегментами на примере добавления версии по фиксированному адресу Печать
Добавил(а) microsin   

Как добавить собственную секцию кода и разместить её по нужному адресу на примере flash-проекта на C, IAR Embedded Workbench for ARM, ver. 5.20.

Иногда бывает необходимо разместить нужные данные в строго заданном месте firmware, чтобы программа могла легко их найти (например, данные о версии программы положить по фиксированному адресу в код). В частности, у меня стояла задача разместить данные о версии программного обеспечения в коде программы. Требования к размещению:

1. Данные должны лежать в начале прошивки, по известному фиксированному адресу.
2. Формат должен быть основан на дате и времени.
3. Формат должен легко читаться человеком.

На ассемблере сохранить строку в коде flash довольно легко, достаточно - добавить в файл board_cstartup_iar.s строки:
        DCB     'V','E','R','S','I','O','N'

или так:
        DCB     "VERSION"

Но чтобы эти данные лежали по нужному адресу, придется немного разобраться с файлом управления линкером ILINK (*.icf) - чтобы задать сегмент с данными версии по нужному адресу, а также разобраться с применением сегментов в коде программы. Вся необходимая информация по теме есть во встроенной документации IAR (Help -> ARM C/C++ Development Guide, файл EWARM_DevelopmentGuide.ENU.pdf, а также Help -> ARM Assembler Reference Guide, файл EWARM_AssemblerReference.ENU.pdf). В этой статье только практика, процесс по шагам. Итак, как положить информацию о версии по фиксированному адресу 0x100100 (резервируется блок размером в 32 байта), с помощью отдельного сегмента (в этом примере файлы проекта находятся в папке c:\asm\bootloader\ewp\, а файл линкера - c:\asm\bootloader\at91lib\board\at91sam7x512\flash.icf):

1. Возьмем на себя смелость отредактировать вручную файл *.icf конфигурации линкера (обычно он редактируется только редактором ICF editor, который можно вызвать в разделе конфигурации линкера в проекте). Итак, сначала редактируем файл flash.icf проекта (не забудьте сделать копию!). Это нужно для того, чтобы выделить место под данные версии (32 байта), разместить это место по нужному адресу (0x100100), и привязать к этому месту секцию кода, где будут лежать данные версии (в нашем примере это секция .versionsection). Вот полный текст получившегося файла flash.icf (изменения выделены жирным шрифтом):

/* Файл управления линкером flash.icf */

/*###ICF### Section handled by ICF editor, don't touch! ****/
/*-Editor annotation file-*/
/* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\a_v1_0.xml" */
/*-Memory Regions-*/
define symbol __ICFEDIT_region_ROM_start__ = 0x100000;
define symbol __ICFEDIT_region_ROM_end__   = 0x17FFFF;
define symbol __ICFEDIT_region_RAM_start__ = 0x200000;
define symbol __ICFEDIT_region_RAM_end__   = 0x21FFFF;
/*-Sizes-*/
define symbol __ICFEDIT_size_startup__  = 0x100;
define symbol __ICFEDIT_size_version__  = 0x20;
define symbol __ICFEDIT_size_vectors__  = 0x100;
define symbol __ICFEDIT_size_cstack__   = 0x1000;
define symbol __ICFEDIT_size_svcstack__ = 0x60;
define symbol __ICFEDIT_size_irqstack__ = 0x60;
define symbol __ICFEDIT_size_heap__     = 0x6000;
/*-Exports-*/
export symbol __ICFEDIT_region_ROM_start__;
export symbol __ICFEDIT_region_ROM_end__;
export symbol __ICFEDIT_region_RAM_start__;
export symbol __ICFEDIT_region_RAM_end__;
export symbol __ICFEDIT_size_startup__;
export symbol __ICFEDIT_size_version__;
export symbol __ICFEDIT_size_vectors__;
export symbol __ICFEDIT_size_cstack__;
export symbol __ICFEDIT_size_svcstack__;
export symbol __ICFEDIT_size_irqstack__;
export symbol __ICFEDIT_size_heap__;
/**** End of ICF editor section. ###ICF###*/

define memory mem with size = 4G;

define region STA_region = mem:[from __ICFEDIT_region_ROM_start__ size __ICFEDIT_size_startup__];
define region VER_region = mem:[from __ICFEDIT_region_ROM_start__+__ICFEDIT_size_startup__ size __ICFEDIT_size_version__];
/* define region ROM_region = mem:[from __ICFEDIT_region_ROM_start__+__ICFEDIT_size_startup__ to __ICFEDIT_region_ROM_end__];
 */
define region ROM_region = mem:[from __ICFEDIT_region_ROM_start__+__ICFEDIT_size_startup__+__ICFEDIT_size_version__ to __ICFEDIT_region_ROM_end__];
define region VEC_region = mem:[from __ICFEDIT_region_RAM_start__ size __ICFEDIT_size_vectors__];
define region RAM_region = mem:[from __ICFEDIT_region_RAM_start__+__ICFEDIT_size_vectors__ to __ICFEDIT_region_RAM_end__];

define block CSTACK    with alignment = 8, size = __ICFEDIT_size_cstack__   { };

define block SVC_STACK with alignment = 8, size = __ICFEDIT_size_svcstack__ { };
define block IRQ_STACK with alignment = 8, size = __ICFEDIT_size_irqstack__ { };
define block HEAP      with alignment = 8, size = __ICFEDIT_size_heap__     { };

initialize by copy { readwrite };

initialize by copy { section .vectors };
do not initialize  { section .noinit };

place in STA_region { section .cstartup };

place in VER_region { section .versionsection };
place in ROM_region { readonly };
place in VEC_region { section .vectors };
place in RAM_region { readwrite, block IRQ_STACK, block SVC_STACK, block CSTACK, block HEAP };

Немного комментариев по коду примера. Код программы лежит в памяти микроконтроллера по абсолютному адресу 0x100000 (определяется символом __ICFEDIT_region_ROM_start__). Размер выделяемого под данные версии блока в 32 байта задается символом __ICFEDIT_size_version__. Адрес размещения 0x100100 нашего блока с версией определяется строчкой "define region VER_region = mem:[from __ICFEDIT_region_ROM_start__ + __ICFEDIT_size_startup__ size __ICFEDIT_size_version__];". Тот факт, что в блоке с данными будет лежать нужная нам секция .versionsection, определяется строчкой "place in VER_region { section .versionsection };". 

2. Теперь осталось применить секцию .versionsection в коде для размещения нужных данных. На ассемблере это сделать проще всего. Например, добавляем в файл board_cstartup_iar.s строки:
        SECTION .versionsection:CODE
        DCB     "VERSION"

Теперь в прошивке по адресу 0x100100 мы увидим слово VERSION.

3. Как добавить данные в секцию .versionsection из кода на C (текст, что мы добавили в board_cstartup_iar.s, закомментируем за ненадобностью):
#pragma section = ".versionsection"
const char version_full [] @ ".versionsection" = "VERSION 18.06.2010 15:25:40";

Теперь если открыть двоичный файл прошивки, то в коде увидим текст версии:

100618firmware_version_dump.PNG

Информацию о версии удобно генерить автоматически из даты и времени, с помощью VBS-скрипта (см. Ссылки).

[Ссылки]

1. IAR EW ARM: автоматическая генерация версии прошивки.
2. IAR 4.0: размещение переменных и данных по заданному адресу

 

Комментарии  

 
+1 #2 Алексей 02.05.2018 20:45
Переменную, содержащую версию, необходимо использовать в программе, иначе компилятор её оптимизирует.
Цитировать
 
 
+1 #1 Armored 09.12.2010 13:04
Отличная статья. Толково написано, и при этом понятным языком.
Цитировать
 

Добавить комментарий


Защитный код
Обновить

Top of Page