Программирование DSP VDK: драйверы устройств и системные службы процессоров Blackfin Thu, March 28 2024  

Поделиться

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

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

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

Здесь представлен перевод части руководства "VisualDSP++ 5.0 Device Drivers and System Services Manual for Blackfin Processors" [1], где содержится общая информация о модели Драйверов Устройств VDK и наборе библиотечных Системных Служб. В документе [1] представлено описание разработки архитектуры Драйвера Устройства и каждого компонента Системной Службы. Также имеется описание вызовов API каждой библиотеки.

[Общая информация о Системных Службах и Драйверах Устройства]

Системные Службы (system services) формируют набор функций, которые обычно можно найти во встраиваемой системе. Каждая Системная Служба фокусируется на отдельных наборах функционала процессора, таких как прямой доступ к памяти (DMA, см. [3]), управление питанием (power management, PM), управление прерываниями (interrupt control, IC, см. [4]), и т. д. Системные Службы в целом предоставляют богатство готового, оптимизированного кода, который упрощает разработку программного обеспечения, позволяя Вам быстрее выпустить на рынок свой продукт на основе процессора Blackfin.

Драйвер Устройства (device driver). Модель Драйверов Устройства предоставляет простой, ясный и знакомый интерфейс с устройствами процессоров Blackfin (внутренними, находящимися на кристалле, и внешними, находящимися снаружи). Главное назначение модели Драйверов Устройства - создать краткий, эффективный и простой в использовании интерфейс, через который приложение может обмениваться данными с Драйверами Устройства. Кроме того, модель Драйверов Устройства и программное обеспечение Менеджера Устройств (device manager) значительно упрощает написание Драйверов Устройства, делая разработку новых Драйверов Устройства весьма прямолинейной.

В текущем релизе VDK Системные Службы и Драйверы Устройства доступны для следующих процессоров Blackfin:

• ADSP-BF504/504F/506F
• ADSP-BF512/514/516/518
• ADSP-BF522/524/526
• ADSP-BF523/525/527
• ADSP-BF531/532/533
• ADSP-BF534/536/537
• ADSP-BF538/539
• ADSP-BF542/544/547/548/549
• ADSP-BF542M/544M/547M/548M/549M
• ADSP-BF561
• ADSP-BF590/592-A

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

[Обзор Системных Служб (System Services)]

В текущей версии VDK библиотека System Services состоит из следующих служб:

Interrupt Control Service. Служба управления прерываниями позволяет приложениям управлять событиями и прерываниями и более эффективно обрабатывать их [4]. Специальный набор функционала позволяет приложению следующее:

• Устанавливать и детектировать привязки приоритетов к периферийным устройствам процессора.
• Использовать стандартные функции на языке C в качестве обработчиков прерывания (ISR).
• Прицеплять и отцеплять (hook, unhook) несколько обработчиков прерываний к одному уровню приоритета, используя возможностей настройки вложенности прерываний (т. е. прерывания могут быть настроены либо с возможностью вытеснения более высокоприоритетным прерыванием, либо без возможности вытеснения).
• Детектировать, выставлено ли системное прерывание.
• Защищать критические области кода (и отменять их защиту) способом, удобным для портирования.

Power Management Service. Служба управления питанием позволяет приложению динамически управлять энергопотреблением, поддерживая возможности, встроенные в процессор Blackfin. Приложению предоставляются следующие специальные функции:

• Установка рабочих частот для ядра (CCLK) и системной шины (SCLK) с помощью вызовов функций.
• Установка и детектирование настроек внутреннего регулятора напряжения процессора.
• Управление переходами процессора между различными рабочими режимами, включая полное включение (full-on), активный режим (active), сон (sleep) и т. д.

External Bus Interface Unit Control Service (EBIU). Служба управления блоком интерфейса внешней шины предоставляет набор подпрограмм для настройки внешних интерфейсов процессора Blackfin, включая контроллер SDRAM. Эта функциональность позволяет Вам:

• Подстраивать частоту обновления и параметры времени SDRAM на оптимальные значения для имеющихся системных тактовых частот.
• Установка индивидуальных настроек интерфейса шины.
• Полная настройка одной функцией известных конфигураций, таких как платформы плат разработчика Blackfin EZ-KIT Lite®.

Deferred Callback Service. Служба отложенных функций обратного вызова (callback) [5] позволяет приложению быть оповещенным об асинхронных событиях, происходящих вне высокоприоритетных подпрограмм ISR. Использование отложенных обратных вызовов повышает общую емкость ввода/вывода системы, одновременно снижая задержки в обработке прерываний. Специфический функционал позволяет приложению следующее:

• Определить, сколько callback-ов может одновременно ожидать своего вызова.
• Определить уровень приоритета прерывания, с которым выполняется служба callback.
• Создать несколько служб callback, где каждая работает на отдельном, отличающемся уровне приоритета прерываний.
• Публиковать callback-и для службы callback с относительным приоритетом среди всех других callback-ов, опубликованных в пределах одной и той же службы callback.

DMA Management Service. Служба управления DMA [3] предоставляет доступ к контроллеру DMA процессора Blackfin. Служба управления DMA позволяет приложению планировать операции DMA (как для DMA периферийных устройств, так и DMA для пересылок по памяти), с поддержкой как линейных, так и двухмерных типов передач DMA. Специфический функционал позволяет приложению следующее:

• Устанавливать и детектировать привязку каналов DMA к периферийным устройствам.
• Конфигурировать отдельные каналы DMA для входящего/исходящего трафика, используя кольцевые (с автобуферизацией) передачи DMA или передачи на основе дескрипторов.
• Управлять Менеджером DMA, чтобы запускать немедленные или отложенные функции обратного вызова при завершении транзакций DMA.
• Ставить дескрипторы в очередь, смешивая линейные и двухмерные передачи на каналах DMA.
• Разрешить Менеджеру DMA автоматически закольцовывать цепочки дескрипторов.
• Постоянно передавать поток данных либо в память, либо из неё, или либо в периферийное устройство, либо из периферийного устройства.
• Инициировать линейные или двухмерные передачи DMA с помощью простых, в стиле языка C, функций наподобие memcpy.

Programmable Flag Service. Служба программируемых флагов [6] предоставляет простой интерфейс к программируемым флагам процессора Blackfin, что иногда называют интерфейсом ввода/вывода общего назначения (general-purpose I/O, GPIO). Это дает приложению возможность получить доступ к программируемым флагам и управлять ими через ясный и целостный интерфейс. Служба программируемых флагов позволяет приложению следующее:

• Конфигурировать направление для любого флага, чтобы он мог работать либо на вход, либо на выход.
• Установка, сброс и переключение значения для всех выходных флагов.
• Считывать значение для всех входных флагов.
• Устанавливать callback-и, в том числе немедленные и отложенные, когда с любым флагом произойдет любое отдельное событие.

Прим. переводчика: почему-то Analog Devices называет ножки портов ввода/вывода процессора (GPIO) флагами, так что служба программируемых флагов всего лишь отвечает за управление портами ввода/вывода процессора.

Timer Service. Служба таймеров [7] предоставляет приложениям, драйверам и службам простой механизм для управления таймерами общего назначения, таймером ядра и сторожевым таймером процессора Blackfin. Служба таймера позволяет приложению следующее:

• Конфигурировать и управлять любым таймером процессора, включая таймер общего назначения (general-purpose timer, таймер ядра (core timer) и сторожевой таймер (watchdog timer).
• Устанавливать callback-и, включая немедленные (live) и отложенные (deferred), когда происходит событие истечения времени таймера.

Port Control Service. Служба управления портами [8] конфигурирует аппаратуру мультиплексирования вывода соответствующим образом, чтобы гарантировать правильную работу периферийных устройств, которые используют общие выводы процессора для входов и выходов. Все Системные Службы и Драйверы Устройств делают автоматические вызовы к службе port control, чтобы беспрепятственно конфигурировать аппаратуру мультиплексирования вывода без какого-либо вмешательства пользователя или приложения, кроме как вызов инициализации службы.

Device Manager. Модель Драйвера Устройства используется для управления устройствами, что относится как к внутренним устройствам процессора Blackfin, так и к внешним, подключаемым снаружи. Специфический функционал позволяет приложению следующее:

• Открыть (open) и закрыть (close) устройства, используемые приложением.
• Конфигурировать устройства и управлять ими.
• Принимать и передавать данные через устройства, используя различные методы потоков данных.

Real-Time Clock Service. Служба часов реального времени (она недоступна для ADSP-BF561) читает и записывает дату и время, и устанавливает callback-и для различных событий, связанных с часами реального времени (RTC). Служба включает в себя следующие функции:

• Установка текущих даты и времени.
• Чтение текущих даты и времени.
• Установка и чтение времени эпохи.
• Callback-и для одиночного оповещения (alarm), каждодневного оповещения, события секундомера (stopwatch event), ежесекундного события, ежеминутного события, ежечасного события, события дня и события завершения записи регистра.
• Сброс секундомера (stopwatch).
• Разрешение или запрет пробуждения процессора от RTC.

File System Service. Служба файловой системы предоставляет для процессора Blackfin доступ к встроенному носителю данных (embedded mass storage media). Файловая система включает следующие функции:

• Операции с файлами (open, close, read, write, seek, tell, IsEOF, remove, rename).
• Операции с директориями (open, close, read, seek, tell, rewind, change, get current, create, remove).
• Другие операции: получение статуса файла или директории, получение количества томов, получение информации о томе, форматирование тома, оповещение о смене (извлечении и установке) тома, опрос носителя, регистрация / отмена регистрации устройства.
• Операции POSIX: opendir, closedir, readdir, readdir_r, rewinddir, seekdir, telldir, rename, mkdir, rmdir, remove.
• Расширяемость: можно вставить или заменить драйверы для доступа к носителю данных.

Pulse-Width Modulation Service. Служба ШИМ (доступная на некоторых новых процессорах Blackfin) упрощает управление аппаратурой PWM, позволяя генерировать сигналы для управления трехфазным силовым инвертором, что применяется в приложении управления мотором. Служба требует, чтобы приложение выбрало мультиплексирование порта, синхронизацию периода и ширины импульса, мертвое время, скважность, состояние разрешения канала, полярность и рабочий режим. Служба позволяет опциональный выбор импульса синхронизации на выходном выводе, внутренний или внешний импульс синхронизации, синхронный или асинхронный внешний импульс синхронизации, уровни IVG для прерывания изменения уровня и для прерывания синхронизации, режима мертвого времени переключения, режим наложения канала, режим управления ключами и запрет прохождения входного сигнала.

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

Каждый вызов API делается стандартным способом в пределах модели реального времени выполнения для системы разработки на языке C (C run-time model). API каждой службы может быть вызван из любой программы на языке C или на языке ассемблера, если это происходит в соответствии соглашениях о вызовах и использования регистров для C run-time model.

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

Например, нужно ли приложению получать оповещение о том, что была завершена обработка дескриптора DMA, и делает ли приложение запрос на отложенные callback-и? Если да, то в этом случае служба управления DMA вовлекает службу отложенных обратных вызовов (deferred callback service) чтобы применить callback в приложении.

Другой пример - совместная работа службы управления питанием и службы EBIU. Предположим, что в системе есть SDRAM, и приложение требует экономии потребляемой мощности путем замедления ядра путем снижения частот CCLK и SCLK. Когда приложение вызывает службу управления питанием для снижения рабочих частот, то служба управления питанием автоматически привлекает службу EBIU, которая подстраивает частоту обновления SDRAM, чтобы компенсировать снижение частоты системной шины SCLK.

На рис. 1-1 показана текущая коллекция Системных Служб и API-взаимодействие между ними.

VDK System Services and API Interactions

Рис. 1-1. System Services и API-взаимодействие между службами.

Зависимости служб. С некоторыми ограничениями приложения могут использовать любую отдельную службу или комбинацию служб. У приложения не работают со всеми службами. Кроме того, каждой службе не нужно привязывать к себе все ресурсы, связанные с системой, которой управляет служба. Например, Менеджер DMA не нуждается в управлении всеми каналами DMA. Система может быть сконфигурирована так, что Менеджер DMA будет управлять только некоторыми каналами, оставляя приложению или другому программному обеспечению управлять другими каналами DMA (для дополнительной информации по каждой службе см. относящиеся к ней разделы). Однако имеются некоторые зависимости служб, которые разработчик приложения должен учитывать.

Все текущие службы, за исключением службы EBIU, привлекают службу управления прерываниями (interrupt control service) для поддержки обработки прерываний. Службы DMA manager, deferred callback и power management каждая зависит от interrupt control service, чтобы иметь поддержку обработки связанных с ними прерываний. Если приложение указало автоматически подстраивать интервалы времени интерфейса SDRAM, то power management service будет использовать EBIU control service, чтобы повлиять на изменения параметров обращения к SDRAM, когда меняется профиль питания / рабочей тактовой частоты процессора.

Когда конфигурируются отложенные обратные вызовы (deferred callbacks, в противоположность к немедленным или отложенным callback-ам, обрабатываемым во время прерывания) DMA manager задействует возможности deferred callback service, чтобы предоставить отложенные callback-и для приложения. Однако, когда конфигуруются немедленные (live) callback-и, DMA manager не использует deferred callback service.

Инструментарий разработки автоматически определяет эти зависимости и ссылки из исполняемого кода только для тех служб, которые действительно требуются приложением. Поскольку каждая служба собрана как отдельный объектный файл в библиотечном файле Системных Служб, Вы можете дополнительно снизить размер кода в конечном приложении, если зададите линкеру уничтожать неиспользуемые объекты (eliminate unused objects - галочка в настройках проекта, за дополнительной информацией обращайтесь к описанию инструментария разработки).

Инициализация служб. Как уже упоминалось, некоторые Системные Службы полагаются на другие Системные Службы; таким образом, требуется предпочтительная последовательность инициализации служб. Обычно лучше всего инициализировать все службы в одном месте, чаще всего когда инициализируется вся система, вместо того чтобы размазывать во времени инициализацию различных служб.

Для большинства приложений будет оптимальной приведенная ниже последовательность инициализации. Инициализация любой службы в последовательности, которая не используется, может быть просто опущена.

1. Interrupt control service (Менеджер Прерываний [4])
2. External bus interface unit (EBIU)
3. Power management service
4. Port control (Служба Управления Портами [8], если применимо)
5. Deferred callback service (Менеджер DCB [5])
6. DMA manager service (Менеджер DMA [3])
7. Programmable flag service (Служба Программируемых Флагов [6])
8. Timer service (Служба Таймеров [7])
9. Real-time clock service
10. Semaphore service

Код для инициализации Системных Служб можно подсмотреть в функции adi_ssl_Init, которая очень часто используется в примерах кода от Analog Devices (например, для процессоров Blackfin см. проекты в каталоге VisualDSP 5.0\Blackfin\Examples\). В имени функции adi_ssl_Init аббревиатура adi означает Analog Devices, а ssl означает System Services Library (библиотека Системных Служб). Таким образом, функция инициализирует все необходимые для приложения системные службы. Вот пример кода такой функции для процессора Blackfin ADSP-BF538:

#include < services/services.h >
#include < drivers/adi_dev.h >
 
#define ADI_SSL_INT_NUM_SECONDARY_HANDLERS  (4) // количество вторичных обработчиков прерывания (2 SPORT DMA * 2)
#define ADI_SSL_DCB_NUM_SERVERS             (4) // количество серверов DCB
#define ADI_SSL_DMA_NUM_CHANNELS            (2) // количество каналов DMA (SPORT)
#define ADI_SSL_FLAG_NUM_CALLBACKS          (0) // количество callback-ов флагов
#define ADI_SSL_SEM_NUM_SEMAPHORES          (0) // количество семафоров
#define ADI_SSL_DEV_NUM_DEVICES             (2) // количество драйверов устройств (SPORT, AD1980) 
 
ADI_DMA_MANAGER_HANDLE adi_dma_ManagerHandle;   // хендл на Менеджер DMA
ADI_DEV_MANAGER_HANDLE adi_dev_ManagerHandle;   // хендл на Менеджер Устройств
 
static  u8  InterruptServiceData        [ADI_INT_SECONDARY_MEMORY * ADI_SSL_INT_NUM_SECONDARY_HANDLERS];
static  u8  DeferredCallbackServiceData [ADI_DCB_QUEUE_SIZE * ADI_SSL_DCB_NUM_SERVERS];
static  u8  DMAServiceData              [ADI_DMA_BASE_MEMORY + (ADI_DMA_CHANNEL_MEMORY * ADI_SSL_DMA_NUM_CHANNELS)];
static  u8  FlagServiceData             [ADI_FLAG_CALLBACK_MEMORY * ADI_SSL_FLAG_NUM_CALLBACKS];
static  u8  SemaphoreServiceData        [ADI_SEM_SEMAPHORE_MEMORY * ADI_SSL_SEM_NUM_SEMAPHORES];
static  u8  DevMgrData                  [ADI_DEV_BASE_MEMORY + (ADI_DEV_DEVICE_MEMORY * ADI_SSL_DEV_NUM_DEVICES)];
 
/*********************************************************************
   Функция: adi_ssl_Init
 
   Описание: инициализирует Системные Службы (system services)
             и Менеджер Устройств (device manager).
*********************************************************************/
u32 adi_ssl_Init(void)
{
    u32 i;
    u32 Result;
 
   ...
/********************************************************************/
#if defined(__ADSP_STIRLING__)      // BF538 EZKit
   ADI_PWR_COMMAND_PAIR ezkit_power[] =
   {
      // 500 МГц ADSP-BF538:
      { ADI_PWR_CMD_SET_PROC_VARIANT,(void*)ADI_PWR_PROC_BF538BBCZ500  },
      // в корпусе MBGA, как на всех китах EZ-KIT:
      { ADI_PWR_CMD_SET_PACKAGE,     (void*)ADI_PWR_PACKAGE_MBGA       },
      // внешнее напряжение для регулятора напряжения 3.3V:
      { ADI_PWR_CMD_SET_VDDEXT,      (void*)ADI_PWR_VDDEXT_330         },
      // частота CLKIN == 25 МГц:
      { ADI_PWR_CMD_SET_CLKIN,       (void*)25                         },
      // конец списка параметров:
      { ADI_PWR_CMD_END, 0 } 
   }; 
 
   // min TWR 1 такт SCLK + 7.5 нс:
   ADI_EBIU_TIMING_VALUE     twrmin       = {1,{7500, ADI_EBIU_TIMING_UNIT_PICOSEC}};
   // период refresh 8192 такта за 64 мс:
   ADI_EBIU_TIMING_VALUE     refresh      = {8192,{64, ADI_EBIU_TIMING_UNIT_MILLISEC}};
   // min TRAS 44 нс:
   ADI_EBIU_TIME             trasmin      = {44, ADI_EBIU_TIMING_UNIT_NANOSEC};
   // min TRP 20 нс:
   ADI_EBIU_TIME             trpmin       = {20, ADI_EBIU_TIMING_UNIT_NANOSEC};
   // min TRCD 20 нс:
   ADI_EBIU_TIME             trcdmin      = {20, ADI_EBIU_TIMING_UNIT_NANOSEC};
   // порог cl 100 МГц:
   u32                       cl_threshold = 100;
   // размер банка 64MB:
   ADI_EBIU_SDRAM_BANK_VALUE bank_size    = {0, {size: ADI_EBIU_SDRAM_BANK_64MB }};
   // ширина адреса столбца 10 бит:
   ADI_EBIU_SDRAM_BANK_VALUE bank_width   = {0, {width: ADI_EBIU_SDRAM_BANK_COL_10BIT}};
 
   ADI_EBIU_COMMAND_PAIR ezkit_ram[] =
   {
      { ADI_EBIU_CMD_SET_SDRAM_BANK_SIZE,     (void*)&bank_size   },
      { ADI_EBIU_CMD_SET_SDRAM_BANK_COL_WIDTH,(void*)&bank_width  },
      { ADI_EBIU_CMD_SET_SDRAM_CL_THRESHOLD,  (void*)cl_threshold },
      { ADI_EBIU_CMD_SET_SDRAM_TRASMIN,       (void*)&trasmin     }, 
      { ADI_EBIU_CMD_SET_SDRAM_TRPMIN,        (void*)&trpmin      }, 
      { ADI_EBIU_CMD_SET_SDRAM_TRCDMIN,       (void*)&trcdmin     }, 
      { ADI_EBIU_CMD_SET_SDRAM_TWRMIN,        (void*)&twrmin      },
      { ADI_EBIU_CMD_SET_SDRAM_REFRESH,       (void*)&refresh     },
      /* Команды для контроллера асинхронной памяти */ 
      { ADI_EBIU_CMD_SET_ASYNCH_CLKOUT_ENABLE,          (void*)&clkout_enable },
      { ADI_EBIU_CMD_SET_ASYNCH_BANK_ENABLE,            (void*)&banks_enable },                                 
      { ADI_EBIU_CMD_SET_ASYNCH_BANK_TRANSITION_TIME,   (void*)&asynch_bank_trans_time  },
      { ADI_EBIU_CMD_SET_ASYNCH_BANK_READ_ACCESS_TIME,  (void*)&asynch_bank_read_access_time  }, 
      { ADI_EBIU_CMD_SET_ASYNCH_BANK_WRITE_ACCESS_TIME, (void*)&asynch_bank_write_access_time  },
      { ADI_EBIU_CMD_SET_ASYNCH_BANK_SETUP_TIME,        (void*)&asynch_bank_setup_time  }, 
      { ADI_EBIU_CMD_SET_ASYNCH_BANK_HOLD_TIME,         (void*)&asynch_bank_hold_time  },
      { ADI_EBIU_CMD_SET_ASYNCH_BANK_ARDY_ENABLE,       (void*)&asynch_bank_ardy_enable  },  
      { ADI_EBIU_CMD_SET_ASYNCH_BANK_ARDY_POLARITY,     (void*)&asynch_bank_ardy_polarity },
      { ADI_EBIU_CMD_END, 0 }
};
#endif
 
/********************************************************************/
// Инициализация всех служб до появления первой ошибки
// (цикл do/while прокручивается только 1 раз).
   do
   {
      // Инициализация Менеджера Прерываний, переданы параметры:
      //    указатель на память для Менеджера Прерываний
      //    размер этой памяти (в байтах)
      //    место, куда будет сохранено количество вторичных обработчиков
      //    параметр для adi_int_EnterCriticalRegion (всегда NULL для VDK и обычных систем, не RTOS)
      if ((Result = adi_int_Init(InterruptServiceData,
                                 sizeof(InterruptServiceData),
                                 &i,
                                 ADI_SSL_ENTER_CRITICAL)) != ADI_INT_RESULT_SUCCESS)
      {
         break;
      }
    
      // Иницаилиазция контроллера внешней шины (EBIU), переданы параметры:
      //    адрес таблицы с параметрами для RAM
      //    0 - всегда 0 когда EBIU инициализируется перед power service
      // Если EBIU уже был инициализирован, то процесс продолжится.
      Result = adi_ebiu_Init(ezkit_ram, 0);
      if ((Result != ADI_EBIU_RESULT_SUCCESS) && (Result != ADI_EBIU_RESULT_ALREADY_INITIALIZED))
      {
         break;
      }
 
      // Инициализация питания, передан параметр:
      //    адрес таблицы, содержащей информацию о процессоре
      // Если питание уже было инициализировано, топроцесс продолжится.
        Result = adi_pwr_Init(ezkit_power);
      if ((Result != ADI_PWR_RESULT_SUCCESS) && (Result != ADI_PWR_RESULT_ALREADY_INITIALIZED))
      {
         break;
      }
    
#if defined(__ADSP_BRAEMAR__) || defined(__ADSP_STIRLING__) || defined(__ADSP_MOAB__)
      // Инициализация службы управления портами (port control), передан параметр
      // для adi_int_EnterCriticalRegion (всегда NULL для VDK и систем не на основе RTOS)
      if ((Result = adi_ports_Init(ADI_SSL_ENTER_CRITICAL)) != ADI_PORTS_RESULT_SUCCESS)
      {
         break;
      }
#endif        
 
      // Инициализация службы отложенных функций обратного вызова (deferred
      // callback service), если это требуется. Переданы параметры:
      //    указатель на данные
      //    размер данных
      //    место, куда будет сохранено количестов серверов
      //    параметр для adi_int_EnterCriticalRegion (всегда NULL для VDK и систем не на основе RTOS)
#if (ADI_SSL_DCB_NUM_SERVERS != 0)
      if ((Result = adi_dcb_Init(DeferredCallbackServiceData,
                                 sizeof(DeferredCallbackServiceData),
                                 &i,
                                 ADI_SSL_ENTER_CRITICAL)) != ADI_DCB_RESULT_SUCCESS)
      {
         break;
      }
#endif
 
      // Инициализация Менеджера DMA, если это необходимо. Переданы параметры:
      //    указатель на память, которую может использовать Менеджер DMA
      //    размер этой памяти (в байтах)
      //    параметр для adi_int_EnterCriticalRegion (всегда NULL для VDK и систем не на основе RTOS)
#if (ADI_SSL_DMA_NUM_CHANNELS != 0)
      if ((Result = adi_dma_Init(DMAServiceData,
                                 sizeof(DMAServiceData),
                                 &i,
                                 &adi_dma_ManagerHandle,
                                 ADI_SSL_ENTER_CRITICAL)) != ADI_DMA_RESULT_SUCCESS)
      {
         break;
      }
#endif
 
      // Инициализация Менеджера Флагов, переданы параметры:
      //   указатель на память, которую может использовать Менеджер Флагов
      //   размер памяти (в байтах)
      //   место, куда будет сохранего количество флагов callback-ов
      //   параметр для adi_int_EnterCriticalRegion (всегда NULL для VDK и систем не на основе RTOS)
      if ((Result = adi_flag_Init(FlagServiceData,
                                  sizeof(FlagServiceData),
                                  &i,
                                  ADI_SSL_ENTER_CRITICAL)) != ADI_FLAG_RESULT_SUCCESS)
      {
         break;
      }
 
      // Инициализация Менеджера Таймеров, переданы параметры:
      //   параметр для adi_int_EnterCriticalRegion (всегда NULL для VDK и систем не на основе RTOS)
      if ((Result = adi_tmr_Init(ADI_SSL_ENTER_CRITICAL)) != ADI_TMR_RESULT_SUCCESS)
      {
         break;
      }
 
#if !defined(__ADSP_TETON__)
      // Инициализация Службы реального времени (RTC service)
      //  параметр для adi_int_EnterCriticalRegion (всегда NULL для VDK и систем не на основе RTOS)
      if ((Result = adi_rtc_Init(ADI_SSL_ENTER_CRITICAL)) != ADI_RTC_RESULT_SUCCESS)
      {
         break;
      }
#endif
 
      // Инициализация Службы Семафоров, если это необходимо, переданы параметры: parameters are
      //    указатель на память, которую может использовать Служба Семафоров
      //    размер этой памяти (в байтах)
      //    параметр для adi_int_EnterCriticalRegion (всегда NULL для VDK и систем не на основе RTOS)
#if (ADI_SSL_SEM_NUM_SEMAPHORES != 0)
      if ((Result = adi_sem_Init(SemaphoreServiceData,
                                 sizeof(SemaphoreServiceData),
                                 &i,
                                 ADI_SSL_ENTER_CRITICAL)) != ADI_SEM_RESULT_SUCCESS)
      {
        break;
      }
#endif
 
      // Инициализация Менеджера Устройств, если это необходимо. Переданы параметры:
      //   указатель на память, которую может использовать Менеджер Устройств
      //   размер этой памяти в байтах
      //   место, куда будет сохранено количество обслуживаемых устройств
      //   место, куда будет сохранен хендл Менеджера Устройств
      //   параметр для adi_int_EnterCriticalRegion (всегда NULL для VDK и систем не на основе RTOS)
#if (ADI_SSL_DEV_NUM_DEVICES != 0)
      if ((Result = adi_dev_Init(DevMgrData,
                               sizeof(DevMgrData),
                               &i,
                               &adi_dev_ManagerHandle,
                               ADI_SSL_ENTER_CRITICAL)) != ADI_DEV_RESULT_SUCCESS)
      {
         break;
      }
#endif
 
      // WHILE (нет ошибок, или один проход до полного завершения
      // инициализации всех служб)
   } while (0);
   return (Result);
}

Обратите внимание, что во многие функции инициализации служб передается константа ADI_SSL_ENTER_CRITICAL. Это значение, которое передается в функцию входа в критический регион кода adi_int_EnterCriticalRegion. Для всех имеющихся в настоящее время примеров кода и библиотек VDK от Analog Devices эта константа определена как NULL, потому что вложение критических регионов кода не используется. Подробнее про критические регионы кода и функцию adi_int_EnterCriticalRegion см. описание Менеджера Прерываний [4].

Termination (завершение работы службы). Многие встраиваемые системы работают непрерывно в бесконечном цикле, и могут не нуждаться в вызовах функции завершения работы службы (service termination function). Приложения, которым не нужно останавливать службы, могут экономить память, никогда не вызывая эту функцию завершения службы.

Для приложений, которым нужно останавливать службы, как и для инициализации, имеется предпочтительная последовательность остановки служб (из-за того, что они зависят друг от друга). Для большинства приложений будет оптимальной приведенная ниже последовательность остановки служб. Остановка любой службы из этой последовательности, которая не используется, может быть просто опущена.

1. PWM service (если применимо)
2. Semaphore service
3. Real-time clock service
4. Timer service (Служба Таймеров [7])
5. Programmable flag service (Служба Программируемых Флагов [6])
6. DMA manager service (Менеджер DMA [3])
7. Deferred callback service (Менеджер DCB [5])
8. Port control (Служба Управления Портами [8], если применимо)
9. Power management service
10.External bus interface unit
11. Interrupt control service (Менеджер Прерываний [4])

Директория Системных Служб и файловая структура. Все файлы для Системных Служб содержатся в подкаталогах директории Blackfin каталога установки VisualDSP++. Другие инструменты разработки могут использовать другую директорию для их тулкитов, но системные службы всегда можно найти в дереве директории Blackfin.

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

Доступ к System Services API. Приложения, использующие system services, должны подключить директорию Blackfin/include/services в настройках путей поиска препроцессора (для компилятора C/C++ и/или ассемблера). Файлы исходного кода пользователя, которые обращаются к API любой из служб, должны просто подключить директивой #include файл services.h, который находится в директории Blackfin/include/services. Файлы пользователя не нуждаются в подключении каких-то других файлов, если нужно использовать system services API.

Функционал system services API универсален и последователен для всех процессоров Blackfin, включая все одноядерные и двухядерные процессоры. Таким образом портируемость приложения между процессорами при использовании Системных Служб облегчается, потому что в проекте VDK нужно поменять только тип используемого целевого процессора Blackfin. Например, программа приложения, работающая на одноядерном ADSP-BF533, может быть без изменений перекомпилирована и запущена на двухядерном процессоре ADSP-BF561.

Чтобы обеспечить такую портируемость API для приложения, system services API должен учитывать специфические варианты целевого процессора. Вы должны гарантировать, что макрос определения варианта процессора определен заранее, когда подключается файл services.h.

Набор инструментария VisualDSP++ автоматически задает макрос определения процессора, когда собирается проект. Разработчики, использующие VisualDSP++, могут не беспокоиться об определении макроса для процессора (достаточно правильно выбрать модель процессора в выпадающем списке настроек проекта VDK).

Однако разработчики, использующие другой инструментарий, должны убедиться в том, что правильно определен макрос, задающий тип процессора. Файл services.h перечисляет варианты поддерживаемых типов процессора. Эти текущие варианты процессора показаны в таблице 1-1, но следует иметь в виду, что таблица может пополняться в связи с появлением новых процессоров Blackfin. Поэтому важно всегда использовать самую свежую редакцию файла services.h.

Таблица 1-1. Варианты процессоров.

Макрос Тип процессора
__ADSPBF504__ Процессор ADSP-BF504
__ADSPBF504F__ Процессор ADSP-BF504F
__ADSPBF506F__ Процессор ADSP-BF506F
__ADSPBF512__ Процессор ADSP-BF512
__ADSPBF514__ Процессор ADSP-BF514
__ADSPBF516__ Процессор ADSP-BF516
__ADSPBF518__ Процессор ADSP-BF518
__ADSPBF522__ Процессор ADSP-BF522
__ADSPBF523__ Процессор ADSP-BF523
__ADSPBF524__ Процессор ADSP-BF524
__ADSPBF525__ Процессор ADSP-BF525
__ADSPBF526__ Процессор ADSP-BF526
__ADSPBF527__ Процессор ADSP-BF527
__ADSPBF531__ Процессор ADSP-BF531
__ADSPBF532__ Процессор ADSP-BF532
__ADSPBF533__ Процессор ADSP-BF533
__ADSPBF534__ Процессор ADSP-BF534
__ADSPBF535__ Процессор ADSP-BF535
__ADSPBF536__ Процессор ADSP-BF536
__ADSPBF537__ Процессор ADSP-BF537
__ADSPBF538__ Процессор ADSP-BF538
__ADSPBF539__ Процессор ADSP-BF539
__ADSPBF542__ Процессор ADSP-BF542
__ADSPBF544__ Процессор ADSP-BF544
__ADSPBF547__ Процессор ADSP-BF547
__ADSPBF548__ Процессор ADSP-BF548
__ADSPBF549__ Процессор ADSP-BF549
__ADSPBF542M__ Процессор ADSP-BF542M
__ADSPBF544M__ Процессор ADSP-BF544M
__ADSPBF547M__ Процессор ADSP-BF547M
__ADSPBF548M__ Процессор ADSP-BF548M
__ADSPBF549M__ Процессор ADSP-BF549M
__ADSPBF561__ Процессор ADSP-BF561
__ADSPBF590__ Процессор ADSP-BF590
__ADSPBF592__ Процессор ADSP-BF592-A

API для вызова system services не меняется при использовании разных типов процессоров, но внутренняя реализация system services будет отличаться в зависимости от специфичного варианта процессора и ревизии его кристалла. Например, количество каналов DMA для ADSP-BF533 отличается от количества каналов DMA ADSP-BF561. Кроме того, могут различаться средства обхода ошибок кристалла разных ревизий одного и того же процессора. Эти отличия учитываются в библиотечном модуле system services. Для дополнительной информации см. раздел "Обзор Системных Служб".

Линковка библиотеки System Services. Весь объектный код для Системных Служб предоставлен в библиотечном файле system services. Файл библиотеки находится в каталоге Blackfin/lib. В этом каталоге имеется библиотечный файл system services для каждых поддерживаемых варианта и ревизии процессора. Вы должны убедиться, что подходящий библиотечный файл подключен в списке объектных файлов для линкера. Все библиотечные файлы Системных Служб именуются по шаблону libsslxxx_yyyz.dlb, где в имени файла присутствуют следующие составные части:

• xxx соответствует варианту (типу) процессора, обычно это 3 цифры, как например 532 для процессора ADSP-BF532, 534 для процессора ADSP-BF534, и т. д.

• _yyy представляет рабочее окружение - этот суффикс задает способ использования библиотеки, такой как vdk для систем на основе VDK, uCOS для систем на основе uCOS, и т. д. Библиотеки, которые собраны отдельно, без привязки к рабочему окружению RTOS, не имеют суффикса_yyy.

• z представляет специальные условия для библиотеки. Может использоваться следующее: y - библиотека собрана для учета всех известных аномалий всех известных ревизий кремния, без дополнительного суффикса y - библиотека не содержит обход каких-либо аномалий процессора.

Библиотечные файлы распределены по подкаталогам директории Blackfin/lib, в соответствии с отдельными ревизиями кремния. Библиотеки в этих подкаталогах собраны для специальной поддержки определенных ревизий кристалла процессоров Blackfin.

Подключение одного библиотечного файла для линкера должно быть сделано с учетом используемой ревизии процессора. Например, если приложение собрано для ревизии кремния 0.2 процессора ADSP-BF532, то RTOS должна использовать линковку файла libss1532.dlb из подкаталога Blackfin/lib/bf532_rev_0.2. В другом примере, если нужно запустить библиотеку system services на ADSP-BF532, и используется VDK, то нужно подключить файл libss1532_vdky.dlb из каталога Blackfin/lib.

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

Задайте использовать отладочные версии библиотек путем выбора Use Debug System libraries на странице Link:Processor диалогового окна Project Options.

В обычных ситуациях не требуется перекомпилировать код библиотек system services. Однако для учета непредвиденных обстоятельств, когда разработчикам требуется адаптировать system services к каким-то особым потребностям, предоставляется возможность пересобрать библиотеку, так как имеются в наличии все необходимые исходные и заголовочные файлы кода библиотеки system services. Дополнительно предоставлены файлы проекта, которые можно использовать в среде разработки VisualDSP++.

Весь исходный код библиотеки system services размещен в следующих директориях:

• Blackfin/lib - здесь содержатся собранные версии библиотеки от компании Analog Devices (*.dlb).

• Blackfin/lib/src/services - здесь содержится весь исходный код и не относящиеся к API подключаемые файлы для библиотеки system services. Эта директория также содержит файлы проектов VisualDSP++, которые можно использовать для пересборки библиотек.

• Blackfin/include/services - здесь находятся все подключаемые файлы API для system services.

Пользователи VisualDSP++ могут просто пересобрать библиотеку system services командой сборки после открытия соответствующего файла проекта VisualDSP++.

Чтобы пересобрать библиотеки с использованием других инструментов:

1. Установите путь поиска подключаемых файлов (include path) для директорий Blackfin/include/services и Blackfin/lib/src/services.
2. Определите вариант процессора в соответствии с определениями в файле services.h.
3. Определите макрос для ревизии кремния __SILICON_REVISION__, чтобы он был установлен в правильное значение. Для дополнительной информации см. описание опции -si-revision в руководстве "C/C++ Compiler and Library manual" для Вашего процессора [2].
4. Выполните компиляцию/ассемблирование всех файлов в директории Blackfin/lib/src/services.
5. Выполните линковку всех нужных объектных файлов в библиотеку. Подключите все объектные файлы, не требующие расширения для операционной системы и все объектные файлы, рассчитанные на соответствующее расширение для операционной системы (под расширением для операционной системы имеется в виду поддержка многопоточной среды выполнения кода, такой как VDK).

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

Что следует учесть при использовании RTOS. При программировании приложения на основе RTOS, т. е. такого приложения, как проект VDK, настоятельно рекомендуется развертывать Системные Службы и модель Драйвера Устройства. Однако при этом следует учесть некоторые обстоятельства, чтобы избежать конфликта с RTOS и успешно применить Системные Службы и Драйверы Устройства в многопоточном приложении.

Дальнейшее обсуждение ограничено VDK, но относится также и к рабочим окружениям других RTOS.

Взаимодействие System Services с VDK. Есть 3 главные обстоятельства, которые нужно учитывать при развертывании Системных Служб и модели Драйвера Устройства в приложениях VDK.

• Обработка прерываний - Менеджер Прерываний (interrupt manager) это краеугольный камень для Системных Служб и модели Драйвера Устройства. Менеджер Прерываний разработан для обслуживания только групп векторов прерываний (interrupt vector groups, IVG), которые запрошены для обработки, как это диктуется каждым вызовом adi_int_CECHook(), оставляя обработку других уровней IVG в соответствии с нуждами пользователя. Таким образом прерывания, обслуживаемые VDK, можно легче использовать совместно с прерываниями, обрабатываемые через system services, при условии, что никакой другой метод не используется для обработки одних и тех же уровней IVG. Нельзя совместить VDK ISR и цепочку interrupt manager назначенными на один уровень IVG, поскольку они перезапишут один другого в таблице векторов событий (event vector table, EVT).

Все каналы DMA и Драйверы Устройства используют уровни IVG по умолчанию, как это определено в регистрах SIC_IARx в момент инициализации устройства (т. е. во время вызова adi_dev_Open()).

• Запрещенные уровни прерывания - Приложение A руководства VisualDSP++ 5.0 Kernel (VDK) User’s Guide детализирует 4 уровня прерываний [EVT3 (EVX), EVT6 (IVTMR), IVG14, и IVG15] зарезервированными для исключительного использования VDK, и они не должны обслуживаться Менеджером Прерываний. Уровень IVG15 также исключен из большинства приложений VisualDSP++, поскольку используется для запуска кода приложений в режиме супервизора процессора (supervisor mode).

• Отложенные функции обратного вызова (deferred callbacks). Менеджер deferred callback (DCB) предоставляет подобную службу для процесса VDK, работающего с приоритетом IVG14. Настоятельно рекомендуется использовать это для VDK-варианта библиотеки system services (и действительно ldf-файлы по умолчанию VDK гарантируют такое использование). Этот вариант в сущности передает callback-и, предоставленные Менеджеру DCB, на уровень обработки 14 VDK. В таком режиме обработки может использоваться только одна очередь callback. Если используется вариант с автономной библиотекой, то может быть обработано несколько очередей, но ни одна из них не может быть назначена на уровень IVG14, потому что это привело бы к конфликту с процессом VDK, работающем на уровне IVG14.

Учитывайте 2 основных соображения, когда развертываете Системные Службы и модель Драйвера Устройств в многопоточном приложении.

• Критические регионы - Системные Службы и Драйверы Устройств используют критические регионы кода, чтобы гарантировать для них атомарность операций с данными. Эти регионы обслуживаются через вызовы функций adi_int_EnterCriticalRegion и adi_int_ExitCriticalRegion, которые определены в файлах adi_int_xxx.c, находящихся в каталогах инсталляции (дополнительную информацию см. в разделе "Interrupt Manager"). Рекомендуется использовать вышеуказанные функции в потоках, которые использует система, вместо использования функций проталкивания / выборки критических регионов VDK (push/pop critical region functions).

• Инициализация Системных Служб и Менеджера Устройств выполняется один раз на целое приложение. Так как их использование может потребоваться в нескольких потоках, то важно, чтобы инициализация была сделана перед любой последовательностью использования Системных Служб и Менеджера Устройств. Кроме того, все Драйверы Устройства, которые требуют подстройки своих интервалов времени, чтобы соответствовать частоте системной шины (применяемая для периферийных устройств процессора частота SCLK), должны применить вызов adi_pwr_GetFreq(), чтобы определить эту частоту (в Герцах). Модуль управления питанием (power management) должен быть инициализирован перед открытием любого Драйвера Устройства.

В основном есть 3 метода, чтобы достичь такого поведения:

• Определите функцию, которая инициализирует Системные Службы и Менеджер Устройств, и вызовите её из модифицируемой пользователем секции подпрограммы старта (startup code), находящейся в файле ассемблера < имя_проекта >_basiccrt.s.

• Назначьте инициализацию потоку загрузки (boot thread), у которого самый высокий приоритет.

• Если Вы хотите завершить поток с инициализацией, то используйте отдельный поток загрузки, чтобы выполнить инициализацию, установив ему самый высокий приоритет, и позвольте уступить выполнение для него со стороны других потоков, пока поток инициализации не будет завершен или уничтожен. С таким методом используйте глобальную память (не память потока), чтобы проинициализировать Системные Службы и Менеджер Устройств.

[Обзор Драйвера Устройства (Device Driver)]

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

Модель Драйвера Устройства компании Analog Devices предоставляет простой, удобный метод для управления со стороны приложения устройствами, которые можно найти как внутри, так и вокруг процессоров Analog Devices. Это также предоставляет простой и эффективный механизм для создания новых Драйверов Устройств.

Обзор Драйвера Устройства раскрывает следующие темы:

• Интерфейс приложения
• Архитектура Драйвера Устройства
• Инициализация драйверов
• Завершение работы драйверов
• Директория и файловая структура Драйвера Устройства

Интерфейс приложения. Модель Драйвера Устройства предоставляет удобный, простой и знакомый интерфейс программирования со стороны приложения (application programming interface, API). Все Драйверы Устройства должны удовлетворять этой модели и использовать простой интерфейс для обращения к драйверу.

Большинство устройств, которые принимают и/или передают данные, иногда в процессе преобразуют данные. Данные инкапсулируются в буфере. Этот буфер может содержать малое количество бит данных (как в случае устройства типа UART, обрабатывающего один байт за раз) или большую порцию данных (как видеоустройство, обрабатывающее кадры NTSC размером приблизительно 1 мегабайт). Приложения обычно предоставляют эти буферы для устройства, хотя может быть и так, что устройства передают буферы из одного устройства в другое без вовлечения в этот процесс приложения.

Актуальный API модели Драйвера Устройства состоит из следующих базовых функций:

C C++ Описание
adi_dev_Open() ::Open() Открытие устройства для использования.
adi_dev_Close() ::Close() Закрытие устройства.
adi_dev_Read() ::SyncRead Предоставляет устройству буферы для приходящих данных.
adi_dev_Write() ::SyncWrite Предоставляет устройству буферы для исходящих данных.
adi_dev_Control() ::IOCtl Устанавливает/детектирует управление и состояние параметров устройства.

В зависимости от направления данных одна из функций чтения или записи может отсутствовать. Например, Вы реализуете драйвер для опроса АЦП, тогда у него может быть реализована функция чтения (adi_dev_Read) и отсутствовать функция записи (adi_dev_Write). Если не требуется управление и получание информации о состоянии устройства, то может также остутствовать (или заменена заглушкой) функция управления (adi_dev_Control).

Подобно API Системных Служб, API Драйвера Устройства разрабатывается так, чтобы вызываться через стандартный интерфейс вызова модели выполнения кода C в реальном времени (C run-time model), используемого средой разработки. API Драйвера Устройства может быть вызван из любой программы на языке C или ассемблера, которые придерживаются соглашения о вызовах функций и использовании регистров C run-time model.

Архитектура Драйвера Устройства. Модель Драйвера Устройства делит свой функционал на 2 основных компонента: Менеджер Устройств (device manager) и физические драйверы (physical drivers).

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

В синхронном режиме, когда приложение вызывает API-функцию adi_dev_Read() для чтения данных из устройства или adi_dev_Write() для отправки данных в устройство, функция API не возвращается в приложение, пока не будет завершена операция чтения или записи. В асинхронном режиме функция API сразу делает возврат в приложение, при этом данные перемещаются в фоновом режиме. Могло бы быть расточительным принудительно для каждого физического драйвера реализовывать обе логики работы - синхронной и асинхронной. Диспетчер устройства предоставляет такой функционал, освобождая каждый физический драйвер от дополнительной реализации этой возможности.

Архитектура Менеджера Устройств показана на рисунке 1-2.

VDK Device Manager Architecture

Рис. 1-2. Архитектура Device Manager.

Менеджер Устройств также предоставляет API приложения для каждого Драйвера Устройства. Это гарантирует, что приложение получает одинаковый, целостный интерфейс, независимо от особенностей каждого устройства.

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

Взаимодействие с Системными Службами (System Services). Как показано на рис. 1-2, модель Драйвера Устройства задействует в своих целях Системные Службы. Каждый программный компонент в системе (независимо от того, является ли это приложением, RTOS если она есть, Менеджером Устройств, или каждым физическим драйвером) может быть доступен и к нему может быть сделано обращение через system services API.

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

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

Хотя модель Драйвера Устройства зависит от Системных Служб, функция инициализации Менеджера Устройств не полагается ни на одну из Системных Служб. Так что текущая ревизия Менеджера Устройств может быть инициализирована перед инициализацией Системных Служб или после неё. Однако будущие версии функции инициализации могут потребовать некоторых возможностей Системных Служб. Таким образом, хорошей практикой будет инициализировать Системные Службы перед инициализацией Менеджера Устройств (подробнее см. раздел, посвященный инициализации Системных Служб).

Завершение работы драйверов. API модели Драйвера Устройства включает в себя функцию завершения (termination), которая может быть вызвана приложением, если больше не требуются Драйверы Устройств. Функция завершения adi_dev_Terminate() вызывается для освобождения всех ресурсов, используемых Менеджером Устройств и любым открытым физическим драйвером. Многие встраиваемые системы работают в бесконечном рабочем цикле, и никогда не вызывают функцию завершения Менеджера Устройств. Приложение, которое работает в бесконечном цикле, может экономить память, никогда не вызывая функцию завершения.

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

Обратите внимание, что из-за зависимости от Системных Служб функция завершения должна быть вызвана перед любой функцией завершения Системных Служб. Это гарантирует, что Системные Службы могут быть вызваны Менеджером Устройств и/или физическими драйверами как часть процедуры выключения.

После того, как Менеджер Устройств был завершен, он должен быть повторно реинициализирован перед тем, как можно будет снова вызвать любой функционал Менеджера Устройств.

Директория и файловая структура Драйвера Устройства. Все файлы для модели Драйвера Устройства содержатся в дереве директорий каталога Blackfin. В инсталляциях VisualDSP++ этот каталог хранит ядро инструментария разработки. Другие средства разработки могут использовать другие имена директорий, но файлы Драйвера Устройства можно всегда найти в дереве папок каталога Blackfin.

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

Доступ к Device Driver API. Исходные файлы пользователя, которые обращаются к API Менеджера Устройств, должны подключить заголовки services.h и adi_dev.h, находящиеся в каталогах Blackfin/include/services и Blackfin/include/drivers соответственно. Дополнительно Ваш исходный файл должен использовать подключаемый файл физического драйвера, к которому осуществляется доступ.

Например, код пользователя, который обращается к драйверу параллельного периферийного интерфейса (parallel peripheral interface, PPI), должен подключить указанные ниже заголовочные файлы в следующем порядке:

#include < services/services.h >    // Системные Службы
#include < drivers/adi_dev.h >      // Менеджер Устройств
#include < drivers/ppi/adi_ppi.h >  // физический драйвер PPI

Организация API и функциональность Драйвера Устройств универсальна и последовательна для всех моделей процессоров Blackfin, включая одноядерные и двухядерные чипы. Независимо от того, для какого процессора Blackfin пишется код приложения, он будет одинаковым для любого процессора. Например, программа приложения, работающая на одноядерном процессоре ADSP-BF533, может быть без изменений перекомпилирована и запущена на многоядерном процессоре ADSP-BF561.

Чтобы обеспечить такую целостность API для приложения, нужно учесть все целевые варианты процессоров для Системных Служб, Менеджера Устройств и физических драйверов. В должны гарантировать, что макрос определения варианта процессора определен и вставлен в тот момент, когда происходит подключение заголовочных файлов Системных Служб (services.h), Менеджера Устройств (adi_dev.h) и физического драйвера.

Тулчейн VisualDSP++ автоматически устанавливает макрос определения процессора, когда происходит сборка проекта. Разработчики приложения, которые используют VisualDSP++, могут не беспокоиться об определении макроса процессора (нужно только правильно выбрать марку процессора в выпадающем списке диалога настроек проекта).

Разработчики приложения, использующие другие средства разработки, должны убедиться, что правильно определен макрос для типа процессора. В файле services.h перечислены все поддерживаемые Системными Службами варианты процессоров (эти варианты перечислены в таблице 1-1). Файл adi_dev.h содержит список семейств процессоров, которые поддерживаются моделью Драйвера Устройства.

Места для файла Драйвера Устройства. Драйверы Устройства для встроенных в кристалл процессора периферийных устройств предоставлены в библиотечном файле libdrvxxx.dlb для различных типов процессора, ревизий кремний и т. п. Драйверы Устройств для периферийных устройств, находящихся не на кристалле процессора (внешних), не включены в эту библиотеку, и должны отдельно подключаться к приложению. Заголовочные файлы для драйверов внутренних периферийных устройств процессора подключаются из следующих подкаталогов:

$ADI_DSP\Blackfin\include\drivers

Здесь $ADI_DSP это путь до каталога установки VisualDSP, который может быть наподобие C:\Program Files\Analog Devices\VisualDSP < номер_версии >.

Исходные файлы для драйверов внутренних устройств находятся в подкаталогах:

$ADI_DSP\Blackfin\lib\src\drivers

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

#include < drivers\codec\adi_ad1836.h >

Исходный код для драйвера внешнего периферийного устройства должен быть добавлен в список модулей исходного кода проектаVisualDSP++. Например, если используется драйвер устройства AD1836, то в проект нужно добавить файл

$ADI_DSP\Blackfin\lib\src\drivers\codec\adi_ad1836.c

Линковка библиотеки драйвера устройства. Весь объектный код Менеджера Устройств и предоставленных компанией Analog Devices физических драйверов подключается в библиотечном файле Драйвера Устройств (device driver library file). Этот файл находится в каталоге Blackfin/lib. В этой директории есть отдельный библиотечный файл для каждого поддерживаемого варианта процессора. Вы должны гарантировать, что подключен соответствующий библиотечный файл - его надо добавить в список объектных файлов для линкера.

Библиотечный файл Драйвера Устройств находится в файле с именем libdrvxxxz.dlb, где:

• xxx соответствует варианту (типу) процессора, обычно это 3 цифры, как например 532 для процессора ADSP-BF532, 534 для процессора ADSP-BF534, и т. д.

• _yyy представляет рабочее окружение - этот суффикс задает способ использования библиотеки, такой как vdk для систем на основе VDK, uCOS для систем на основе uCOS, и т. д. Библиотеки, которые собраны отдельно, без привязки к рабочему окружению RTOS, не имеют суффикса_yyy.

• z представляет специальные условия для библиотеки. Может использоваться следующее: y - библиотека собрана для учета всех известных аномалий всех известных ревизий кремния, без дополнительного суффикса y - библиотека не содержит обход каких-либо аномалий процессора.

Библиотечные файлы распределены по подкаталогам директории Blackfin/lib, в соответствии с отдельными ревизиями кремния. Библиотеки в этих подкаталогах собраны для специальной поддержки определенных ревизий кристалла процессоров Blackfin.

Для процесса линковки должен быть подключен только один файл библиотеки Драйвера Устройств. Правильно выбирайте библиотечный файл, базируясь на используемом варианте процессора в Вашей системе. Например, разрабатывается приложение для silicon revision 0.2 процессора ADSP-BF532, тогда должен использоваться файл libdrv532.dlb из подкаталога Blackfin/lib/bf532_rev_0.2. Другой пример: разработчик хочет версию Драйвера Устройства, работающую на любой ревизии кремния ADSP-BF532, тогда он должен использовать файл libdrv532y.dlb из подкаталога Blackfin/lib.

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

Задайте использовать отладочные версии библиотек путем выбора Use Debug System libraries на странице Link:Processor диалогового окна Project Options.

В обычных ситуациях не требуется пересобирать библиотеку Драйверов Устройств. Однако для учета непредвиденных обстоятельств, когда разработчикам требуется адаптировать Драйверов Устройств к каким-то особым потребностям, предоставляется возможность пересобрать библиотеку, так как имеются в наличии все необходимые исходные и заголовочные файлы кода библиотеки Драйверов Устройств. Дополнительно предоставлены файлы проекта, которые можно использовать в среде разработки VisualDSP++.

Весь исходный код библиотеки Драйверов Устройств размещен в следующих директориях:

• Blackfin/lib - этот каталог содержит версии библиотечных файлов Драйвера Устройств, собранные компанией Analog Devices (*.dlb).

• Blackfin/lib/src/drivers - этот каталог содержит все файлы исходного кода и не относящиеся к API заголовочные файлы для Менеджера Устройств и предоставленных компанией Analog Devices физических драйверов. Также в этой директории находятся файлы проектов VisualDSP++, которые можно использовать, чтобы пересобрать библиотеки.

• Blackfin/include/drivers - этот каталог содержит заголовочные файлы API Менеджера Устройств и заголовочные файлы предоставленных компанией Analog Devices физических драйверов.

Пользователи VisualDSP++ могут пересобрать библиотеку Драйверов Устройств командой сборки после открытия подходящего файла проекта VisualDSP++.

Чтобы пересобрать библиотеки с использованием других средств разработки:

1. Установите путь поиска подключаемых файлов (include path) для директорий Blackfin/include/drivers и Blackfin/lib/src/drivers.
2. Определите вариант процессора в соответствии с определениями в файле services.h.
3. Определите макрос для ревизии кремния __SILICON_REVISION__, чтобы он был установлен в правильное значение. Для дополнительной информации см. описание опции -si-revision в руководстве "C/C++ Compiler and Library manual" для Вашего процессора [2].
4. Выполните компиляцию/ассемблирование всех файлов в директории Blackfin/lib/src/drivers.
5. Выполните линковку всех нужных скомпилированных/ассемблированных объектных файлов в библиотеку.

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

[Замечания от переводчика]

Библиотека системных служб и драйверов для процессоров Blackfin от компании Analog Devices (модули и многие функции этой библиотеки начинаются с префикса adi_) оставляют двоякое впечатление. С одной стороны, это хорошая попытка привести к единому API доступ к зоопарку железа различных моделей процессоров. Однако с другой стороны... получилось нечто похожее на библиотеки Arduino.

И действительно, как и с Arduino, у Вас есть выбор - либо каждый раз при переходе на новый процессор изучать детали его кишочек по даташиту, либо изучать документацию на библиотеку системных служб и сервисов (а на это тоже надо время) в надежде, что это в будущем позволит сэкономить время и усилия. И точно так же, как с Arduino, эффективно использовать библиотеку получится только при условии, что изучили документацию, разобрались с примерами кода, и всё-таки хорошо ориентируетесь в архитектуре целевого процессора. Причем для обработчиков прерываний и критичных по времени выполнения участков кода библиотеки ADI скорее всего будут неудачным выбором, особенно если Вы любите писать и отлаживать код в конфигурации Debug. Стоит также добавить, что при использовании библиотеки можно столкнуться с трудно выявляемыми благами - из-за ошибок в самой библиотеке или (что бывает чаще) из-за прочитанной по диагонали документации.

Так что же делать? Выбор остаётся за Вами. ИМХО, однократно и редко выполняемые блоки кода (такие как инициализация периферийных устройств процессора) можно строить на вызовах функций ADI. Критичный же код - который должен работать максимально быстро, и который должен быть при этом максимально понятен - надо писать вручную.

[Ссылки]

1. VisualDSP++ 5.0 Device Drivers and System Services Manual for Blackfin® Processors site:analog.com.
2. Опции командной строки компилятора Blackfin.
3. VDK: менеджер DMA.
4. VDK: менеджер прерываний.
5. VDK: менеджер отложенных функций обратного вызова.
6. VDK: служба программируемых флагов.
7. VDK: служба таймеров.
8. VDK: служба управления портами.

 

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


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

Top of Page