VDK обробники переривань (ISR), dsp, programming
Починаючи з 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++). Наприклад розглянемо таке:
і в домені потоків:
Обмін даними з доменом потоків. VDK надає набір макросів на асемблері та API, які можуть бути викликані з ISR на C/C++ та використані для обміну системним станом із доменів потоків. Докладніше див. розділ "Assembly Macros and C/C++ ISR APIs".
Асемблерні макроси викликаються з домену переривань; тому вони не роблять припущень про стан процесора, доступні регістри або параметри. Іншими словами, макроси асемблера можна викликати без розгляду збереження стану процесора.
Ось для прикладу три еквівалентні виклики VDK_ISR_POST_SEMAPHORE_() :
Крім того, макроси асемблера не вплинуть ні на будь-який код перевірки умови, не буде зроблено жодних припущень щодо наявності вільного місця в будь-якому з апаратних стеків (наприклад, для лічильника програм 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".
У системах, де не прив'язане до апаратури переривання не має найнижчого рівня пріоритету, всі інші переривання з нижчими пріоритетами повинні працювати так, щоб на весь час їхнього переривання повинні бути заборонені. Не виконання цієї вимоги може призвести до непередбачуваної поведінки системи.