Коллизии прерываний

Тема в разделе "Микроконтроллеры AVR", создана пользователем ostrov, 7 апр 2016.

  1. ostrov

    ostrov Гуру

    Простой вопрос, ответ на который найти сходу не получилось. Допустим, запускаю прерывание по таймеру. Потом еще одно и еще одно, в общем несколько, на сколько хватит таймеров. Все с разным периодом. Рано или поздно произойдет ситуации когда в один квант времени должны будут сработать два прерывания. Или сработать второе пока выполняется первое. Или сразу несколько в один момент. Что в этом случае произойдет?

    Сработает только одно, остальные проигнорируются?
    Они выстроятся в очередь и сработают как только так сразу?
    МК встанет и задымится?

    К чему нужно быть готовым и стоит ли заморачиваться разведением событий по времени?
     
  2. Megakoteyka

    Megakoteyka Оракул Модератор

  3. ostrov

    ostrov Гуру

    Из форума я понял, что прерывания по таймерам имеют высший приоритет и, при желании можно разрешать прерывание из прерывания. Лишь бы они не использовали одинаковые ресурсы при этом. Что же, выход, конечно, но только при крайней необходимости.
     
  4. Unixon

    Unixon Оракул Модератор

    Понятия приоритета прерывания как и вложенных прерываний в AVR не существует, оно руками создается искусственно.
     
  5. Unixon

    Unixon Оракул Модератор

    Вообще интересно, как отработает AVR, если ситуацию создать искусственно. Объявить обработчики INT0,1 и одновременно триггернуть обе ноги, просто связав из вместе. По идее сначала должны установиться оба флага прерывания, одно из них вызваться (какое?), а вот как при выходе из обработчика будут сниматься флаги... и что будет, если флаги прерываний оставить не снятыми...
     
  6. AlexU

    AlexU Гуру

    Вообще в офф.доке всё чётко и ясно написано -- прерывания обрабатываются в порядке приоритета. Приоритет каждого прерывания можно узнать из таблицы в соответствующем разделе. Для ATmega328P самым приоритетным является прерывание RESET, далее INT0 и т.д.. Самый низкий приоритет у прерывния SPM READY.
    В соответствии с приоритетом сначала вызовется обработчик прерывания INT0, а потом INT1.
    Флаги снимаются перед вызовом обработчика прерывания. Оставить флаги не снятыми не получиться -- их можно только заново установить. Но опять же после выхода из прерывания контроллер обязательно выполняет хотя бы одну инструкцию "основного кода", а потом снова вызывает обработчики прерываний, если были установлены соответствующие им флаги.

    Это некорректное утверждение -- т.к. вложенные прерывания существуют. Вот только в отличие от других архитектур (тех же x86 и AMD64) при вызове обработчика прерывания происходит глобальное маскирование прерываний. Поэтому нужно явно указывать на возможность возникновения вложенных прерываний путём размаскирования. В x86, наоборот, в обработчиках прерываний нужно явно глобально маскировать прерывания, что бы запретить вложенные прерывания.
     
  7. Unixon

    Unixon Оракул Модератор

    Ткните пальцем где именно. По диагонали читал - не увидел.

    Вот именно неосуществимость вложенных прерываний без явных действий я и имел ввиду под их несуществованием. Может быть, так говорить не совсем корректно.
     
  8. AlexU

    AlexU Гуру

    Странно слышать такое от опытного специалиста, ну да ладно мы все "не без греха".
    Документация на ATmega328P.
    Раздел "7.7 Reset and Interrupt Handling":
     
  9. Unixon

    Unixon Оракул Модератор

    Ничего странного, даташиты в голове не держу. Раздел 7.7 второпях пропустил, все накручивал мимо круги по описаниям регистров в разделах 12 и 13, которые собственно и относятся к прерываниям, там искал как "pending interrupts" реализованы. Вот, что самое главное из 12 и 13 вынесли куда-то там в 7.x, это еще догадаться нужно.
     
  10. ostrov

    ostrov Гуру

    И все же. Одновременно вызываются два прерывания по таймеру. Сработают оба, сработает одно (которое?), не сработает никто?
     
  11. Unixon

    Unixon Оракул Модератор

    Оба. Если ничего не делать, то по очереди, в порядке убывания приоритета (см. таблицу векторов). Если что-то делать, то можно вложенные организовать в удобном себе порядке.
     
    ostrov нравится это.
  12. Onkel

    Onkel Гуру

    теоретически да, но возможно переполнение стека и прочие непрогнозируемые гадости. Так что функции обработки прерывания хорошо делать по принципу "ударил - убежал", и без вложения.
     
  13. Airbus

    Airbus Радиохулиган Модератор

    Таблица векторов прерывания микроконтроллера ATmega328 выглядит следующим образом:

    • [*]0x0000 RESET - сброс
      [*]0x0002 INT0 - внешнее прерывание 0
      [*]0x0004 INT1 - внешнее прерывание 0
      [*]0x0006 PCINT0 - прерывание по изменению состояния нулевой группы выводов
      [*]0x0008 PCINT1 - прерывание по изменению состояния первой группы выводов
      [*]0x000A PCINT2 - прерывание по изменению состояния второй группы выводов
      [*]0x000C WDT - прерывание от сторожевого таймера
      [*]0x000E TIMER2 COMPA - прерывание от таймера/счетчика T2 при совпадении с A
      [*]0x0010 TIMER2 COMPB - прерывание от таймера/счетчика T2 при совпадении с B
      [*]0x0012 TIMER2 OVF - прерывание по переполнению таймера/счетчика T2
      [*]0x0014 TIMER1 CAPT - прерывание от таймера/счетчика T1 по записи
      [*]0x0016 TIMER1 COMPA - прерывание от таймера/счетчика T1 при совпадении с A
      [*]0x0018 TIMER1 COMPB - прерывание от таймера/счетчика T2 при совпадении с B
      [*]0x001A TIMER1 OVF - прерывание по переполнению таймера/счетчика T1
      [*]0x001C TIMER0 COMPA - прерывание от таймера/счетчика T0 при совпадении с A
      [*]0x001E TIMER0 COMPB - прерывание от таймера/счетчика T0 при совпадении с B
      [*]0x0020 TIMER0 OVF - прерывание по переполнению таймера/счетчика T1
      [*]0x0022 SPI, STC - прерывание по окончанию передачи модуля SPI
      [*]0x0024 USART, RX - прерыванию по окончанию приема модуля USART
      [*]0x0026 USART, UDRE - прерывание по опустошению регистра данных модуля USART
      [*]0x0028 USART, TX - прерывание по окончанию приема модуля USART
      [*]0x002A ADC - прерывание по завершению преобразования АЦП
      [*]0x002C EE READY - прерывание по готовности памяти EEPROM
      [*]0x002E ANALOG COMP - прерывание от аналогового компаратора
      [*]0x0030 TWI - прерывание от модуля I2C (TWI)
      [*]0x0032 SPM READY - прерывание по готовности flash памяти
     
  14. Unixon

    Unixon Оракул Модератор

    Да, именно поэтому и "можно, но не нужно".

    p.s. Не глядя в даташит я поначалу думал, что отработает только одно прерывание - первое, которое успело произойти, а остальные, произошедшие до возврата из обработчика, просто проигнорируются, но такой странный дизайн как-то не укладывался в голове. Но в AVR с этим все в порядке, есть и шифратор приоритета и выборка вектора и возможность руками поправить флаги.
     
    Последнее редактирование: 8 апр 2016
  15. ostrov

    ostrov Гуру

    В итоге, если ничего руками не править и не разрешать прерывания из прерываний принудительно, будут ли они выполняться автоматически по очереди?
     
  16. Unixon

    Unixon Оракул Модератор

    Да, похоже, что именно так и будет. Можно даже проверить... и очень просто.
     
  17. AlexU

    AlexU Гуру

    Будут, вот только очередь с некоторыми особенностями. Когда происходит событие, которое должно обработаться обработчиком прерывания (например, пин изменил своё состояние или пришёл символ по USART), устанавливается соответствующий флаг. Этот флаг говорит о том, что, как только появиться возможность, нужно запустить соответствующий обработчик прерывания. Если до запуска обработчика прерывания произойдёт ещё одно или несколько таких же событий, то флаг прерывания как был поднят, так и останется поднятым. И не смотря на то, что одно и то же событие произошло несколько раз, обработчик прерывания будет вызван только один раз. Т.е., если по каким-то причинам прерывания будут запрещены, можно пропустить одно или несколько событий, скажем так, одного и того же типа.
    Если же события были разными (для каждого есть свой флаг), то, когда появится возможность вызвать обработчик прерывания, вызовется обработчик для прерывания с наиболее высоким приоритетом. После выхода из обработчика прерывания, будет выполнена одна инструкция "основной программы". Затем, если можно будет обрабатывать прерывания, будет вызван следующий по приоритету обработчик прерывания, потом опять одна инструкция "программы" и т.д., пока не обработаются все поднятые флаги прерываний.
     
  18. ostrov

    ostrov Гуру

    Про флаги интересно. В данный момент интересуют прерывания по таймеру, к меня их несколько, не будут ли толкаться жопами мешая друг другу? Делаю по возможности минимально, но все же.

    Например как?
     
  19. Unixon

    Unixon Оракул Модератор

    В обработчиках дергаете ноги, смотрите осциллографом.
     
  20. Onkel

    Onkel Гуру

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