Программирование DSP VDK: обработчики прерываний (ISR) Fri, October 11 2024  

Поделиться

Нашли опечатку?

Пожалуйста, сообщите об этом - просто выделите ошибочное слово или фразу и нажмите Shift Enter.

VDK: обработчики прерываний (ISR) Печать
Добавил(а) microsin   

Начиная с версии VisualDSP++ 4.0, обработчики прерываний VDK (Interrupt Service Routines, ISR) можно писать на ассемблере, C или C++. Все предыдущие релизы VDK ограничивали пользователей языком ассемблера для написания ISR. Хотя поддержка новых языков добавила гибкости, все же следует иметь в виду, что при написании ISR на языках C/C++ нужно учитывать некоторые соображения, касающиеся производительности, и есть определенные ограничения, которые описаны далее.

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

Архитектура прерываний VDK не поддерживает стратегию signal.h для обработки прерываний.

[Разрешение и запрет прерываний]

Каждая из архитектур процессора имеет незначительно отличающийся от других архитектур механизм для маскирования (запрета) и демаскирования (разрешения) прерываний. Некоторые архитектуры требуют, чтобы состояние маски прерываний было сохранено в памяти перед тем, как может быть запущен кода обработки прерывания или код обработки исключения, и перед возвратом маска должна быть вручную восстановлена. Поскольку kernel инсталлирует прерывания (а также на некоторых архитектурах инсталлирует обработчики исключений exception handler), прямая запись в регистр маскирования прерываний (interrupt mask register) может привести к непредсказуемым результатам. Таким образом, VDK предоставляет простое и платформонезависимое API, чтобы упростить доступ к маске прерываний.

Вызов GetInterruptMask() возвратит действительное значение маски прерываний, даже если она была временно сохранена ядром в приватное хранилище. Подобным образом работают функции SetInterruptMaskBits() и ClearInterruptMaskBits(), которые устанавливают и очищают маску прерываний устойчивым и безопасным способом. Будут разрешены уровни прерываний (interrupt levels) с их соответствующими наборами бит в маске прерываний, когда прерывания глобально разрешены. Для подробной информации о маске прерываний см. аппаратное руководство (даташит Hardware Reference manual) на Ваш используемый процессор.

VDK также представляет стандартный путь для глобального включения и выключения прерываний. Наподобие необслуживаемых регионов кода (unscheduled regions, в которых работа планировщика запрещена), VDK поддерживает критические регионы (critical regions), где прерывания запрещены. Вызов PushCriticalRegion() запрещает прерывания, и вызов PopCriticalRegion() заново разрешает прерывания. Эти вызовы API реализуют интерфейс в виде стека, как это описано в разделе "Protected Regions". Пользователям не рекомендуется выключать прерывания для больших кусков кода, поскольку это увеличивает латентность в обработке прерываний.

[Архитектура прерываний]

Обработчики прерываний VDK (Interrupt Service Routine, ISR) можно написать полностью на ассемблере или на C/C++. Ниже объясняются достоинства и недостатки каждого из используемых языков.

Обработчики прерываний на ассемблере. ISR, написанные на ассемблере, будут самым эффективным способом обслуживания прерываний. Устраняется лишняя нагрузка для сохранения и восстановления состояния процессора (processor state), а также устраняется необходимость настройки среды выполнения кода языка C (C run-time environment). ISR на ассемблере должны сохранять и восстанавливать только те регистры, которые были использованы в коде ISR. Облегченная природа ISR на ассемблере также благоприятна в случае использования вложенных прерываний (interrupt nesting), и когда требуется максимально уменьшить латентность обработки прерываний. По умолчанию VDK разрешает вложенность прерываний для тех процессоров, которые это поддерживают.

Обработчики прерываний на C/C++. ISR, написанные на языках C/C++ могут значительно упростить кодирование подпрограмм обработки, но здесь наблюдаются лишние задержки, связанные с реализацией кода ISR на языке высокого уровня. Среда выполнения языка (C/C++ run-time environment) должна быть настроена на входе в ISR, за что приходится расплачиваться задержкой до выполнения реального кода обработки ISR. Также на входе в ISR должно быть произведено необходимое сохранение состояния процессора (processor state), которое должно быть затем восстановлено на выходе из ISR. Если C/C++ ISR вызывает функции, которые не представлены в том же самом модуле кода, то тогда будет сохранено (и затем восстановлено) полное состояние процессора, если не использовалась прагма regs_clobbered для указания регистров, модифицируемых функцией (подробности см. в руководстве пользователя по компилятору и библиотекам для Вашего процессора, C/C++ Compiler and Library Manual). Дополнительное внимание должно быть уделено тому, что библиотеки реального времени выполнения кода (run-time library) в основном предоставляют небезопасный для обработки прерываний код (not interrupt-safe), который не может использоваться для ISR (подробности также см. в руководстве пользователя по компилятору и библиотекам для Вашего процессора, C/C++ Compiler and Library Manual). Таким образом, есть определенные ограничения на то, что может быть выполнено в ISR на языках C/C++.

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

По умолчанию VDK резервирует как минимум 2 прерывания: прерывание таймера (timer interrupt, используется планировщиком, так генерируются тики VDK) и программное прерывание самого низкого приоритета (software interrupt). Обсуждение прерывания таймера см. в разделе "Timer ISR". Информацию по низкоуровневому программному прерыванию см. в разделе "Reschedule ISR". Информацию по любым дополнительным резервируемым VDK прерываниям для отдельных процессоров см. Приложение A "Processor-Specific Notes".

Глобальные данные. Часто ISR требуют обмена данными в обоих направлениях с доменом потоков (thread domain), не основанном на семафорах (semaphore), битах событий (event bits) и активациях драйвера устройства (device driver activations). ISR может использовать глобальные переменные для получения данных домена потоков, но Вы должны помнить, что требуется обрамить критическим регионом любой доступ к этим глобальным данным (как на чтение, так и на модификацию), и декларировать переменную этих данных как volatile (языки C/C++). Для примера рассмотрим следующее:

/* MY_ISR.asm */
.EXTERN _my_global_integer;
< REG > = data;
DM(_my_global_integer) = < REG >;
/* завершение ISR, разрешение прерываний и RTI. */

и в домене потоков:

/* My_C_Thread.c */
volatile int my_global_integer;
/* Доступ к глобальным данным ISR */
VDK_PushCriticalRegion();
if (my_global_integer == 2)
   my_global_integer = 3;
VDK_PopCriticalRegion();

Обмен данными с доменом потоков. VDK предоставляет набор макросов на ассемблере и API, которые могут быть вызваны из ISR на C/C++ и использованы для обмена системным состоянием с доменов потоков. Подробнее см. раздел "Assembly Macros and C/C++ ISR APIs".

Ассемблерные макросы вызываются из домена прерываний; поэтому они не делают предположений о состоянии процессора, доступных регистрах или параметрах. Другими словами, макросы ассемблера можно вызывать без рассмотрения сохранения состояния процессора.

Вот для примера три эквивалентных вызова VDK_ISR_POST_SEMAPHORE_():

.VAR/DATA semaphore_id;
 
/* Прямая передача значения */
VDK_ISR_POST_SEMAPHORE_(kSemaphore1);
 
/* Передача значения в регистре */
< REG > = kSemaphore1;
VDK_ISR_POST_SEMAPHORE_(< REG >);
 
/* < REG > не был испорчен */
/* Публикация семафора, в последний раз с использованием DM */
DM(semaphore_id) = < REG >;
VDK_ISR_POST_SEMAPHORE_(DM(semaphore_id));

Кроме того, макросы ассемблера не повлияют ни на какой-либо код проверки условия, не будет сделано никаких предположений по наличию свободного места в любом из аппаратных стеков (например, для счетчика программ PC или состояния процессора), и все внутренние структуры данных VDK останутся нетронутыми.

C/C++ ISR API предоставляет эквивалентную функциональность для кода ISR, написанного на C/C++.

Макросы ассемблера и функции API, вызываемые из C/C++ ISR, запускают низкоуровневое программное прерывание, если требуется работа планировщика для домена потоков после обслуживания всех других прерываний. Обсуждение низкоуровневого программного прерывания см. в разделе "Reschedule ISR". В Приложении A "Processor-Specific Notes" см. дополнительную информацию по поводу ISR API.

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

[Timer ISR]

По умолчанию VDK резервирует для себя прерывание таймера. Таймер используется для вычисления интервала round-robin, засыпания потока на нужное время, и для работы периодических семафоров. Один тик VDK определяется как время между прерываниями таймера (по умолчанию длительность тика установлена на 0.1 мс, но это можно поменять настройкой проекта на закладке Kernel). Время тика это максимальное разрешение по времени, которое может выполнять kernel. Прерывание таймера может вызывать низкоуровневое программное прерывание (см. "Reschedule ISR"). Есть возможность поменять прерывание, используемое VDK для прерывания таймера (для дополнительной информации см. online Help). Дополнительно можно задать None для прерывания таймера VDK, если службы времени VDK не требуются.

[Reschedule ISR]

VDK определяет самое низкое по приоритету прерывание, не привязанное ни к какому аппаратному устройству, как reschedule ISR. Этот ISR поддерживает обслуживание системы, когда прерывание приводит к такому изменению состояния системы, что может стать готовым к выполнению (ready) более высокоуровневый поток. Если новый поток становится ready, и система находится в обслуживаемом регионе кода (scheduled region), то ISR программного прерывания сохраняет контекст текущего потока и переключает контекст выполнения на новый поток. Если прерывание активировало драйвер устройства (device driver), то это низкоуровневое программное прерывание вызывает функцию диспетчера для драйвера устройства. Для дополнительной информации см. раздел "Dispatch Function".

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

[Ссылки]

1. Обзор VisualDSP++ Kernel RTOS (VDK).
2. VDK: менеджер прерываний.

 

Добавить комментарий


Защитный код
Обновить

Top of Page