|
Сохранение контекста в прерываниях, IAR |
|
|
|
May 14 2008, 11:51
|
Частый гость
 
Группа: Свой
Сообщений: 169
Регистрация: 10-11-05
Из: Воронеж
Пользователь №: 10 687

|
Да простят меня модераторы, если вопрос избитый, но всезнающий поиск вразумительного ответа мне не дал. А проблема, имхо, достаточно часто встречающаяся: Имеем некоторое прерывание, которое должно автономно обработать некоторый блок данных и по окончании работы сообщить об этом основному софту. Например, рассмотрим отправку пакета по УАРТ. Основную массу действий (а именно, выборку очередного байта из памяти и его отправку) прерывание делает своими силами, но, вот беда: когда оно закончит, оно должно вызвать некоторую функцию, которая должна просигнализировать основной программе о выполнении задания. Вариант с глобальной переменной отпадает сразу, т.к. ситуация гипотетическая и сигналом в данном случае может служить семафор или еще какие-либо средство РТОС. Естественно компилятор, видя в прерывании вызов внешней, неизвестной ему функции, далает сохранение кучи регистров в стек. Однако, если отправляемый пакет состоит из 1000 байтов, то 999 раз контекст сохранится зря и только последний раз, когда работа завершена, действительно необходимо слить регистры в стек и вызвать функцию - сигнал. Я хочу, чтобы контекст сохранялся только 1 раз из 1000, когда уже ясно, что необходим вызов внешней функции. Пока единственное решение, приходящее мне в голову, это писать код прерывания на асме и сохранять регистры вручную не на входе в прерывание, а в ветке проверки условия окончания задания. Но что-то мне подсказывает, что этот вопрос можно решить директивами/ключевыми словами/intrinsic функциями/другими расширениями языка, не прибегая к полному написанию кода прерывания на асме. Только вот пока такой вариант в голову не приходит  Подскажите, плз, кто и как избавляется от подобного оверхеда? PS: Интересует решение для компилятора ИАР.
|
|
|
|
|
 |
Ответов
|
May 15 2008, 06:36
|

Гуру
     
Группа: Свой
Сообщений: 2 399
Регистрация: 10-05-06
Из: г. Новочеркасск
Пользователь №: 16 954

|
Цитата(zltigo @ May 15 2008, 08:53)  Уточнение - для AVR - обязательно, если это только не очень "тяжелый обработчик" и без того использущий массу регистров. "Обязательно" - это слишком категорично. Бывают проекты в которых необходимо обрабатывать очень частые прерывания, большая часть которых не требует сложных действий (а, значит и ресурсов процессора - тех же регистров). Возникает желание сэканомить на сохранении-востановлении контекста... Если "тяжелую" часть обработчика выделить в отдельную функцию и при её вызове самому позаботиться о сохранении-восстановлении регистров, то можно получить неплохой результат. Вот так это можно сделать в ICC Код void func(void) // Функция, вызываемая из процедуры обработки прерывания { ............... }
#pragma interrupt_handler proc_interrupt:x void proc_interrupt(void) // Процедура обработки прерывания { ............ if(...) { asm("xcall push_lset"); // Вызов стандартной функции сохранения регистров asm("xcall _func"); // Вызов функции void func(void) asm("xcall pop_lset"); // Вызов стандартной функции восстановления регистров } ............ } при этом, при входе(выходе) в(из) процедуры обработки прерывания proc_interrupt транслятор генерит код, сохраняющий(востанавливающий) необходимый минимум регистров. Если, ассемблерные вставки заменить на с-ишный вызов функции func(); , то транслятор генерит код сохраняющий(востанавливающий) все регистры.
|
|
|
|
|
May 15 2008, 16:46
|

Йа моск ;)
     
Группа: Модераторы
Сообщений: 4 345
Регистрация: 7-07-05
Из: Kharkiv-city
Пользователь №: 6 610

|
Цитата(zltigo @ May 15 2008, 09:41)  В данном случае идет речь о чисто сишных + расширения компилятора возможностях. Вообщем, есть достаточно простой метод. Без асма, но надо проследить один момент (об этом чуть позже). Я обычно поступаю следующим образом Код //Флаг необходимости запуска тяжелой части #define NeedRunPart2 GPIOR0_Bit0 //Флаг блокировки, если не нужно разрешать прерывания, можно убрать #define Part2Lock GPIOR0_Bit1
#pragma diag_suppress=Ta006 __interrupt void Int_part1(void) { //Легкая часть прерывания ....
if (....) NeedRunPart2=1; .... }
__interrupt void Int_part2(void) { //Тут вызываем функции, извращаемся как хотим .... .... .... } #pragma diag_default=Ta006
#pragma vector=какой надо __interrupt __raw void INT_dispatch(void) { ((void(*)(void))Int_part1)(); __disable_interrupt(); if (!NeedRunPart2) return; if (Part2Lock) return; Part2Lock=1; NeedRunPart2=0; __enable_interrupt(); ((void(*)(void))Int_part1)(); __disable_interrupt(); Part2Lock=0; } Главное тут - проверить, чтобы проверяемые и устанавливаемые флаги были в младших адресах пространства ввода-вывода, чтобы компилятор мог пользоваться SBIC/SBIS для проверки и SBI/CBI для манипуляций. Тогда можно не сохранять контекст в диспечере прерываний - эти комманды не портят SREG и другие регистры. Вот такой код получается у диспечера: Код // 34 __interrupt __raw void INT_dispatch(void) INT_dispatch: // 35 { // 36 ((void(*)(void))Int_part1)(); RCALL Int_part1 // 37 __disable_interrupt(); CLI // 38 if (!NeedRunPart2) return; SBIS 0x1E, 0x00 RJMP ??INT_dispatch_0 // 39 if (Part2Lock) return; SBIC 0x1E, 0x01 RJMP ??INT_dispatch_0 // 40 Part2Lock=1; SBI 0x1E, 0x01 // 41 NeedRunPart2=0; CBI 0x1E, 0x00 // 42 __enable_interrupt(); SEI // 43 ((void(*)(void))Int_part1)(); RCALL Int_part1 // 44 __disable_interrupt(); CLI // 45 Part2Lock=0; CBI 0x1E, 0x01 // 46 } ??INT_dispatch_0: RETI Кстати, приведенный код разрешает вложенные прерывания, для выполнения быстрой части пока выполняется медленная часть. Если этого не нужно, можно упростить. И на посошок, не забыть запретить варнинг линкеру, что производится вызов обработчика прерывания как фунцкции.
--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
|
|
|
|
Сообщений в этой теме
gladov Сохранение контекста в прерываниях May 14 2008, 11:51 prottoss Цитата(gladov @ May 14 2008, 19:51) Не по... May 14 2008, 12:03 gladov ЦитатаНе понятно, для какой платформы вопрос.
Дума... May 14 2008, 12:56  prottoss Цитата(gladov @ May 14 2008, 20:56) Думал... May 14 2008, 13:13 SasaVitebsk Цитата(gladov @ May 14 2008, 15:51) Подск... May 14 2008, 12:15 Палыч Цитата(gladov @ May 14 2008, 14:51) Естес... May 14 2008, 12:39 zltigo Цитата(gladov @ May 14 2008, 13:51) Я хоч... May 14 2008, 13:28 defunct У AVR есть возможность отделить прерывание непреры... May 14 2008, 13:35 IgorKossak Цитата(defunct @ May 14 2008, 16:35) У AV... May 15 2008, 05:05 prottoss Цитата(gladov @ May 14 2008, 19:51) Напри... May 14 2008, 13:48 zltigo Цитата(prottoss @ May 14 2008, 15:48) Пох... May 14 2008, 13:52 prottoss может вот это поможет - комменты на русском. Драйв... May 14 2008, 14:03 AHTOXA Цитата(zltigo @ May 14 2008, 19:52) Естес... May 14 2008, 18:10 zltigo Цитата(AHTOXA @ May 14 2008, 20:10) Вызов... May 14 2008, 19:56  Дон Амброзио Цитата(zltigo @ May 14 2008, 23:56) Это у... May 14 2008, 20:46
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|