Прерываемые приложения
Процесс обработки прерываний
Когда сигнал прерывания достигает центрального процессора, запускается процесс подготовки к обработке прерывания:
- Процессор завершает выполнение текущей инструкции. Некоторые процессоры делают это для большинства инструкций, за исключением специальных длинных инструкций, выполнение которых прерывается.
- Состояние процессора записывается в стек. Это состояние обычно состоит из содержимого регистров процессора, включая программный счетчик (PC), который хранит адрес следующей выполняемой инструкции. RISC-V ничего не заносит в стек. Вместо этого в специальный регистр, называемый Machine Exception PC (MPEC), копируется только программный счетчик.
- Некоторые архитектуры переходят в специальный режим выполнения обработчика. Этот режим имеет иные привилегии, чем в обычный пользовательский режим. Наличие нескольких режимов выполнения полезно для реализации операционной системы. RISC-V выполняет обычные потоки в пользовательском режиме и переключается в машинный режим для обработки прерываний.
- Источник прерывания используется для поиска соответствующего обработчика прерывания. Процессор получает информацию об устройстве ввода-вывода, которое сгенерировало прерывание, и ищет его конкретный обработчик в таблице поиска, называемой вектором прерываний. Эта таблица содержит ряд адресов, и программист отвечает за заполнение этой таблицы адресами обработчиков прерываний, которые были написаны для всех поддерживаемых прерываний. RISC-V может работать как с одним обработчиком прерываний, так и с вектором.
- Выполняется выбранный обработчик прерывания Код, написанный программистом для обработчика прерываний, будет исполняться до тех пор, пока он не завершит выполнение. Вместо завершения работы, обработчик прерывания инициирует процесс выхода из прерывания
- Состояние процессора извлекается из стека. Благодаря этому действию все регистры восстанавливают состояние, в котором они находились, когда выполнение было прервано. Опять же, это включает в себя счетчик команд (PC), так что следующая инструкция для выполнения известна. И снова, единственное, что извлекает RISC-V - PC из регистра MEPC.
- Восстанавливается исходный режим выполнения. В архитектурах, реализующих более одного режима выполнения, режим обработчика является эксклюзивным для процедур обслуживания прерываний, и режим выполнения прерванного кода восстанавливается. В RISC-V обычно восстанавливается режим пользователя.
- Выполнение возобновляется с того места, где оно было прервано. В этот момент могут обрабатываться другие прерывания. Однако некоторые процессоры поддерживают вложенные прерывания - то есть один обработчик прерывания может быть прерван другим устройством ввода/вывода с более высоким приоритетом.
Несколько слов об обработчиках прерываний
Мотивация использования подхода, основанного на прерываниях, заключается в том, чтобы избежать остановки выполнения кода с помощью блокирующих функций или блокирующих циклов, поэтому следует, что обработчики прерываний должны быть краткими.
Основное приложение было прервано (подумайте об этом, как о том, чтобы заставить кого-то выйти с совещания), поэтому ваш код должен перейти прямо к делу. В обработчике прерывания есть место только для срочного кода. Все остальное должно быть отложено до главного цикла. Поэтому общее эмпирическое правило - избегать длинных вычислений в обработчиках прерываний (ISR).
Кроме того, нет ничего хорошего в том, чтобы пройти через все трудности разработки приложения, управляемого прерываниями только для того, чтобы написать блокирующие подпрограммы обслуживания прерываний. Даже случайно. Поэтому, помимо отказа от использования блокирующего кода, еще одним общим правилом при написании обработчиков прерываний является отказ от использования циклов. Всегда пишите код обработчика прерываний без циклов, если это возможно.
Для получения дополнительных советов по написанию обработчиков прерываний, вы можете прочитать статью в блоге Embedded Artistry.
Использование прерываний с микроконтроллером FE310
Before diving into the interrupt usage process for the FE3190, here is an attempt to not scare you away by looking at the big picture.
Прежде чем погрузиться в процесс использования прерываний для FE3190, здесь мы попытаемся не отпугнуть вас, взглянув на общую картину.
Оказывается, FE310 использует несколько уровней одного и того же процесса, который мы только что видели, потому что у него есть несколько уровней контроллеров прерываний. Это происходит потому, что RISC-V описывает использование прерываний только в своей спецификации режимов привилегий. За пределами этой спецификации производители должны реализовать свои контроллеры прерываний и свои модули ввода/вывода, которые имеют некоторые шаги конфигурации для прерываний.
Микроконтроллер FE310 использует 3 уровня сигналов разрешения/отсрочки прерывания, и весь процесс может быть запутанным из-за большого количества регистров и лишних шагов. Чтобы упростить ситуацию, на следующей схеме приведены регистры, участвующие в интересующем нас процессе:
Микроконтроллер FE310 - Уровень 1: Ядро процессора
Ядро процессора обслуживает только 3 возможных источника прерываний: MEI, MSI и MTI. Нас интересует MEI, машинное внешнее прерывание. Вот регистры процессора, показанные на схеме (они не привязаны к памяти):
- mstatus.mie (Machine Interrupt-Enable, Включение машинных прерваний) Это глобальный бит разрешения прерываний или инвертированная версия классической маски прерываний. Установка этого бита разрешает все прерывания, а сброс - запрещает все прерывания.
- mie.meie (Machine External Interrupt-Enable, Включение машинных внешних прерываний) Это бит разрешения прерывания для прерывания MEI. Помните: существует 3 источника прерываний, поэтому каждый из них имеет бит разрешения прерывания.
- mip.meip (Machine External Interrupt Pending, Ожидание внешнего машинного прерывания)Это бит ожидания прерывания (флага прерывания) для прерывания MEI.
- mtvec (Machine Trap Vector, Вектор машинного прерывания) Это вектор прерывания. Он может работать как вектор для MEI, MSI, MTI и некоторых исключений или хранить адрес единственного обработчика прерываний для всех источников.
Микроконтроллер FE310 - Уровень 2: Контроллер прерываний платформенного уровня (ПЛИС)
Этот контроллер отвечает за так называемые глобальные прерывания, которые поступают от устройств ввода/вывода (GPIO, PWM, SPI, I2C и т.д.). Вот интересующие нас регистры с привязкой к памяти:
- enable1 и enable2 (Interrupt-Enable, доступность прерывания) Эти 32-битные регистры содержат биты разрешения прерывания для всех поддерживаемых запросов ввода/вывода. Эти биты организованы в 64-битное слово в соответствии с отображением источников ПЛИС, которое присваивает идентификатор каждому поддерживаемому источнику прерывания. Младшая половина этого 64-битного слова - это enable1, а старшая половина - enable2.
- pending1 и pending2 (Interrupt Pending, флаги прерывания) Эти 32-битные регистры содержат биты ожидания прерывания (или флаги прерывания) для всех источников прерывания ввода/вывода, что соответствует порядку следования битов в регистрах разрешения прерывания.
- priority1 - priority52 (Priority Registers, Регистры приоритетов) Приоритеты не устанавливаются по умолчанию, поэтому хорошей практикой является установление желаемого приоритета для всех прерываний, которые вы собираетесь использовать. Эти регистры предназначены для каждого из 52 источников прерываний ПЛИС. Приоритет 0 означает "не прерывать", а приоритет 7 - высший приоритет. Эти регистры расположены по адресам 0x0C000004 - 0x0C0000D0.
- claim (Interrupt Claim/Complete Register, Регистр подтверждения прерывания) Этот регистр используется для утверждения прерывания. То есть, для утверждения завершения прерывания при запуске обработчика прерывания. Чтение этого регистра возвращает идентификатор ожидающего прерывания с наивысшим приоритетом.
Микроконтроллер FE310 - Уровень 3: Устройство ввода/вывода
Различные устройства ввода/вывода могут по-разному реализовывать свои регистры прерываний, но обычно они имеют следующие регистры, привязанные к памяти:
- X_ie (Interrupt-Enable, Разрешение прерывания) В зависимости от устройства ввода/вывода, оно может реализовывать некоторое количество битов разрешения прерывания. Устройство GPIO0 имеет регистры разрешения прерывания для нарастающего фронта, спадающего фронта, высокого и низкого состояния всех своих 32 выводов. Устройства ШИМ не имеют регистров разрешения прерывания.
- X_ip (Interrupt Pending, Ожидание прерывания) В зависимости от устройства ввода/вывода, оно может реализовать некоторое количество битов ожидания прерывания. Устройство GPIO0 имеет регистры ожидания прерывания для прерываний, упомянутых выше. Устройства ШИМ имеют 4 бита ожидания прерывания (по одному на канал) в уже известном нам регистре pwmcfg.