реклама на сайте
подробности

 
 
5 страниц V   1 2 3 > »   
Reply to this topicStart new topic
> Вопрос по IAR, Настройки среды программирования
d7d1cd
сообщение Nov 8 2013, 18:19
Сообщение #1


Местный
***

Группа: Участник
Сообщений: 442
Регистрация: 26-11-10
Пользователь №: 61 199



Привет всем. Подскажите, возможно ли настроить IAR так, чтобы он сделал компиляцию кода (например какой-то отдельной функции или всего кода) строго в определенный участок флешь памяти (от сих до сих, так сказать)?
Go to the top of the page
 
+Quote Post
Xenia
сообщение Nov 8 2013, 18:35
Сообщение #2


Гуру
******

Группа: Модератор 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 другой адрес.
Go to the top of the page
 
+Quote Post
d7d1cd
сообщение Nov 9 2013, 04:51
Сообщение #3


Местный
***

Группа: Участник
Сообщений: 442
Регистрация: 26-11-10
Пользователь №: 61 199



При попытке компиляции IAR выдает ошибку Fatal Error[e163]: The command line symbol "_..X_FLASH_END" in -Z(CODE)BOOT=_..X_FLASH_BOOT-_..X_FLASH_END is not defined.

Сообщение отредактировал d7d1cd - Nov 9 2013, 15:38
Go to the top of the page
 
+Quote Post
Xenia
сообщение Nov 9 2013, 15:56
Сообщение #4


Гуру
******

Группа: Модератор 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-файл именно для своего типа МК и сделать определение, подобное тому, как там определены сегменты кода.
Go to the top of the page
 
+Quote Post
d7d1cd
сообщение Nov 9 2013, 17:31
Сообщение #5


Местный
***

Группа: Участник
Сообщений: 442
Регистрация: 26-11-10
Пользователь №: 61 199



Цитата(Xenia @ Nov 9 2013, 19:56) *
А потому попытайте сначала самый легкий способ - на числах, вдруг сработает?

Определил сегмент так:
Код
-Z(CODE)BOOT=F002-F0FF

И все получилось! Компилятор расположил код функции с адреса 0xF002. Спасибо.

По расположению кода теперь разобрался. Есть другой вопрос. В функции я использую переменные. Как указать компилятору при определении переменной, что эта переменная должна быть физически расположена по адресу 0x0200, например? Или как указать, что массив данных должен начинаться с адреса 0x0421?
Go to the top of the page
 
+Quote Post
Xenia
сообщение Nov 9 2013, 20:19
Сообщение #6


Гуру
******

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



Цитата(d7d1cd @ Nov 9 2013, 21:31) *
По расположению кода теперь разобрался. Есть другой вопрос. В функции я использую переменные. Как указать компилятору при определении переменной, что эта переменная должна быть физически расположена по адресу 0x0200, например? Или как указать, что массив данных должен начинаться с адреса 0x0421?


Точно так же! Только на этот раз "pragma location" прописывается не перед функцией, а перед определением переменной или массива. Только просите память не из сегмента CODE, а из сегмента DATA. У нас на форуме на такой вопрос уже отвечали:
http://electronix.ru/forum/index.php?s=&am...t&p=1020355
Go to the top of the page
 
+Quote Post
d7d1cd
сообщение Nov 10 2013, 10:30
Сообщение #7


Местный
***

Группа: Участник
Сообщений: 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
Go to the top of the page
 
+Quote Post
Xenia
сообщение Nov 10 2013, 12:25
Сообщение #8


Гуру
******

Группа: Модератор 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.
Неужели я не могу так же в программе назначить свои переменные?

А вы попробуйте. Думаю, что вполне можете и так. Только внутри фигурных скобок этого не делайте.
Go to the top of the page
 
+Quote Post
d7d1cd
сообщение Nov 10 2013, 13:42
Сообщение #9


Местный
***

Группа: Участник
Сообщений: 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;
}

В принципе то, что объявление переменных выше указанными способами не предусматривает их инициализации, мне и надо. По удобству я считаю, что второй способ лучше.
С объявлением глобальных переменных тоже теперь ясно. А можно ли локальную переменную объявить так, чтобы она была связана с конкретным регистром?
Go to the top of the page
 
+Quote Post
Xenia
сообщение Nov 10 2013, 13:53
Сообщение #10


Гуру
******

Группа: Модератор 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) *
А можно ли локальную переменную объявить так, чтобы она была связана с конкретным регистром?

Полагаю, что нельзя.
Go to the top of the page
 
+Quote Post
d7d1cd
сообщение Nov 10 2013, 14:04
Сообщение #11


Местный
***

Группа: Участник
Сообщений: 442
Регистрация: 26-11-10
Пользователь №: 61 199



Хорошо. А возможно ли какой-то локальной переменной присвоить значение какого-то регистра? И еще: при объявлении локальной переменной ей назначается какой-то регистр. Возможно ли сделать так, чтобы значение этого регистра предварительно было сохранено в стеке, а после окончания работы функции восстановлено из него?
Go to the top of the page
 
+Quote Post
SSerge
сообщение Nov 10 2013, 14:45
Сообщение #12


Профессионал
*****

Группа: Свой
Сообщений: 1 719
Регистрация: 13-09-05
Из: Novosibirsk
Пользователь №: 8 528



Цитата(d7d1cd @ Nov 10 2013, 21:04) *
Возможно ли сделать так, чтобы значение этого регистра предварительно было сохранено в стеке, а после окончания работы функции восстановлено из него?

Оставьте эту работу компилятору, это его проблемы.


--------------------
Russia est omnis divisa in partes octo.
Go to the top of the page
 
+Quote Post
Xenia
сообщение Nov 10 2013, 14:53
Сообщение #13


Гуру
******

Группа: Модератор 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 пользоваться нельзя.
Go to the top of the page
 
+Quote Post
d7d1cd
сообщение Nov 10 2013, 14:57
Сообщение #14


Местный
***

Группа: Участник
Сообщений: 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 переменная объявлена локально. Почему же ошибка?
Go to the top of the page
 
+Quote Post
rezident
сообщение Nov 11 2013, 20:28
Сообщение #15


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Цитата(d7d1cd @ Nov 10 2013, 19:57) *
Если же переменную ААА объявить глобально (вне функции main), то ошибки нет. Хотя в справке к IAR переменная объявлена локально. Почему же ошибка?

Компилятор строку с inline assembler сам не разбирает. Он просто вставляет ее в текст объектного (ассемблерного) модуля. А поскольку в вашем примере переменная AAA в Си-шном модуле нигде более не используется, то оптимизатор компилятора выкидывает ее за ненадобностью. И вот когда объектный модуль попадает "на стол" к линкеру, то линкер приходит в недоумение, что это за объект AAA вдруг обнаружился? Т.к. компилятор про объект AAA ничего (адрес объекта) линкеру не сообщил и более того - совсем выкинул из программы.
Вообще ассемблерные вставки в Си это перманентное зло. Если вам нужно что-то особенное, оптимизированные под свои задачи, то используйте отдельные законченные функции, полностью написанные на ассемблере. О том, как правильно писать такие функции и о правилах передачи аргументов в/из asm-функций из/в Си-функции, описано в документации. А вставлять отдельные ассемблерные команды посреди Си-шного исходника бросьте сразу, еще не начиная rolleyes.gif

Ну и еще раз напомню про отличия типов переменных. Тип переменной влияет на ее размещение в памяти и область видимости.
Переменные типа global (глобальная) и static (статическая) размещаются в памяти данных, т.е. под них выделяются ячейки памяти с постоянным адресом.
Переменные типа auto (автоматическая или локальная) размещаются на стеке или в РОН (по усмотрению компилятора), но постоянного адреса в памяти они не имеют.
Переменные типа register (регистровая) в принципе могут быть как глобальными (если объявлена вне функции с указанием конкретного регистра) так и локальными (объявлена без указания регистра внутри функции). Переменные типа register это тип данных с наиболее быстрым доступом. А для того, чтобы доступ к ним был быстрым, предполагается, что размещаться они должны в РОН. Но проблема состоит в том, что если заранее в опциях проекта для переменных типа register не зарезервировать конкретные регистры (в IAR EW430 возможно резервировать только R4 и R5), то компилятор обращается с ними очень вольно и в большинстве случаев пилюет на такую декларацию с высокой колокольни, трактуя локальные register как обычные переменные auto.
Область видимости global - вся программа.
Область видимости static - данный конкретный модуль или функция, если static объявлена внутри функции.
Область видимости auto - функция или блок оператора в котором она объявлена.
Go to the top of the page
 
+Quote Post

5 страниц V   1 2 3 > » 
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 3rd August 2025 - 03:18
Рейтинг@Mail.ru


Страница сгенерированна за 0.01488 секунд с 7
ELECTRONIX ©2004-2016