Blackfin: библиотека службы RTC Печать
Добавил(а) microsin   

В этой статье приведен перевод документации [1] с описанием части библиотек системных служб (system services library, SSL), касающейся аппаратных часов реального времени (real-time clock, RTC). Такие часы встроены в большинство моделей процессоров Blackfin (в настоящий момент кроме двухядерных процессоров семейства Teton [2]). Интерфейс программирования (API) библиотеки службы RTC позволяет генерировать и обслуживать события RTC стандартным, универсальным способом - так же, как обслуживаются события и ресурсы других системных служб.

Служба RTC предоставляет простой для использования API. В дополнение к чтению и записи данных и времени, служба позволяет приложению стандартным способом координировать 8 разных событий RTC, независимо от модели процессора Blackfin. Можно разрешить 5 периодических событий, возникающих каждую секунду, каждую минуту, каждый час, каждые сутки (в полночь), и каждые сутки в определенное время. Есть событие будильника, возникающее в определенную дату и время. Также есть события обратного отсчета секунд (stopwatch), которое происходит по истечении заданного промежутка времени. И еще есть событие, которое сигнализирует о завершении всех ожидающих записей в регистры RTC (об этом подробнее далее, также см. [3]).

В этой документации описаны базовые операции со службой RTC, интерфейс программирования (API) и инструкции для инициализации и использования службы RTC в клиентском приложении.

Отладочная версия библиотеки SSL (она компилируется с заданным макроопределением ADI_SSL_DEBUG) предоставляет проверку параметров функций API и другие возможные условия возникновения ошибок. Analog Devices настоятельно рекомендует использовать при разработке ПО отладочные версии библиотеки, и после процедуры тестирования библиотека может быть скомпилирована в версии релиза (без макроопределения ADI_SSL_DEBUG).

[Работа службы RTC]

Инициализация службы RTC. Перед использованием службы RTC приложение должно инициализировать эту службу вызовом функции adi_rtc_Init(). В отличие от некоторых системных служб, которые требуют от приложения предоставления памяти для службы на этапе инициализации, служба RTC не требует для этого дополнительной памяти. Единственный параметр, передаваемый в функцию adi_rtc_Init(), это параметр критического региона кода, который может использоваться позже, если Менеджер Прерываний [4] вызывался с настройкой защиты критических областей кода. В текущей реализации системных служб для этого параметра используется нулевой указатель NULL (в большинстве примеров в качестве параметра передается макрос ADI_SSL_ENTER_CRITICAL, определенный в заголовке adi_ssl_Init.h как NULL). Для дополнительной информации см. "Protecting Critical Code Regions" [1]. Также см. [5].

Перед инициализацией службы RTC приложение также должна инициализировать Менеджер Прерываний с помощью функции adi_int_Init(). Если используется отложенный вызов callback-функций (вместо немедленного, в контексте прерывания), то также необходимо инициализировать Менеджер Отложенных Вызовов (deferred callback, DCB) путем запуска функции adi_dcb_Init() (см. [6]).

Некоторые регистры аппаратуры RTC (memory-mapped registers, MMR) имеют определенные ограничения, связанные с тем, что запись в них должна осуществляться только 1 раз в течение одного цикла 1 Гц. Значение, записанное в такой MMR, не войдет в действие до наступления следующего тика 1 Гц, и последующее значение, записанное в тот же самый регистр до наступления этого следующего тика, будет отброшено. Служба RTC реализует механизм кэширования таких регистров, решающий эту проблему, чем гарантируется отсутствие потери необходимого функционала. При этом приложение не должно напрямую обращаться к регистрам MMR RTC, полностью полагаясь только на вызовы API-функций службы RTC.

Как только приложение вызвало adi_rtc_Init(), кэши регистров RTC очищаются. Устанавливается бит прескалера, чтобы счетчик часов срабатывал с дискретностью 1 Гц (подразумевается, что к выводам RTXI и RTXO подключен кварц на 32.768 кГц [3]), как происходит у обычных часов. Инициализируется среда callback-вызовов RTC, и регистр флагов событий RTC очищается, тем самым сбрасываются все события RTC, ожидающие обработки. Обработчик прерываний RTC (ISR) подцепляется к цепочке приоритета IVG, и служба RTC становится готовой к работе. Прерывания RTC в этот момент инициализированы для пробуждения процессора (вывода его из режимов пониженного энергопотребления). Если такое поведение не нужно, то приложение может вызвать API-функцию adi_rtc_DisableWakeup().

Завершение работы службы RTC. Когда приложению больше не нужен функционал службы RTC, оно вызывает функцию завершения adi_rtc_Terminate(). Эта функция удаляет все установленные callback-вызовы с очисткой всех определенных статически структур данных.

Установка и чтение даты и времени. Для установки даты и времени служба RTC предоставляет API-функцию adi_rtc_SetDateTime(). Для использования этой функции приложение декларирует структуру типа tm (определена в заголовочном файле time.h).

struct tm {
   int tm_sec;
   int tm_min;
   int tm_hour;
   int tm_mday;
   int tm_mon;
   int tm_year;
   int tm_wday;
   int tm_yday;
   int tm_isdst;
};

Приложение устанавливает поля этой структуры значениями месяца, дня, года, часа, минуты и секунды, и передает указатель на эту структуру в функцию adi_rtc_SetDateTime(). Функция преобразует предоставленные в структуре tm данные в 32-битный целочисленный формат, и загружает полученные данные в регистр RTC_STAT, где аппаратура RTC отсчитывает реальные время и дату. Ниже на картинке показана структура регистра RTC_STAT [3]. Каждое поле в структуре tm представлено диапазоном бит в регистре RTC_STAT.

adi rtc RTC STAT structure

Функцию adi_rtc_SetDateTime() нужно вызвать только 1 раз, однако возможны и последующие повторные вызовы. Установленные дата и время вступят в действие на следующем тике 1 Гц, и время будет автоматически увеличиваться на 1 секунду с каждым тиком 1 Гц, пока предоставляется питание VDDRTC (обычно это маломощная литиевая батарейка на 3V [3]). Приложение может обращаться к API-функциям RTC для получения текущей даты и времени, или может установить callback-вызовы для обслуживания событий RTC.

Служба RTC предоставляет API-функцию adi_rtc_GetDateTime(), которая позволяет приложению получить текущие дату и время из MMR-регистра RTC_STAT. Для использования этой функции приложение декларирует структуру типа tm, и передает указатель на неё в функцию adi_rtc_GetDateTime. Функция adi_rtc_GetDateTime считывает дату и время из регистра RTC_STAT, и преобразует прочитанные данные, возвращая их в структуре tm.

Служба RTC поддерживает часы реального времени только в тех рамках, которые предоставляет аппаратура RTC. Служба не делает подстройку часов на летнее время, также не делается учет зон времени. Приложение может само довольно просто осуществить такие коррекции времени, поскольку дата и время сохраняется в структуре tm для совместимости со стандартными функциями времени, которые можно найти в VisualDSP C/C++ Compiler Run-Time Library.

[События RTC]

Служба RTC предоставляет механизм для обработки заранее определенных событий, обслуживаемых на уровне прерываний во время обычного выполнения кода программы. Каждое событие (event) идентифицируется уникальным числом (Event ID), эти числа определены в заголовочном файле adi_rtc.h. Приложение предоставляет callback-функцию для обработки события. Служба RTC также предоставляет механизм для установки и удаления callback-функций, и запуск callback-функций, когда наступают соответствующие этой функции события аппаратуры RTC. Всего поддерживается 8 разных событий RTC. Приложение разрешает обработку нужного события путем вызова функции adi_rtc_InstallCallback(), в которую передается значение Event ID.

Периодическое событие секунды. Приложение может разрешить возникновение прерывания, когда изменяется счетчик секунд в регистре RTC_STAT. Это событие прерывания разрешается, когда приложение вызывает функцию adi_rtc_InstallCallback() передавая в неё значение аргумента ADI_RTC_EVENT_SECONDS. Это событие становится разрешенным, и прерывания будут периодически возникать каждую секунду, пока приложение не запретит это событие передачей аргумента ADI_RTC_EVENT_SECONDS в функцию adi_rtc_RemoveCallback().

Периодическое событие минуты. Приложение может разрешить возникновение прерывания, когда изменяется счетчик минут в регистре RTC_STAT. Это событие прерывания разрешается, когда приложение вызывает функцию adi_rtc_InstallCallback() передавая в неё значение аргумента ADI_RTC_EVENT_MINUTES. Это событие становится разрешенным, и прерывания будут периодически возникать каждую минуту, пока приложение не запретит это событие передачей аргумента ADI_RTC_EVENT_MINUTES в функцию adi_rtc_RemoveCallback().

Периодическое событие часа. Приложение может разрешить возникновение прерывания, когда изменяется счетчик часов в регистре RTC_STAT. Это событие прерывания разрешается, когда приложение вызывает функцию adi_rtc_InstallCallback() передавая в неё значение аргумента ADI_RTC_EVENT_HOURS. Это событие становится разрешенным, и прерывания будут периодически возникать каждый час, пока приложение не запретит это событие передачей аргумента ADI_RTC_EVENT_HOURS в функцию adi_rtc_RemoveCallback().

Периодическое событие дня (суток). Приложение может разрешить возникновение прерывания, когда наступает полночь при изменении счетчика суток в регистре RTC_STAT. Это событие прерывания разрешается, когда приложение вызывает функцию adi_rtc_InstallCallback() передавая в неё значение аргумента ADI_RTC_EVENT_DAYS. Это событие становится разрешенным, и прерывания будут периодически возникать каждые сутки, пока приложение не запретит это событие передачей аргумента ADI_RTC_EVENT_DAYS в функцию adi_rtc_RemoveCallback().

Периодические или однократные события обратного отсчета времени. Приложение может настроить событие stopwatch на возникновение прерывания, когда истечет заданный период времени (заданный в секундах). Одно и то же событие stopwatch может быть либо периодическим, либо однократным. Событие становится разрешенным, когда приложение передает аргумент ADI_RTC_EVENT_STOPWATCH в функцию adi_rtc_InstallCallback(), также передавая при этом количество секунд для заданной длительности времениn. По умолчанию событие stopwatch происходит только однократно (one-shot stopwatch event). Callback-функция может тогда либо запретить это событие передачей аргумента ADI_RTC_EVENT_STOPWATCH в функцию adi_rtc_RemoveCallback(), или может повторно разрешить событие stopwatch путем вызова функции adi_rtc_ResetStopwatch(). Если событие stopwatch заново разрешено таким образом, то оно становится периодическим.

Однократное событие будильника. Приложение может разрешить событие будильника (alarm event), которое однократно вызовет прерывание в указанный день и указанное время. Это событие прерывания разрешается, когда приложение передает аргумент ADI_RTC_EVENT_ONCE_ALM в функцию adi_rtc_InstallCallback(), передавая при этом также и структуру tm, содержащую дату и время срабатывания будильника. После того, как произойдет событие будильника, callback может быть удален передачей аргумента ADI_RTC_EVENT_ONCE_ALM в функцию adi_rtc_RemoveCallback(). Тогда может быть запланировано другое такое же событие путем повторной установки callback. После установки планирования этого события можно путем удаления callback отменить его до того, как событие сработает.

Периодическое событие будильника. Приложение может разрешить прерывания будильника, которое будет срабатывать каждый день (сутки) в указанное время, пока будильник не будет запрещен. Это событие прерывания становится разрешенным, когда приложение передает аргумент ADI_RTC_EVENT_EACH_DAY_ALM в функцию adi_rtc_InstallCallback(), передавая также структуру tm, где содержится время дня, на которое настраивается будильник. Это событие остается разрешенным, и прерывание будет происходить каждые сутки в указанное время, пока приложение не вызовет функцию adi_rtc_RemoveCallback(), передав в неё аргумент ADI_RTC_EVENT_EACH_DAY_ALM.

Событие завершения записи в MMR RTC. Все операции записи в MMR-регистры RTC_STAT, RTC_ALARM, RTC_SWCNT и RTC_ICTL синхронизируются с тиками 1 Гц. Приложению иногда необходимо оповещение, что такая запись завершилась. Для этой цели можно разрешить прерывание, когда завершились все ожидающие синхронизации записи в регистры RTC. Это событие становится разрешенным, когда приложение передает аргумент ADI_RTC_EVENT_WRITES_COMPLETE в функцию adi_rtc_InstallCallback(). Событие остается разрешенным до тех пор, пока приложение не запретит это событие путем вызова функции adi_rtc_RemoveCallback() с аргументом ADI_RTC_EVENT_WRITES_COMPLETE.

[Callback-функции]

Приложение может разрешить события RTC и обрабатывать их путем определения и установки callback для этого события. Callback это просто функция (так называемая функция обратного вызова), связанная с определенным событием или группой событий, и которая вызывается всякий раз, когда происходит связанное событие. Для каждого события можно написать отдельную callback-функцию, или можно написать одну callback-функцию, которая будет обрабатывать все события RTC, фильтруя события с помощью оператора case. Если callback-функция не является "отложенного" типа (deferred), то она выполняется в контексте подпрограммы обработки прерывания (ISR). Этот ISR работает как часть службы RTC, и вызывается из Менеджера Прерываний всякий раз, когда возникло одно из возможных событий RTC. Служба RTC предоставляет функцию для установки callback-ов, функцию для удаления callback-ов, и обработчик, который запускает callback-функции. Приложение, в свою очередь, предоставляет callback-функцию (или несколько callback-функций), которая управляет обработкой каждого события, и также не обязательную структуру данных, состоящую из специфической для события информации, которая передается в callback-функцию из обработчика службы RTC. На первый взгляд все это кажется запутанным и непонятным, однако позже будет приведен поясняющий пример кода, где демонстрируется, как используется эта структура.

Список callback-функций. Для обработки callback-ов служба RTC хранит таблицу (список) с записями по каждому из 8 событий. Каждая запись хранит указатель на callback-функцию, или NULL, если соответствующий callback не был установлен. Когда приложение вызывает функцию adi_rtc_InstallCallback, передавая в неё Event ID, служба RTC вставляет указатель на callback-функцию в запись списка событий. Когда происходит это событие, обработчик RTC использует запись для нахождения и выполнения callback-функции, привязанной к этому событию. Когда приложение вызывает adi_rtc_RemoveCallback для запрета события, указатель на callback-функцию удаляется из списка callback для этого события.

Установка callback. Чтобы установить callback для одного из событий RTC, приложение просто вызывает API-функцию adi_rtc_InstallCallback, передавая в неё Event ID. Для некоторых событий, таких как будильники и события stopwatch, в эту функцию передается еще и другая информация (время срабатывания будильника или длительность периода stopwatch). Функция adi_rtc_InstallCallback использует эту информацию для конфигурирования аппаратных регистров RTC, чтобы в заданное время генерировалось прерывание. Опциональная структура данных ClientHandle также передается в функцию adi_rtc_InstallCallback, где содержится информация, сохраняемая в callback-списке, и передаваемая в callback-функцию при её вызове.

Удаление callback. Приложение может запретить обработку события путем передачи Event ID в качестве параметра в функцию adi_rtc_RemoveCallback. Эта функция удаляет callback из callback-списка для этого события, и также конфигурирует аппаратные регистры RTC, чтобы для этого события больше не происходило прерывание.

Обработчик прерывания RTC. У службы RTC есть обработчик прерывания, который "подцеплен в цепочку" группы вектора прерываний (interrupt vector group, IVG). Обработка таких цепочек осуществляется Менеджером Прерываний. Обратите внимание на разницу между обработчиком прерывания, определенном в службе RTC, и обработчиком прерывания (interrupt service routine, ISR), который определен в Менеджере Прерываний для обработки события определенного уровня IVG. ISR Менеджера Прерываний выполнит обработчик прерывания RTC, когда произойдет необходимое событие аппаратуры RTC. Обработчик прерывания читает флаги событий в регистре RTC_ISTAT, чтобы определить источник, который вызвал прерывание. Затем этот обработчик просматривает callback-список на предмет поиска записи для этого события (см. выше "Список callback-функций"). Эта запись укажет на callback-функцию, и на её параметр ClientHandle (см. далее "Использование в callback-функции параметра ClientHandle"). Этот обработчик выполнит callback с передачей ей параметра ClientHandle. Когда callback завершится, управление перейдет в обработчик прерывания RTC, который в свою очередь вернет управление Менеджеру Прерываний.

Использование в callback-функции параметра ClientHandle. В функцию adi_rtc_InstallCallback также передается как аргумент структура опциональных данных, которая называется ClientHandle. Это определяемая пользователем структура, где содержится специфическая для события информация, которая сохраняется в записи callback-списка вместе с указателем на callback-функцию. Когда происходит событие, Менеджер Прерываний выполнит обработчик прерывания RTC. Этот обработчик прерывания использует callback-список для поиска адреса callback-функции и информации ClientHandle, которая должна быть передана в эту callback-функцию.

[Пример]

Вместе с установкой VisualDSP++ 5.0 предоставляется проект примера PeriodicStopwatch (также есть и другие примеры использования службы RTC: EachDayAlarm, OnceAlarm, OneShotStopwatch, RTCPeriodicDays, RTCPeriodicHours, RTCPeriodicMinutes, RTCPeriodicSeconds, SetGetDateTime). Пример PeriodicStopwatch демонстрирует использование функций adi_rtc_InstallCallback и adi_rtc_RemoveCallback для установки события stopwatch и его обработки в callback-функции. Также демонстрируется использование функции adi_rtc_ResetStopwatch для повторного разрешения события stopwatch, и использование ClientHandle для удобного управления обработкой события, чтобы периодическое событие stopwatch происходило каждые 5 секунд в течение 20 секунд, и затем все останавливалось.

В следующем примере кода определена структура данных STOPWATCH_INFO, у которой есть 3 информационных поля, по указателю на структуру вся эта информация передается в callback. Первое поле показывает, что это событие периодическое. Второе поле показывает количество секунд, которое callback-функция использует, когда заново разрешает stopwatch-событие (в этом примере 5). Третье поле говорит, сколько раз нужно повторно разрешать stopwatch-событие (в этом примере 3). Если это поле установлено в 0, то событие повторяется непрерывно. Аргумент ClientHandle используется, чтобы передать эту структуру данных в функцию adi_rtc_InstallCallback.

typedef struct
{
   // Должны ли эти callback-вызовы быть периодическими,
   // или вызов должен быть однократным:
   u32 PeriodicFlag;
   // Значение для записи в регистр обратного отсчета stopwatch,
   // когда stopwatch-событие повторно разрешается:
   u32 SecondsCounter;
   // Сколько раз нужно повторно разрешить stopwatch-событие:
   u32 NumRepetitions;
} STOPWATCH_INFO;

В этом примере предоставляется callback-функция RTCCallback, в которой есть оператор switch, обрабатывающий все события RTC (здесь показана только обработка события STOPWATCH). Callback-функция принимает 3 аргумента:

void *ClientHandle
u32 EventID
void *pArg

ClientHandle содержит указатель на структуру, который передается как параметр в функцию adi_rtc_InstallCallback, когда устанавливается callback. Обработчик прерывание передает этот аргумент в callback-функцию, когда происходит прерывание. EventID задает, какое из 8 возможных событий сгенерировало вызов callback, в этом примере событие stopwatch. Аргумент pArg гибкий, указанный как тип void*, и он зарезервирован для передачи любой уместной информации, которая нужна для callback-функции, чтобы обработать событие. Callback выполняет оператор switch по значению EventID, и выполняет ту ветвь case, который соответствует нужному EventID. Для события stopwatch callback-функция видит, что установлен флаг PeriodicFlag, поэтому вызывается функция adi_rtc_ResetStopwatch, чтобы повторно разрешить событие, используя значение количества секунд NumSeconds для установки счетчика stopwatch. Ниже показан код примера из callback-функции, где обрабатывается событие stopwatch.

static void RTCCallback ( void *ClientHandle, u32 Event, void *pArg )
{
   STOPWATCH_INFO CountdownStruct = *(STOPWATCH_INFO*)ClientHandle;
   switch ( (u32)Event )
   {
      /* Событие истечения таймаута stopwatch: */
   case ADI_RTC_EVENT_STOPWATCH:
      /* Инкремент счетчика срабатывания событий stopwatch */
      SWEventCounter++;
      /* Использование полей структуры данных, чтобы определить,
         что все действия завершены */
      /* Если должно быть однократное событие ...*/
      if ( ( CountdownStruct.PeriodicFlag == 0 )
      /* ... или если оно периодическое ... */
      || ( ( CountdownStruct.PeriodicFlag == 1 )
      /* ... но счетчик событий stopwatch достиг последнего повторения */
         && (SWEventCounter == CountdownStruct.NumRepetitions)
      /* Если NumRepetitions == 0, то повторения бесконечны. */
         && (CountdownStruct.NumRepetitions != 0 ) ) )
      {
         adi_rtc_RemoveCallback( ADI_RTC_EVENT_STOPWATCH );
         StopwatchCompleteFlag = 1;
         SWEventCounter = 0;
      }
      else
      {
         /* Ветка else подразумевает, что события периодические, и либо
            количество повторений бесконечное, либо счетчик пока не
            достиг последнего повторения, так что здесь мы повторно
            разрешим событие. */
         adi_rtc_ResetStopwatch( CountdownStruct.SecondsCounter );
      }
      break;
   case ...

В функции main примера callback устанавливается на событие stopwatch. Повторения событий происходят 20 секунд до завершения всех действий. Здесь показаны соответствующие секции функции main.

int main()
{
   int NumSeconds;
   int* pNumSeconds;
   /* Структура для передачи информации при установке stopwatch callback: */
   STOPWATCH_INFO StopwatchCallbackInfo;
   /* И указатель на неё: */
   STOPWATCH_INFO* pStopwatchCallbackInfo;
   /* Инициализация системных служб, включая службу RTC: */
   Result = adi_ssl_Init();
   /* Обнуление флага, сигнализирующего о завершении всех действий: */
   StopwatchCompleteFlag = 0;
   /* Инициализация статического счетчика количества прошедших событий: */
   SWEventCounter = 0;
   /* При повторном разрешении stopwatch будет установлен на 5 секунд: */
   StopwatchCallbackInfo.SecondsCounter = 5;
   /* События stopwatch будут происходить периодически: */
   StopwatchCallbackInfo.PeriodicFlag = 1;
   /* Срабатывания stopwatch будут повторно разрешены 3 раза: */
   StopwatchCallbackInfo.NumRepetitions = 3;
   /* Инициализация указателя на структуру, через которую передается
      информация в callback */
   pStopwatchCallbackInfo = &StopwatchCallbackInfo;
   /* Первый таймаут stopwatch произойдет через то же самое время,
      на которое сбрасывается значение stopwatch, т. е. 5 секунд: */
   NumSeconds = StopwatchCallbackInfo.SecondsCounter;
   /* Установка stopwatch callback: */
   adi_rtc_InstallCallback(ADI_RTC_EVENT_STOPWATCH,
                           (void*)pStopwatchCallbackInfo, NULL, RTCCallback,
                           (void*)NumSeconds);
   /* Ожидание срабатывания события stopwatch. После 5 секунд оно будет
      повторено три раза. */
   while( StopwatchCompleteFlag == 0 );
   /* Сюда код дойдет через 20 секунд. */
   ...
}

[Справочник по API RTC]

В этой секции находится подробная информация по структурам данных и функциям интерфейса программирования (API) службы RTC.

Примечание: эту часть документации, как и описание каждой API-функции, я убрал под спойлер, потому что основное уже было изложено, и самый лучший источник надежной информации по программированию - исходный код, который находится в папках каталога установки VisualDSP++ (см. каталог Examples, ищите модули кода EachDayAlarm.c, OnceAlarm.c, OneShotStopwatch.c, PeriodicStopwatch.c, RTCPeriodicDays.c, RTCPeriodicHours.c, RTCPeriodicMinutes.c, RTCPeriodicSeconds.c, SetGetDateTime.c). Также можете скачать проект целиком для процессора ADSP-BF538F по ссылке [10].

[Нотация и соглашение об именовании]

Чтобы избавиться от возможного конфликта имен с другими программными библиотеками от Analog Devices (или из других источников), служба RTC использует однозначную систему именования имен в коде, когда перечисления получают префикс ADI_RTC_. Функции и глобальные переменные используют аналогичный префикс с символами в нижнем регистре: adi_rtc_.

Каждая функция RTC API возвратит код ошибки типа ADI_RTC_RESULT. Наподобие других служб библиотек SSL возвращаемое нулевое значение (0 = ADI_RTC_RESULT_SUCCESS) показывает отсутствие ошибки (успешное завершение) вызова функции API. Любое другое ненулевое значение показывает какой-то специфичный тип ошибки. Коды ошибок для службы RTC, уникальные и отличающиеся от всех других кодов ошибок библиотек SSL, определены в include-файле adi_rtc.h, так что причину ошибки можно определить по коду ошибки, найденному в этом файле.

Функции API работают с аппаратными MMR-регистрами RTC (читают и записывают их), избавляя программиста от необходимости вникать в излишние подробности. Таблица функций API и их краткое описание:

Функция Назначение
adi_rtc_Init Инициализирует службу RTC.
adi_rtc_Terminate Завершает работу службы RTC.
adi_rtc_SetDateTime Устанавливает текущие дату и время.
adi_rtc_GetDateTime Получает текущие дату и время.
adi_rtc_InstallCallback Настраивает запуск callback-функции при возникновении нужного события RTC.
adi_rtc_RemoveCallback Отменяет запуск callback-функции при возникновении определенного события RTC.
adi_rtc_SetEpoch Устанавливает текущие год, месяц и дату (так называемое "время эпохи").
adi_rtc_GetEpoch Получает текущие год, месяц и дату.
adi_rtc_EnableWakeup Разрешает пробуждение процессора от любого прерывания RTC.
adi_rtc_DisableWakeup Запрещает пробуждение процессора от любого прерывания RTC.
adi_rtc_ResetStopwatch Повторно запускает настроенный обратный отсчет времени.

Каждая из этих API-функций вернет значение типа ADI_RTC_RESULT, которое показывает успех (когда возращено ADI_RTC_RESULT_SUCCESS) или ошибку вызова функции. Коды возврата определены в таблице 11-5. Ниже приведено описание структур и типов данных, используемых в API RTC.

[Типы и перечисления RTC API]

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

Структура tm. Это стандартная для языка C структура для хранения времени, предоставляемая в подключаемом файле time.h системы программирования VisualDSP++ 5.0. В структуре tm находятся поля для секунды, минуты, часа, дня, месяца, года, плюс 3 дополнительные поля, которые не используются службой RTC (см. таблицу 11-2).

Таблица 11-2. Поля структуры tm.

Тип и имя поля Описание поля
int tm_sec Сколько прошло секунд текущей минуты.
int tm_min Сколько прошло минут текущего часа.
int tm_hour Который час суток (0 .. 23).
int tm_mday День месяца (1 .. 31).
int tm_mon Какой месяц, начиная с января.
int tm_year Какой год относительно 1900.
int tm_wday Какой день недели начиная с понедельника (0 .. 6).
int tm_yday Номер дня, начиная от 1 января (0 .. 365).
int tm_isdst Флаг учета летнего времени (службой RTC это поле не учитывается и не обрабатывается).

Когда используются функции adi_rtc_SetDateTime() и adi_rtc_GetDateTime(), используется дата эпохи 1 января 1970 года. Хотя это самая ранняя дата, которая может быть сохранена/прочитана через эти функции, год все еще должен вводиться с использованием стандартной для языка C даты эпохи 1900.

Например, самое малое число, которое можно ввести для этого поля, равно 70. Причина этого в том, поля что года, месяца и дня сохраняются как 15-битный счетчик дней в регистре RTC_STAT, что ограничивает интервал отсчета даты в 32768 дней (примерно 89.5 лет).

Поскольку структура tm стандартная (может использоваться и другими библиотеками, кроме RTC), и аппаратура RTC не поддерживает учет перехода на летнее время, поле tm_isdst в API RTC не используется. Функция adi_rtc_GetDateTime() всегда вернет в этом поле значение 0.

Структура tm используется для совместимости с библиотечными функциями asctime, gmtime, mktime и ctime, которые более подробно описаны в секции "C Run-Time Library reference" документации "VisualDSP++ 5.0 C/C++ Compiler and Library Manual for Blackfin Processors" [7].

ADI_RTC_EPOCH. Эта структура содержит поля для года, месяца и дня. Она используется для опциональной модификации времени эпохи, которая по умолчанию соответствует 1 января 1970 (см. таблицу 11-3).

Таблица 11-3. ADI_RTC_EPOCH.

Тип и имя поля Описание поля
u32 year Год эпохи - [0,*]
u32 month Месяц года эпохи - [1,12]
u32 day День месяца эпохи - [1,31]

Идентификаторы событий (Event ID). Всего есть 8 возможных типов асинхронных событий RTC, используемых как идентификаторы EventID:

Таблица 11-4. Event ID и их описание.

Имя идентификатора Значение Описание события
ADI_RTC_EVENT_SECONDS 0xA0001 Периодическое прерывание каждую секунду.
ADI_RTC_EVENT_MINUTES 0xA0002 Периодическое прерывание каждую минуту.
ADI_RTC_EVENT_HOURS 0xA0003 Периодическое прерывание каждый час.
ADI_RTC_EVENT_DAYS 0xA0004 Периодическое прерывание каждый день (сутки).
ADI_RTC_EVENT_STOPWATCH 0xA0005 Однократное прерывание окончания обратного отсчета секунд.
ADI_RTC_EVENT_EACH_DAY_ALM 0xA0006 Периодическое прерывание будильника, возникающее каждые сутки в одно и то же установленное время.
ADI_RTC_EVENT_ONCE_ALM 0xA0007 Однократное прерывание будильника, которое сработает в определенный день и определенное время.
ADI_RTC_EVENT_WRITES_COMPLETE 0xA0008 Прерывание, сигнализирующее о завершении ожидающей операции записи в регистр RTC.

Коды возврата. Каждая из API-функций службы RTC вернет код результата, который можно транслировать с помощью заголовочного файла adi_rtc.h. Эти коды возврата сведены в таблицу 11-5.

Таблица 11-5. Коды, возвращаемые из функций службы RTC.

Имя кода возврата Значение Описание
ADI_RTC_RESULT_SUCCESS 0 Стандартный успешный возврат.
ADI_RTC_RESULT_FAILED 1 Стандартная, не определенная ошибка.
ADI_RTC_RESULT_START 0xA0000 Ошибка запуска, базовый (начальный код ошибок RTC).
ADI_RTC_ENUMERATION_START
ADI_RTC_RESULT_INVALID_EVENT_ID 0xA0001 Недопустимое значение Event ID.
ADI_RTC_RESULT_INTERRUPT_MANAGER_ERROR 0xA0002 Ошибка, возвращенная из Менеджера Прерываний.
ADI_RTC_RESULT_ERROR_REMOVING_CALLBACK 0xA0003 Для указанного Event ID не был ранее установлен callback.
ADI_RTC_RESULT_CALL_IGNORED 0xA0004 Функция не выполнена.
ADI_RTC_RESULT_NOT_INITIALIZED 0xA0005 Служба RTC не была инициализирована.
ADI_RTC_RESULT_CALLBACK_NOT_INSTALLED 0xA0006 Не был установлен callback.
ADI_RTC_RESULT_DATETIME_OUT_OF_RANGE 0xA0007 Поле структуры tm вышло за пределы.
ADI_RTC_RESULT_SERVICE_NOT_SUPPORTED 0xA0008 Для этого процессора не предусмотрена поддержка службы RTC.
ADI_RTC_RESULT_ALREADY_INITIALIZED 0xA0009 Служба RTC уже была инициализирована.
ADI_RTC_RESULT_CALLBACK_ALREADY_INSTALLED 0xA000A Нельзя дважды установить один и тот же callback.
ADI_RTC_RESULT_CALLBACK_CONFLICT 0xA000B Нельзя одновременно установить callback-и для двух типов будильника.

[Зависимости]

В этой секции описаны взаимные зависимости между службой RTC и другими системными службами библиотеки SSL.

Служба Менеджера Прерываний. Поскольку служба RTC основана на вызове callback-функции для обработки событий, приложение должно инициализировать менеджер прерываний перед тем, как будет инициализирована служба RTC. Внутри функции adi_rtc_Init() вызывается Менеджер Прерываний, чтобы "прицепить" обработчик прерывания RTC, который вызывает callback-функцию. Внутри функции adi_rtc_Terminate() также вызывается Менеджер Прерываний, чтобы "отцепить" обработчик прерываний RTC.

Приложение может выбрать, нужно ли пробуждение процессора от прерывания RTC (генерацию сигнала wakeup, приводящее к выходу процессора из режима пониженного энергопотребления). Служба RTC предоставляет API-функцию adi_rtc_DisableWakeup(), которая вызывает функцию adi_int_SICWakeup() Менеджера Прерываний, передавая ей peripheral ID для RTC и флаг FALSE. Также служба RTC предоставляет API-функцию adi_rtc_EnableWakeup(), которая вызывает вызовет функцию adi_int_SICWakeup() Менеджера Прерываний, передавая ей peripheral ID для RTC и флаг TRUE, что бы все события прерываний RTC приводили к генерации сигнала пробуждения для процессора.

Служба отложенных callback-вызовов. Вызов callback-функции может быть отложен на более благоприятное время (deferred). Это означает, что выполнение callback произойдет позже, позволяя более приоритетному потоку выполниться раньше. В этом случае callback не будет выполняться в контексте обработчика прерывания. Вместо этого обработчик прерывания вызовет adi_dcb_Post(), чтобы оповестить Менеджер Отложенных Вызовов (deferred callback, DCB [6]) о возникновении этого события. Подробнее см. главу 5 "Deferred Callback Manager" документации [1] (также см. [6]), где подробно описано, как DCB-менеджер обрабатывает callback-вызовы.

Функция adi_rtc_Init() инициализирует службу RTC, как это описано ранее в секции "Инициализация службы RTC".

ADI_RTC_RESULT adi_rtc_Init(void *pCriticalRegionArg);

Функция принимает аргумент типа void*, где находится параметр критического региона.

Коды возврата:

ADI_RTC_RESULT_SUCCESS Не было ошибки (успешный возврат).
Любое другое значение Произошла ошибка. Расшифровку возвращенного значения см. в таблице 11-5 (врезка "API службы RTC").

Функция adi_rtc_Terminate() завершает функционирование службы RTC, как это описано ранее в секции "Завершение работы службы RTC".

ADI_RTC_RESULT adi_rtc_Terminate(void);

Коды возврата:

ADI_RTC_RESULT_SUCCESS Не было ошибки (успешный возврат).
Любое другое значение Произошла ошибка. Расшифровку возвращенного значения см. в таблице 11-5 (врезка "API службы RTC").

Функция adi_rtc_SetDateTime() вызывается для программирования даты и времени в регистре RTC_STAT. Новая дата и время вступит в действие по завершении записи, которое наступит на следующем тике 1 Гц [3].

ADI_RTC_RESULT adi_rtc_SetDateTime(struct tm *pDateTime);

Функция принимает один аргумент, указатель на структуру tm, которая определена в файле time.h.

Коды возврата:

ADI_RTC_RESULT_SUCCESS Не было ошибки (успешный возврат).
Любое другое значение Произошла ошибка. Расшифровку возвращенного значения см. в таблице 11-5 (врезка "API службы RTC").

Функция adi_rtc_GetDateTime() вызывается для чтения даты и времени из регистра RTC_STAT.

ADI_RTC_RESULT adi_rtc_GetDateTime(struct tm *pDateTime);

Функция принимает один аргумент, указатель на структуру tm, которая определена в файле time.h.

Коды возврата:

ADI_RTC_RESULT_SUCCESS Не было ошибки (успешный возврат).
Любое другое значение Произошла ошибка. Расшифровку возвращенного значения см. в таблице 11-5 (врезка "API службы RTC").

Функция adi_rtc_InstallCallback() устанавливает callback для события RTC.

ADI_RTC_RESULT adi_rtc_InstallCallback(ADI_RTC_EVENT_ID EventID,
                                       void *ClientHandle,
                                       ADI_DCB_HANDLE DCBHandle,
                                       ADI_DCB_CALLBACK_FN ClientCallback,
                                       void *Value);

Аргументы для функции показаны в таблице 11-1.

Таблица 11-1. Параметры для функции adi_rtc_InstallCallback.

Тип и имя параметра Описание
ADI_RTC_EVENT_ID EventID Значение из перечисления, которое задает событие RTC, для которого устанавливается callback.
void *ClientHandle Идентификатор, определяемый и предоставляемый приложением. Это значение передается в callback-функцию (см. раздел "Пример").
ADI_DCB_HANDLE DCBHandle Дескриптор, возвращенный из службы DCB, если используются отложенные callback-вызовы. Если callback должен вызываться немедленно (в контексте прерывания), то здесь должен быть указан NULL.
ADI_DCB_CALLBACK_FN ClientCallback Имя callback-функции (указатель на эту функцию) клиента
void *Value Служба RTC использует этот параметр при установке callback будильников или для callback обратного отсчета времени (т. е. stopwatch). Здесь задается дата/время (для будильника) или интервал в секундах (для stopwatch). Для установки других видов callback этот параметр не используется (можно передать NULL).

Коды возврата:

ADI_RTC_RESULT_SUCCESS Не было ошибки (успешный возврат).
Любое другое значение Произошла ошибка. Расшифровку возвращенного значения см. в таблице 11-5 (врезка "API службы RTC").

Функция adi_rtc_RemoveCallback() удаляет функционал callback для указанного события. Она сбросит бит в регистре RTC_ICTL, чтобы событие было запрещено.

Вызов adi_rtc_RemoveCallback из callback-функции не поддерживается, и это приведет к неопределенному поведению.

ADI_RTC_RESULT adi_rtc_RemoveCallback(ADI_RTC_EVENT_ID EventID);

Функция принимает один параметр EventID, которое задает одно из 8 возможных событий RTC, для которого callback будет удален. См. таблицу 11-4 (врезка "API службы RTC"), где показаны возможные идентификаторы событий и их назначение.

Коды возврата:

ADI_RTC_RESULT_SUCCESS Не было ошибки (успешный возврат).
Любое другое значение Произошла ошибка. Расшифровку возвращенного значения см. в таблице 11-5 (врезка "API службы RTC").

Функция adi_rtc_SetEpoch() устанавливает только дату, месяц и год (так называемое время эпохи), не затрагивая время.

ADI_RTC_RESULT adi_rtc_SetEpoch(ADI_RTC_EPOCH *pEpoch);

Функция принимает один параметр, указатель на структуру времени эпохи, где заданы новые год, месяц и дата. См. таблицу 11-3 (врезка "API службы RTC"), где описаны поля этой структуры.

Функция adi_rtc_SetEpoch всегда возвратится с успешным результатом ADI_RTC_RESULT_SUCCESS.

Функция adi_rtc_GetEpoch() вернет время эпохи (год, месяц, дату) в предоставленной структуре.

ADI_RTC_RESULT adi_rtc_GetEpoch(ADI_RTC_EPOCH *pEpoch);

Функция принимает один параметр, указатель на структуру времени эпохи, где заданы новые год, месяц и дата. См. таблицу 11-3 (врезка "API службы RTC"), где описаны поля этой структуры.

Функция adi_rtc_GetEpoch всегда возвратится с успешным результатом ADI_RTC_RESULT_SUCCESS.

Функция adi_rtc_EnableWakeup() вызывает Менеджер Прерываний, чтобы разрешить бит RTC в регистре пробуждения контроллера системных прерываний [8]. Вследствие этого все разрешенные события прерывания RTC будут пробуждать процессор (выводить его из режимов пониженного энергопотребления [9]).

ADI_RTC_RESULT adi_rtc_EnableWakeup(void);

Функция не принимает аргументов. Она вызовет функцию adi_int_SICWakeup Менеджера Прерываний, передав ей флаг TRUE.

Коды возврата:

ADI_RTC_RESULT_SUCCESS Не было ошибки (успешный возврат).
Любое другое значение Произошла ошибка. Расшифровку возвращенного значения см. в таблице 11-5 (врезка "API службы RTC").

Функция adi_rtc_DisableWakeup() вызывает Менеджер Прерываний, чтобы запретить бит RTC в регистре пробуждения контроллера системных прерываний [8]. Вследствие этого ни одно из событий прерывания RTC не будут пробуждать процессор (эти прерывания не будут выводить процессор из режимов пониженного энергопотребления [9]).

ADI_RTC_RESULT adi_rtc_DisableWakeup(void);

Функция не принимает аргументов. Она вызовет функцию adi_int_SICWakeup Менеджера Прерываний, передав ей флаг FALSE.

Коды возврата:

ADI_RTC_RESULT_SUCCESS Не было ошибки (успешный возврат).
Любое другое значение Произошла ошибка. Расшифровку возвращенного значения см. в таблице 11-5 (врезка "API службы RTC").

Функция adi_rtc_ResetStopwatch() используется для повторного разрешения события stopwatch (обратный отсчет времени) без переинициализации callback-функции события stopwatch. Функция adi_rtc_ResetStopwatch() может быть вызвана как из callback, так и вне его, однако adi_rtc_ResetStopwatch() не должна вызваться, если соответствующий callback не был установлен. Событие stopwatch однократное ("one-shot"), однако оно может использоваться как периодическое событие, если вызвать эту функцию после того, как возникнет событие stopwatch, и выполнится соответствующий callback (или внутри этого callback). Эта функция установит в регистре RTC_SWCNT отсчитываемое количество секунд NumSeconds, и повторно разрешит событие установкой соответствующего бита в регистре RTC_ICTL.

ADI_RTC_RESULT adi_rtc_ResetStopwatch(u32 NumSeconds);

В функцию передается один параметр, который задает количество секунд периода обратного отсчета. Это время пройдет до следующей генерации события stopwatch.

Коды возврата:

ADI_RTC_RESULT_SUCCESS Не было ошибки (успешный возврат).
Любое другое значение Произошла ошибка. Расшифровку возвращенного значения см. в таблице 11-5 (врезка "API службы RTC").

[Ссылки]

1. VisualDSP++ 5.0 Device Drivers and System Services Manual for Blackfin® Processors site:analog.com.
2Неофициальная классификация семейств процессоров Blackfin.
3ADSP-BF538 RTC.
4VDK: менеджер прерываний.
5Специфика использования VDK для процессоров Blackfin.
6. VDK: менеджер отложенных функций обратного вызова.
7. VisualDSP++ 5.0 C/C++ Compiler and Library Manual for Blackfin Processors site:analog.com.
8. ADSP-BF538: обработка событий (прерывания, исключения).
9. ADSP-BF538: динамическое управление питанием.
10190211TestRTC.zip - исходный код проекта, где демонстрируется служба RTC с ежесекундной генерацией прерывания.