Преодолевая пределы. Часть вторая. Ресурсы в 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 и запускаем проект на отладку. Снова получаем автоматическую прошивку, только уже не без предупреждений:
Сообщение об ошибке при запуске
Сообщение об ошибке при запуске
В прочем ничего страшного тут нет. Просто отключаем лишний компонент среды и радуемся жизни.

Результат

В прочем результат не отличается от первой статьи. Все три способа работают одновременно, что и не вызывало сомнения.
Вывод текста из всех ресурсов вывод изображения из ресурса STVD вывод изображения из ресурса асемблерного проекта IAR вывод изображения из ресурса C проекта IAR

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

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

Вторым плюсом является простота прошивки с применением отладчика. Нет риска, ошибиться при указании диапазона адресов и случайно затереть что-то нужное. Среда самостоятельно прошивает только относящуюся к проекту область.

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

Из минусов по-прежнему остаётся шанс что-нибудь забыть/потерять при прошивке.

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

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

В заключительной части я продемонстрирую более интересную возможность: формирование двоичных библиотек в среде IAR.

Файлы: odo_with_rc.zip, complite_iar.s19.zip

< Предыдущая Следующая >