Что плохого в использовании обработчиков прерываний в качестве слушателей событий

Моя система достаточно проста, чтобы работать без ОС, я просто использую обработчики прерываний, как если бы я использовал прослушиватель событий в настольной программе. Во всем, что я читаю онлайн, люди стараются тратить как можно меньше времени на обработчики прерываний и возвращают контроль задачам. Но у меня нет ОС или реальной системы задач, и я не могу найти информацию о дизайне для целей без ОС.

В основном у меня есть один обработчик прерываний, который считывает порцию данных с USB и записывает данные в память, и один обработчик прерываний, который считывает данные, отправляет данные в GPIO и снова планирует себя в аппаратном таймере.

Что плохого в использовании прерываний, как я, и в использовании NVIC (я использую cortex-M3) для управления рабочей иерархией?

5 ответов

Прежде всего, в контексте этого вопроса давайте обратимся к ОС как к планировщику.

Теперь, в отличие от потоков, подпрограммы обработки прерываний находятся "выше" схемы планирования.

Другими словами, планировщик не имеет "контроля" над ними.

ISR входит в исполнение в результате прерывания HW, которое устанавливает ПК на другой адрес в секции кода (точнее, на вектор прерывания, где вы "делаете несколько вещей" перед вызовом ISR).

Следовательно, по существу, приоритет любого ISR выше, чем приоритет потока с наивысшим приоритетом.

Таким образом, одной из очевидных причин проводить как можно меньше времени в ISR, является "побочный эффект", который ISR оказывают на схему планирования, которую вы разрабатываете для своей системы.

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

Однако, если вложенные ISR не разрешены, прерывания должны быть отключены с момента возникновения прерывания и до завершения соответствующего ISR. В этом случае, если какое-либо прерывание происходит во время выполнения ISR, ваша программа будет эффективно игнорировать его.

Таким образом, чем дольше вы проводите внутри ISR, тем выше вероятность того, что вы "пропустите" прерывание.

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

В программировании на голое железо прерывания похожи на события, но они не отправляются в очередь.

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

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

В системах на базе ОС также рекомендуется использовать очереди, семафоры и "задачи обработки прерываний" для обработки прерываний.

Вы должны спросить себя, могут ли все события быть своевременными при любых обстоятельствах:

Например;

  • Если ваша система прерываний была запущена до завершения, будет ли обслуживание одного прерывания вызывать недопустимую задержку в обслуживании другого?
  • С другой стороны, если система прерываний основана на приоритетах и ​​имеет приоритет, будет ли обслуживание прерывания с высоким приоритетом недопустимо задерживать более низкое?

В последнем случае вы могли бы использовать Rate Monotonic Analysis, чтобы назначить приоритеты, чтобы обеспечить наибольшую отзывчивость (обработчики с самым коротким временем выполнения получают самый высокий приоритет). В первом случае ваша система может не иметь определенной степени детерминизма, и производительность будет изменяться как при загрузке события, так и при изменении кода.

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

Для более сложного планирования существует ряд простых, недорогих или бесплатных планировщиков RTOS, которые обеспечивают многозадачность, синхронизацию, IPC и службы синхронизации с очень маленькими размерами и могут работать на очень низком оборудовании. Если у вас есть аппаратный таймер и 10 Кбайт кода (иногда меньше), вы можете развернуть ОСРВ.

Я беру вашу описанную проблему в первую очередь

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

Проблема расстановки приоритетов существует, однако, в этом случае может случиться так, что если вы перегрузите сторону USB (с данными с другого конца кабеля), и обработка прерываний будет иметь более высокий приоритет, чем та, которая запускается таймером при обработке GPIO, сторона GPIO может пропускать тики (как объяснили другие, прерывания не могут стоять в очереди).

В вашем случае это о том, что можно было бы рассмотреть.

Некоторое общее руководство

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

Выше я описал общую концепцию, наблюдаемую на 8-битных процессорах и AVR 32-битных (у меня есть опыт работы с ними).

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

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

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

Если вы можете правильно спроектировать свою архитектуру с учетом необходимых асинхронных задач, обход без ОС (с точки зрения отсутствия многозадачности) может оказаться даже более хорошим решением. Чтобы разработать его должным образом, нужно больше думать, однако позже проблем с блокировкой будет гораздо меньше. Я прошел через несколько критически важных для безопасности проектов, спроектированных с помощью одной фоновой "задачи", с очень небольшим и небольшим количеством прерываний, а требования к опыту и техническому обслуживанию в отношении этих проблем (особенно отслеживание ошибок) были вполне удовлетворительными по сравнению с некоторыми другими в компании. построены на многозадачных концепциях.

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

Обычный подход, конечно, состоит в том, чтобы быстро входить и выходить, сохраняя достаточно информации, чтобы справиться с задачей на переднем плане. Задача переднего плана, конечно же, должна вращать колеса в поисках флагов событий, расстановки приоритетов и т. Д.

Конечно, вы можете сделать его более сложным, и когда наступит прерывание / событие, сохраните состояние и вернитесь к обработчику forground в режиме forground, а не в режиме прерывания.

Теперь это все общее, но специфичное для cortex-m3. Я не думаю, что есть действительно режимы, такие как ARM старшего брата. До тех пор, пока вы используете подход в реальном времени и убедитесь, что ваши обработчики являются детерминированными, и вы разрабатываете свою систему и гарантируете, что не произойдет ситуации, когда события / прерывания складываются так, что ответ не будет детерминированным, не слишком поздно или слишком долго или теряет вещи это нормально

Другие вопросы по тегам