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

В этой статье приведен перевод раздела "Interrupt Manager" документации VisualDSP++ 5.0 Device Drivers and System Services Manual for Blackfin® Processors [1]. Описывается менеджер прерываний VDK процессора Blackfin, который управляет прерываниями (событиями) и осуществляет их обслуживание. Рассматриваются следующие вопросы:

• Инициализация Менеджера Прерываний
• Завершение работы Менеджера Прерываний
• Функции контроллера событий ядра (CEC)
• Функции системного контроллера прерываний (SIC)
• Защита критических регионов кода
• Модификация IMASK
• Файловая структура
• Документация по API Interrupt Manager

Примечание: менеджер прерываний можно использовать не только в приложениях VDK, но и в обычных программах (не RTOS). Выигрыш в том, что упрощается управление над всеми прерываниями в программе, и их обработка унифицируется, что благоприятно сказывается на читаемости и портируемости кода.

Процессор Blackfin использует двухярусный механизм управления прерываниями и событиями. Прерывания системного уровня управляются системным контроллером прерываний (system interrupt controller, SIC). Все сигналы прерываний периферийных устройства перенаправляются через SIC, после чего, в зависимости от настроек SIC, перенаправляются контролеру событий ядра (core event controller, CEC). CEC обрабатывает эти события, и в зависимости от настроек CEC, запускает на выполнение векторы обработки прерываний процессора [2].

Менеджер Прерываний (Interrupt Manager, далее этот термин оставлен в тексте без перевода) предоставляет функции, позволяющие приложению управлять всеми аспектами SIC и CEC. Он делает это таким образом, что события и прерывания управляются и обрабатываются эффективным и в то же время кооперативным способом.

Процессор Blackfin предоставляет 16 уровней прерываний и событий. Эти уровни, которые называются группами векторов прерываний (interrupt vector groups, IVG), пронумерованы от 0 до 15, и самый малый номер соответствует самому высокому приоритету. Некоторые уровни IVG выделены на заранее определенные события, такие как emulation, reset, non-maskable interrupt (NMI) и т. д. Другие уровни IVG, от 7 до 15, считаются событиями общего назначения (general-purpose events), и они обычно используются для прерываний системного уровня (от периферийных устройств), или как программные прерывания (software interrupts).

Вся обработка IVG осуществляется в CEC. Когда срабатывает определенный IVG (если предположить, что событие разрешено), CEC просматривает подходящую запись в таблице векторов событий (event vector table, EVT), и запускает на выполнение вектор по адресу из таблицы, туда где обрабатывается событие.

Все прерывания периферийных устройств сначала попадают в SIC. Если предположить, что SIC был запрограммирован (соотвествующие прерывания разрешены установкой бит в регистрах SIC_IMASK0 и SIC_IMASK1), прерывания периферии затем перенаправляются для обработки в CEC. SIC предоставляет богатую функциональность для обработки и поддержки прерываний от периферийных устройств. В дополнение к разрешению/запрету маршрутизации прерываний от периферийных устройств в CEC, контроллер SIC позволяет привязывать прерывания периферийных устройств к любому из уровней general-purpose IVG контроллера CEC, и управлять выходом процессора из режима ожидания при поступлении этих прерываний.

ADSP BF538 Interrupt Processing Block Diagram

В системах, которые применяют процессоры Blackfin, часто имеется большее количество потенциальных источников прерывания, чем уровней IVG. Как указывалось выше, некоторые события (такие как NMI) привязываются один-к-одному на уровень IVG. Другие события, обычно события, обычно случающиеся не очень часто, такие как прервания ошибок периферийных устройств, часто сопрягаются на одном уровне IVG.

Interrupt Manager позволяет приложению получить полный контроль на тем, как прерывания должны быть обработаны, должны ли они быть замаскированы или демаскированы, должны ли обрабатываться индивидуальным уровнем IVG или совмещать несколько прерываний на одном уровне IVG, должен ли процессор пробуждаться от прерывания и т. д. Interrupt Manager также позволяет создавать цепочки обработчиков прерываний (interrupt handler chains). Обработчик прерывания это вызываемая на языке C функция (внимание, это не ISR), которая предоставлена приложением для обработки прерывания. Через Interrupt Manager приложение может прицепить любое количество обработчиков к одному уровню IVG. Когда несколько событий совмещено на одном уровне IVG, это позволяет каждому обработчику быть разработанному независимо от любого другого, и позволяет приложению обработать эти прерывания прямым и понятным способом.

Кроме того, Interrupt Manager обрабатывает только те уровни IVG и системные прерывания, которые приложение направляет для управления к Interrupt Manager. Это дает разработчику приложения получить полный и беспрепятственный доступ к любому уровню IVG или системному прерыванию, чтобы вручную управлять прерываниями.

Многоядерным процессоры Blackfin расширяют эту возможность подключением одного SIC и одного CEC для каждого ядра. Это предоставляет максимум гибкости, и дает разработчикам самим решать, как привязать прерывания к определенному ядру, нескольким ядрам, и т. д. Когда используются многоядерные процессоры Blackfin, обычно используется по одному Interrupt Manager-у на каждое ядро. Поскольку нет никаких причин предоставлять несколько Interrupt Manager для одноядерных процессоров, эта служба на них не поддерживается. Разработчики не должны пытаться инстанцировать больше чем один Interrupt Manager на ядро.

Следуя конвенции всех Системных Служб, Interrupt Manager использует уникальное и однозначное именование, чтобы защититься от конфликтов. Все перечисляемые значения, операторы и макросы Interrupt Manager используют префикс ADI_INT_, в то время как все функции Interrupt Manager используют префикс adi_int_.

Все функции Interrupt Manager API возвращают код типа ADI_INT_RESULT. Список кодов возврата см. в файле adi_int.h. Наподобие всех Системных Служб, код возврата, который сигнализирует об успешном завершении, для Interrupt Manager определен как 0 (или ADI_INT_RESULT_SUCCESS). Это позволяет приложениям быстро и просто определить, была ли какая-либо ошибка в обработке.

[Инициализация Менеджера Прерываний]

Чтобы использовать Interrupt Manager, функция должна его инициализировать. Функция, которая инициализирует Interrupt Manager, называется adi_int_Init. Приложение, которое вызывает adi_int_Init, передает в неё аргумент, который определяет память, которую Interrupt Manager использует для своей работы.

Объем предоставленной памяти зависит от количества вторичных обработчиков, используемых приложением. Когда используется соединение в цепочку обработчиков (interrupt handler chaining), Interrupt Manager считает первый подцепленный на уровень IVG обработчик прерывания как первичный (primary interrupt handler). Любые дополнительные обработчики, которые привязываются к тому же самому уровню IVG, считаются вторичными (secondary handlers). Без любой дополнительной памяти от приложения Interrupt Manager может поддерживать только один первичный обработчик на каждый уровень IVG. Если приложение никогда не использует больше одного обработчика на каждый уровень IVG (т. е. есть только один первичный обработчик и нет вторичных обработчиков), то приложению не нужно предоставлять дополнительную память для Interrupt Manager в аргументе функции инициализации.

Имеется макрос ADI_INT_SECONDARY_MEMORY, который применяется для получения размера памяти (в байтах), требуемого для одного вторичного обработчика. Таким образом, приложение должно предоставить функции инициализации n порций ADI_INT_SECONDARY_MEMORY, где n это количество поддерживаемых вторичных обработчиков.

Другой параметр, который передается функции инициализации, это параметр, который Interrupt Manager передает функции adi_int_EnterCriticalRegion(). Это значение зависит от рабочего окружения приложения. См. описание функции adi_int_EnterCriticalRegion для дополнительной информации.

Будучи вызванной, функция инициализации инициализирует внутренние структуры данных и делает возврат. Во время инициализации не делается никаких изменений с контроллерами CEC или SIC. После инициализации может быть вызвана любая другая функция Interrupt Manager API.

[Завершение работы Менеджера Прерываний]

Когда больше не требуется функциональность Interrupt Manager, приложение может вызвать функцию завершения (termination) для Interrupt Manager, adi_int_Terminate(). Множество приложений работает в бесконечном цикле, и никогда не вызывают эту функцию завершения.

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

[Функции контроллера событий ядра (CEC)]

Нужны только 2 функции для управления контроллером событий ядра (core event controller, CEC): adi_int_CECHook() и adi_int_CECUnhook(), как описано ниже.

adi_int_CECHook(). Функция adi_int_CECHook() используется для прикрепления (hook) обработчиков прерывания к цепочке обработчиков для уровня IVG. При вызове этой функции приложение передает номер обслуживаемого IVG, адрес обработчика, параметр, который Interrupt Manager автоматически передает обратно в обработчик, когда он вызывается, и флаг, показывающий, разрешается или нет вложенность прерываний для этого уровня IVG.

Сама по себе функция обработчика это обычная функция, вызываемая в стиле языка C, которая удовлетворяет типу ADI_INT_HANDLER_FN. Обработчик прерывания это не ISR, а стандартная функция C. Когда срабатывает уровень IVG, Interrupt Manager вызывает обработчик прерывания для обработки события. Interrupt Manager передает в обработчик прерывания аргумент клиента, который  был ранее передан в Interrupt Manager через функцию adi_int_CECHook(). Обработчик прерывания предпринимает любые действия по обработке события прерывания, после чего делает возврат либо значения ADI_INT_RESULT_PROCESSED, либо ADI_INT_RESULT_NOT_PROCESSED.

Обработчики прерываний должны быть написаны так, что они быстро опрашивают систему, чтобы определить, должно ли событие, вызвавшее прерывание, быть обработано обработчиком прерывания. Если событие, вызвавшее прерывание, не то, которое ожидает этот обработчик, то он должен немедленно сделать возврат с кодом ADI_INT_RESULT_NOT_PROCESSED. Тогда Interrupt Manager автоматически вызовет следующий обработчик прерывания, подцепленный к одному уровню IVG (если он имеется в цепочке обработчиков). Если событие, вызвавшее прерывание, ожидается обработчиков, то он выполнит его обработку и при этом должен вернуть код ADI_INT_RESULT_PROCESSED.

Параметр вложенности имеет значение только когда вызывается первый обработчик, подцепленный к цепочке обработчиков IVG. Первый обработчик прерывания, подцепленный к цепочке IVG, называется первичным (primary handler). Любые дополнительные обработчики, подцепленные к цепочке на тот же самый уровень IVG, называются вторичными (secondary handlers). Когда первичный обработчик подцеплен к цепочке, Interrupt Manager загружает ISR в соответствующую запись таблицы векторов событий (event vector table, EVT). Если флаг вложенности установлен, то ISR, который Interrupt Manager загрузил для обработки цепочки обработчиков, будет поддерживания вложенность прерываний (interrupt nesting). Если флаг вложенности очищен, то ISR, который Interrupt Manager загрузил, не будет поддерживать вложенность прерываний. Когда вторичные обработчики подцеплены в цепочку IVG, параметр флага вложенности игнорируется.

И наконец, функция adi_int_CECHook() демаскирует соответствующий бит регистра IMASK контроллера CEC, разрешая тем самым обработку прерывания.

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

Interrupt Manager поддерживает эту методику, и он оптимизирован так, чтобы позволить экстремально эффективно обработать первичные обработчики прерываний. Несмотря на то, что вторичные обработчики обрабатываются также эффективно, они вызываются все же позже первичного обработчика прерываний. Вторичные обработчики прицепляются в цепочку IVG так, что они будут обработаны по принципу последним пришел, первым вышел (last-in, first-out, LIFO). Это означает, что когда сработало событие, после вызова первичного обработчика (если предположить, что первичный обработчик не вернул код ADI_INT_RESULT_PROCESSED), Interrupt Manager вызовет вторичный обработчик из цепочки, который был прицеплен последним в цепочку, за ним предпоследний, и т. д.

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

adi_int_CECUnhook(). Функция adi_int_CECUnhook() используется для отцепления обработчика от цепочки обработчиков определенного уровня IVG. При вызове этой функции приложение передает в неё номер IVG и адрес функции обработчика, которая должна быть исключена из цепочки.

Функция удаляет обработчик прерывания из цепочки обработчиков для указанного уровня IVG. Если удаляется первичный обработчик, то последний подцепленный в цепочку обработчик становится первичным вместо него. Если после удаления обработчика из IVG-цепочки больше в ней не осталось обработчиков, то функция adi_int_CECUnhook() маскирует соответствующий бит в регистре IMASK контроллера CEC, запрещая тем самым это прерывание.

Обработчики прерываний (Interrupt Handlers; внимание, не путать обработчики прерываний с ISR!). Поскольку обработчики регистрируются с помощью Interrupt Manager, и вовлекаются в обработку из встроенной процедуры ISR для определенного уровня IVG (и здесь может быть несколько прерываний, ожидающих своей обработки на одном и том же уровне IVG), отдельные обработчики прерывания не должны использовать инструкцию RTI при своем завершении. Вместо этого они должны делать обычный возврат, как функция, используя инструкцию RTS. Фактически обработчики прерывания это ни что другое, как простая подпрограмма на языке C. Таким образом, каждый обработчик прерывания периферийного устройства должен удовлетворять следующему шаблону:

ADI_INT_HANDLER(mjk_SPORT_RX_handler)
{
   ... ... // код пользователя
}

Здесь ADI_INT_HANDLER это макрос, определенный так:

#define ADI_INT_HANDLER(NAME) \
   void (*NAME)(void *ClientArg)

[Функции системного контроллера прерываний (SIC)]

VDK предоставляет следующие функции, которыми приложение может получить полный контроль над системным контроллером прерываний (system interrupt controller, SIC):

adi_int_SICEnable – разрешает передачу в CEC прерывания от периферийного устройства.

adi_int_SICDisable – запрещает передачу в CEC прерывания от периферийного устройства.

adi_int_SICSetIVG – устанавливает уровень IVG, с которым будет обрабатываться прерывание периферийного устройства.

adi_int_SICGetIVG – определяет уровень IVG, к которому привязано прерывание от периферийного устройства.

adi_int_SICWakeup – задает, должно ли прерывание от периферийного устройства пробуждать процессор (вызывать его выход из состояния ожидания idle).

adi_int_SICInterruptAsserted – определяет, было ли выставлено прерывание от периферийного устройства.

adi_int_SICGlobalWakeup – запрещает всем прерываниям выводить из сна процессор, или восстанавливает все пробуждения в предыдущее состояние.

За исключением функции глобального запрета/разрешения пробуждения, все эти функции SIC получают как параметр значение из перечисления (enum), которое уникально идентифицирует прерывание от периферийного устройства. Перечисление ADI_INT_PERIPHERAL_ID идентифицирует каждый возможный источник прерывания для процессора. Это перечисление определено в файле adi_int.h (см. содержимое этого файла для получения полного списка значений для каждого поддерживаемого процессора Blackfin).

adi_int_SICDisable. Функция adi_int_SICDisable() используется для запрета передачи прерывания периферийного устройства в контроллер CEC. Будучи вызванной, функция программирует соответствующий регистр IMASK контроллера SIC, чтобы запретить прерывание от периферийного устройства.

adi_int_SICEnable. Функция adi_int_SICEnable() используется для разрешения передачи прерывания периферийного устройства в контроллер CEC. Будучи вызванной, функция программирует соответствующий регистр IMASK контроллера SIC, чтобы разрешить прерывание от периферийного устройства.

adi_int_SICGetIVG. Функция adi_int_SICGetIVG() используется для определения, к какому уровню IVG привязано прерывание периферийного устройства.

В дополнение к параметру ADI_INT_PERIPHERAL_ID, в эту функцию передается информация, указывающая на место в памяти для результата. Функция опрашивает надлежащее поле в соответствующем регистре назначения прерывания (SIC interrupt assignment register) и сохраняет уровень IVG (от 0 до 15), на который привязано прерывание периферийного устройства.

adi_int_SICInterruptAsserted. Функция adi_int_SICInterruptAsserted() используется, чтобы определить, было ли выставлено прерывание от периферийного устройства. Хотя эта функция может быть вызвана в любое время, она предназначена для того, чтобы быть вызванной в самом начале обработчика прерывания приложения, чтобы определить, нужно ли этому обработчику обслуживать выставленное прерывание периферийного устройства.

Вместо обычного использования кода возврата ADI_INT_RESULT_SUCCESS эта функция возвращает код ADI_INT_RESULT_ASSERTED или ADI_INT_RESULT_NOT_ASSERTED после успешного завершения. Если в параметрах вызова были ошибки, то эта функция может возвратить код ошибки.

adi_int_SICSetIVG. Функция adi_int_SICSetIVG() используется, чтобы установить уровень IVG, к которому будет привязано прерывание от периферийного устройства. При включении питания процессор Blackfin вовлекает привязку прерываний периферийных устройств по умолчанию к уровням IVG. Эта функция изменяет привязку по умолчанию. В дополнение к параметру ADI_INT_PERIPHERAL_ID, этой функции передается уровень IVG (от 0 до 15), к которому должно быть привязано прерывание от периферийного устройства. Функция модифицирует подходящее поле в соответствующем регистре назначения прерываний контроллера SIC (SIC interrupt assignment register), чтобы обеспечить новую привязку.

adi_int_SICWakeup. Функция adi_int_SICWakeup() используется для разрешения или запрета пробуждения процессора от прерывания периферийного устройства, когда сработало прерывание, и процессор находится в состоянии ожидания (idle state). В дополнение к параметру ADI_INT_PERIPHERAL_ID, этой функции передается флаг TRUE/FALSE. Если флаг в значении TRUE, то регистр пробуждения от прерывания контроллера SIC (SIC interrupt wakeup register) программируется так, что указанное прерывание от периферийного устройства будет пробуждать процессор при срабатывании прерывания. Если флаг в состоянии FALSE, то SIC interrupt wakeup register программируется для запрета пробуждения ядра процессора при срабатывании прерывания от этого периферийного устройства.

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

adi_int_SICGlobalWakeup. Регистр пробуждения от прерывания контроллера SIC (SIC interrupt wakeup register) содержит биты, которые соответствуют каждому периферийному устройству, и они задают, может или нет периферийное устройство выводить процессор из режима ожидания. По умолчанию все биты в SIC interrupt wakeup register установлены.

Функция adi_int_SICGlobalWakeup() используется для того, чтобы глобально запретить пробуждение от прерываний всех периферийных устройств путем сброса в 0 всех бит SIC interrupt wakeup register. Эта функция также используется для восстановления SIC interrupt wakeup register в предыдущее состояние. В эту функцию передается флаг TRUE/FALSE и указатель на структуру ADI_INT_WAKEUP_REGISTER, в которую сохраняются значения регистра пробуждения, когда глобально запрещается пробуждение от всех прерываний, или откуда берутся данные, когда снова разрешается (точнее восстанавливается предыдущее) состояние пробуждения.

Если в флаг передано FALSE, то эта функция обрабатывает поля в SIC interrupt wakeup register, и сохраняет их значения в соответствующие поля структуры ADI_INT_WAKEUP_REGISTER, на которую указывает аргумент функции. SIC interrupt wakeup register программируется так, что ни для одного прерывания не разрешается разбудить ядро.

Если в флаг передано TRUE, то эта функция программирует SIC wakeup register значениями полей из структуры ADI_INT_WAKEUP_REGISTER, на которую ссылается параметр указателя функции. Предполагается, что эти значения были получены предыдущем вызовом функции adi_int_SICGlobalWakeup.

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

/* Декларируется структура для сохранения состояния регистра настройки
   пробуждения от прерываний (SIC interrupt wakeup register) */
ADI_INT_WAKEUP_REGISTER RegIWR;
 
/* Глобально запрещаются прерывания, при этом структура RegIWR
   заполняется значением SIC interrupt wakeup register */
adi_init_SICGlobalWakeup(FALSE, &RegIWR);
 
/* Разрешить пробуждение от PLL, чтобы изменить режимы энергопотребления */
adi_int_SICWakeup(ADI_INT_PLL_WAKEUP, 1);
 
/* Разрешаются любые другие пробуждения, которые должны выводить из сна процессор */
...
 
/* Перевод процессора в режим сна */
adi_pwr_SetPowerMode(ADI_PWR_MODE_SLEEP);
 
/* При пробуждении восстановление состояния пробуждения в предыдущие настройки */
adi_int_SICGlobalWakeup(TRUE, &RegIWR);

[Защита критических регионов кода]

Во встраиваемых системах часто необходимо защитить определенные критические участки выполняемого кода. Это часто необходимо, когда какая-то логическая последовательность команд обновляет или модифицирует некоторую часть данных (происходит атомарная операция). В таких случаях другой логической последовательности команд, находящаяся в коде обработчика прерывания (или другом потоке системы RTOS), запрещено вмешиваться в процесс обновления критических данных.

С этой целью Interrupt Manager предоставляет 2 функции, которые можно использовать как обрамление критического региона кода: adi_int_EnterCriticalRegion() и adi_int_ExitCriticalRegion(). Приложение вызывает функцию adi_int_EnterCriticalRegion() в начале критического региона кода, и затем вызывает adi_int_ExitCriticalRegion() в конце этого критического региона кода. Эти функции всегда должны использоваться парно.

Реальная реализация этих функций может меняться в зависимости от имеющегося рабочего окружения, в котором работает код. Например, в обычной системе (где не используется RTOS наподобие VDK или FreeRTOS), действия в этих функциях могут отличаться от действий в системе, основанной на RTOS. Однако принцип использования остается одинаковым, независимо от реализации. Таким образом, код приложения всегда работает одинаково, и не требует изменения в зависимости от рабочего окружения.

Функции adi_int_EnterCriticalRegion() передается аргумент типа void *, и она возвращает тип void *. Значение, возвращенное из функции adi_int_EnterCriticalRegion(), всегда должно быть передано соответствующей (парной) функции adi_int_ExitCriticalRegion(). Вот пример такой последовательности кода:

...
Value = adi_int_EnterCriticalRegion(pArg);
...               // критическая область кода
adi_int_ExitCriticalRegion(Value);
...

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

Например, может случиться так, что в критическом регионе кода отключены прерывания. Обычно разработчику нельзя допустить, чтобы прерывания были отключены на продолжительное время. Так что эти функции должны использоваться экономно и рассудительно.

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

...
Value = adi_int_EnterCriticalRegion(pArg);
...               // критическая область кода
Foo();            // вызов функции Foo()
adi_int_ExitCriticalRegion(Value);
...
 
void Foo(void)
{
   void *Value;
   ...
   Value = adi_int_EnterCriticalRegion(pArg);
   ...            // критическая область кода
   adi_int_ExitCriticalRegion(Value);
   ...
}

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

Значение pArg, переданное в функцию adi_int_EnterCriticalRegion(), зависит от реальной реализации для имеющегося рабочего окружения. В некоторых операционных системах это значение не используется и может быть равно NULL. Для дополнительной информации по параметру pArg просмотрите исходный файл для определенного рабочего окружения adi_int_xxx.c в каталоге Blackfin/lib/src/services, где xxx указывает на предназначенное рабочее окружение.

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

[Модификация IMASK]

Приложениям редко требуется модифицировать регистр IMASK процессора, Interrupt Manager сам модифицирует значение регистра IMASK для корректного управления контроллером CEC. В некоторых рабочих окружениях, основанных на RTOS, сама система RTOS плотно управляет содержимым регистра IMASK, и предоставляет также функции, которые позволяют манипулировать содержимым IMASK.

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

Предоставлены 2 зависящие от рабочего окружения функции, чтобы можно было устанавливать и сбрасывать биты регистра IMASK: adi_int_SetIMASKBits и adi_int_ClearIMASKBits. Эти функции получают в качестве параметров значение, которое соответствует регистру IMASK целевого процессора. Когда вызывается функция adi_int_SetIMASKBits(), то она устанавливает в лог. 1 те биты регистра IMASK, у которых в соответствующей позиции бит переданного значения имеется лог. 1. Когда вызывается adi_int_ClearIMASKBits() функция, то она сбрасывает те биты регистра IMASK, в позиции которых переданного в функцию значения имеется лог. 1.

Рассмотрим следующий пример кода. Предполагается, что IMASK это 32-битное значение, и оно содержит 0x00000000 на входе в этот код:

...
...               // IMASK === 0x00000000
ReturnCode = adi_int_SetIMASKBits(0x00000003);
...               // IMASK == 0x00000003
ReturnCode = adi_int_ClearIMASKBits(0x00000001);
...               // IMASK == 0x00000002
ReturnCode = adi_int_ClearIMASKBits(0x00000002);
...               // IMASK == 0x00000000

В то время как весьма маловероятно, что приложению когда-либо понадобится напрямую менять значения отдельных бит IMASK, Interrupt Manager использует эти функции для управления контроллером CEC.

Примеры. Вместе с VisualDSP++ поставляются примеры, демонстрирующие использование Interrupt Manager. Их можно найти в подкаталогах папки Blackfin/EZ-Kits.

[Файловая структура]

API для Interrupt Manager определен в заголовочном файле adi_int.h. Этот файл находится в подкаталоге Blackfin/include/services, и автоматически подключается в файле services.h, находящемся в том же подкаталоге. Так что в код приложения нужно подключать только заголовочный файл services.h.

Приложения должны быть слинкованы с одним из библиотечных файлов Системных Служб (system services). Эти файлы находятся в каталоге Blackfin/lib. См. раздел "DMA Manager" в даташите [1], чтобы правильно выбрать библиотечный файл.

Для удобства весь исходный код Interrupt Manager размещен в каталоге Blackfin/lib/src/services. Весь код, зависящий от рабочего окружения, находится в файле adi_int_xxx.c, где xxx указывает на целевое рабочее окружение. Эти файлы никогда не должны присоединяться к проекту, потому что соответствующая библиотека Системных Служб уже содержит требуемый объектный код.

[Документация по API Interrupt Manager]

В этом разделе приведены описания функций модуля Interrupt Manager, формирующие его интерфейс программирования (application programming interface, API).

Функция adi_int_Init() инициализирует отдельную область памяти для Interrupt Manager. Она также инициализирует другие таблицы и векторы в Interrupt Manager. Эта функция вызывается только один раз на ядро. Для каждого ядра выделяется отдельная область памяти.

ADI_INT_RESULT adi_int_Init(void *pMemory,
                            const size_t MemorySize,
                            u32 *pMaxEntries,
                            void *pEnterCriticalArg);

Аргументы:

pMemory Указатель на предоставленную приложением область памяти, которую будет использовать Interrupt Manager
MemorySize Размер в байтах области памяти, которую будет использовать Interrupt Manager
pMaxEntries На выходе из функции этот аргумент содержит количество записей для вторичных обработчиков прерывания, которые Interrupt Manager может поддерживать на предоставленной области памяти.
pEnterCriticalArg Параметр, который передается в функцию adi_int_EnterCriticalRegion.

Возвращаемое значение:

ADI_INT_RESULT_SUCCESS Означает успешную инициализацию Менеджера Прерываний

Если в параметрах pMemory указать NULL и MemorySize указать 0, то на один аппаратный уровень прерывания может быть привязан только один обработчик прерывания (первичный). Это вполне допустимо, когда для нужд приложения хватает всех аппаратных уровней IVG.

Параметр pEnterCriticalArg всегда NULL для систем на основе VDK. Этот параметр передается в функцию adi_int_EnterCriticalRegion, обозначающую начало критический регион кода. Для систем, которые не используют вложенные критические регионы, параметр pEnterCriticalArg не имеет смысла, и может быть равен NULL. Подробнее см. раздел "Защита критических регионов кода".

Функция adi_int_Terminate() завершает работу Interrupt Manager. Вся память, использовавшаяся Interrupt Manager, освобождается, все обработчики отцепляются, и все группы векторов прерываний (interrupt vector groups, IVG), которые были разрешены и управлялись Interrupt Manager, запрещаются.

Функция adi_int_Terminate не изменяет настройки контроллера системных прерываний (system interrupt controller, SIC). Если требуются изменения в SIC, то приложение должно сделать соответствующие вызовы функций по управлению SIC до вызова adi_int_Terminate().

ADI_INT_RESULT adi_int_Terminate(void);

Возвращаемое значение:

ADI_INT_RESULT_SUCCESS Означает успешное завершение работы Менеджера Прерываний

Функция adi_int_CECHook() инструктирует Interrupt Manager прицепить указанный обработчик к цепочке обработчиков прерывания, привязанной к указанному уровню IVG.

По выходе из этого вызова контроллер событий ядра (core event controller, CEC) программируется таким образом, что указанный уровень IVG демаскируется (т. е. разрешается для обработки), система правильно конфигурируется для обработки прерывания через ISR-ы, встроенные в код Interrupt Manager. Затем эти ISR-ы будут вовлекать вызовы обработчика прерываний, который указан в аргументах функции adi_int_CECHook(). В зависимости от состояния параметра NestingFlag, Interrupt Manager устанавливает встроенный ISR либо с поддержкой вложенности прерываний, либо без разрешения вложенности.

При первом вызове adi_int_CECHook() для указанного уровня IVG, Interrupt Manager регистрирует встроенный ISR на этот уровень IVG, и устанавливает предоставленный обработчик как первичный для указанного уровня IVG. Последующие вызовы adi_int_CECHook для того же самого уровня IVG создадут цепочку вторичных обработчиков прерываний, которые будут привязаны к этому уровню IVG, и будут вызываться после первичного обработчика прерываний. Для вторичных обработчиков прерывания параметр NestingFlag игнорируется, поскольку будет разрешаться или запрещаться вложенность, установленная ранее для первичного обработчика прерываний.

Параметр ClientArg, предоставленный для функции adi_int_CECHook, указывает на адрес функции обработчика прерывания, которая будет вызвана в ответ на прерывание.

ADI_INT_RESULT adi_int_CECHook(u32 IVG,
                               ADI_INT_HANDLER_FN Handler,
                               void *ClientArg,
                               u32 NestingFlag);

Аргументы:

IVG Номер группы прерываний, к которой должен быть подцеплен обработчик
Handler Адрес функции обработчика, который должен быть добавлен в цепочку обработчиков прерываний
ClientArg Параметр типа void *, передаваемый в обработчик прерываний
NestingFlag Аргумент, который выбирает, будет ли разрешена вложенная обработка прерываний, или нет для указанного IVG. Этот параметр имеет значение только для первичного обработчика в цепочке.

Возвращаемые значения:

ADI_INT_RESULT_SUCCESS Обработчик прерывания был успешно добавлен в цепочку обработчиков
ADI_INT_RESULT_NO_MEMORY Недостаточно памяти для добавления обработчика в цепочку обработчиков прерываний
ADI_INT_RESULT_INVALID_IVG Недопустимый уровень IVG

Функция adi_int_CECUnhook() инструктирует Interrupt Manager отцепить указанный обработчик прерывания от цепочки обработчиков, привязанной к указанному IVG.

Если указанный обработчик единственный в цепочке, то CEC программируется для запрета (маскирования) указанного IVG, и ISR, встроенный в Interrupt Manager, удаляется из IVG-записи таблицы векторов событий (event vector table, EVT).

Если цепочка для указанного IVG содержит несколько обработчиков, то указанный обработчик просто удаляется из цепочки. Если был удален первичный обработчик, и в цепочке есть вторичные обработчики, то первичным становится обработчик, который был добавлен в цепочку последним.

ADI_INT_RESULT adi_int_CECUnhook(u32 IVG,
                                 ADI_INT_HANDLER_FN Handler,
                                 void *ClientArg);

Аргументы:

IVG Номер группы прерываний, к которой должен быть подцеплен обработчик
Handler Адрес функции обработчика, который должен быть удален из цепочку обработчиков прерываний
ClientArg Параметр типа void *, передаваемый в обработчик прерываний. Для успешного удаления обработчика значение этого параметра должно соответствовать значению, которое было ранее передано в функцию adi_int_CECHook() при подключении обработчика.

Возвращаемые значения:

ADI_INT_RESULT_SUCCESS Обработчик прерывания был успешно удален из цепочки обработчиков
ADI_INT_RESULT_INVALID_IVG Недопустимый уровень IVG

Функция adi_int_ClearIMaskBits() используется Interrupt Manager, чтобы сбросить указанные биты регистра IMASK. Хотя приложение может вызвать эту функцию, приложение не должно пытаться модифицировать биты регистра IMASK, которые представляют группы векторов прерываний (interrupt vector groups, IVG); управлять битами должен только сам Interrupt Manager.

Реализация этой функции зависит от рабочего окружения. В обычном приложении (не RTOS) эта функция определяет, находится ли процессор в защищенном регионе кода (см. описание функций adi_int_EnterCriticalRegion и adi_int_ExitCriticalRegion). Если это так, то сохраненное значение IMASK соответственным образом обновляется, и текущее действующее в пределах защищенной секции значение IMASK остается неизменным.

После вызова самой последней функции adi_int_ExitCriticalRegion из вложенных критического регионов кода, восстанавливается сохраненное значение IMASK с новыми настройками для бит. Если при входе в adi_int_ClearIMaskBits процессор не находится в критическом регионе кода, то соответствующим образом обновляется сразу действующее значение регистра IMASK.

Информацию о подробностях реализации для этой функции в других рабочих окружениях можно найти в файле adi_int_xxx.c, размещенной в каталоге blackfin/lib/src/services/int, где xxx указывает на целевое рабочее окружение.

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

void adi_int_ClearIMASKBits(ADI_INT_IMASK BitsToClear);

Аргумент:

BitsToClear Маска для битов регистра IMASK, значение которых должно быть сброшено в 0. Бит в маске, установленный в 1, задает сброс соответствующего бита в регистре IMASK. Бит в маске, заданный в 0, не окажет влияния на соответствующий бит в регистре IMASK.

Функция adi_int_EnterCriticalRegion() создает условия выполнения кода, чтобы он был защищен от вытеснения другим кодом, так что формируется так называемый критический регион кода. Парная для неё функция adi_int_ExitCriticalRegion снимает эти условия. Эти две функции используются как обрамление секции кода, которая требует непрерывного выполнения, так что в нем можно осуществлять атомарные операции над любыми данными. Эти функции следует использовать осмотрительно и экономно - только в тех случаях, когда требуется действительно защитить некоторый кусок кода.

Возвращаемое из этой функции значение должно быть передано соответствующей функции adi_int_ExitCriticalRegion.

Реальные условия защиты кода зависят от рабочего окружения. В обычных приложениях (не RTOS) эта функция эффективно запрещает прерывания, сохраняя текущее значение IMASK во временную ячейку памяти. Функция adi_int_ExitCriticalRegion сохраняет оригинальное значение IMASK. Эти функции реализуют в себе счетчик использования для поддержки вложенных вызовов, благодаря чему критические регионы можно делать вложенными. Когда критические регионы вложены друг в друга, значение IMASK изменяется только на самом последнем уровне вложенности. В одиночной версии (без вложений) параметр pArg не имеет значения.

Информацию по реализации этой функции для разных рабочих окружений можно найти в файле adi_int_xxx.c, находящемся в каталоге blackfin/lib/src/services/int, где xxx указывает на целевое рабочее окружение.

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

void *adi_int_EnterCriticalRegion(void *pArg);

Аргумент:

pArg Смысл этого аргумента зависит от реализации. См. файл adi_int_xxx.h для подробного описания значения этого параметра для рабочего окружения xxx.

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

Функция adi_int_ExitCriticalRegion() удаляет условия, установленные функцией adi_int_EnterCriticalRegion с целью защиты критического региона кода. Эти две функции используются как обрамление для секции кода, которая нуждается в защите от вытеснения другим кодом. Эти функции следует использовать осмотрительно и экономно - только в тех случаях, когда требуется действительно защитить некоторый кусок кода.

Параметр pArg, передаваемый в функцию adi_int_ExitCriticalRegion должен быть всегда равен значению, возвращенному из соответствующей комплементарной функции adi_int_EnterCriticalRegion (для дополнительной информации см. описание функции adi_int_EnterCriticalRegion).

void adi_int_ExitCriticalRegion(void *pArg);

Аргументы:

pArg В этом аргументе должно быть передано значение, возвращенное из вызова функции adi_int_EnterCriticalRegion().

Функция adi_int_GetCurrentIVGLevel() считывает уровень IVG, на котором сейчас работает процессор.

ADI_INT_RESULT adi_int_GetCurrentIVGLevel(u32 *pIVG);

Аргумент:

pIVG Указатель на ячейку памяти, в которой будет сохранен текущий уровень IVG.

Возвращаемые значения:

ADI_INT_RESULT_SUCCESS Был успешно считан и возвращен уровень IVG.
ADI_INT_RESULT_NOT_ASSERTED В настоящий момент нет активного прерывания.

Функция adi_int_GetLibraryDetails() принимает указатель на структуру данных ADI_INT_LIBRARY_DETAILS. На выходе эта функция возвращает подробную информацию о библиотеке в структуре ADI_INT_LIBRATY_DETAILS.

ADI_INT_RESULT adi_int_GetLibraryDetails(ADI_INT_LIBRARY_DETAILS *pLibraryDetails);

Аргумент:

pLibraryDetails Указатель на структуру ADI_INT_LIBRARY_DETAILS, в которой будет сохранена информация о библиотеке.

Возвращаемое значение:

ADI_INT_RESULT_SUCCESS Функция завершилась успешно.

Функция adi_int_SICDisable() конфигурирует системный контроллер прерываний (system interrupt controller, SIC) так, чтобы запретить указанное прерывание и предотвратить его передачу в контроллер событий ядра (core event controller, CEC).

Функция adi_int_SICDisable просто программирует системный регистр маски прерываний, чтобы замаскировать (запретить) прерывания от указанного периферийного устройства, тем самым препятствуя их передаче в контроллер CEC.

ADI_INT_RESULT adi_int_SICDisable(const ADI_INT_PERIPHERAL_ID PeripheralID);

Аргумент:

PeripheralID Значение из перечисления ADI_INT_PERIPHERAL_ID, которая идентифицирует источник прерывания (аппаратное периферийное устройство процессора).

Возвращаемые значения:

ADI_INT_RESULT_SUCCESS SIC был успешно сконфигурирован.
ADI_INT_RESULT_INVALID_PERIPHERALID Указан недопустимый идентификатор PeripheralID.

Функция adi_int_SICEnable() конфигурирует системный контроллер прерываний (system interrupt controller, SIC) так, чтобы разрешить указанное прерывание и позволить его передачу в контроллер событий ядра (core event controller, CEC).

Функция adi_int_SICEnable просто программирует системный регистр маски прерываний, разрешить прерывания от указанного периферийного устройства, чтобы они передавались в контроллер CEC.

ADI_INT_RESULT adi_int_SICEnable(const ADI_INT_PERIPHERAL_ID PeripheralID);

Аргумент:

PeripheralID Значение из перечисления ADI_INT_PERIPHERAL_ID, которая идентифицирует источник прерывания (аппаратное периферийное устройство процессора).

Возвращаемые значения:

ADI_INT_RESULT_SUCCESS SIC был успешно сконфигурирован.
ADI_INT_RESULT_INVALID_PERIPHERALID Указан недопустимый идентификатор PeripheralID.

Функция adi_int_SICGetIVG() определяет текущую привязку источника прерываний периферийного устройства к уровню IVG. Будучи вызванной, эта функция читает соответствующий регистр(ы) назначения прерываний для указанного периферийного устройства, и сохраняет записанный там (привязанный) уровень IVG в ячейку памяти, предоставленную приложением (на неё указывает переданный параметр pIVG). Эта функция не делает никаких модификаций настроек аппаратуры и контроллера прерываний.

ADI_INT_RESULT adi_int_SICGetIVG(const ADI_INT_PERIPHERAL_ID PeripheralID,
                                 u32 *pIVG);

Аргументы:

PeripheralID Значение из перечисления ADI_INT_PERIPHERAL_ID, которая идентифицирует источник прерывания (аппаратное периферийное устройство процессора).
pIVG Указатель на ячейку памяти для 32-битного целого числа без знака, куда функция запишет уровень IVG, к которому привязан указанный идентификатор периферийного устройства.

Возвращаемые значения:

ADI_INT_RESULT_SUCCESS Функция завершена успешно.
ADI_INT_RESULT_INVALID_PERIPHERALID Указан недопустимый идентификатор PeripheralID.
ADI_INT_RESULT_INVALID_IVG Недопустимый уровень IVG.

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

ADI_INT_RESULT adi_int_SICInterruptAsserted(const ADI_INT_PERIPHERAL_ID PeripheralID);

Аргумент:

PeripheralID Значение из перечисления ADI_INT_PERIPHERAL_ID, которая идентифицирует источник прерывания (аппаратное периферийное устройство процессора).

Возвращаемые значения:

ADI_INT_RESULT_INVALID_PERIPHERALID Указан недопустимый идентификатор PeripheralID.
ADI_INT_RESULT_ASSERTED Прерывание было выставлено для указанного периферийного устройства.
ADI_INT_RESULT_NOT_ASSERTED Прерывание предназначено не для указанного периферийного устройства.

Функция adi_int_SICSetIVG() устанавливает привязку источника прерываний аппаратуры к указанному уровню IVG. Будучи вызванной, функция модифицирует соответствующий регистр(ы) назначения прерываний указанного периферийного устройства, чтобы для него был задан указанный уровень IVG. Эта функция не разрешает и не запрещает прерывания.

ADI_INT_RESULT adi_int_SICSetIVG(const ADI_INT_PERIPHERAL_ID PeripheralID,
                                 const u32 IVG);

Аргументы:

PeripheralID Значение из перечисления ADI_INT_PERIPHERAL_ID, которая идентифицирует источник прерывания (аппаратное периферийное устройство процессора).
IVG Группа векторов прерываний, к которому должно быть привязано прерывание от указанного периферийного устройства.

Возвращаемые значения:

ADI_INT_RESULT_SUCCESS Функция завершена успешно.
ADI_INT_RESULT_INVALID_PERIPHERALID Указан недопустимый идентификатор PeripheralID.
ADI_INT_RESULT_INVALID_IVG Недопустимый уровень IVG.

Функция adi_int_SetIMaskBits() используется Interrupt Manager, чтобы установить определенные биты в регистре IMASK. Хотя приложение может вызвать эту функцию, приложение не должно пытаться модифицировать биты регистра IMASK, которые представляют группы векторов прерываний (interrupt vector groups, IVG); управлять битами должен только сам Interrupt Manager.

Реализация этой функции зависит от рабочего окружения. В обычном приложении (не RTOS) эта функция определяет, находится ли процессор в защищенном регионе кода (см. описание функций adi_int_EnterCriticalRegion и adi_int_ExitCriticalRegion). Если это так, то сохраненное значение IMASK соответственным образом обновляется, и текущее действующее в пределах защищенной секции значение IMASK остается неизменным.

После вызова самой последней функции adi_int_ExitCriticalRegion из вложенных критического регионов кода, восстанавливается сохраненное значение IMASK с новыми настройками для бит. Если при входе в adi_int_ClearIMaskBits процессор не находится в критическом регионе кода, то соответствующим образом обновляется сразу действующее значение регистра IMASK.

Информацию о подробностях реализации для этой функции в других рабочих окружениях можно найти в файле adi_int_xxx.c, размещенной в каталоге blackfin/lib/src/services/int, где xxx указывает на целевое рабочее окружение.

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

void adi_int_SetIMASKBits(ADI_INT_IMASK BitsToSet);

Аргумент:

BitsToSet Маска для битов регистра IMASK, значение которых должно быть установлено в 0. Бит в маске, установленный в 1, задает установку соответствующего бита в регистре IMASK. Бит в маске, заданный в 0, не окажет влияния на соответствующий бит в регистре IMASK.

Функция adi_intSICWakeup() конфигурирует системный контроллер прерываний (system interrupt controller, SIC) так, чтобы разрешить или запретить выводить и сна процессор для указанного прерывания периферийного устройства.

Функция adi_int_SICWakeup просто соответствующим образом программирует контроллер SIC. Она не влияет на актуальную обработку прерываний.

ADI_INT_RESULT adi_int_SICWakeup(const ADI_INT_PERIPHERAL_ID PeripheralID,
                                 u32 WakeupFlag);

Аргументы:

PeripheralID Значение из перечисления ADI_INT_PERIPHERAL_ID, которая идентифицирует источник прерывания (аппаратное периферийное устройство процессора).
WakeupFlag Разрешает/запрещает пробуждение ядра (или ядер) процессора при поступлении прерывания от указанного периферийного устройства.

Возвращаемые значения:

ADI_INT_RESULT_SUCCESS SIC был успешно сконфигурирован.
ADI_INT_RESULT_INVALID_PERIPHERALID Указан недопустимый идентификатор PeripheralID.

Функция adi_int_SICGlobalWakeup() используется для программирования регистра пробуждения (wakeup register) системного контроллера прерываний (system interrupt controller, SIC), чтобы запретить всем прерываниям периферийных устройств делать пробуждение ядра процессора, или для восстановления регистра пробуждения SIC в предыдущее состояние.

Если в флаг передано FALSE, то эта функция сохраняет содержимое SIC interrupt wakeup register в структуре ADI_INT_WAKEUP_REGISTER, на которую указывает аргумент функции. SIC interrupt wakeup register программируется так, что ни для одного прерывания не разрешается разбудить ядро (все биты этого регистра обнуляются).

Если в флаг передано TRUE, то эта функция программирует SIC wakeup register значениями полей из структуры ADI_INT_WAKEUP_REGISTER, на которую ссылается параметр указателя функции. Предполагается, что эти значения были получены предыдущем вызовом функции adi_int_SICGlobalWakeup.

Функция adi_int_SICGlobalWakeup никак не влияет на актуальную обработку прерываний.

ADI_INT_RESULT adi_int_SICGlobalWakeup(u32 WakeupFlag,
                                       pADI_INT_WAKEUP_REGISTER SaveIWR);

Аргументы:

WakeupFlag Разрешает/запрещает пробуждение ядра (или ядер) процессора при поступлении прерываний от периферийных устройств.
SaveIWR Указатель на структуру, используемую для сохранения состояния регистра wakeup. Структура определена в соответствии с типом процессора в файле adi_int.h.

Возвращаемое значение:

ADI_INT_RESULT_SUCCESS Значение регистра wakeup контролера SIC было успешно запрограммировано в соответствии с аргументами функции.

[Ссылки]

1. VisualDSP++ 5.0 Device Drivers and System Services Manual for Blackfin® Processors site:analog.com.
2. ADSP-BF538: обработка событий (прерывания, исключения).
3. VDK: обработчики прерываний (ISR).