|
|
  |
Вопрос по IAR, Настройки среды программирования |
|
|
|
Nov 8 2013, 18:35
|

Гуру
     
Группа: Модератор FTP
Сообщений: 4 479
Регистрация: 20-02-08
Из: Москва
Пользователь №: 35 237

|
Цитата(d7d1cd @ Nov 8 2013, 22:19)  Подскажите, возможно ли настроить IAR так, чтобы он сделал компиляцию кода (например какой-то отдельной функции или всего кода) строго в определенный участок флешь памяти (от сих до сих, так сказать)? Дописать перед функцией pragma location, а в опциях линкера (ExtraOptions) определить это место, как сегмент. Например, так было достигнуто размещение функции ReadFuse() в загрузочной оласти: Код #pragma location="BOOT" void ReadFuse() { ... } Сам сегмент был определен так: Код -D_..X_FLASH_BOOT=F000 -Z(CODE)BOOT=_..X_FLASH_BOOT-_..X_FLASH_END Вместо BOOT можно написать какое-то другое слово, а вместо F000 другой адрес.
|
|
|
|
|
Nov 9 2013, 15:56
|

Гуру
     
Группа: Модератор FTP
Сообщений: 4 479
Регистрация: 20-02-08
Из: Москва
Пользователь №: 35 237

|
Цитата(d7d1cd @ Nov 9 2013, 08:51)  Спасибо за ответ. Что значит 2 точки в коде: Код -D_..X_FLASH_BOOT=F000 -Z(CODE)BOOT=_..X_FLASH_BOOT-_..X_FLASH_END То есть задается только адрес начала размещения? Нет, здесь задается именно сегмент памяти от сих до сих, где будут размещены ВСЕ функции, которые к данному сегменту приписаны. Т.е. если у вас несколько функций приписаны к сегменту BOOT, то все они в него попадут друг за дружкой. И тогда строго формально нельзя будет предсказать, с какого адреса одна из тех функций начинается, хотя практически линкер укладывает их тела в тот сегмент в порядке упоминания в тексте программы. Поэтому, чтобы разместить функцию строго по определенному адресу, вам придется сделать уникальный сегмент только для нее! Тогда уж она точно окажется в том ряду первой и попадет на начало сегмента. Точки и подчеркивание, думаю, нечего не означают, просто придают именам уникальность, чтобы те случайно не совпали с именами каких-то объектов в программе. Т.е. _..X_FLASH_BOOT - это одно имя целиком, а директива D (от слова define) лишь приписывает ей значение. Само же определение сегмента задано во второй строке, после директивы Z. Вообще-то, я сама глубоко с этим не разбиралась, а просто механически переделала под свое имя (BOOT) определение какого-то другого сегмента в том же самом стиле (это видно в xcl-файле для данного типа МК). Рисковать не хотелось, а надо было сделать по-быстрому. Думаю, что в данном случае вполне годилось бы самое примитивное определение без всяких дефиниций: -Z(CODE)BOOT=F000-F100 где задается имя сегмента, а его границы выставлены прямо в числах. Определения имени границ сегментов нужны в файле конфигурации только затем, чтобы связать все сегменты в одну цепочку. Поэтому там каждое имя повторяется по меньшей мере 2 раза - в качестве конца предыдущего сегмента и начале последующего. Мой случай был в этом отношении примитивным, т.к. загрузочная область была заведомо пуста. В вашем случае дело может вылиться в то, что придется переписывать файл конфигурации под себя. Тогда его надо скопировать его в свой проект из: \Program Files\IAR Systems\Embedded Workbench 6.5\430\config\lnk430f5529.xcl (так этот файл называется для MSP430F5529, но у вас может быть другой МК) переключить проект на него вместо умолчания, а потом внести в него исправления. Редактировать исходный файл конфигурации нельзя, можно только копию! Проблема тут в том, что вся память уже поделена на сегменты! А потому свой сегмент придется буквально вклинивать между существующими, раздвинув в каком-то месте границы. Тут ситуация, как на политической карте мира - вам не создать нового государства, не потеснив в границах соседей, поскольку вся земля уже поделена. Однако разбираться в том файле, уж тем более редактировать его, довольно противно. А потому попытайте сначала самый легкий способ - на числах, вдруг сработает? Цитата(d7d1cd @ Nov 9 2013, 08:51)  А что будет, если скомпилированный код не умещается от указанного места расположения до конца флешь памяти? В этом случае линкер ошибку должен выдать. Примерно такую же, когда код слишком велик для памяти данного МК. Цитата(d7d1cd @ Nov 9 2013, 08:51)  При попытке компиляции IAR выдает ошибку Fatal Error[e163]: The command line symbol "_..X_FLASH_END" in -Z(CODE)BOOT=_..X_FLASH_BOOT-_..X_FLASH_END is not defined. Дефиниции границ сегментов могут довольно сильно отличаться по именам у разных МК. Советую вам найти xcl-файл именно для своего типа МК и сделать определение, подобное тому, как там определены сегменты кода.
|
|
|
|
|
Nov 9 2013, 17:31
|
Местный
  
Группа: Участник
Сообщений: 442
Регистрация: 26-11-10
Пользователь №: 61 199

|
Цитата(Xenia @ Nov 9 2013, 19:56)  А потому попытайте сначала самый легкий способ - на числах, вдруг сработает? Определил сегмент так: Код -Z(CODE)BOOT=F002-F0FF И все получилось! Компилятор расположил код функции с адреса 0xF002. Спасибо. По расположению кода теперь разобрался. Есть другой вопрос. В функции я использую переменные. Как указать компилятору при определении переменной, что эта переменная должна быть физически расположена по адресу 0x0200, например? Или как указать, что массив данных должен начинаться с адреса 0x0421?
|
|
|
|
|
Nov 10 2013, 10:30
|
Местный
  
Группа: Участник
Сообщений: 442
Регистрация: 26-11-10
Пользователь №: 61 199

|
Попытался указать переменной конкретный адрес. Ничего не получается. В опциях линкера я указал: Код -Z(DATA)VARIABLE=0200-020F В коде прописал: Код #pragma location = "VARIABLE" char data = 1; Однако при выполнении кода в симуляторе я вижу, что цифра 1 попадает в регистр R14, а не в диапазон 0x0200-0x020F. Ошибок нет. Что не так то опять? P.S. Посмотрел файл io430x24x.h. Есть там много строк, подобных этой: Код /* ADC12 Interrupt Flag */ __no_init volatile unsigned short ADC12IFG @ 0x01A4; Как я понимаю, здесь переменной ADC12IFG "назначается" адрес 0x01A4. Неужели я не могу так же в программе назначить свои переменные?
Сообщение отредактировал d7d1cd - Nov 10 2013, 11:41
|
|
|
|
|
Nov 10 2013, 12:25
|

Гуру
     
Группа: Модератор FTP
Сообщений: 4 479
Регистрация: 20-02-08
Из: Москва
Пользователь №: 35 237

|
Цитата(d7d1cd @ Nov 10 2013, 14:30)  В коде прописал: Код #pragma location = "VARIABLE" char data = 1; Однако при выполнении кода в симуляторе я вижу, что цифра 1 попадает в регистр R14, а не в диапазон 0x0200-0x020F. Ошибок нет. Что не так то опять? Если у вас переменная в регистр попала, то это локальная переменная, объявленная внутри блока из фигурных скобок. Такие переменные называются "автоматическими", имеют ограниченное время жизни, а потому и располагаются на стеке или в регистрах. А чтобы застолбить переменную или массив в памяти, они должны быть глобальными, т.е. объявленными вне функций или с декларатором static. Цитата(d7d1cd @ Nov 10 2013, 14:30)  Посмотрел файл io430x24x.h. Есть там много строк, подобных этой: Код /* ADC12 Interrupt Flag */ __no_init volatile unsigned short ADC12IFG @ 0x01A4; Как я понимаю, здесь переменной ADC12IFG "назначается" адрес 0x01A4. Неужели я не могу так же в программе назначить свои переменные? А вы попробуйте. Думаю, что вполне можете и так. Только внутри фигурных скобок этого не делайте.
|
|
|
|
|
Nov 10 2013, 13:42
|
Местный
  
Группа: Участник
Сообщений: 442
Регистрация: 26-11-10
Пользователь №: 61 199

|
Сделал объявление переменной глобально, то есть вне функции. Все хорошо, но работает только с атрибутом __no_init: Код #pragma location = "VARIABLE" __no_init volatile char data;
int main( void ) { data = 1; } Далее я попробовал сделать как в стандартном файле. Все тоже заработало, но тоже только с атрибутом __no_init: Код __no_init volatile char X @ 0x0210;
int main( void ) { data = 1; } В принципе то, что объявление переменных выше указанными способами не предусматривает их инициализации, мне и надо. По удобству я считаю, что второй способ лучше. С объявлением глобальных переменных тоже теперь ясно. А можно ли локальную переменную объявить так, чтобы она была связана с конкретным регистром?
|
|
|
|
|
Nov 10 2013, 13:53
|

Гуру
     
Группа: Модератор FTP
Сообщений: 4 479
Регистрация: 20-02-08
Из: Москва
Пользователь №: 35 237

|
Цитата(d7d1cd @ Nov 10 2013, 17:42)  Все хорошо, но работает только с атрибутом __no_init В принципе то, что объявление переменных выше указанными способами не предусматривает их инициализации, мне и надо. По удобству я считаю, что второй способ лучше. С объявлением глобальных переменных тоже теперь ясно. Так оно и быть должно. Все обнуляемые переменные и массивы попадают в сегмент NEAR_Z (у других МК может называться по иному), который обнуляется при запуске (в процедуре startup). А раз у вас данные расположены в другом/самодельном сегменте, то инициализации они не получат. То, что аттрибут __no_init требуется синтаксически не знала (в старых версиях не был обязателен). Цитата(d7d1cd @ Nov 10 2013, 17:42)  А можно ли локальную переменную объявить так, чтобы она была связана с конкретным регистром? Полагаю, что нельзя.
|
|
|
|
|
Nov 10 2013, 14:53
|

Гуру
     
Группа: Модератор FTP
Сообщений: 4 479
Регистрация: 20-02-08
Из: Москва
Пользователь №: 35 237

|
Цитата(d7d1cd @ Nov 10 2013, 18:04)  Хорошо. А возможно ли какой-то локальной переменной присвоить значение какого-то регистра? И еще: при объявлении локальной переменной ей назначается какой-то регистр. Возможно ли сделать так, чтобы значение этого регистра предварительно было сохранено в стеке, а после окончания работы функции восстановлено из него? На этот вопрос мне трудно дать конкретный ответ, т.к. нас с вами разделяют архитектуры: я - преимущественно AVR-щица, а вы - пользователь MSP430. Обмениваться опытом нам позволяет лишь общий компилятор IAR, и то лишь в той мере, в которой существует подобие между реализациями для этих двух архитектур. Согласно стандартам языка C/C++, вы имеете возможность добавить декларатор "register", если хотите, чтобы локальная переменная заводилась не на стеке, а в регистре: register char data; или char register data; Только эта декларация является лишь пожеланием, которое компилятор может проигнорировать, даже не выдав по этому поводу никакого сообщения. Что же касается массивов, то это почти безнадега. То, насколько у компилятора есть возможности удовлетворить данное пожелание, сильно зависит от числа свободных регистров в данной архитектуре. В архитектуре AVR имеется 32 регистра, и хотя младшие из них специализированы, то все равно остается дофига других. В таких случаях компилятор довольно охотно удовлетворяет просьбу "register", хотя и трудно заранее предвидеть, какой по номеру регистр он для этой цели выберет. А, скажем, на архитектуре x86 такие пожелания удовлетворяются крайне редко, т.к. там всего 7 регистров, причем, совсем не лишних. Поэтому мне трудно предсказать, насколько компилятор для MSP430 окажется покладистым. Еще в AVR-ном варианте есть возможность зарезервировать отдельные регистры (начиная с R15 и ниже) под глобальные переменные. Например: __regvar __no_init volatile long data@12; // data занимает 4 регистра: R12,R13,R14,R15 Но эти же же регистры приходится изымать из обращения в опциях проекта, чтобы компилятор их не использовал. При этом пользоваться можно только библиотекой clib (которая регистры R5-R15 либо не использует, либо сохраняет/восстанавливает их значения), а библиотекой dlib пользоваться нельзя.
|
|
|
|
|
Nov 10 2013, 14:57
|
Местный
  
Группа: Участник
Сообщений: 442
Регистрация: 26-11-10
Пользователь №: 61 199

|
Цитата(SSerge @ Nov 10 2013, 18:45)  Оставьте эту работу компилятору, это его проблемы. Я понимаю, но у меня задача очень специфическая. Нашел я тут как делать вставки на ассемблере: Код int main( void ) { int AAA; asm("MOV.W R15, &AAA"); } Однако тут компилятор выдает ошибку: Цитата Error[Og005]: Unknown symbol in inline assembly: "AAA" Если же переменную ААА объявить глобально (вне функции main), то ошибки нет. Хотя в справке к IAR переменная объявлена локально. Почему же ошибка?
|
|
|
|
|
Nov 11 2013, 20:28
|
Гуру
     
Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882

|
Цитата(d7d1cd @ Nov 10 2013, 19:57)  Если же переменную ААА объявить глобально (вне функции main), то ошибки нет. Хотя в справке к IAR переменная объявлена локально. Почему же ошибка? Компилятор строку с inline assembler сам не разбирает. Он просто вставляет ее в текст объектного (ассемблерного) модуля. А поскольку в вашем примере переменная AAA в Си-шном модуле нигде более не используется, то оптимизатор компилятора выкидывает ее за ненадобностью. И вот когда объектный модуль попадает "на стол" к линкеру, то линкер приходит в недоумение, что это за объект AAA вдруг обнаружился? Т.к. компилятор про объект AAA ничего (адрес объекта) линкеру не сообщил и более того - совсем выкинул из программы. Вообще ассемблерные вставки в Си это перманентное зло. Если вам нужно что-то особенное, оптимизированные под свои задачи, то используйте отдельные законченные функции, полностью написанные на ассемблере. О том, как правильно писать такие функции и о правилах передачи аргументов в/из asm-функций из/в Си-функции, описано в документации. А вставлять отдельные ассемблерные команды посреди Си-шного исходника бросьте сразу, еще не начиная Ну и еще раз напомню про отличия типов переменных. Тип переменной влияет на ее размещение в памяти и область видимости. Переменные типа global (глобальная) и static (статическая) размещаются в памяти данных, т.е. под них выделяются ячейки памяти с постоянным адресом. Переменные типа auto (автоматическая или локальная) размещаются на стеке или в РОН (по усмотрению компилятора), но постоянного адреса в памяти они не имеют. Переменные типа register (регистровая) в принципе могут быть как глобальными (если объявлена вне функции с указанием конкретного регистра) так и локальными (объявлена без указания регистра внутри функции). Переменные типа register это тип данных с наиболее быстрым доступом. А для того, чтобы доступ к ним был быстрым, предполагается, что размещаться они должны в РОН. Но проблема состоит в том, что если заранее в опциях проекта для переменных типа register не зарезервировать конкретные регистры (в IAR EW430 возможно резервировать только R4 и R5), то компилятор обращается с ними очень вольно и в большинстве случаев пилюет на такую декларацию с высокой колокольни, трактуя локальные register как обычные переменные auto. Область видимости global - вся программа. Область видимости static - данный конкретный модуль или функция, если static объявлена внутри функции. Область видимости auto - функция или блок оператора в котором она объявлена.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|