Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Как в Keil для ARM указать точное расположение процедуры в памяти FLASH
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Romanello
Нужно расположить функцию в заанее известном месте в памяти контроллера и потом обращаться к ней, кстати как потом можно будет обратиться к этой функции из другой функции?

Заранее спасибо.
aaarrr
Цитата(Romanello @ Oct 2 2007, 18:32) *
Нужно расположить функцию в заанее известном месте в памяти контроллера и потом обращаться к ней, кстати как потом можно будет обратиться к этой функции из другой функции?

Воспользуйтесь поиском, ключевое слово - scatter.
Обращаться к функции можно будет так же, как и к любой другой - линкер ведь будет знать её расположение.
defunct
Цитата(aaarrr @ Oct 2 2007, 18:08) *
Воспользуйтесь поиском, ключевое слово - scatter.
Обращаться к функции можно будет так же, как и к любой другой - линкер ведь будет знать её расположение.

Может быть речь о разных программах?
В одной программе некая сервисная функция кладется по оговоренному адресу, из другой программы, эта сервисная функция вызывается. Тогда первое ваше предложение верно, а второе насчет линкера не пригодится, т.к. линкер может и не знать где располагается требуемая функция. В обход линкера можно например создать тип сервисной функции и указатель, и написав макрос или проинициализировать такой уазатель вручную, вызывать сервисную функию с любого адреса (в примере вызов функции по адресу 0x1000):

создаем типы:
Код
typedef void __service_func(void);
typedef __service_func *__p_service_func;


используем так:
Код
int main( void )
{
    __p_service_func foo = (__p_service_func)0x1000;
    ...
    foo();

или так:
Код
#define CALL_SERVICE( addr )  ( ((__p_service_func)( addr )) () )

int main( void )
{
    CALL_SERVICE( 0x1000 );
aaarrr
Цитата(defunct @ Oct 3 2007, 01:01) *
Может быть речь о разных программах?

Тогда проще и логичнее использовать SWI, благо оно именно для таких целей и предусматривалось.
romashko
Цитата(Romanello @ Oct 3 2007, 01:32) *
...кстати как потом можно будет обратиться к этой функции из другой функции?


#define Address 0x10000000 //адрес по которому расположена функция
#define CALL (*(void(*)(void)) Address) //функция CALL()

int main(void)
{
...
CALL(); //вызов функции по адресу 0x10000000
...
}
Romanello
Функция которая размещена по определенному адресу и основная программа компилируется в разное время и в разных местах. Из всего вышесказанного не понял как указать размещение программы в памяти по определееному адресу.
aaarrr
Цитата(Romanello @ Oct 3 2007, 16:56) *
Функция которая размещена по определенному адресу и основная программа компилируется в разное время и в разных местах.

Тогда лучше SWI, или в таком решении что-то не устраивает?

Цитата(Romanello @ Oct 3 2007, 16:56) *
Из всего вышесказанного не понял как указать размещение программы в памяти по определееному адресу.

Размещать лучше не программу, а таблицу переходов - это дает некоторую гибкость.
Указать размещение этой таблицы нужно линкеру, делается это через scatter description file. Описание можно найти в документации.
Romanello
Цитата(aaarrr @ Oct 3 2007, 17:01) *
Тогда лучше SWI, или в таком решении что-то не устраивает?
Размещать лучше не программу, а таблицу переходов - это дает некоторую гибкость.
Указать размещение этой таблицы нужно линкеру, делается это через scatter description file. Описание можно найти в документации.



ЧТо такое SWI и как это выглядит в KEIL компиляторе?
aaarrr
Цитата(Romanello @ Oct 3 2007, 20:09) *
ЧТо такое SWI и как это выглядит в KEIL компиляторе?

SWI - это программное прерывание. Почитать про него можно в описании архитектуры ARM. В Keil выглядит так же, как и в любом другом месте.
Сергей Борщ
Цитата(defunct @ Oct 3 2007, 00:01) *
создаем типы:
используем так:
А если так:
Код
extern void func1();
extern int func2(int, char);
extern char func3(long);
А линкеру указать конкретные адреса функций. В IAR это делается ключем командной строки линкера -Dfunc1=0x1000 -Dfunc2=0x2000 или в .xcl-файле, в WinAVR - -wl,--defsym,func1=0x1000 или в файле для ld. Предполагаю, что в Кейле есть такая же возможность. Насчет таблицы тоже мысль очень правильная - при изменении самих функций не придется перекраивать вторую программу. Причем в таблице могут быть не адреса, а команды B func1, B func2. Такую таблицу, конечно, придется писать на ассемблере.
Romanello
Цитата(aaarrr @ Oct 3 2007, 20:22) *
SWI - это программное прерывание. Почитать про него можно в описании архитектуры ARM. В Keil выглядит так же, как и в любом другом месте.


А как программное прерывание привязать к выполнению функции из определенного адреса. Можно же просто обратиться в определенный адрес. А мен нужно разместить функцию по определленному адресу. Зачем для этого создавать таюлицу переходов, да еще на ассемблере?
aaarrr
Цитата(Romanello @ Oct 4 2007, 12:50) *
А как программное прерывание привязать к выполнению функции из определенного адреса.

Не нужно ничего привязывать. Вся прелесть SWI в том, что вызов всегда будет одинаков. А разбираться, какая функция соответствует вызову будет обработчик SWI.

Цитата(Romanello @ Oct 4 2007, 12:50) *
Зачем для этого создавать таюлицу переходов, да еще на ассемблере?

Затем, что никто не гарантирует, что функцию удастся разместить по нужному адресу. Особенно, если она не одна. Да и возни с каждой отдельной функцией будет слишком много.
Это просто разумное решение для такой задачи.
Сергей Борщ
Цитата(Romanello @ Oct 4 2007, 11:50) *
Зачем для этого создавать таюлицу переходов, да еще на ассемблере?
А вы попробуйте. Потом чуть измените одну из функций и у вас "поплывут" адреса всех остальных. Придется исправлять и перекомпилировать приложение, в котором эти функции вызываются. А с таблицей все точки входа во все функции будут располагаться всегда в одном и том же месте, вне зависимости от размера функций.
Николай Z
Цитата(Romanello @ Oct 2 2007, 18:32) *
Нужно расположить функцию в заанее известном месте в памяти контроллера и потом обращаться к ней, кстати как потом можно будет обратиться к этой функции из другой функции?


Cоветов тут уже надавали кучу и без меня...
А у меня всего один вопрос имеющий отношение к делу:
А зачем вообще какую-то функцию нужно располагать в "заранее известном месте..."?

По-моему логично сперва понять - а нужно ли это и зачем, а уж потом решать такую задачу...
bodja74
Цитата(Николай Z @ Oct 4 2007, 13:03) *
А зачем вообще какую-то функцию нужно располагать в "заранее известном месте..."?

BootLoader,API(IAP),типа дисковая ось.
Romanello
Цитата(bodja74 @ Oct 4 2007, 14:52) *
BootLoader,API(IAP),типа дисковая ось.


Точно, мне нужно создать типа этого. Будет по определленному адресу вызов процедуры, а она в зависимости от параметров будет уже вызывать нужные функции. Так вот эта функция и нужные функции будут компилироваться вместе (поэтому я думаю таблица переходов не нужна, компилятор сам подставит нужные значения), а программу которая будет вызывать эту функцию будет писаться отдельно и соответственно компилироваться тоже будет отдельно, поэтому я и хочу узнать как мне разместить функцию по указанному адресу и как ее вызвать?. Если можно напишите просто пример
Сергей Борщ
Цитата(Romanello @ Oct 4 2007, 15:39) *
Будет по определленному адресу вызов процедуры, а она в зависимости от параметров будет уже вызывать нужные функции.
Т.е. то, что линкер мог сделать на этапе компиляции (вызвать сразу нужную функцию), ваша функция будет делать на этапе выполнения. А смысл?
Wano
А например если зашить во флэш где-нить в конец к примеру UCOS smile.gif ,а дальше возиться только с графикой. Чего каждый раз ось заливать,когда время тратит.Ну эт я образно конечно тут ляпнул.
Shkn
Можно поиграться с прагмой, например
#pragma userclass (CODE = CODE_FLASH), где FLASH задаешь в настройках проекта закладка ликера.

для возврата в исходное значение
#pragma userclass (CODE = default)

посмотри http://electronix.ru/forum/index.php?showtopic=36070, может наведет на правильную мысль
iit
Пример скаттер файла.

FLASH_LOAD 0x00 0x40000
{

ROM_EXEC 0x00 0x10000
{
startup.o (INIT,+FIRST) ; executed on hard reset
*(+RO)
}

BOOT_EXEC 0x10000 0x10000
{
project_set.o(boot_func); В этой области размещается наша функция
}

RAM 0x40000000 0x4000
{

* (+RW, +ZI) ; any remaining code inc C lib.
}

EEPROM 0xF0000000 UNINIT 0x100
{
project_set.o(eeprom_config)
}

EXRAM 0x81000000 0x200000
{

ExtRAM.o (+RW, +ZI)
}
}

В project_set.c
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
#pragma arm section code = "boot_func", rwdata = "boot_func"

UINT32 boot_fun(UINT32 code)
{
if (code != 0)
{
return 0;
}
else
{
return 10;
}
}

#pragma arm section code, rwdata, zidata
//-----------------------------------------------------------------------------

Выполняем буилд проекта и смотрим в мап-файле
boot_fun 0x00010000 ARM Code 28 project_set.o(boot_func)

Всех делов.
Romanello
Спасибо за ответы буду разбираться и пробовать.
VIRt
Все очень просто. Описываеш например как:

void (* fptr)();

ну и например

void f1 (void) {
//Do something
}

Инициализация делается так:

fptr = &f1;

Вызывается также как обычная функция:

fptr();

можно также передавать и получать параметры:
тип (* fptr)(список переменных)....

Таким методом вызывать функцию через указатель...
Далее можно сделать либо список, либо таблицу указателей. И работать с ними.
У меня на таймере так куча задач реализовано. Причем можна добавлять задачу, изменять дискрет выполнения в мсек., включать/выключать, удалять из списка. Функции на выполнение все внешние...
Николай Z
Цитата(Сергей Борщ @ Oct 4 2007, 17:02) *
Т.е. то, что линкер мог сделать на этапе компиляции (вызвать сразу нужную функцию), ваша функция будет делать на этапе выполнения. А смысл?


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

Цитата(VIRt @ Oct 5 2007, 13:45) *
[code]void (* fptr)();

ну и например

void f1 (void) {
//Do something
}

Инициализация делается так:
fptr = &f1;

Вызывается также как обычная функция:
fptr();


Возникла необходимость делать абдейты на процессоре LPC2378 на IAR.
Для этого был сделан загрузчик, который находится в неперезаписываемой области Flash.
Кроме перепрограммирования оставшейся Flash он еще должен уметь вызывать пару функций из
перезаписываемой области. Для этого по фиксированному адресу в перезаписываемой Flash должны находиться указатели на функции, которые могут находиться в коде где угодно
(функции типа void func(void)).

Прочитал http://electronix.ru/forum/index.php?showt...amp;mode=linear
Попробовал разместить void f1 (void) в памяти.

Просто вот так работает

void start(void)
void (* fptr)() = &start;

А вот так нет.

#pragma location = "MYROM"
__root const void (* fptr)() = &start;

Помогите пожалуйста победить эту штуку 05.gif
Vitaliy_ARM
Победил!!! Так как адрес у функции 32-разрядный, преобразовал его в DWORD, а при вызове преобразую обратно. Вот кусок кода:
Код
void start(void)
{  
}

#pragma location = "CODE"
__root const dword StartPointer = (dword)&start;

void (* fptr)();

void main(void)
{
  fptr = (void(*)())StartPointer;
  TargetInit();
  fptr();
  while(1);
}


При вызове fptr(), вызывается start();
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.