Страница 1 из 2
События в AVRGCC C++, как реализовать ?
Добавлено: Пт дек 16, 2016 09:53:53
Pit-Bul
Хочу по прерыванию делать калбеки чтобы в теле прерывания не выполнять длительные обработки, есть ли возможность в AVRGCC C++ реализовать классические калбеки или какой другой хитрый способ.
P.S.: Delegate.h не нашел в инклудах, так что в классическом виде наверное не реализовать.
Re: События в AVRGCC C++, как реализовать ?
Добавлено: Пт дек 16, 2016 10:00:34
ARV
в моём понимании "классический callback" - это просто вызов из обработчика прерывания пользовательской функции, задаваемой в run-time... и это абсолютно ничем принципиально не отличается от "длительной обработки" в прерываниях.
ускоряет обработку прерываний очередь сообщений, но в AVR для этого маловато памяти... да и лично я не понимаю смысла этой задумки.
если я что-то понял не правильно - поправьте меня.
Re: События в AVRGCC C++, как реализовать ?
Добавлено: Пт дек 16, 2016 10:07:00
Z_h_e
Если я правильно понял что Вы хотите, то в обработчике прерывания сделать то, что надо сделать быстро и в нем же установить пользовательский флаг.
В основной рутине программы уже вызывать функции согласно установленным пользовательским флагам.
Re: События в AVRGCC C++, как реализовать ?
Добавлено: Пт дек 16, 2016 10:31:24
Pit-Bul
Z_h_e, по сути вы правы, но я не хочу полагаться на while в функции main, ибо есть ситуации когда я не могу предсказать попадет в этот while программа или нет. Я хочу в прерывании дернуть делегат, что приведет, как я думаю, к выходу из прерывания и начнет выполнять обработчик команды, или же мне просто надо отдохнуть и собрать мысли в кучу.
Re: События в AVRGCC C++, как реализовать ?
Добавлено: Пт дек 16, 2016 10:44:16
ARV
Pit-Bul писал(а):что приведет, как я думаю, к выходу из прерывания и начнет выполнять обработчик команды
т.е. по сути вы хотите разрешить обработку других прерываний, не дожидаясь завершения обработки текущего? так это делается без всяких новомодных слов:
Код: Выделить всё
ISR(MY_vect, ISR_NOBLOCK){
// тут обрабатываете прерывание, но при этом остальные прерывания так же будут вызываться, прерывая эту функцию
}
или так
Код: Выделить всё
ISR(My_vect){
static uint8_t busy = 0;
if(busy) return;
busy = 1;
sei();
// дальше делаете обработку, не мешая другим прерываниям обрабатываться
busy = 0; // это обязательно в конце обработки
}
Re: События в AVRGCC C++, как реализовать ?
Добавлено: Пт дек 16, 2016 13:04:40
ptr128
Несколько опасно.
1. Для перменной busy нужно запретить кеширование ее значения в регистре
2. Перед установкой busy в ноль, бывает смысл запретить прервания и убедиться, что нет пропущенных событий.
То есть, примерно так:
Код: Выделить всё
ISR(My_vect){
volatile static uint8_t busy = 0;
uint8_t loop_control;
if(busy) return;
busy = 1;
do {
sei();
// дальше делаете обработку, не мешая другим прерываниям обрабатываться
cli();
// Проверяем, нет ли пропущенных событий
if ( something_exists ) {
loop_control=1;
} else {
loop_control=0;
}
} while(loop_control);
// И только если таких нет, сбрасываем флаг занятости обработчика и завершаем работу обработчика
busy = 0; // это обязательно в конце обработки
}
Re: События в AVRGCC C++, как реализовать ?
Добавлено: Пт дек 16, 2016 13:20:05
Z_h_e
ptr128 писал(а):2. Перед установкой busy в ноль, бывает смысл запретить прервания и убедиться, что нет пропущенных событий.
Переменная размером в байт стирается одной командой. Ровно столько же потребуется для запрета прерывания.
Re: События в AVRGCC C++, как реализовать ?
Добавлено: Пт дек 16, 2016 13:45:58
ptr128
Но если прерывания не запрещены, то между проверкой на пропущенные события и сбросом busy флага можно пропустить событие, если между этими командами возникнет прерывание.
Re: События в AVRGCC C++, как реализовать ?
Добавлено: Пт дек 16, 2016 14:14:25
Z_h_e
Пожалуй соглашусь с запретом прерываний перед обнулением busy, чтобы случайно снова не войти в обработчик прерывания в котором находишься, стек можно переполнить если это будет очень часто это происходить. Но добавлять разрешение не надо, ибо это будет автоматом.
Но логику проверки событий не понимаю, что Вы хотели тут сделать?
Вообще мне кажется надо постараться избежать алгоритма вложенных прерываний, граблями попахивает.
Re: События в AVRGCC C++, как реализовать ?
Добавлено: Пт дек 16, 2016 14:33:54
ptr128
Z_h_e писал(а):Но добавлять разрешение не надо, ибо это будет автоматом.
Специально не проверял, но во всех примерах в даташит на ATMega328P перед выходом из прерывания выполняют команду sei. Поэтому я тоже так делаю. Я с AVR знаком то всего три месяца. Или C автоматом sei генерит при выходе из обработчика прерываний?
Z_h_e писал(а):
Но логику проверки событий не понимаю, что Вы хотели тут сделать?
Например, если это прерывание по приему байта UART, можно проверить в UCSRnA биты RXCn и DORn
Z_h_e писал(а):Вообще мне кажется надо постараться избежать алгоритма вложенных прерываний, граблями попахивает.
Собственно говоря, busy флаг и ограничивает вложенность перерываний.
Хотя тут я с Вами согласен и сам предпочитаю организацию очереди событий, разгребаемой основной программой.
Например, кольцевой буфер из N структур, состоящих из указателя на обработчик события и параметр для этого обработчика.
Re: События в AVRGCC C++, как реализовать ?
Добавлено: Пт дек 16, 2016 14:38:16
ARV
ptr128 писал(а):Или C автоматом sei генерит при выходе из обработчика прерываний?
Из обработчика прерываний Си генерит команду reti, которая и разрешает прерывания
Re: События в AVRGCC C++, как реализовать ?
Добавлено: Пт дек 16, 2016 14:56:09
Z_h_e
ptr128 писал(а):Специально не проверял, но во всех примерах в даташит на ATMega328P перед выходом из прерывания выполняют команду sei.
Терзают смутные сомнения, что есть такие примеры в ДШ обработчиков прерываний.
Добавлено after 7 minutes 36 seconds:
ptr128 писал(а):Например, если это прерывание по приему байта UART, можно проверить в UCSRnA биты RXCn и DORn
Абсолютно бесполезное занятие. Флаг события будет сброшен, если оно возникнет до Вашей проверки.
busy==1, возникает событие, программа входит в тот же обработчик котором была и тут же выходит. Флаг события утерян.
Re: События в AVRGCC C++, как реализовать ?
Добавлено: Пт дек 16, 2016 14:57:04
ARV
рассматривая сферических коней вы как-то упустили из виду, что повторный вход в обработчик прерывания до его завершения - это не просто грабли, это катастрофа в большинстве случаев. если часть событий обработчик пропускает (хоть из-за busy, хоть из-за запрета прерываний и т.п.), что он сможет хорошего сделать-то? я ввел busy скорее как инструмент отладки, по уму там надо было какой-то светодиод зажечь, дескать "что-то идет не так"... а пропускать обработку - это уже не нормально.
ну и если уж делать по-вашему, то перед сбросом busy логичнее не прерывания запрещать, а сбрасывать флаг запроса ЭТОГО прерывания, в надежде, что запросы поступают все-таки реже, чем каждые 2-4 такта

Re: События в AVRGCC C++, как реализовать ?
Добавлено: Пт дек 16, 2016 15:07:07
ptr128
Z_h_e писал(а):ptr128 писал(а):Специально не проверял, но во всех примерах в даташит на ATMega328P перед выходом из прерывания выполняют команду sei.
Терзают смутные сомнения, что есть такие примеры в ДШ обработчиков прерываний.
Все разглядел. Это делается, если выход из прерывания не по reti. Так что sei перед выходом из прерывания действительно не требуется.
Z_h_e писал(а):ptr128 писал(а):Например, если это прерывание по приему байта UART, можно проверить в UCSRnA биты RXCn и DORn
Абсолютно бесполезное занятие. Флаг события будет сброшен
Какой флаг? В честь чего будут сброшены в UCSRnA биты RXCn и DORn?
Кто их сбросит?
ARV писал(а):если часть событий обработчик пропускает (хоть из-за busy, хоть из-за запрета прерываний и т.п.), что он сможет хорошего сделать-то?
В приведеном мной примере:
ptr128 писал(а):
если это прерывание по приему байта UART, можно проверить в UCSRnA биты RXCn и DORn
обработать очередной байт из UDRn (при установленном RXCn) и предпринять какие-то действия, если было переполнение (при установленном DORn).
Чем это плохо?
Re: События в AVRGCC C++, как реализовать ?
Добавлено: Пт дек 16, 2016 15:08:46
Z_h_e
ptr128 писал(а):Это делается, если выход из прерывания не по reti.
зачем нужно перед ret ставить sei если есть специально обученная команда, где такое может понадобится?
ptr128 писал(а):В честь чего будут сброшены в UCSRnA биты RXCn и DORn?
Кто их сбросит?
Переходя на вектор прерывания, МК очищает соответствующий флаг. Как же иначе то, иначе его бы ручками надо было бы сбрасывать в прерывании, Вы же этого не делаете, что Вас тут удивило?
Re: События в AVRGCC C++, как реализовать ?
Добавлено: Пт дек 16, 2016 15:10:37
ptr128
ARV писал(а):перед сбросом busy логичнее не прерывания запрещать, а сбрасывать флаг запроса ЭТОГО прерывания
А вот так как раз стек не heap и наезжает. Спасибо, не надо.
Re: События в AVRGCC C++, как реализовать ?
Добавлено: Пт дек 16, 2016 15:11:19
Z_h_e
Кстати, если поставить sei перед ret возникает опасность зависнуть в обработчике с переполнением стека, не может быть чтобы такое в ДШ было.
Re: События в AVRGCC C++, как реализовать ?
Добавлено: Пт дек 16, 2016 15:12:58
ARV
предположим, байты в УАРТ сыплятся каждые 10 мс, а обработка одного байта занимает 11 мс... вошли в прерывание, и начинаем обработку... вроде доделали - "смотрим события"... а там уже флажок нового байта... т.е. из прерывания не выходим, обрабатываем свеженький... только закончили - а уже новенький есть... я верно понял предлагаемый вами вариант обработки событий до выхода из обработчика?
если же байты идут каждые 12 мс, то даже и без флага busy ничего не произойдет... и контроль событий вообще не нужен.
Re: События в AVRGCC C++, как реализовать ?
Добавлено: Пт дек 16, 2016 15:15:33
ARV
ptr128 писал(а):как раз стек не heap и наезжает
как это он наезжает? я же сказал: предполагается, что запросы прерывания следуют реже, чем те самые такты, что тратятся на сброс флага и выход из обработчика... если они следуют чаще - то выше показано, что это тот же каюк, но с другой стороны...
Re: События в AVRGCC C++, как реализовать ?
Добавлено: Пт дек 16, 2016 15:19:29
ptr128
Z_h_e писал(а):ptr128 писал(а):Это делается, если выход из прерывания не по reti.
зачем нужно перед ret ставить sei если есть специально обученная команда, где такое может понадобится?
Из прерывания можно выйти не только по reti (или ret). Никто не запрещает, выходить из прерывания по JMP, не забыв проинициализировать SP.
Z_h_e писал(а):
ptr128 писал(а):В честь чего будут сброшены в UCSRnA биты RXCn и DORn?
Кто их сбросит?
Переходя на вектор прерывания, МК очищает соответствующий флаг. Как же иначе то, иначе его бы ручками надо было бы сбрасывать в прерывании, Вы же этого не делаете, что Вас тут удивило?
Очень удивило. Читаю даташит и вижу совершенно обратное Вашему утверждению:
Bit 7 – RXCn: USART Receive Complete
This flag bit is set when there are unread data in the receive buffer and cleared when the receive buffer is empty
(i.e., does not contain any unread data).
Bit 3 – DORn: Data OverRun
This bit is set if a Data OverRun condition is detected. A Data OverRun occurs when the receive buffer is full
(two characters), it is a new character waiting in the Receive Shift Register, and a new start bit is detected. This
bit is valid until the receive buffer (UDRn) is read.
Добавлено after 2 minutes 13 seconds:
Z_h_e писал(а):Кстати, если поставить sei перед ret
У Вас навязчивая идея?
ptr128 писал(а):
sei перед выходом из прерывания действительно не требуется.