|
Как в Keil для ARM указать точное расположение процедуры в памяти FLASH |
|
|
|
Oct 2 2007, 21:01
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата(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 );
|
|
|
|
|
Oct 2 2007, 22:59
|
Частый гость
 
Группа: Свой
Сообщений: 85
Регистрация: 25-12-06
Пользователь №: 23 865

|
Цитата(Romanello @ Oct 3 2007, 01:32)  ...кстати как потом можно будет обратиться к этой функции из другой функции? #define Address 0x10000000 //адрес по которому расположена функция #define CALL (*(void(*)(void)) Address) //функция CALL() int main(void) { ... CALL(); //вызов функции по адресу 0x10000000 ... }
|
|
|
|
|
Oct 3 2007, 13:01
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Цитата(Romanello @ Oct 3 2007, 16:56)  Функция которая размещена по определенному адресу и основная программа компилируется в разное время и в разных местах. Тогда лучше SWI, или в таком решении что-то не устраивает? Цитата(Romanello @ Oct 3 2007, 16:56)  Из всего вышесказанного не понял как указать размещение программы в памяти по определееному адресу. Размещать лучше не программу, а таблицу переходов - это дает некоторую гибкость. Указать размещение этой таблицы нужно линкеру, делается это через scatter description file. Описание можно найти в документации.
|
|
|
|
|
Oct 3 2007, 16:09
|
Частый гость
 
Группа: Свой
Сообщений: 138
Регистрация: 10-03-05
Пользователь №: 3 204

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

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(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. Такую таблицу, конечно, придется писать на ассемблере.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Oct 4 2007, 08:50
|
Частый гость
 
Группа: Свой
Сообщений: 138
Регистрация: 10-03-05
Пользователь №: 3 204

|
Цитата(aaarrr @ Oct 3 2007, 20:22)  SWI - это программное прерывание. Почитать про него можно в описании архитектуры ARM. В Keil выглядит так же, как и в любом другом месте. А как программное прерывание привязать к выполнению функции из определенного адреса. Можно же просто обратиться в определенный адрес. А мен нужно разместить функцию по определленному адресу. Зачем для этого создавать таюлицу переходов, да еще на ассемблере?
|
|
|
|
|
Oct 4 2007, 09:20
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Цитата(Romanello @ Oct 4 2007, 12:50)  А как программное прерывание привязать к выполнению функции из определенного адреса. Не нужно ничего привязывать. Вся прелесть SWI в том, что вызов всегда будет одинаков. А разбираться, какая функция соответствует вызову будет обработчик SWI. Цитата(Romanello @ Oct 4 2007, 12:50)  Зачем для этого создавать таюлицу переходов, да еще на ассемблере? Затем, что никто не гарантирует, что функцию удастся разместить по нужному адресу. Особенно, если она не одна. Да и возни с каждой отдельной функцией будет слишком много. Это просто разумное решение для такой задачи.
|
|
|
|
|
Oct 4 2007, 10:03
|
Местный
  
Группа: Участник*
Сообщений: 418
Регистрация: 20-08-07
Пользователь №: 29 930

|
Цитата(Romanello @ Oct 2 2007, 18:32)  Нужно расположить функцию в заанее известном месте в памяти контроллера и потом обращаться к ней, кстати как потом можно будет обратиться к этой функции из другой функции? Cоветов тут уже надавали кучу и без меня... А у меня всего один вопрос имеющий отношение к делу: А зачем вообще какую-то функцию нужно располагать в "заранее известном месте..."? По-моему логично сперва понять - а нужно ли это и зачем, а уж потом решать такую задачу...
Сообщение отредактировал Николай Z - Oct 4 2007, 10:04
|
|
|
|
|
Oct 4 2007, 12:39
|
Частый гость
 
Группа: Свой
Сообщений: 138
Регистрация: 10-03-05
Пользователь №: 3 204

|
Цитата(bodja74 @ Oct 4 2007, 14:52)  BootLoader,API(IAP),типа дисковая ось. Точно, мне нужно создать типа этого. Будет по определленному адресу вызов процедуры, а она в зависимости от параметров будет уже вызывать нужные функции. Так вот эта функция и нужные функции будут компилироваться вместе (поэтому я думаю таблица переходов не нужна, компилятор сам подставит нужные значения), а программу которая будет вызывать эту функцию будет писаться отдельно и соответственно компилироваться тоже будет отдельно, поэтому я и хочу узнать как мне разместить функцию по указанному адресу и как ее вызвать?. Если можно напишите просто пример
|
|
|
|
|
Oct 5 2007, 04:52
|
Участник

Группа: Новичок
Сообщений: 15
Регистрация: 28-08-07
Пользователь №: 30 105

|
Можно поиграться с прагмой, например #pragma userclass (CODE = CODE_FLASH), где FLASH задаешь в настройках проекта закладка ликера. для возврата в исходное значение #pragma userclass (CODE = default) посмотри http://electronix.ru/forum/index.php?showtopic=36070, может наведет на правильную мысль
|
|
|
|
|
Oct 5 2007, 05:35
|
Участник

Группа: Свой
Сообщений: 72
Регистрация: 8-11-04
Из: Томск
Пользователь №: 1 070

|
Пример скаттер файла.
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)
Всех делов.
|
|
|
|
|
Oct 5 2007, 10:45
|
Участник

Группа: Новичок
Сообщений: 48
Регистрация: 28-03-06
Пользователь №: 15 573

|
Все очень просто. Описываеш например как:
void (* fptr)();
ну и например
void f1 (void) { //Do something }
Инициализация делается так:
fptr = &f1;
Вызывается также как обычная функция:
fptr();
можно также передавать и получать параметры: тип (* fptr)(список переменных)....
Таким методом вызывать функцию через указатель... Далее можно сделать либо список, либо таблицу указателей. И работать с ними. У меня на таймере так куча задач реализовано. Причем можна добавлять задачу, изменять дискрет выполнения в мсек., включать/выключать, удалять из списка. Функции на выполнение все внешние...
Сообщение отредактировал VIRt - Oct 5 2007, 10:56
|
|
|
|
|
Oct 5 2007, 11:00
|
Местный
  
Группа: Участник*
Сообщений: 418
Регистрация: 20-08-07
Пользователь №: 29 930

|
Цитата(Сергей Борщ @ Oct 4 2007, 17:02)  Т.е. то, что линкер мог сделать на этапе компиляции (вызвать сразу нужную функцию), ваша функция будет делать на этапе выполнения. А смысл? Вот и я в полном недоумении - зачем это собственно надо... Если хочется - можно конечно задать в линкере фиксированное в памяти расположение секций программы... Но на кой это надо - не понимаю абсолютно... Логичнее поступать прямо наоборот.
Сообщение отредактировал Николай Z - Oct 5 2007, 11:01
|
|
|
|
|
Jan 28 2008, 15:38
|
Знающий
   
Группа: Свой
Сообщений: 509
Регистрация: 19-07-07
Из: г. Таганрог
Пользователь №: 29 246

|
Не стал плодить тем. Пишу в похожую. Цитата(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; Помогите пожалуйста победить эту штуку
Сообщение отредактировал Vitaliy_ARM - Jan 28 2008, 15:46
--------------------
Умные речи подобны строкам, напечатанным курсивом. К. Прутков
|
|
|
|
|
Jan 30 2008, 22:20
|
Знающий
   
Группа: Свой
Сообщений: 509
Регистрация: 19-07-07
Из: г. Таганрог
Пользователь №: 29 246

|
Победил!!! Так как адрес у функции 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();
Сообщение отредактировал Vitaliy_ARM - Jan 30 2008, 22:21
--------------------
Умные речи подобны строкам, напечатанным курсивом. К. Прутков
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|