Реклама на сайте English version  DatasheetsDatasheets

KAZUS.RU - Электронный портал. Принципиальные схемы, Datasheets, Форум по электронике

Новости электроники Новости Литература, электронные книги Литература Документация, даташиты Документация Поиск даташитов (datasheets)Поиск PDF
  От производителей
Новости поставщиков
В мире электроники

  Сборник статей
Электронные книги
FAQ по электронике

  Datasheets
Поиск SMD
Он-лайн справочник

Принципиальные схемы Схемы Каталоги программ, сайтов Каталоги Общение, форум Общение Ваш аккаунтАккаунт
  Каталог схем
Избранные схемы
FAQ по электронике
  Программы
Каталог сайтов
Производители электроники
  Форумы по электронике
Помощь проекту

Микроконтроллеры, АЦП, память и т.д Темы касающиеся микроконтроллеров разных производителей, памяти, АЦП/ЦАП, периферийных модулей...

 
Опции темы
Непрочитано 21.08.2010, 17:10  
alex_312
Прохожий
 
Аватар для alex_312
 
Регистрация: 08.08.2010
Сообщений: 7
Сказал спасибо: 1
Сказали Спасибо 1 раз в 1 сообщении
alex_312 на пути к лучшему
По умолчанию Re: Как изменить адрес подпрограммы обработки прерывания?

Сообщение от kison Посмотреть сообщение
Попобуйте в реале, удивитесь результату. Куча регистров уйдет в стек, ведь компилятор по сути вызывает обычную функцию по указателю. Которая имеет право изменять Call used регистры, что в прерывании недопустимо. Так что вместо экономии тактов 30-40 в начале уйдет на сохранение регистров.


Это не в функцию разворачивается, а сего лишь аттрибуты функции присваивает.
Так что чисто на Си ничего не получится, минимум - разместить обработчики на неиспользованных векторах и переключать эти обработчики из ассемблерной обертки. И хранить указатель в регистровой переменной. Ограничение - количество свободных векторов прерывания. Впрочем можно в каждый еще ветвления вставлять. А нормально сделать получится только если обработчики будут тоже на ассемблере. Тут скорость почти максимальна. Оверхед - 8 тактов на вход и 7 на выход.
А что мне удивятся, это вы удивитесь, когда посмотрите ассемблерный листинг и увидите что любое прерывание начинается с того что сохраняются все (практически все) регистры в стек, а перед выходом из прерывания они восстанавливаются из стека.

И, кстати, про необходимость ручного сохранения/восстановления регистров я писал.
Смотрите пост №6https://kazus.ru/forums/showpost.php...09&postcount=6
Реклама:

Последний раз редактировалось alex_312; 21.08.2010 в 17:20.
alex_312 вне форума  
Непрочитано 21.08.2010, 18:34  
kison
Почётный гражданин KAZUS.RU
 
Регистрация: 13.12.2004
Сообщений: 3,172
Сказал спасибо: 11
Сказали Спасибо 692 раз(а) в 504 сообщении(ях)
kison на пути к лучшему
По умолчанию Re: Как изменить адрес подпрограммы обработки прерывания?

Сообщение от alex_312 Посмотреть сообщение
А что мне удивятся, это вы удивитесь, когда посмотрите ассемблерный листинг и увидите что любое прерывание начинается с того что сохраняются все (практически все) регистры в стек, а перед выходом из прерывания они восстанавливаются из стека.
Я бы удивился, если бы Вы оказались правы. Но на самом деле:
Код:
uint8_t a;
volatile uint8_t result;

ISR(INT1_vect)
{
result  = a;
}
И листинг
Код:
11:       {
+0000002D:   921F        PUSH    R1               Push register on stack
+0000002E:   920F        PUSH    R0               Push register on stack
+0000002F:   B60F        IN      R0,0x3F          In from I/O location
+00000030:   920F        PUSH    R0               Push register on stack
+00000031:   2411        CLR     R1               Clear Register
+00000032:   938F        PUSH    R24              Push register on stack
12:       result  = a;
+00000033:   91800061    LDS     R24,0x0061       Load direct from data space
+00000035:   93800060    STS     0x0060,R24       Store direct to data space
+00000037:   918F        POP     R24              Pop register from stack
+00000038:   900F        POP     R0               Pop register from stack
+00000039:   BE0F        OUT     0x3F,R0          Out to I/O location
+0000003A:   900F        POP     R0               Pop register from stack
+0000003B:   901F        POP     R1               Pop register from stack
+0000003C:   9518        RETI                     Interrupt return
В стек идут 3 регистра и SREG. Три это почти все из 32?
А теперь то же, но через указатель. Т.е. то, что Вы предложили.
Код:
void Func(void);
typedef void (*FuncPtr_t)(void);

FuncPtr_t pFunc = Func;
uint8_t a;
volatile uint8_t result;

void Func(void)
{
result = a;
}

ISR(INT1_vect)
{
(*pFunc)();
}
И ее результат. Учтите, там только вызов функции, никакой полезной работы уже нет.
Код:
@00000032: __vector_2
21:       {
+00000032:   921F        PUSH    R1               Push register on stack
+00000033:   920F        PUSH    R0               Push register on stack
+00000034:   B60F        IN      R0,0x3F          In from I/O location
+00000035:   920F        PUSH    R0               Push register on stack
+00000036:   2411        CLR     R1               Clear Register
+00000037:   932F        PUSH    R18              Push register on stack
+00000038:   933F        PUSH    R19              Push register on stack
+00000039:   934F        PUSH    R20              Push register on stack
+0000003A:   935F        PUSH    R21              Push register on stack
+0000003B:   936F        PUSH    R22              Push register on stack
+0000003C:   937F        PUSH    R23              Push register on stack
+0000003D:   938F        PUSH    R24              Push register on stack
+0000003E:   939F        PUSH    R25              Push register on stack
+0000003F:   93AF        PUSH    R26              Push register on stack
+00000040:   93BF        PUSH    R27              Push register on stack
+00000041:   93EF        PUSH    R30              Push register on stack
+00000042:   93FF        PUSH    R31              Push register on stack
22:       (*pFunc)();
+00000043:   91E00060    LDS     R30,0x0060       Load direct from data space
+00000045:   91F00061    LDS     R31,0x0061       Load direct from data space
+00000047:   9509        ICALL                    Indirect call to (Z)
+00000048:   91FF        POP     R31              Pop register from stack
+00000049:   91EF        POP     R30              Pop register from stack
+0000004A:   91BF        POP     R27              Pop register from stack
+0000004B:   91AF        POP     R26              Pop register from stack
+0000004C:   919F        POP     R25              Pop register from stack
+0000004D:   918F        POP     R24              Pop register from stack
+0000004E:   917F        POP     R23              Pop register from stack
+0000004F:   916F        POP     R22              Pop register from stack
+00000050:   915F        POP     R21              Pop register from stack
+00000051:   914F        POP     R20              Pop register from stack
+00000052:   913F        POP     R19              Pop register from stack
+00000053:   912F        POP     R18              Pop register from stack
+00000054:   900F        POP     R0               Pop register from stack
+00000055:   BE0F        OUT     0x3F,R0          Out to I/O location
+00000056:   900F        POP     R0               Pop register from stack
+00000057:   901F        POP     R1               Pop register from stack
+00000058:   9518        RETI                     Interrupt return
В стек идут уже 14 регистров + SREG. 11 лишних, по два такта на PUSH - 22 лишних такта. А тут топикстартер из за 5 лишних расстраивается.
kison вне форума  
Непрочитано 21.08.2010, 21:27  
testerplus
Прописка
 
Регистрация: 26.01.2009
Сообщений: 249
Сказал спасибо: 23
Сказали Спасибо 102 раз(а) в 61 сообщении(ях)
testerplus на пути к лучшему
По умолчанию Re: Как изменить адрес подпрограммы обработки прерывания?

Сообщение от Godzilla82 Посмотреть сообщение
У меня как раз такая задача, когда всё упирается в эти самые лишние 3-5 тактов. Нужно по адресу вектора прерывания поменять адрес перехода на нужную подпрограмму. Думаю, что это возможно сделать средствами СИ (пусть даже с ассемблерными вставками). Поэтому и спрашиваю.
А не рассматривается вариант с двумя таймерами? В одном режиме разрешено прерывание от одного таймера, в другом - от другого. Или на одном таймере, но использовать источники прерываний 1) по переполнению, 2) по compare
testerplus вне форума  
Непрочитано 22.08.2010, 01:27  
nml
Супер-модератор
 
Аватар для nml
 
Регистрация: 13.03.2004
Адрес: Minsk
Сообщений: 2,378
Сказал спасибо: 1,956
Сказали Спасибо 1,328 раз(а) в 578 сообщении(ях)
nml на пути к лучшему
По умолчанию Re: Как изменить адрес подпрограммы обработки прерывания?

Сообщение от Godzilla82 Посмотреть сообщение
Например, есть два режима работы контроллера. В одном режиме по прерыванию от таймера должны выполняться одни действия. В другом режиме - по этому же прерыванию - другие действия.
Вектор изменить нельзя. Напишите в начале обработчика
Код:
if (mode) {сделать то-то} else {сделать нетото}
А такты экономьте за счет алгоритма и тонкостей компилятора.
__________________
[ жизнь приятна и красива, если выпить литр пива ]
nml вне форума  
Непрочитано 22.08.2010, 05:00  
Godzilla82
Почётный гражданин KAZUS.RU
 
Регистрация: 29.10.2006
Сообщений: 1,446
Сказал спасибо: 99
Сказали Спасибо 317 раз(а) в 233 сообщении(ях)
Godzilla82 на пути к лучшему
Сообщение Re: Как изменить адрес подпрограммы обработки прерывания?

Сообщение от testerplus Посмотреть сообщение
А не рассматривается вариант ...
Сообщение от nml Посмотреть сообщение
...такты экономьте за счет алгоритма и тонкостей компилятора.
Так и придётся. Думал, что есть простое и красивое решение. Заменил вектор - и вуаля

Подумываю о таком финте:
PHP код:
int adr;

void proc1(void)
{
...
}

void proc2(void)
{
...
}

ISR(...)
{
call adr;
}

void main(void)
{
...
if(
uslovieadr proc1;
else        
adr proc2;

Понятно, что это и не СИ, и не ассемблер, но свою мысль я донёс. Как такое сделать?

Последний раз редактировалось Godzilla82; 22.08.2010 в 05:04.
Godzilla82 вне форума  
Непрочитано 22.08.2010, 13:46  
kison
Почётный гражданин KAZUS.RU
 
Регистрация: 13.12.2004
Сообщений: 3,172
Сказал спасибо: 11
Сказали Спасибо 692 раз(а) в 504 сообщении(ях)
kison на пути к лучшему
По умолчанию Re: Как изменить адрес подпрограммы обработки прерывания?

Сообщение от Godzilla82 Посмотреть сообщение
Понятно, что это и не СИ, и не ассемблер, но свою мысль я донёс. Как такое сделать?
В 8 сообщении рабочий пример на ассемблере. Причем без оверхеда, скорость почти максимум. 1 такт лишний всего если вектора под RJMP и вообще без потерь если вектора под JMP.
Недостаток один - только ассемблер.
В 12 сообщении пример с вызовом функции по указателю из прерывания. Достоинство - чистый Си. Недостаток - жуткие тормоза. Там указатель на функцию pFunc, присваивая ему разные адреса функций можно переназначать обработчик. Причины тормознутости в 10 сообщении.
Это все и есть тот финт, о котором подумываете.
kison вне форума  
Непрочитано 22.08.2010, 14:04  
Godzilla82
Почётный гражданин KAZUS.RU
 
Регистрация: 29.10.2006
Сообщений: 1,446
Сказал спасибо: 99
Сказали Спасибо 317 раз(а) в 233 сообщении(ях)
Godzilla82 на пути к лучшему
Сообщение Re: Как изменить адрес подпрограммы обработки прерывания?

Сообщение от kison Посмотреть сообщение
В 8 сообщении рабочий пример на ассемблере. Причем без оверхеда, скорость почти максимум. 1 такт лишний всего если вектора под RJMP и вообще без потерь если вектора под JMP.
Недостаток один - только ассемблер.
Ассемблер для меня пока не вариант. Думаю, и в будущем - тоже.

Сообщение от kison Посмотреть сообщение
В 12 сообщении пример с вызовом функции по указателю из прерывания. Достоинство - чистый Си. Недостаток - жуткие тормоза.
В том-то и дело, что жуткие... А если использовать вызов процедуры по ассемблерной вставке? Получится, что некоторые используемые регистры не будут помещены в стек?

В общем, чё-то это всё на Си совсем грустно выглядит...
Godzilla82 вне форума  
Непрочитано 22.08.2010, 14:24  
kison
Почётный гражданин KAZUS.RU
 
Регистрация: 13.12.2004
Сообщений: 3,172
Сказал спасибо: 11
Сказали Спасибо 692 раз(а) в 504 сообщении(ях)
kison на пути к лучшему
По умолчанию Re: Как изменить адрес подпрограммы обработки прерывания?

Сообщение от Godzilla82 Посмотреть сообщение
В общем, чё-то это всё на Си совсем грустно выглядит...
Это может и весело выглядеть. Оказывается есть вариант, но 8 тактов на входе он отъест.
Во всяком случае в WinAvr срабатывает. Можно имя вектора указывать произвольно. Не только ISR(INT1_vect), но и ISR(SuperVect) проходит. Компилятор честно создает обработчик, правда варнинг выдает что вектора для него нет, но с этим придется смириться. Так что количество обработчиков неограниченно
Смотрите 4-е сообщение, там алгоритм расписан. Единственное - после icall нужно снова запретить прерывания, и восстановить из стека R30 и R31, затем reti. А может cli и не нужно, надо обдумать это. SREG в обертке сохранять не нужно.

Последний раз редактировалось kison; 22.08.2010 в 14:32.
kison вне форума  
Сказали "Спасибо" kison
Godzilla82 (22.08.2010)
Непрочитано 22.08.2010, 17:50  
alex_312
Прохожий
 
Аватар для alex_312
 
Регистрация: 08.08.2010
Сообщений: 7
Сказал спасибо: 1
Сказали Спасибо 1 раз в 1 сообщении
alex_312 на пути к лучшему
По умолчанию Re: Как изменить адрес подпрограммы обработки прерывания?

Сообщение от kison Посмотреть сообщение
Я бы удивился, если бы Вы оказались правы. Но на самом деле:
Код:
uint8_t a;
volatile uint8_t result;

ISR(INT1_vect)
{
result  = a;
}
И листинг
Код:
11:       {
+0000002D:   921F        PUSH    R1               Push register on stack
+0000002E:   920F        PUSH    R0               Push register on stack
+0000002F:   B60F        IN      R0,0x3F          In from I/O location
+00000030:   920F        PUSH    R0               Push register on stack
+00000031:   2411        CLR     R1               Clear Register
+00000032:   938F        PUSH    R24              Push register on stack
12:       result  = a;
+00000033:   91800061    LDS     R24,0x0061       Load direct from data space
+00000035:   93800060    STS     0x0060,R24       Store direct to data space
+00000037:   918F        POP     R24              Pop register from stack
+00000038:   900F        POP     R0               Pop register from stack
+00000039:   BE0F        OUT     0x3F,R0          Out to I/O location
+0000003A:   900F        POP     R0               Pop register from stack
+0000003B:   901F        POP     R1               Pop register from stack
+0000003C:   9518        RETI                     Interrupt return
В стек идут 3 регистра и SREG. Три это почти все из 32?
А теперь то же, но через указатель. Т.е. то, что Вы предложили.
Код:
void Func(void);
typedef void (*FuncPtr_t)(void);

FuncPtr_t pFunc = Func;
uint8_t a;
volatile uint8_t result;

void Func(void)
{
result = a;
}

ISR(INT1_vect)
{
(*pFunc)();
}
И ее результат. Учтите, там только вызов функции, никакой полезной работы уже нет.
Код:
@00000032: __vector_2
21:       {
+00000032:   921F        PUSH    R1               Push register on stack
+00000033:   920F        PUSH    R0               Push register on stack
+00000034:   B60F        IN      R0,0x3F          In from I/O location
+00000035:   920F        PUSH    R0               Push register on stack
+00000036:   2411        CLR     R1               Clear Register
+00000037:   932F        PUSH    R18              Push register on stack
+00000038:   933F        PUSH    R19              Push register on stack
+00000039:   934F        PUSH    R20              Push register on stack
+0000003A:   935F        PUSH    R21              Push register on stack
+0000003B:   936F        PUSH    R22              Push register on stack
+0000003C:   937F        PUSH    R23              Push register on stack
+0000003D:   938F        PUSH    R24              Push register on stack
+0000003E:   939F        PUSH    R25              Push register on stack
+0000003F:   93AF        PUSH    R26              Push register on stack
+00000040:   93BF        PUSH    R27              Push register on stack
+00000041:   93EF        PUSH    R30              Push register on stack
+00000042:   93FF        PUSH    R31              Push register on stack
22:       (*pFunc)();
+00000043:   91E00060    LDS     R30,0x0060       Load direct from data space
+00000045:   91F00061    LDS     R31,0x0061       Load direct from data space
+00000047:   9509        ICALL                    Indirect call to (Z)
+00000048:   91FF        POP     R31              Pop register from stack
+00000049:   91EF        POP     R30              Pop register from stack
+0000004A:   91BF        POP     R27              Pop register from stack
+0000004B:   91AF        POP     R26              Pop register from stack
+0000004C:   919F        POP     R25              Pop register from stack
+0000004D:   918F        POP     R24              Pop register from stack
+0000004E:   917F        POP     R23              Pop register from stack
+0000004F:   916F        POP     R22              Pop register from stack
+00000050:   915F        POP     R21              Pop register from stack
+00000051:   914F        POP     R20              Pop register from stack
+00000052:   913F        POP     R19              Pop register from stack
+00000053:   912F        POP     R18              Pop register from stack
+00000054:   900F        POP     R0               Pop register from stack
+00000055:   BE0F        OUT     0x3F,R0          Out to I/O location
+00000056:   900F        POP     R0               Pop register from stack
+00000057:   901F        POP     R1               Pop register from stack
+00000058:   9518        RETI                     Interrupt return
В стек идут уже 14 регистров + SREG. 11 лишних, по два такта на PUSH - 22 лишних такта. А тут топикстартер из за 5 лишних расстраивается.
уважаемый кисон, вы превратно поняли смысл моего предложения, я НИГДЕ не предлагал в обработчике прерывания вызывать функцию через указатель - это раз.

А во вторых, исходники которые вы продемонстрировали ровным счетом ничего не показывают (кроме нормальной работы оптимизатора), я думаю если бы у торикстартера в прерывании выполнялось простое присваивание то не стоит городить огород.

Мое решение основано на том, что нам известен адрес вектора, и я показал как его поменять.
alex_312 вне форума  
Непрочитано 22.08.2010, 17:51  
alex_312
Прохожий
 
Аватар для alex_312
 
Регистрация: 08.08.2010
Сообщений: 7
Сказал спасибо: 1
Сказали Спасибо 1 раз в 1 сообщении
alex_312 на пути к лучшему
По умолчанию Re: Как изменить адрес подпрограммы обработки прерывания?

Сообщение от nml Посмотреть сообщение
Вектор изменить нельзя. Напишите в начале обработчика
Код:
if (mode) {сделать то-то} else {сделать нетото}
А такты экономьте за счет алгоритма и тонкостей компилятора.
И чего же такого святого в векторе прерывания?
alex_312 вне форума  
 

Закладки
Опции темы

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.

Быстрый переход

Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
[Решено] Как внедрялась АСУ chermnv Отвлекитесь, эмбеддеры! 743 14.02.2010 23:11
[Решено] Третье Послание Человечеству lelkanet Отвлекитесь, эмбеддеры! 201 06.01.2010 00:33
Вход в прерывания для PIC микроконтроллеров dimmich Микроконтроллеры, АЦП, память и т.д 4 06.12.2009 17:17
Keil C51 как изменить адрес загрузки Kabron Микроконтроллеры, АЦП, память и т.д 4 09.10.2009 23:31


Часовой пояс GMT +4, время: 23:30.


Powered by vBulletin® Version 3.8.4
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd. Перевод: zCarot