Вопросы настройки, программирования, прошивки микроконтроллеров и микросхем программируемой логики
Тема закрыта

AVR прерывание прерывания

Сб июл 21, 2012 23:29:20

Прочитал что прерывания выполняются в очереди приоритета, если срабатывают одновременно

Т.е. при одновременной подаче сигнала на INT0 и INT1 выполниться сначала INT0, а затем INT1

А что будет если подать сигнал на INT0 в то время, когда выполняется код в INT1
Контроллер дождётся выполнения INT1, а затем запустит INT0 или прервёт INT1 и выполнит INT0 ?

Re: AVR прерывание прерывания

Вс июл 22, 2012 00:04:13

входя в обработчик прерывания, avr микроконтроллер сбрасывает флаг разрешения прерывания поэтому INT1 выполнится до конца. Однако при подаче сигнала на INT0 флаг прерывания INTF0 установится, и, по-видимому, при завершении обработки INT1 сработает переход на обработчик INT0.

Поэтому поведение зависит от значения флага I в регистре SREG на момент прихода сигнала INT0.
Последний раз редактировалось brutal Вс июл 22, 2012 00:20:19, всего редактировалось 1 раз.

Re: AVR прерывание прерывания

Вс июл 22, 2012 00:16:52

можно насильно включить флаг глобального разрешения прерываний,а нужно ли?Так окажутся все прерывания запутанными и какой нибудь коллапс нагрянет :))

Re: AVR прерывание прерывания

Вс июл 22, 2012 06:49:47

Коллапса не будет, если объем стека позволяет :)

Re: AVR прерывание прерывания

Вс июл 22, 2012 19:01:46

А причём здесь объём стека? Колапс , если не иметь мозгов, наступит при любом объёме

Re: AVR прерывание прерывания

Вс июл 22, 2012 19:33:36

объем стека как бы при всем)))

Re: AVR прерывание прерывания

Вс июл 22, 2012 20:10:53

sx386 писал(а):Прочитал что прерывания выполняются в очереди приоритета, если срабатывают одновременно
Совершенно верно. Если установлено одновременно несколько флагов запроса прерывания и установлен флаг Global Interrupt Enable, начнет выполняться разрешенное прерывание с наивысшим приоритетом.

Приоритетность прерывания определяется адресом его вектора: чем меньше адрес, тем выше приоритет.

sx386 писал(а):Т.е. при одновременной подаче сигнала на INT0 и INT1 выполниться сначала INT0, а затем INT1
Согласно старшинству приоритетов (см. выше): чем меньше адрес вектора, тем выше приоритет. Обычно приоритет INT0 выше, чем у INT1, но моделей AVR много, поэтому за все не могу ручаться.

sx386 писал(а):А что будет если подать сигнал на INT0 в то время, когда выполняется код в INT1
Контроллер дождётся выполнения INT1, а затем запустит INT0 или прервёт INT1 и выполнит INT0 ?
При входе в прерывание флаг Global Interrupt Enable автоматически сбрасывается, запрещая дальнейшие прерывания. Если он будет явно установлен в программе обработки прерывания, то новый запрос с наивысшим приоритетом прервет текущий обработчик. Приоритет прерывания уже запущенного обработчика при этом не имеет значения: если одновременно выставлены запросы INT0 и INT1 и оба они разрешены, начнет обрабатываться INT0; если далее в обработчике INT0 будет установлен флаг Global Interrupt Enable, то текущий обработчик будет вытеснен обработчиком INT1, а по его завершении будет продолжен (если кто-то еще снова не вытеснит).

Точно так же уже запущенный обработчик INT1 будет прерван более приоритетным INT0 лишь в том случае, если сам установит Global Interrupt Enable. Приоритет важен лишь в момент выбора одного прерывания из нескольких одновременных запросов.

Есть еще одна тонкость: если в данный момент обрабатывается прерывание, а другой запрос уже ожидает своей очереди, то после завершения текущего обработчика производится возврат в прерванную программу, выполняется одна инструкция, и лишь затем запускается новый обработчик. Эту задержку следует учитывать, если время реакции на прерывание очень критично.

Re: AVR прерывание прерывания

Пн июл 23, 2012 01:06:39

BCluster писал(а):объем стека как бы при всем)))

Ну для С наверное, asm более свободен в этом отношении, там всё решает внимательность.

Re: AVR прерывание прерывания

Пн июл 23, 2012 10:28:42

Внимательность не так уж сильно зависит от языка программирования.

Помимо переполнения стека, есть еще одни грабли, на которые можно наступить, разрешая прерывания внутри обработчика. Если обработчик прерывания нереентерабелен (что вполне вероятно), то повторное прерывание, возникшее во время обработки предыдущего, приведет к непредсказуемым последствиям. Причем диагностировать такую ситуацию гораздо сложнее, чем переполнение стека.

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

Re: AVR прерывание прерывания

Пн июл 23, 2012 22:10:37

Goldsmith писал(а): Если обработчик прерывания нереентерабелен (что вполне вероятно), то повторное прерывание, возникшее во время обработки предыдущего, приведет к непредсказуемым последствиям.
Можете рассказать об этом подробнее или кинуть ссылочку, где об этом можно почитать?

Re: AVR прерывание прерывания

Пн июл 23, 2012 23:16:08

где об этом можно почитать?

+1
Насколько я помню , реентерабельность относится к одному и тому же куску кода , которым одновременно могут воспользоваться несколько пользователей не мешая друг другу , при этом на код накладывается куча условий. И как это понятие применимо к вложенным прерываниям?
Ну а если уж это невыполнимо, то хотя бы сбрасывать флаг разрешения данного прерывания в начале его обработки.
Что обычно делается процессором автоматически при входе в обработчик прерывания , если это прерывание разрешено или всё таки нет?

Re: AVR прерывание прерывания

Пн июл 23, 2012 23:38:32

Хотя вложенных прерываний стоит избегать, бывают случаи, когда без них логика становится ещё запутанней, и больше шансов нарваться на грабли. Тут важно понимать одно: в какой момент какое прерывание может наступить. Редко они используются все и сразу.

Например: есть прерывание с относительно длительным обработчиком (и без него никак, либо очень сложно). Есть второе прерывание, которое необходимо обработать моментально, и выполняется оно быстро, при том не модифицирует данные, с которым работает первое. И если больше никаких прерываний не используется, то вполне вариант принудительно разрешить прерывания внутри первого, при этом мы практически ничего не теряем, избавляемся от громоздкости и неповоротливости кода.
Но если есть ещё хоть одно (третье) прерывание, способное повлиять на работу первого, этот вариант отпадает.

Re: AVR прерывание прерывания

Пн июл 23, 2012 23:43:39

DrHlus писал(а):
Goldsmith писал(а):Можете рассказать об этом подробнее или кинуть ссылочку, где об этом можно почитать?
Если хотите подробно, то можно почитать, например, здесь:

Arnold S. Berger. Embedded Systems Design: An Introduction to Processes, Tools, and Techniques, раздел "Nested Interrupts and Reentrancy".
Bruce Powel Douglass. Real-Time Design Patterns: Robust Scalable Architecture for Real-Time Systems, раздел 7.2 "Critical Section Pattern".
Jean J. Labrosse. Embedded Systems Building Blocks, Second Edition. Complete and Ready-to-Use Modules in C, раздел 2.11 "Reentrancy".

Конечно, это не единственные источники, просто первое, что попалось под руку из книг о встроенных системах. Или можно почитать в учебниках по архитектуре операционных систем, там практически те же проблемы с реентерабельностью и во многом схожие методы решения.

Или попробую коротко своими словами. Конечно, пример немного притянут за уши, но в целом ситуацию попробую обрисовать.

Предположим, у нас есть таймер, генерирующий прерывания с частотой килогерц. Каждую тысячную миллисекунду счетчик миллисекунд обнуляется и увеличивается счетчик секунд:

Код:
void обработчик_прерывания_1кГц(void)
{
  счетчик_миллисекунд++;
  if (счетчик_миллисекунд >= 1000)
  { // прошла секунда
    счетчик_миллисекунд = 0;
    счетчик_секунд++;
  }
  // еще какие-то действия
}

Предположим такую последовательность событий:
    счетчик_миллисекунд == 999;

    вошли в обработчик прерывания от таймера;

    инкрементировали счетчик_миллисекунд == 1000;

    условие (счетчик_миллисекунд >= 1000) выполнено, вошли внутрь if (строка, помеченная комментарием // прошла секунда);

    получили какое-то другое прерывание и вошли в его обработчик, обработчик таймера отложен;

    тем временем прошла миллисекунда, повторно вошли в обработчик прерывания от таймера, первый экземпляр обработчика все еще отложен;

    инкрементировали счетчик_миллисекунд == 1001;

    условие (счетчик_миллисекунд >= 1000) выполнено, вошли внутрь if;

    обнулили счетчик_миллисекунд, инкрементировали счетчик_секунд, выполнили остаток кода;

    вышли из вложенного (второго) прерывания от таймера;

    вернулись в отложенный обработчик на помеченную строку (внутрь if);

    снова обнулили счетчик_миллисекунд, инкрементировали счетчик_секунд, выполнили остаток кода;

    вернулись из первого прерывания от таймера.


Итак, имеем все "прелести" вложеннного вызова нереентерабельного обработчика: потеряли миллисекунду (дважды обнулен счетчик), зато получили лишнюю секунду (дважды инкрементировали).

Немного сумбурно и громоздко получилось, но, надеюсь, идея все же понятна.
Последний раз редактировалось Goldsmith Вт июл 24, 2012 00:51:02, всего редактировалось 1 раз.

Re: AVR прерывание прерывания

Вт июл 24, 2012 00:21:34

ILYAUL писал(а):Насколько я помню , реентерабельность относится к одному и тому же куску кода , которым одновременно могут воспользоваться несколько пользователей не мешая друг другу , при этом на код накладывается куча условий. И как это понятие применимо к вложенным прерываниям?
Наличие нескольких пользователей вовсе не обязательно, иначе получилось бы, что весь код в однопользовательской системе автоматически становится реентерабельным, а это отнюдь не так. Реентерабельный код может выполняться параллельно несколькими потоками в процессе одного пользователя и даже в одном потоке, если это рекурсивный вызов.

Вот вполне корректное определение реентерабельности:
reentrant adj. Said of software that can be executed multiple times simultaneously. A reentrant function can be safely called recursively or from multiple tasks. The key to making code reentrant is to ensure mutual exclusion whenever accessing global variables or shared registers.
Jack Ganssle, Michael Barr. Embedded Systems Dictionary.

Вложенное прерывание именно к этому и приводит - поток выполнения инструкций входит в область кода, в которой уже находится другой поток (отложенный, если в системе единственное вычислительное ядро). Вы совершенно правильно заметили, что на этот код должны накладываться определенные условия, и если они не выполнены, программа ведет себя некорректно (пример я привел в предыдущем посте).

Что обычно делается процессором автоматически при входе в обработчик прерывания , если это прерывание разрешено или всё таки нет?
Обычно в известных мне архитектурах (хотя, конечно, известны мне далеко не все) при входе в обработчик прерывания автоматически сбрасывается флаг запроса этого прерывания. Бит (он же флаг) разрешения прерывания остается неизменным, его следует устанавливать/сбрасывать явно в коде.

Re: AVR прерывание прерывания

Вт июл 24, 2012 00:44:16

ploop писал(а):Например: есть прерывание с относительно длительным обработчиком (и без него никак, либо очень сложно).
Довольно часто (из собственной практики я бы даже сказал: "всегда", но жизнь зачастую оказывается разнообразнее наших представлений о ней) удается все же сократить обработчик прерывания до разумно-минимальных размеров, оставив в нем лишь действительно критичные по времени операции (например, забрать из регистров ввода данные, пока они не затерлись следующей порцией). Затем обработчик помещает событие в очередь и завершает работу. Обработкой данных из очереди займется уже другая задача в соответствии с назначенным ей приоритетом, которая никак не мешает прерываниям.

Такой подход и пиковые всплески активности поможет пережить (буфер разумных размеров сгладит пик), и проблемы с битвой приоритетов позволит избежать, если нет требований крайне жесткого реального времени. Еще один бонус - небольшие аппаратно-зависимые функции обработки проще будет портировать на другую платформу при необходимости, если, конечно, они не на ассемблере писаны; обработчик очереди событий, выполняющий основную часть работы, не будет жестко связан с оборудованием.

Re: AVR прерывание прерывания

Вт июл 24, 2012 06:32:47

Да это понятно всё.
Я хотел сказать то, что вы в своём примере очень хорошо подчеркнули фразой "тем временем прошла миллисекунда", то есть второй обработчик может (т.е. такая ситуация в принципе возможна) перекрыть по времени первый.
Тут да, применять не в коем случае нельзя.

Re: AVR прерывание прерывания

Вт июл 24, 2012 08:12:19

ploop писал(а):Я хотел сказать то, что вы в своём примере очень хорошо подчеркнули фразой "тем временем прошла миллисекунда", то есть второй обработчик может (т.е. такая ситуация в принципе возможна) перекрыть по времени первый.
Тут да, применять не в коем случае нельзя.
Точно. К тому же пример-то специально упрощенный, чтобы читателям проще логику отследить. А если к тому же обработчиков не два, а поболее, да к тому же глобально прерывания постоянно разрешены, и любой обработчик в любой момент перебивается другим экземпляром, в том числе самим собой по вложенной обработке, то получим неиссякающий источник непериодических глюков, причем очень трудно воспроизводимых в системе отладки (а то, что возможно в принципе, все равно рано или поздно произойдет).

Собственно, вот что имел в виду под фразой, которая и вызвала вопросы:
Goldsmith писал(а):Помимо переполнения стека, есть еще одни грабли, на которые можно наступить, разрешая прерывания внутри обработчика. Если обработчик прерывания нереентерабелен (что вполне вероятно), то повторное прерывание, возникшее во время обработки предыдущего, приведет к непредсказуемым последствиям. Причем диагностировать такую ситуацию гораздо сложнее, чем переполнение стека.

Re: AVR прерывание прерывания

Вт июл 24, 2012 08:38:46

В последнем проекте была ситуация:
1. Основной цикл. Куча математики, работает очень долго: где-то секунду на одну итерацию. Там же вывод на индикатор, что даёт естественную задержку его обновления около секунды.
2. Таймер, и его прерывание каждые 10мс (100 раз в секунду). Там тоже объёмный код, но работает фиксированное время, около 5-6мс (сам на себя наложиться не может.
3. Внешнее прерывание INTx, внутри которого несколько операций, т.е. считанные микросекунды.

Всего два прерывания. Внутри прерывания таймера разрешил вложенные, и убил двух зайцев: таймер корректно работает, не усложняя основной цикл, и отработка внешнего прерывания происходит всегда вовремя.

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

Так что не так страшен чёрт, если подходить с умом.

Re: AVR прерывание прерывания

Вт июл 24, 2012 09:22:15

ploop писал(а):Так что не так страшен чёрт, если подходить с умом.
Тут ключевой момент:
ploop писал(а):2. Таймер ... сам на себя наложиться не может.
С таймером проще: вы точно знаете период прерываний, и если так же точно знаете длительность его обработки (в обработчике нет циклов и непредсказуемых условных операторов), то можете дать гарантию, что повторного вхождения в обработчик не будет. Заведомо кратковременный другой обработчик также не создает проблем (если только по INTx гарантированно исключен шквал запросов). В данном частном случае проблема реентерабельности не возникнет, конечно.

Если же событие асинхронное и возникает в непредсказуемые моменты, черт станет гораздо страшнее. Единственный способ не попасть в ловушку - запрещать повторное прерывание от этого же источника при входе в обработчик и разрешать (при необходимости) непосредственно перед выходом. Глобально прерывания запрещать не обязательно. Только в этом случае нереентерабельные обработчики не создадут проблем, о которых DrHlus спрашивал в начале темы.

Re: AVR прерывание прерывания

Вт июл 24, 2012 11:40:49

...Затем обработчик помещает событие в очередь и завершает работу.

Ну вообще-то это стандартный подход к написанию обработчиков прерываний.
...проще будет портировать на другую платформу при необходимости, если, конечно, они не на ассемблере писаны;

Это Вы давненько с asm не работали, портировать его с платформы на платформу не так уж и сложно. Главное правильно сразу написать макросы.
Тема закрыта