В этой статье приведен перевод раздела "Timer Service" из документации "VisualDSP++ 5.0 Device Drivers and System Services Manual for Blackfin® Processors" [1]. Описывается Служба Таймеров, предоставляющая простой в использовании интерфейс программирования (API) для доступа к таймеру ядра, сторожевому таймеру (watchdog), таймерам общего назначения процессора Blackfin.
Рассматриваются следующие вопросы:
• Общее описание работы Службы Таймеров • Интерфейс программирования (API) • Публичные типы данных, перечисления и макросы
Используя возможности других системных служб, Служба Таймеров позволяет клиенту управлять всеми таймерами и координировать их работой стандартным способом, независимо от используемого целевого процессора. Служба Таймеров также предоставляет для клиентов такую функцию, как callback, позволяющую оповещать о событиях истечения заданного времени таймера.
Прим. переводчика: под "клиентом" подразумевается код программы приложения или код потока (для многопоточных приложений).
Для поддержки всех функций Службы Таймеров требуется использование Менеджера Прерываний [2] и Менеджера DCB [3]. Если вызовы callback-функций делаются не откладываемыми, а немедленно исполняемыми в обработчике прерывания таймера, то Менеджер DCB не нужен. Если callback-функции не нужны, то тогда не нужен ни Менеджер Прерываний, ни Менеджер DCB.
Чтобы уменьшить необходимое количество ножек корпуса процессора, выводы таймеров иногда совмещаются на тех же выводах, которые используют другие периферийные устройства. Служба Таймеров не предоставляет функционал арбитража для управления мультиплексированием вывода процессора. Поэтому программа клиента должна гарантировать, чтобы периферийное устройство и Служба Таймеров не использовали один и тот же вывод одновременно. Для процессоров ADSP-BF531, ADSP-BF532, ADSP-BF533 и процессоров ADSP-BF561, это требует гарантии корректной установки соответствующих регистров управления периферийными устройствами. Для ADSP-BF534, ADSP-BF536, ADSP-BF537 (и будущих) процессоров Служба Таймеров автоматически привлекает службу управления портами, чтобы повлиять на любые изменения в мультиплексоре вывода. При этом никакое вмешательство пользователя не требуется.
Служба Таймеров использует недвусмысленное соглашение об именовании, обеспечивающее отсутствие конфликтов имен с другими программными библиотеками от Analog Devices или других источников кода. Все значения перечислений и операторы typedef используют префикс ADI_TMR_, и функции и глобальные переменные используют эквивалентный префикс в нижнем регистре adi_tmr_.
Каждая функция в интерфейсе программирования (API) Службы Таймеров возвратит код ошибки из перечисления типа ADI_TMR_RESULT. Как и у всех системных служб, возвращаемое значение 0 (ADI_TMR_RESULT_SUCCESS) показывает отсутствие ошибок. Не нулевое значение показывает ошибку. Как и у всех системных служб, коды ошибок Службы Таймеров являются уникальными, отличающимися от всех других системных служб. Подключаемый файл adi_tmr.h перечисляет все коды ошибки, которые возвращает Служба Таймеров.
Проверка параметров в отладочных версиях библиотеки Системных Служб предоставляют более полный тест параметров API-функции и условий, которые могут привести к ошибкам. Компания Analog Devices настоятельно рекомендует разрабатывать приложения с помощью debug-версий библиотеки Системных Служб, и заключительное тестирование и окончательную разработку следует выполнять на release-версии библиотеки.
[Общее описание работы Службы Таймеров]
В этом разделе описаны общие принципы работы Службы Таймеров. Подробное описание каждой функции см. в разделе "Интерфейс программирования (API) Службы Таймеров".
Инициализация Службы Таймеров. Перед использованием Службы Таймеров клиент должен должен сначала её инициализировать. Для этого клиент передает функции инициализации adi_tmr_Init() параметр, который передается функции критического региона, чтобы защитить регион кода. Также опционально в функцию инициализации передается непрерывный блок памяти, чтобы служба могла использовать функции обратного вызова (callback).
Если клиент задал использование callback-функции, то её вызов будет срабатывать, когда время таймера истекло. См. секцию "Функции обратного вызова (callback)" для получения дополнительной информации о функционировании callback-ов. В отличие от других системных служб, когда клиент предоставляет службе память, чтобы она могла работать, Служба Таймеров не требует никакой дополнительной памяти.
Завершение работы Службы Таймеров. Когда клиенту больше не нужна функциональность Службы Таймеров, вызывается функция завершения adi_tmr_Terminate(). Эта функция деинсталлирует все инсталлируемые callback-и таймеров и закрывает все открытые таймеры.
Идентификаторы таймеров (Timer ID). Всем функциям API Службы таймеров, кроме функций инициализации и завершения, передается параметр, который идентифицирует управляемый таймер. Подключаемый файл для службы таймеров adi_tmr.h, задает идентификаторы таймеров, поддерживаемые используемым процессором. Параметр timer ID определен как тип u32, но это не простое значение перечисления. В действительности timer ID это комплексное значение, которое содержит информацию, специфичную для таймера, и которую можно объединить операцией ИЛИ таким образом, что несколько таймеров можно разрешить или запретить одновременно.
Базовые функции таймеров. Функции, описанные в этом разделе, являются общими для всех типов таймеров: таймеры общего назначения, таймер ядра, сторожевой таймер. В эти функции может быть передан любой индивидуальный идентификатор таймера (timer ID), независимо от того, к какому таймеру этот идентификатор относится - таймеру общего назначения, таймеру ядра или сторожевому таймеру.
adi_tmr_Open. Функция adi_tmr_Open() вызывается, чтобы открыть таймер. В зависимости от используемого процессора Blackfin, эта функция инициализирует аппаратуру, необходимую для работы таймера. Эта функция также сбрасывает таймер в его настройки по умолчанию. См. также описание функции во врезке adi_tmr_Open.
adi_tmr_Close. Когда таймер больше не нужен вызывается функция adi_tmr_Close(), чтобы закрыть и выключить таймер. В настоящее время для всех процессоров Blackfin эта функция ничего не делает, а только возвращает управление в вызывающий код. Будущие типы процессоров Blackfin могут потребовать от этой функции каких-нибудь манипуляций с аппаратурой, когда закрывается таймер. См. также описание функции во врезке adi_tmr_Close.
adi_tmr_Reset. Если приложение должно сбросить таймер в настройки по умолчанию в любое время, а не когда таймер открывается, оно использует функцию adi_tmr_Reset(). Регистры конфигурации таймера сбрасываются в свое значение по умолчанию, которое устанавливается при включении питания, статус ошибки очищается, и т. д. См. также описание функции во врезке adi_tmr_Reset.
Функции таймеров общего назначения. В этой секции описаны функции, применяемые только для обычных таймеров. Как правило, в процессоре Blackfin таких таймеров несколько. Эти функции вернут ошибку, если в них будет передан неправильный идентификатор таймера, такой как core timer ID или watchdog timer ID.
adi_tmr_GPControl. Функция adi_tmr_GPControl() конфигурирует таймер общего назначения. В эту функцию передается timer ID, идентификатор команды (command ID), указывающий адресуемый параметр функции, и параметр, зависящий от команды. Список идентификаторов команд, применимый для таймеров общего назначения и соответствующие командам параметры описаны во врезке ADI_TMR_GP_CMD. См. также описание функции во врезке adi_tmr_GPControl.
adi_tmr_GPGroupEnable. Функция adi_tmr_GPGroupEnable() разрешает или запрещает таймер общего назначения или сразу группу таймеров общего назначения. В эту функцию передается параметр, в котором задан либо один идентификатор таймера, либо сразу несколько, объединенных друг с другом операцией ИЛИ. Также передается флаг, показывающий, что нужно сделать с таймером или группой таймеров - разрешить (если значение флага TRUE) или запретить (если значение флага FALSE).
Эта функция предпринимает все возможные меры, чтобы одновременно разрешить или запретить группу таймеров. Если нижележащая аппаратура определенного процессора Blackfin позволяет для таймеров одновременное управление, то функция предпринимает необходимые действия для одновременного разрешения или запрета таймеров. Если же нижележащая аппаратура не позволяет для указанного таймера одновременное управление, то функция пытается разрешить или запретить таймеры максимально быстро, как это только возможно. См. также описание функции во врезке adi_tmr_GPGroupEnable.
Функции таймера ядра. Описанные в этой секции функции используются только для таймера ядра (core timer).
adi_tmr_CoreControl. Функция adi_tmr_CoreControl() используется для конфигурирования таймера ядра. Аналогично функции управления таймерами общего назначения, эта функция принимает идентификатор команды, указывающую адресуемый параметр функции, и параметр, зависящий от команды. Список команд, применимых к таймеру ядра, и соответствующих зависящих от команды параметров описан во врезке ADI_TMR_CORE_CMD.
См. также описание функции во врезке adi_tmr_CoreControl.
Функции сторожевого таймера. Описанные в этой секции функции используются только для сторожевого таймера (watchdog timer).
adi_tmr_WatchdogControl. Функция adi_tmr_WatchdogControl() конфигурирует сторожевой таймер. Аналогично функциям управления таймерами общего назначения и таймером ядра, эта функция принимает идентификатор команды, указывающую адресуемый параметр функции, и параметр, зависящий от команды. См. также описание функции во врезке adi_tmr_WatchdogControl.
Список команд, применимых к сторожевому таймеру, и соответствующих зависящих от команды параметров описан во врезке ADI_TMR_WDOG_CMD.
Функции таймеров периферийного устройства. Функции, описанные в этой секции, используются только для таймеров общего назначения и сторожевого таймера. Передача идентификатора таймера ядра в эти функции приведет к ошибке, которая будет возвращена в вызывающий код.
adi_tmr_GetPeripheralID. Функция adi_tmr_GetPeripheralID() может быть вызвана, чтобы определить идентификатор периферийного устройства (peripheral ID) для указанного таймера. Хотя эта функция обычно не нужна, она все-таки может быть полезна, если требуется более изощренная логика управления прерыванием, чем может быть предоставлена Службой Таймеров. Значение peripheral ID может быть передано в функции обслуживания прерывания. Имейте в виду, что таймер ядра не имеет связанного peripheral ID, потому что таймер ядра привязан к фиксированному уровню IVG. Несмотря на это, идентификатор таймера ядра может быть передан в эту функцию, и она не возвратит код ошибки. См. также описание функции во врезке adi_tmr_GetPeripheralID.
Функции обратного вызова (callback). Как и другие системные службы, Служба Таймеров использует механизм callback-ов, чтобы оповещать клиента об асинхронных событиях, таких как истечение времени таймера. Callback-и могут использоваться для всех типов таймеров: таймеры общего назначения, таймер ядра, сторожевой таймер.
Таймеры процессора Blackfin могут конфигурироваться для генерации прерываний. Служба Таймеров предоставляет внутренний обработчик прерывания (ISR), который обрабатывает прерывания от аппаратуры таймеров. Этот ISR делает соответствующие вызовы в callback-функции клиентского приложения. Когда клиент устанавливает callback на таймер, параметр для функции установки диктует, как будет использоваться callback-немедленно (live) или его выполнение будет отложено (deferred). Live callback-и выполняются прямо в контексте обработчика прерывания, а отложенные callback-и выполняются после завершения ISR, с меньшим приоритетом, с помощью Службы DCB [3].
Когда используется возможность callback для Службы Таймеров, клиентам не надо предпринимать никакие программные действия вне API Службы Таймеров. Не требуется делать вызовы Менеджера Прерываний [2] или Службы DCB [3], кроме инициализации этих служб при необходимости.
Обратите внимание, что для клиентов доступны все возможности Службы Таймеров, и можно не использовать любую из возможностей callback-функции.
adi_tmr_InstallCallback. Функция adi_tmr_InstallCallback() используется для установки callback для указанного таймера. В дополнение к идентификатору таймера (timer ID), клиент предоставляет флаг пробуждения (wakeup flag), адрес callback-функции, хендл клиента и хендл Службы DCB.
Флаг пробуждения задает, должен ли процессор выходить из состояния пониженного энергопотребления (low-power state), когда происходит событие таймера.
Адрес callback-функции задает функцию обратного вызова типа ADI_DCB_CALLBACK_FN (см. описание Менеджера DCB [3] для получения подробной информации). Будучи вызванной, callback-функция получает следующие 3 параметра:
• ClientHandle – значение, предоставленное клиентом при инсталляции callback • ADI_TMR_EVENT_TIMER_EXPIRED – показывает, что произошло событие callback таймера • TimerID – идентификатор таймера, который сгенерировал вызов callback
Когда функции установки callback adi_tmr_InstallCallback был передан параметр хендла Службы DCB, равный NULL, callback-функция будет выполняться немедленно (live), прямо в коде ISR. Если же хендл Службы DCB не NULL, то Служба Таймеров использует Службу DCB для запуска callback-функции.
Одна callback-функция может быть установлена и использована для любого количества таймеров; при этом callback-функция может использовать параметр TimerID, чтобы определить, какой таймер сгенерировал callback. Однако обратите внимание, что что на определенный таймер может быть инсталлирована только одна callback-функция.
Функция установки callback не изменяет управление таймером. Подробнее см. описание функции во врезке adi_tmr_InstallCallback.
adi_tmr_RemoveCallback. Функция adi_tmr_RemoveCallback() используется при удалении callback-а для указанного таймера. Эта функция запрещает генерацию для таймера и удаляет callback из внутренних таблиц. Для этого таймера больше не будут срабатывать callback-и, пока не будет выполнена повторная установка callback. Функция удаления callback не меняет управление таймером. Подробнее см. описание функции во врезке adi_tmr_RemoveCallback.
В этой врезке приведены примеры кода, иллюстрирующие, как получить доступ к таймерам и использовать их функционал через Службу Таймеров. Этот пример инициализирует Службу Таймеров, конфигурирует несколько таймеров общего назначения, таймер ядра и сторожевой таймер. Также показано использование callback-ов. Все функции Службы Таймеров возвращают коды ошибки, которые на практике должны быть проверены, чтобы убедиться в успешном завершении функции. Приведенные здесь примеры кода не делают этих проверок.
Инициализация. Перед использованием Службы Таймеров она должна быть инициализирована. Следующий фрагмент инициализирует эту службу.
ADI_TMR_RESULT Result; // возвращаемое значение
Result = adi_tmr_Init(NULL);
После завершения этой функции Служба Таймеров инсталлирована и готова к использованию. Эта функция не меняет ничего в настройках таймеров, она просто инициализирует внутренние структуры данных.
Открытие таймера. После того, как служба инициализирована, можно открыть любые таймеры, которые нужны. В этом примере кода будут открыты 2 таймера общего назначения, таймер ядра и сторожевой таймер.
Result = adi_tmr_Open(ADI_TMR_GP_TIMER_0);
Result = adi_tmr_Open(ADI_TMR_GP_TIMER_1);
Result = adi_tmr_Open(ADI_TMR_CORE_TIMER);
Result = adi_tmr_Open(ADI_TMR_WDOG_TIMER);
Функция открытия сбросит таймер в настройки по умолчанию, какие таймер получает после включения питания или сброса процессора, с очисткой любых ожидающих обработки состояний и т. д.
Конфигурирование таймера. После того, как таймер открыт, его можно сконфигурировать. Функции adi_tmr_GPControl(), adi_tmr_CoreControl() и adi_tmr_WatchdogControl() используются для конфигурирования таймеров общего назначения, таймера ядра и сторожевого таймера соответственно.
Каждой из этих функций предоставляется идентификатор команды, обычно задающей параметр для управления и значение параметра. Обратите внимание, что функции, управляющей таймером общего назначения, передается также и идентификатор таймера (потому что таймеров общего назначения в процессоре несколько). Команды для таймеров могут быть заданы индивидуально или совместно, как таблица.
Result = adi_tmr_CoreControl(ADI_TMR_CORE_CMD_TABLE,
CoreTable);
Result = adi_tmr_GPControl(ADI_TMR_GP_TIMER_0,
ADI_TMR_GP_CMD_SET_PERIOD,
(void*)0x800000);
Result = adi_tmr_GPControl(ADI_TMR_GP_TIMER_0,
ADI_TMR_GP_CMD_SET_WIDTH,
(void*)0x400000);
Result = adi_tmr_GPControl(ADI_TMR_GP_TIMER_0,
ADI_TMR_GP_CMD_SET_TIMER_MODE,
(void*)0x1);
Result = adi_tmr_GPControl(ADI_TMR_GP_TIMER_1,
ADI_TMR_GP_CMD_SET_PERIOD,
(void*)0x800000);
Result = adi_tmr_GPControl(ADI_TMR_GP_TIMER_1,
ADI_TMR_GP_CMD_SET_WIDTH,
(void*)0x400000);
Result = adi_tmr_GPControl(ADI_TMR_GP_TIMER_1,
ADI_TMR_GP_CMD_SET_TIMER_MODE,
(void*)0x1);
Result = adi_tmr_WatchdogControl(ADI_TMR_WDOG_CMD_EVENT_SELECT,
(void*)0x0);
Result = adi_tmr_WatchdogControl(ADI_TMR_WDOG_CMD_SET_COUNT,
(void*)0x12345678);
Обратите внимание, что в вышеприведенном фрагменте был разрешен таймер ядра и сразу будучи сконфигурированным, и таймеры общего назначения, и сторожевой таймер разрешены не были. Любой таймер может быть разрешен через таблицу команд, обычно последней записью в таблице. В целях иллюстративного примера разрешение сторожевого таймера и таймеров общего назначения показаны отдельно в секции "Разрешение и запрет таймеров".
Разрешение и запрет таймеров. После того, как таймер был сконфигурирован, его можно разрешить. Когда используется таблица команд, таймер может быть разрешен через команду в таблице, как показано в секции "Конфигурирование таймера". Обычно команда для разрешения таймера будет последней в таблице. Альтернативно таймеры могут быть разрешены отдельным вызовом подходящей управляющей функции. Далее таймеры общего назначения могут быть разрешены и запрещены группой.
Следующий фрагмент показывает, как разрешить сторожевой таймер и затем одновременно (группой) разрешить таймеры общего назначения 0 и 1.
Result = adi_tmr_WatchdogControl(ADI_TMR_WDOG_CMD_ENABLE_TIMER, (void*)TRUE);
Result = adi_tmr_GPGroupEnable(ADI_TMR_GP_TIMER_0 | ADI_TMR_GP_TIMER_1, TRUE);
Когда таймер запрещен, он может быть запрещен как часть таблицы команд (хотя это маловероятно). Чаще таймеры запрещаются через один вызов управляющей функции. Также , как и было в разрешении таймеров общего назначения, эти таймеры могут быть запрещены одновременно (группой). Следующий фрагмент кода иллюстрирует, как запретить сторожевой таймер и одновременно запретить сразу 2 таймера 0 и 1.
Result = adi_tmr_WatchdogControl(ADI_TMR_WDOG_CMD_ENABLE_TIMER, (void*)FALSE);
Result = adi_tmr_GPGroupEnable(ADI_TMR_GP_TIMER_0 | ADI_TMR_GP_TIMER_1, FALSE);
Установка callback-функции. Хотя приложения могут установить аппаратные обработчики прерывания (ISR), чтобы напрямую обработать прерывания от таймеров (см. описание Менеджера Прерываний [2]), Служба Таймеров предоставляет простой, легкий в использовании механизм callback-функций, предоставляющий эквивалентный функционал.
Следующий фрагмент кода иллюстрирует, как инсталлировать callback-функцию. Можно использовать отдельные функции для каждого таймера, или можно использовать одну callback-функцию для любого количества таймеров. Этот фрагмент показывает установку одной callback-функции для двух таймеров общего назначения, таймера ядра и сторожевого таймера. Оператор switch в callback-функции идентифицирует, какой таймер сгенерировал вызов callback-функции.
...
Result = adi_tmr_InstallCallback(ADI_TMR_GP_TIMER_0, TRUE,
(void*)0x00000000, NULL, Callback);
Result = adi_tmr_InstallCallback(ADI_TMR_GP_TIMER_1, TRUE,
(void*)0x11111111, NULL, Callback);
Result = adi_tmr_InstallCallback(ADI_TMR_CORE_TIMER, TRUE,
(void*)0x22222222, NULL, Callback);
Result = adi_tmr_InstallCallback(ADI_TMR_WDOG_TIMER, TRUE,
(void*)0x33333333, NULL, Callback);
...
void Callback(void*ClientHandle, u32 Event, void*pArg)
{
// Event = ADI_TMR_EVENT_TIMER_EXPIREDswitch ((u32)pArg)
{
case ADI_TMR_GP_TIMER_0:
// Здесь делается обработка события истечения времени таймера общего назначения 0.// ClientHandle = 0x00000000break;
case ADI_TMR_GP_TIMER_1:
// Здесь делается обработка события истечения времени таймера общего назначения 1.// ClientHandle = 0x11111111break;
case ADI_TMR_CORE_TIMER:
// Здесь делается обработка события истечения времени таймера ядра.// ClientHandle = 0x22222222break;
case ADI_TMR_WDOG_TIMER:
// Здесь делается обработка события истечения времени сторожевого таймера.// ClientHandle = 0x33333333break;
}
}
Когда запускается callback-функция, её параметр ClientHandle получает значение, заданное при установке callback-а, параметр Event равен ADI_TMR_EVENT_TIMER_EXPIRED, и параметр pArg содержит идентификатор таймера, который вызвал срабатывание callback-а. Этот пример передает NULL для хендла Службы DCB, чем задается немедленный (live) вызов callback-а для таймеров.
Удаление callback-ов. Когда приложению больше не нужен callback, его можно удалить без влияния на другие настройки таймера. Следующий фрагмент кода иллюстрирует, как удалять callback-и.
Result = adi_tmr_RemoveCallback(ADI_TMR_GP_TIMER_0);
Result = adi_tmr_RemoveCallback(ADI_TMR_GP_TIMER_1);
Result = adi_tmr_RemoveCallback(ADI_TMR_CORE_TIMER);
Result = adi_tmr_RemoveCallback(ADI_TMR_WDOG_TIMER);
Вызовы callback-функции больше не будут производиться, и функции callback сами по себе будут удалены их Службы Таймеров.
Завершение. Когда больше не требуется функциональность, предоставляемая Службой Таймеров, приложение завершает эту службу. Следующий фрагмент кода завершает работу Службы Таймеров.
Result = adi_tmr_Terminate();
После завершения Служба Таймеров должна быть инициализирована повторно, если снова нужно вызвать какую-нибудь её функцию.
[Интерфейс программирования (API)]
В этом разделе предоставлено описание интерфейса программирования Службы Таймеров (API).
! Приведенная здесь информация была точна на момент создания этого документа. Однако следует проверить содержимое подключаемого файла adi_tmr.h Службы Таймеров, чтобы получить текущую версию информации.
Хендл на область данных, содержащих критический регион данных. Это передается в функцию adi_int_EnterCriticalRegion, что используется внутри модуля. Подробнее см. описание Менеджера Прерываний [2].
Возвращаемые значения:
ADI_TMR_RESULT_SUCCESS
Служба Таймеров успешно инициализирована.
любое другое значение
Произошла ошибка. См. коды ошибок во врезке ADI_TMR_RESULT.
Функция adi_tmr_Open() открывает таймер. Регистры таймера сбрасываются в свои значения по умолчанию (power-up values, которые они получают при включении питания или сбросе процессора), условия информации состояния очищаются, и т. д. Будущие модели Blackfin могут потребовать эту функцию для выполнения дополнительных действий по некоторым манипуляциям аппаратурой при открытии таймера.
! На многоядерных процессорах Blackfin каждое ядро имеет собственный таймер ядра. Однако сторожевой таймер и таймеры общего назначения являются общими для ядер. Когда Служба Таймеров работает на многоядерных процессорах, убедитесь, что несколько ядер не пытаются одновременно использовать один и тот же сторожевой таймер и один и тот же таймер общего назначения.
ADI_TMR_RESULT adi_tmr_Open (u32 TimerID);
Аргумент:
TimerID
Значение перечисления, уникально идентифицирующее таймер для открытия.
Возвращаемые значения:
ADI_TMR_RESULT_SUCCESS
Операция успешно завершена.
любое другое значение
Произошла ошибка. См. коды ошибок во врезке ADI_TMR_RESULT.
Функция adi_tmr_Terminate() закрывает Службу Таймеров. Любые установленные callback-и удаляются. После завершения службы функция инициализации должна быть вызвана повторно, чтобы снова стали доступны функции Службы Таймеров.
ADI_TMR_RESULT adi_tmr_Terminate (void);
Возвращаемые значения:
ADI_TMR_RESULT_SUCCESS
Операция успешно завершена.
любое другое значение
Произошла ошибка. См. коды ошибок во врезке ADI_TMR_RESULT.
Функция adi_tmr_Close() вызывается приложением, когда таймер больше не нужен. В настоящее время эта функция ничего не делает (это просто заглушка, немедленно возвращающая управление). Будущие модели процессоров Blackfin могут потребовать от этой функции неких манипуляций над аппаратурой при закрытии таймера.
ADI_TMR_RESULT adi_tmr_Close (u32 TimerID);
Аргумент:
TimerID
Значение перечисления, уникально идентифицирующее таймер для закрытия.
Возвращаемые значения:
ADI_TMR_RESULT_SUCCESS
Операция успешно завершена.
любое другое значение
Произошла ошибка. См. коды ошибок во врезке ADI_TMR_RESULT.
Функция adi_tmr_Reset() сбрасывает регистры таймера в их значения по умолчанию (power-up values, которые получают регистры таймера при включении питания или сбросе процессора). При этом будут очищены любые индикаторы статуса, ожидающие обработки (флаги прерываний и т. д.). Поскольку функция adi_tmr_Reset вызывается внутри функции adi_tmr_Open, приложению редко когда нужно вызывать adi_tmr_Reset.
ADI_TMR_RESULT adi_tmr_Reset (u32 TimerID);
Аргумент:
TimerID
Значение перечисления, уникально идентифицирующее таймер для сброса.
Возвращаемые значения:
ADI_TMR_RESULT_SUCCESS
Операция успешно завершена.
любое другое значение
Произошла ошибка. См. коды ошибок во врезке ADI_TMR_RESULT.
Функция adi_tmr_GPGroupEnable() одновременно разрешает или запрещает сразу несколько таймеров общего назначения (групповая операция). Эта функция предпринимает все усилия для того, чтобы одновременно разрешить или запретить группу таймеров. Если нижележащая аппаратура какого-либо определенного процессора Blackfin позволяет управлять одновременно сразу всеми указанными таймерами, то это будет сделано. Если же аппаратура не позволяет одновременного управления указанными таймерами, то такое управление таймерами будет выполнено по очереди, максимально быстро, как только это возможно.
Обратите внимание, что в зависимости от определенного процессора Blackfin, когда разрешается таймер (таймеры), эта функция дополнительно конфигурирует мультиплексирование портов, основываясь на конфигурационных настройках таймера.
Например, на процессорах ADSP-BF534, ADSP-BF536, ADSP-BF537 (и будущих моделях), если таймер общего назначения сконфигурирован как таймер PWM (ШИМ) с активным выходным выводом, то эта функция конфигурирует логику управления порта через службу управления портами, чтобы разрешить аппаратное функционирования вывода TMRx. На процессорах ADSP-BF531, ADSP-BF532, ADSP-BF533 и ADSP-BF561 processors, не требуется управлять логикой управления портами. От пользователя не требуется никаких действий со службой управления портами.
Значения из перечисления, соединенные в группу операцией ИЛИ (может быть задана групповая операция для одного или нескольких таймеров общего назначения).
EnableFlag
Значение TRUE задает разрешить работу таймера (или группы таймеров), FALSE означает запретить работу таймера (таймеров).
Возвращаемые значения:
ADI_TMR_RESULT_SUCCESS
Функция успешно завершена.
любое другое значение
Произошла ошибка. См. коды ошибок во врезке ADI_TMR_RESULT.
Функция adi_tmr_InstallCallback() устанавливает callback-функцию, которая будет запущена, когда истечет время таймера. Обратите внимание, что функция, предоставленная клиентом, это именно callback-функция, на обработчик прерывания (не ISR). Функция установки callback никак не меняет конфигурацию таймера, его значения и т. п.
Значение из перечисления, уникально идентифицирующее таймер, для которого устанавливается callback.
WakeupFlag
Если срабатывает событие, этот флаг задает, будет ли выведен процессор из режима пониженного энергопотребления.
ClientHandle
Идентификатор, определенный и предоставленный клиентом. Это значение будет передано в callback-функцию.
DCBHandle
В этом параметре указывается NULL, если вызов callback должен быть немедленным (прямо из обработчика прерывания), или здесь должен быть хендл на Службу DCB, в этом случае callback будет вызван отложено, после завершения обработчика аппаратного прерывания (ISR).
ClientCallback
Адрес клиентской callback-функции.
Возвращаемые значения:
ADI_TMR_RESULT_SUCCESS
Функция обратного вызова успешно установлена.
любое другое значение
Произошла ошибка. См. коды ошибок во врезке ADI_TMR_RESULT.
Функция adi_tmr_RemoveCallback() удаляет callback от указанного таймера. Эта функция никак не меняет конфигурацию таймера, значение его счетчика и регистров, и т. д.
! Вызов adi_tmr_RemoveCallback из тела callback-функции не поддерживается и может привести к непредсказуемому поведению.
Функция adi_tmr_GetPeripheralID() может быть вызвана для определения идентификатора периферийного устройства (peripheral ID) для указанного таймера. Хотя эта функция обычно не требуется, она может быть полезной для реализации более изощренной логики управления прерыванием, чем предоставляет Служба Таймеров. Идентификатор периферийного устройства может быть передан в функции из тела обработчика прерывания. Обратите внимание, что таймер ядра не имеет связанного с ним идентификатора периферийного устройства, потому что таймер ядра привязан к жестко заданному уровню IVG. Однако в эту функцию может быть передан идентификатор таймера ядра, и функция не вернет кода ошибки.
Значение из перечисления, уникально идентифицирующее таймер.
pPeripheralID
Указатель на ячейку, куда будет сохранено значение идентификатора периферийного устройства таймера.
Возвращаемые значения:
ADI_TMR_RESULT_SUCCESS
Функция обратного вызова успешно установлена.
любое другое значение
Произошла ошибка. См. коды ошибок во врезке ADI_TMR_RESULT.
[Публичные типы данных, перечисления и макросы]
В этом разделе приведены определения структур данных и перечислений, используемых Службой Таймеров.
! Всегда проверяйте содержимое файла подключаемого заголовка adi_tmr.h, чтобы получить самую актуальную информацию.
Идентификаторы таймеров (Timer ID). Служба Таймеров предоставляет уникальный идентификатор для каждого таймера. Timer ID это 32-битные значения, которые не просто индекс; вместо этого они представляют комбинацию из двух информационных частей. Биты 31..27 в timer ID это индекс, перечисляющий каждый таймер в системе, включая таймеры общего назначения, таймер ядра и сторожевой таймер. Биты 26..0 используются только для таймеров общего назначения, формируя маску, чтобы можно было их разрешать и запрещать одновременно, групповой операцией.
В файле adi_tmr.h предоставлены макросы для создания timer ID, для доступа к значениям бит 26..0 и для доступа к значениям бит 31..27. Эти макросы используются внутри Службы Таймеров, и обычно они не нужны для применения в приложениях. Однако, когда приложению нужно опросить все таймеры общего назначения, идентификаторы timer ID могут быть созданы макросом ADI_TMR_CREATE_GP_TIMER_ID(x), где x это число от 0 до числа ADI_TMR_GP_TIMER_COUNT-1.
Например, следующий фрагмент кода иллюстрирует, как открыть все таймеры общего назначения.
u32 i, TimerID;
ADI_TMR_RESULT Result;
for (i =0; i < ADI_TMR_GP_TIMER_COUNT; i++)
{
TimerID = ADI_TMR_CREATE_GP_TIMER_ID(i);
Result = adi_tmr_Open(TimerID);
}
Для большинства функций в API Службы Таймеров значение timer ID передается в функцию для идентификации адресуемого таймера. Однако функция adi_tmr_GPGroupEnable() может в качестве параметра получить одно значение timer ID, или сразу несколько значений timer ID, объединенных друг с другом операцией ИЛИ. Структура значений timer ID позволяет в одном передаваемом параметре для функции идентифицировать сразу несколько таймеров общего назначения.
Связанные макросы. Эти макросы определены для использования Службой Таймеров.
ADI_TMR_CREATE_GP_TIMER_ID
Создает timer ID для указанного индекса таймера общего назначения.
ADI_TMR_CREATE_CORE_TIMER_ID
Создает timer ID для указанного индекса таймера ядра.
ADI_TMR_CREATE_WDOG_TIMER_ID
Создает timer ID для указанного индекса сторожевого таймера.
ADI_TMR_GET_TIMER_INDEX
Получает индекс таймера по указанному timer ID.
ADI_TMR_GET_GP_TIMER_MASK
Получает маску для указанного одного timer ID или для логического ИЛИ нескольких timer ID.
Каждый вызов API-функции Службы Таймеров возвратит значение из перечисления типа ADI_TMR_RESULT в качестве кода возврата. Подобно всем системным службам, код успешного завершения определен как 0, и код обычной ошибки определен как 1. Это позволяет вызывающей функции быстро оценить код возврата проверкой его на нулевое или не нулевое значение.
Полное описание кодов возврата для Службы Таймеров начинается со значения ADI_TMR_ENUMERATION_START, чтобы упростить идентификацию.
Мнемоника
Код
Описание
ADI_TMR_RESULT_SUCCESS
0
Обычный успешный результат вызова.
ADI_TMR_RESULT_FAILED
1
Обычная неудача вызова.
ADI_TMR_RESULT_NOT_SUPPORTED
Операция не поддерживается.
ADI_TMR_RESULT_BAD_TIMER_ID
0x70002
Недопустимое значение timer ID.
ADI_TMR_RESULT_BAD_TIMER_IDS
0x70003
Недопустимые значения timer ID.
ADI_TMR_RESULT_BAD_TIMER_TYPE
Операция не подходит для предоставленного timer ID.
Перечисление ADI_TMR_EVENT определяет тип произошедшего события callback. Имеется только одно значение, ADI_TMR_EVENT_TIMER_EXPIRED. Этот тип перечисления отличается от всех других типов событий системных служб, благодаря для всех системных служб можно использовать только один универсальный callback, независимо от того, какое событие обрабатывается. Коды событий для Службы Таймеров начинается со значения ADI_TMR_ENUMERATION_START, чтобы упростить идентификацию.
В таблице 8-1 перечислены команды, которые можно выполнить для таймера ядра. Эти идентификаторы команды (command ID) передаются как параметр в функцию adi_tmr_CoreCommand(). В дополнение к command ID, параметр Value (типа void *) также передается в функцию. Смысл параметра Value зависит от передаваемого значения идентификатора команды. Таблица 8-1 также описывает параметр Value для каждого идентификатора команды.
Таблица 8-1. Команды, выполняемые для Core Timer.
Command ID
Value
Описание
ADI_TMR_CORE_CMD_TABLE
ADI_TMR_CORE_CMD_VALUE_PAIR *
Начало таблицы команд.
ADI_TMR_CORE_CMD_END
игнорируется
Конец таблицы команд.
ADI_TMR_CORE_CMD_PAIR
ADI_TMR_CORE_CMD_VALUE_PAIR *
Пара команд.
ADI_TMR_CORE_CMD_SET_ACTIVE_MODE
TRUE - активный режим FALSE - пониженное энергопотребление
Устанавливает для таймера активный режим или режим экономии питания.
ADI_TMR_CORE_CMD_ENABLE_TIMER
TRUE - разрешен FALSE - запрещен
Разрешает или запрещает работу таймера.
ADI_TMR_CORE_CMD_SET_AUTO_RELOAD
TRUE - автоперезагрузка FALSE - нет автоперезагрузки
Разрешает или отменяет автоматическую загрузку значения таймера.
ADI_TMR_CORE_CMD_HAS_INTERRUPT_OCCURRED
u32 * TRUE - разрешено FALSE - запрещено
Показывает, было ли прерывание таймера.
ADI_TMR_CORE_CMD_RESET_INTERRUPT_OCCURRED
игнорируется
Очистка индикатора о том, что было прерывание таймера.
В таблице 8-2 перечислены команды, которые можно выполнить для сторожевого таймера. Эти идентификаторы команды (command ID) передаются как параметр в функцию adi_tmr_WatchdogCommand(). В дополнение к command ID, параметр Value (типа void *) также передается в функцию. Смысл параметра Value зависит от передаваемого значения идентификатора команды. Таблица 8-2 также описывает параметр Value для каждого идентификатора команды.
Таблица 8-2. Команды, выполняемые для Watchdog Timer.
Command ID
Value
Описание
ADI_TMR_WDOG_CMD_TABLE
ADI_TMR_WDOG_CMD_VALUE_PAIR *
Начало таблицы команд.
ADI_TMR_WDOG_CMD_END
игнорируется
Конец таблицы команд.
ADI_TMR_WDOG_CMD_PAIR
ADI_TMR_WDOG_CMD_VALUE_PAIR *
Пара команд.
ADI_TMR_WDOG_CMD_EVENT_SELECT
0 - сброс 1 - NMI 2 - прерывание общего назначения 3 - нет события
Устанавливает тип события, которое происходит при истечении сторожевого таймера.
ADI_TMR_WDOG_CMD_ENABLE_TIMER
TRUE - разрешен FALSE - запрещен
Разрешает или запрещает работу таймера.
ADI_TMR_WDOG_CMD_HAS_EXPIRED
u32 * TRUE - разрешено FALSE - запрещено
Показывает, было ли истечение времени таймера.
ADI_TMR_WDOG_CMD_RESET_EXPIRED
игнорируется
Очистка индикатора о том, что было истечение времени таймера.
ADI_TMR_WDOG_CMD_GET_STATUS
u32 *
Сохраняет текущее значение счетчика таймера в указанную ячейку памяти.
ADI_TMR_WDOG_CMD_SET_COUNT
u32
Устанавливает значение счетчика таймера.
ADI_TMR_WDOG_CMD_RELOAD_STATUS
u32 *
Перезагружает регистр состояния из значения регистра счетчика.
В таблице 8-3 перечислены команды, которые можно выполнить для таймеров общего назначения. Эти идентификаторы команды (command ID) передаются как параметр в функцию adi_tmr_GPCommand(). В дополнение к command ID, параметр Value (типа void *) также передается в функцию. Смысл параметра Value зависит от передаваемого значения идентификатора команды. Таблица 8-3 также описывает параметр Value для каждого идентификатора команды.
Таблица 8-3. Команды, выполняемые для General-Purpose Timer-ов.
Command ID
Value
Описание
ADI_TMR_GP_CMD_TABLE
ADI_TMR_GP_CMD_VALUE_PAIR *
Начало таблицы команд.
ADI_TMR_GP_CMD_END
игнорируется
Конец таблицы команд.
ADI_TMR_GP_CMD_PAIR
ADI_TMR_GP_CMD_VALUE_PAIR *
Пара команд.
ADI_TMR_GP_CMD_SET_PERIOD
u32
Устанавливает значение периода для таймера (записывает значение Value в регистр TIMERx_PERIOD).
ADI_TMR_GP_CMD_GET_PERIOD
u32 *
Сохраняет текущее значение периода таймера в указанную ячейку памяти (читает значение регистра TIMERx_PERIOD).
ADI_TMR_GP_CMD_SET_WIDTH
u32
Указывает значение ширины импульса для таймера (записывает значение Value в регистр TIMERx_WIDTH).
ADI_TMR_GP_CMD_GET_WIDTH
u32 *
Сохраняет текущее значение ширины импульса для таймера в указанную ячейку памяти (читает значение регистра TIMERx_WIDTH).
ADI_TMR_GP_CMD_GET_COUNTER
u32 *
Сохраняет текущее значение счетчика таймера в указанную ячейку памяти (читает регистр TIMERx_COUNTER).
Устанавливает режим работы таймера (записывает Value в поле TMODE регистра TIMERx_CONFIG).
ADI_TMR_GP_CMD_SET_PULSE_HI
TRUE - положительное действие импульса FALSE - отрицательное действие импульса
Устанавливает действие импульса для таймера. Записывает бит PULSE_HI регистра TIMERx_CONFIG). Если выход TMRx разрешен, и если Value=false (по умолчанию), то по окончанию счета на выходе TMRx будет лог. 1. Если TMRx разрешен, и если Value=true, то по окончании счета на выходе TMRx будет лог. 0.
ADI_TMR_GP_CMD_SET_COUNT_METHOD
TRUE - счет до окончания периода FALSE - счет до окончания ширины импульса
Устанавливает метод счета. Записывает поле PERIOD_CNT регистра TIMERx_CONFIG. Если Value=true, то в режиме PWM на выходе TMRx (если он разрешен) может аппаратно, без участия процессора, формироваться частота.
Разрешает или запрещает вывод TMRx. Записывает поле OUT_DIS регистра TIMERx_CONFIG. По умолчанию ножка выхода TMRx разрешена.
ADI_TMR_GP_CMD_SET_CLOCK_SELECT
TRUE - PWM_CLK FALSE - SCLK
Выбирает вход тактов для таймера. Записывает поле CLK_SEL регистра TIMERx_CONFIG. По умолчанию для таймера используется частота тактирования системной шины (SCLK, соответствует Value=false).
ADI_TMR_GP_CMD_SET_TOGGLE_HI
TRUE - PULSE_HI меняется на каждом периоде FALSE - использовать запрограммированное состояние
Устанавливает режим переключения. Записывает поле TOGGLE_HI регистра TIMERx_CONFIG.
ADI_TMR_GP_CMD_RUN_DURING_EMULATION
TRUE - таймер работает в режиме эмуляции FALSE - таймер не считает в режиме эмуляции
Разрешает или запрещает таймер, когда процессор обрабатывает прерывание эмулятора. Записывает поле EMU_RUN регистра TIMERx_CONFIG.
ADI_TMR_GP_CMD_GET_ERROR_TYPE
u32 * 0 - нет ошибки 1 - переполнение счета 2 - ошибка регистра периода 3 - ошибка регистра ширины
Сохраняет тип произошедшей ошибки в указанную ячейку памяти.
ADI_TMR_GP_CMD_IS_INTERRUPT_ASSERTED
u32 * TRUE - выставлено FALSE - не выставлено
Сохраняет состояние выставления прерывания в указанную ячейку памяти.
ADI_TMR_GP_CMD_CLEAR_INTERRUPT
игнорируется
Очищает прерывание таймера.
ADI_TMR_GP_CMD_IS_ERROR
u32 * TRUE - ошибка FALSE - нет ошибки
Сохраняет информацию об ошибке в указанную ячейку памяти.
ADI_TMR_GP_CMD_CLEAR_ERROR
игнорируется
Очистка состояния ошибки таймера.
ADI_TMR_GP_CMD_IS_SLAVE_ENABLED
u32 * TRUE - разрешено FALSE - запрещено
Сохраняет состояние подчиненного устройства в указанную ячейку памяти.
ADI_TMR_GP_CMD_IMMEDIATE_HALT
игнорируется
Немедленно останавливает таймер в режиме PWM.
ADI_TMR_GP_CMD_ENABLE_TIMER
TRUE - разрешен FALSE - запрещен
Разрешает или запрещает работу таймера. Записывает нужный бит в регистр TIMER_ENABLE или TIMER_DISABLE.
ADI_TMR_GP_CMD_SET_ENABLE_DELAY
u32
Количество тактов SCLK для задержки между разрешением каждого таймера.