Преодолевая пределы. Часть вторая. Ресурсы в IAR.

В первой части я продемонстрировал, как ресурсы могут быть созданы средствами ST Visual Develop. Но естественно держать проект в двух студиях несколько не удобно. В текущей публикации я расскажу, как все необходимые ресурсы могут быть созданы в среде разработки IAR.


Использование ресурсов в IAR

Кроме упомянутого способа задания адреса для ресурса через define, IAR поддерживает собственный способ задания адреса для переменных и констант через #pragma location. Так рассмотрим небольшой пример:
// Задание адреса с помощью макросов
#define intro ((const unsigned char*)0xA000)
#define string ((const char*)0xA1F8)
// Задание адреса с помощью директивы pragma
#pragma location=0xA200
__no_init const unsigned char intro2[504];
// Задание адреса в помощью оператора @
__no_init const char string2[8] @0xA3F8;

В результате для всех вариантов вызовов функций будет сгенерирован одинаковый код:
LCD_writeString("IAR  Resources");
    008459    AE8560         LDW       X, #?<Constant "IAR  Resources">
    00845C    CD819B         CALL      LCD_writeString
    …
    LCD_writeString( string );
    008468    AEA1F8         LDW       X, #0xA1F8
    00846B    CD819B         CALL      LCD_writeString
    …
    LCD_writeString( string2 );
    008477    AEA3F8         LDW       X, #string2
    00847A    CD819B         CALL      LCD_writeString
    …
    LCD_screen ( &intro[0] );
    008483    AEA000         LDW       X, #0xA000
    008486    CD80F8         CALL      LCD_screen
    …
    LCD_screen ( &intro2[0] );
    00848F    AEA200         LDW       X, #intro2
    008492    CD80F8         CALL      LCD_screen

Какой из способов выбрать, решайте сами. Задание через #pragma и @ не переносимо на другие компиляторы, но «лучше следит» за типами данных. Правда есть сомнения, что с применением #pragma не даст о себе знать лимит по размеру кода. Проверить это пока не удалось.

Создание ASM проекта ресурсов в IAR

Создаем в рабочем пространстве разрабатываемого проекта новый ассемблерный проект и попробуем переделать его в проект ресурса.
Мне так и не удалось найти в ассемблере IAR простого способа задания адреса для участка кода, аналогичного .ORG в AVR. В целом способ задания адреса похож на способ, примененный в ассемблере STVD:
  1. объявляем регион памяти в определённой адресной области;
  2. объявляем помещение требуемых секций в выделенный регион памяти;
  3. указываем для кода/данных принадлежность к требуемой секции.
Только вот объявлять новые секции в ассемблерном коде, как это было в STVD, мы не можем. Для этих целей нужен отдельный файл, предназначенный для linker’а.
И так, создадим в папке проекта *.icf файл линкера:
/////////////////////////////////////////////////////////////////
//      Replace ILINK command file for Resource
/////////////////////////////////////////////////////////////////

define memory with size = 16M;

define region ResourceZone = [from 0xA200 to 0xA3FF];

/////////////////////////////////////////////////////////////////

place at start of ResourceZone  { ro section .recource2 };

/////////////////////////////////////////////////////////////////

Здесь мы объявили регион «ResourceZone» размером в 512 байт и начинающийся с адреса 0xA200. Далее мы указали что в данном регионе следует разместить секцию «.recource2».
Теперь нам надо указать линкеру использование нового файла конфигурации, взамен стандартного. Для этого убеждаемся что в окне Workspace у нас выбран проект ресурса, а не какой либо из файлов кода, после чего идем в меню Project -> Options и в открывшемся окне в списке категорий слева выбираем Linker. На закладке Config в группе Linker configuration file устанавливаем флажок Override default и в поле указываем путь к созданному *.icf файлу.

С линкером разобрались, теперь надо разобраться с компилятором. В ассемблерном *.s файле заменяем код на следующее:
MODULE  asmmain

        PUBLIC  __iar_program_start
        PUBLIC  main

        SECTION `.recource2`:CODE:NOROOT(0)

__iar_program_start:
main:

image:
	db $5e, $a2, $40, $80, $00, $00, $00, $00
	… ещё 61 строка данных …
	db $07, $0f, $1f, $3f, $7e, $7c, $78, $30
string:
	db "FD.IAR"
	end

Строка с SECTION сообщает, что дальнейший код/данные должны помещаться в секцию «.recource2». Метки __iar_program_start и main нужны дабы утихомирить компилятор с отладчиком пытающихся разобраться, откуда должно начаться выполнение. Теперь осталось только задать формирование *.s19 файла, что в принципе не обязательно. В опциях проекта в категории Output Converter на закладке Output:
  1. устанавливаем флажок Generate additional output;
  2. в выпадающем списке Output format выбираем Motorola;
  3. в группе Output file устанавливаем флажок Override default и в окне задаем имя выходного файла с расширением *.s19.

Теперь о приятном. Если в опциях проекта в категории Debugger задать в качестве отладчика ST-Link, то при запуске на отладку проекта студия зальет собранный ресурс в контроллер без каких либо проблем и возражений (естественно, если вы выбрали в настройках проекта правильный контроллер). Да к тому же начнется отладка прошивки и отладчик будет активно мигать светодиодом. Авто-остановки не будет, т.к. меткой входа указан адрес ресурса, а он никогда не выполняется, но есть возможность приостановить выполнение вручную.

Создание С проекта ресурсов в IAR

Создаем в рабочем пространстве разрабатываемого проекта новый Си проект и попробуем переделать его в проект ресурса. А после разбора ассемблерного проекта это не должно составить большой проблемы.
Аналогично создаем *.icf файл линкера:
/////////////////////////////////////////////////////////////////
//      Replace ILINK command file for Resource
/////////////////////////////////////////////////////////////////

define memory with size = 16M;

define region ResourceZone = [from 0xA400 to 0xA5FF];

/////////////////////////////////////////////////////////////////

place at start of ResourceZone  { ro section .recource3 };

/////////////////////////////////////////////////////////////////

Точно так же подменяем в опциях проекта файл конфигурации линкера и выходной файл:


Содержимое *.c файла переписываем следующим образом:
typedef struct {
  unsigned char image[504];
  char string[8];
} Resource3;

#pragma location=".recource3"
const Resource3 recource3 = {
  {
    0x00,  … ещё 5 сотен значений … , 0x0f, 0x06, 0x00,
  },
  "C.Image"
};

Все ресурсы оформлены в виде структуры, для которой указано размещение в секции ".recource3" которая в соответствии с правилами линкера находится по адресу 0xA400 и составляет 512 байт. Оформление в виде одной структуры нам необходимо, что бы при компиляции не были выброшены «неиспользуемые» данные.
Теперь о «точке входа». Функцию main мы выбросили, т.к. она нам не нужна. Так же нам не нужен и генерируемый средой код настройки окружения, не нужна таблица векторов прерываний. Что бы всё это дело отключить идей в настройки проекта в категорию Linker на закладку Library:
  1. снимаем флажок Automatic runtime library selection;
  2. устанавливаем флажок Override default program entry;
  3. выбираем пункт Entry symbol и в окне вводим имя нашей структуры recource3.

Благодаря этому, во-первых, сама структура не сможет быть удалена «как не используемая». Во-вторых, при компиляции проекта мы не получим ошибки «точка входа не найдена». В-третьих, в код не будет добавлено ничего лишнего. Как-то это получалось через Defined by application сделать, но уже не вспомню.

И снова о приятном. Указываем в качестве отладчика ST-Link и запускаем проект на отладку. Снова получаем автоматическую прошивку, только уже не без предупреждений:


В прочем ничего страшного тут нет. Просто отключаем лишний компонент среды и радуемся жизни.

Результат

В прочем результат не отличается от первой статьи. Все три способа работают одновременно, что не вызывает сомнения.


Плюсы и минусы

Несомненным плюсом является возможность собрать все проекты (код и ресурсы) разрабатываемого устройства в одном рабочем пространстве (workspace):

Вторым плюсом является простота прошивки с применением отладчика. Нет риска, ошибиться при указании диапазоне адресов и случайно затереть что-то нужное. Среда самостоятельно прошивает только относящуюся к проекту область.
Третьим плюсом является возможность отладки при работе с проектом ресурса. Правда, только в режиме инструкций и без подстановки кода, но это лучше чем ничего. Вероятно, есть способ научить среду подтягивать отладочную информацию из других проектов.
Из минусов по-прежнему остаётся шанс что-нибудь забыть/потерять при прошивке.

Вместо заключения

Естественно, что данная модель удобнее для сопровождения. Так возможность разрабатывать и прошивать одной средой позволяет держать все необходимые компоненты вместе. Меньше риск что-либо забыть записать или не нарочно стереть. Но при этом мы не можем создавать ресурсы большего размера, чем позволяет среда разработки. В прочем «Война и мир» в каждом проекте нам не требуется, так что данный подход вполне хорош.
В заключительной части я продемонстрирую более интересную возможность: формирование двоичных библиотек в среде IAR.

< Предидущая Следующая >
  • +3
  • 30 ноября 2011, 08:31
  • angel5a
  • 2
Файлы в топике: odo_with_rc.zip, complite_iar.s19.zip

Комментарии (6)

RSS свернуть / развернуть
Очень полезный материал, ждем продолжения. Было бы здорово увидеть пример, как в один кристалл допустим на 32 Кб. записать две прошивки по 16 и в зависимости от начального условия выполнять разный код. Такая возможность позволит более гибко использоваться серийное устройство.
Про кряки с тобой полностью согласен, воровство это не правильно. Иногда использование кряка невозможно по уставу фирмы, а изучать новый бесплатный софт нет времени, тогда данный метод очень выручает.
0
На данный момент я не знаю как перенести таблицу векторов прерываний в другую область. Собственно исследования в этой области я и не проводил пока. Из «очевидного»:
1. захардкорить в бутлодер (который по совместительству будет и прошивку выбирать) обработчики для всех прерываний, которые будут производить косвенный вызов целевого обработчика. Толко данный способ добавит дополнительно тактов 20 ко времени обслуживания прерывания, что порой может быть недопустимо.
2. Переписывать таблицу прерываний из «образцовой в целевой прошике». Потери в производительности во время выполнения не будет, но при старте устройства для определения необходимости смены прошивки и собственно перепрошивки потребуется время.
Для стм32 и LPC в этом плане лучше, т.к. для таблицы векторов прерываний можно задать либо произвольный адрес, либо смапировать на оперативную память (тогда таблица векторов при старте копируется в оперативку, что гораздо быстрее). Для стм8 не скажу возможно ли такое.
Все способы имеют плюсы и минусы, но главное что такая возможность есть.
0
Не знаю, как в других верcиях IAR, а в kikstart EW8051 есть «секретный ключик» сдвигающий ограничение с 4К до 16К кода. Цитата из документации:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The special 16kb kickstart version of the EW8051 7.51A is now available to SimpliciTI users who are developing on one of the following TI RF SoC platforms: CC2510-CC2511DK, CC11100-CC1111DK, CC2430DK or CC2430ZDK. The 16kb “SimpliciTI-mode” can be activated by enabling the command line option ‘--ks_version’ for the linker (project->options->linker->extra options). This is part of the default setting for SimpliciTI 1.1.1 now. Customers buying the TI development kits should be able to fully evaluate all sample applications available in the SimpliciTI distribution.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0
  • avatar
  • SMK2
  • 01 декабря 2011, 09:50
Опять таки, применение данного ключа разрешается для указанных отладочных модулей купленных у TI. Применение в других целях так же нарушает лицензию, как и кейгены.
Однако для владельцев указанных модулей информация будет полезна.
0
есть одна мысля по поводу разделения кода на несколько проектов:
1 — выносим в отдельный проект более-менее независимые сервисные функции, такие как драйвера устройств (LCD, USART, и т.д.), а возможно и жирные функции стандартной библиотеки, такие как printf.
2 — прототипы экспортируемых функций выносим в отдельный заголовок.
3 — редактируем linker configuration file этого проекта, чтоб наш код располагался в нужных адресах, не знаю, правда, что делать с с векторами прерываний и стартап кодом, от них нужно как-то избавится.
4 — указываем линкеру генерировать map файл — в нем будут имена и адреса всех экспортируемых функций.
5 — на своём любимом скриптовом языке пишем простую утилитку, которая читает подготовленный заголовок и для каждой функции ищет ёё адрес в map файле. После чего генерирует новый заголовок с функциями-обёртками.
Исходный заголовок:
void Foo(int a);
...
int Bar(int a, char *s);

Сгенерированный заголовок:
inline void Foo(int a)
{
   typedef void (*Foo_ptr_t)(int);
   ((Foo_ptr_t)0xF00ADD7)(a);
}
...
int Bar(int a, char *s)
{
   typedef void (*Bar_ptr_t)(int, char *);
   ((Bar_ptr_t)0xBA7ADD7)(a, s);
}

А дальше подключаем в главный проект этот сгенерированный заголовок и пользуемся функциями из него как родными.
Не решенной в этом методе остается проблема стартапа и векторов прерываний, может у компилятора/линкера есть какая опция, чтоб их не генерировать. Или может быть их поместить в какую-то отдельную секцию, а потом ее удалить.
0
Вам в третью часть.
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.