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

В этой статье приведен перевод раздела "DMA Manager" из документации "VisualDSP++ 5.0 Device Drivers and System Services Manual for Blackfin® Processors" [1]. Описывается менеджер прямого доступа к памяти (direct memory access, DMA) и его интерфейс программирования (API).

Рассматриваются следующие вопросы:

• Теория функционирования Менеджера DMA
• Описание API Менеджера DMA
• Публичные структуры данных, перечисления и макросы

Менеджер DMA предоставляет разработчику приложения средства для управления трафиком DMA через множество каналов. Можно настраивать каналы DMA, использовать функции обратного вызова (callback) для клиентского приложения, вызываемые при завершении передачи. Как часть Системных Служб (system services), Менеджер DMA предоставляет простой для использования интерфейс с контроллером DMA. Менеджер DMA был разработан для следующих целей:

• Устранить необходимость в непосредственном доступе к отображенным на память регистрам процессора (memory-mapped register, MMR), путем вызовов функций интерфейса программирования (application programming interface, API).

• Снять ограничения на тип перемещения данных. Поддерживаются все типы дескрипторов как для одиночных, так и для кольцевых буферов. Можно использовать одномерные (1D) и двухмерные (2D) передачи DMA.

• Предоставляется простой интерфейс для выполнения блочного копирования данных между различными областями данных, используя как 1D, так и 2D memory DMA (перемещение данных в памяти, MDMA), т. е. блочное копирование данных между внутренней и внешней памятью одним вызовом функции, очень похожим на вызов функции memcpy из стандартной библиотеки C.

• При завершении передачи DMA срабатывает прерывание, и высокоуровневая информация о событии передается в предоставленные пользователем функции обратного вызова (callback). Например, если прерывание срабатывает на каждом внутреннем цикле кольцевой передачи 2D DMA, событие может быть передано в функцию обратного вызова по завершении каждого внутреннего цикла.

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

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

Примечание: в тексте этого руководства часто встречается термин "клиент". Под этим подразумевается код приложения или код потока приложения, который применяет функции Менеджера DMA.

И наконец, все значения перечисления (enum) и операторы определения типа (typedef) используют префикс для имен ADI_DMA_, и функции и глобальные переменные используют эквивалентный префикс adi_dma_.

[Теория функционирования Менеджера DMA]

Менеджер DMA используется для управления контроллером DMA процессора Blackfin. Менеджер DMA поддерживает периферийное устройство DMA для перемещения данных между разными областями памяти (memory DMA, или MDMA) и между памятью и различными встроенными в кристалл процессора периферийными устройствами (peripheral DMA, PDMA).

Менеджер DMA может управлять любым количеством каналов DMA. Вы указываете, какими каналами управляет Менеджер DMA. Приложение может использовать остальные каналы (которые не находятся под управлением Менеджера DMA) для любых целей; т. е. каналы управляются Менеджером DMA независимо.

Поддерживаются различные режимы передач контроллера DMA процессора Blackfin, включая цепочки дескрипторов (descriptor chains), кольцевые буферы (использованием функцию автобуфера процессора Blackfin) и одиночные передачи (one-shot transfer). Также поддерживаются одномерные (линейные, 1D) передачи, и двухмерные (матричные, 2D) передачи.

Менеджеру DMA можно указать оповещать клиента (через функцию callback клиента) о событии завершения передачи. Дополнительно callback-функция клиента вовлекается при неожиданном событии, таком как ошибка DMA. Вместо с Системными Службами менеджер DMA позволяет клиенту указать callback-и на лету, т. е. клиентская callback-функция может быть запущена на уровне аппаратного прерывания, либо отложена на уровень обычного кода (deferred), тогда она будет выполнена вне контекста обработчика аппаратного прерывания.

Инициализация Менеджера DMA. Чтобы использовать Менеджер DMA, клиент должен сначала его инициализировать. Менеджер DMA не использует статических данных, так что шаг инициализации используется для предоставления Менеджеру DMA области памяти для использования в обслуживании контроллера DMA.

Менеджер DMA требует малое, фиксированное количество памяти, и переменное количество памяти, в зависимости от количества одновременно открытых каналов DMA, требуемых для системы. Обратите внимание, что MDMA для каждого отдельного потока DMA требуют двух каналов DMA - один для источника, и другой для места назначения в памяти. Предоставляются макросы для определения количества памяти (в байтах), требуемого для базовой памяти и памяти канала (ADI_DMA_BASE_MEMORY и ADI_DMA_CHANNEL_MEMORY соответственно).

Например, если клиент хочет инициализировать Менеджер DMA, и иметь самое большее 4 одновременно работающих канала DMA и один поток MDMA, то количество требуемой памяти будет следующим:

(ADI_DMA_BASE_MEMORY + (ADI_DMA_CHANNEL_MEMORY * 6))

Будучи вызванной, функция инициализации adi_dma_Init() инициализирует память, которая была ей передана. Как и все функции Менеджера DMA, функция инициализации вернет код возврата, который показывает успешное завершение вызова функции или её специфическую произошедшую ошибку. Все функции DMA API возвратят ADI_DMA_RESULT_SUCCESS, чтобы показать успешное завершение. Все коды ошибки имеют имена в виде ADI_DMA_RESULT_XXXX.

В дополнение к коду возврата, функция adi_dma_Init() вернет количество каналов, которыми Менеджер DMA может управлять одновременно, и указатель (handle) на Менеджер DMA. Возвращенное количество каналов может быть проверено, чтобы убедиться, что Менеджер DMA может управлять запрашиваемым количеством каналов. Возвращенное значение handle для Менеджера DMA позже передается в вызовы функций adi_dma_Open и adi_dma_MemoryOpen, которые используют этот handle для идентификации Менеджера DMA, который управляет каналом. Передача этого handle позволяет функциям быстро идентифицировать область памяти, используемую для обслуживания открытого открытого канала (каналов). После того, как Менеджер DMA был проинициализирован, могут быть открыты для использования каналы DMA и потоки памяти.

Хотя можно создать несколько менеджеров DMA в системах с одноядерным процессором Blackfin, нет никакой выгоды так делать.

Завершение работы Менеджера DMA. Когда Менеджер DMA больше не нужен, клиент может его завершить вызовом функции adi_dma_Terminate. Этой функции передается handle Менеджера DMA, которое было получено клиентом при вызове функции adi_dma_Init. Менеджер DMA закрывает любые открытые каналы и потоки, и делает возврат. После возврата из функции adi_dma_Terminate() может быть повторно использована та память, которая была задействована Менеджером DMA вызовом adi_dma_Init().

! Во многих встраиваемых системах Менеджер DMA никогда не завершается.

Memory DMA и Peripheral DMA. Как описано в руководстве по аппаратуре процессора Blackfin [2], контроллер DMA процессора поддерживает оба вида DMA - peripheral DMA (PDMA, прямой доступ к памяти для периферийных устройств) и memory DMA (MDMA, прямой доступ к памяти для пересылок между областями памяти). Независимо от того, что используется - PDMA или MDMA - клиент планирует активность Менеджера DMA на базе блоков вместо того, чтобы отслеживать выборку за выборкой. Хотя блок данных может быть определен для одной выборки данных, это очень редкий случай использования. Намного чаще блоки данных выбираются по количеству, требуемому для обработки. В этом документе всюду используется термин "буфер", что относится к этому блоку данных.

PDMA перемещает блоки данных между периферийным устройством, встроенным в кристалл процессора Blackfin, и областями памяти процессора (чаще всего в контексте Драйвера Устройства [3]). Например, такое периферийное устройство, как PPI, использует DMA для перемещения блоков данных устройство PPI (или из него). Также Драйвер Устройства для PPI обычно использует Менеджер DMA, чтобы управлять потоком данных через PPI.

MDMA описывает перемещение данных между различными областями памяти процессора Blackfin. Например, большие объемы данных используются для обработки видео, при этом кадры видео могут храниться во внешней памяти SDRAM, и могут по частям с помощью DMA перемещаться во внутреннюю память L1 для обработки.

Менеджер DMA полностью поддерживает PDMA и MDMA. Когда используется PDMA, клиенты задействуют возможности Менеджера DMA на базе канала. Когда используется MDMA, клиенты могут выбрать управление потоками в памяти как индивидуальные каналы источника и места назначения, используя такие же техники, как предоставлены для PDMA, или альтернативно могут управлять MDMA как одиночным потоком в памяти, используя высокоуровневые функции adi_dma_MemoryXXXX().

Управление потоками в памяти. Когда нужна передача MDMA, управление и планирование MDMA реализуется намного проще с помощью высокоуровневых потоков в памяти. Функции adi_dma_MemoryXXXX() предоставляют простой, эффективный метод перемещения данных между различными областями памяти с помощью контроллера DMA процессора Blackfin.

Общая последовательность использования потоков в памяти состоит в открытии потока (open memory stream), планирования необходимых передач, и затем в закрытии потока (close memory stream), когда он больше не нужен. Во многих встраиваемых системах потоки в памяти никогда не закрываются, и вместо этого все время остаются открытыми.

Чтобы открыть поток памяти (memory stream), клиент вызывает функцию adi_dma_MemoryOpen. В эту функцию клиент передает следующие параметры:

• Указатель handle на Менеджер DMA, который управляет потоком.

• Идентификатор потока (stream ID, значение типа ADI_DMA_STREAM_ID), который идентифицирует поток MDMA при его использовании.

• Указатель handle клиента, который передается обратно в функцию обратного вызова (callback), которую предоставил клиент. Это значение предоставляется клиентом, и предположительно может что-то значить для клиента, когда передается обратно в его client-функцию. С помощью этого значения клиент может связать значение с потоком, который привел к вызову callback-функции.

• Указатель на место, в которое Менеджер DMA сохраняет handle потока памяти (stream handle). Этот stream handle является значением, определяемым Менеджером DMA, и оно уникально идентифицирует поток для Менеджера DMA.

• Хендл на службу отложенных функций обратного вызова (deferred callback service [4]) или значение NULL. Если предоставлено значение NULL, то Менеджер DMA делает так называемые live callback-и для приложения. Live callback работает в контексте аппаратного обработчика прерывания. Если предоставлен handle службы отложенных функций обратного вызова, то все callback-и для потока будут использовать эту службу, чтобы выполнить отложенную обработку вызова callback-функции, после того как завершится ISR аппаратного прерывания (в этом случае callback-функция выполняется в низкоприоритетном контексте deferred callback service).

Передачи по памяти (Memory Transfers). Как только был открыт поток памяти, клиент может выдать для потока задание с использованием функций adi_dma_MemoryCopy и/или adi_dma_MemoryCopy2D. Линейные (одномерные) передачи в памяти используют первую функцию, двухмерные передачи последнюю. Один и тот же поток может использоваться как для одномерных, так и для двухмерных передач, так что клиент может запланировать одномерную передачу на указанном потоке, и может затем запланировать двухмерную передачу на том же потоке.

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

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

• Хендл потока (stream handle). Это значение предоставлено клиенту во время вызова функции открытия потока adi_dma_MemoryOpen().

• Начальный адрес места назначения, куда будут копироваться данные.

• Начальный адрес источника, откуда будут копироваться данные.

• Ширина (в байтах) каждого отдельного копируемого элемента. Менеджер DMA использует это значение для планирования 8-, 16- или 32-битных передач.

• Количество копируемых элементов.

• Адрес callback-функции, которая будет вызвана по завершении передачи. Вовлечение callback-функции зависит от значения handle службы обратных вызовов, которое было предоставлено для потока, когда он было открыт - либо при отложенном (deferred) выполнении, либо при немедленном (live) выполнении прямо в ISR аппаратного прерывания.

Если в функцию adi_dma_MemoryCopy() передано значение NULL для параметра адреса callback-функции, то передача произойдет синхронно, и функция adi_dma_MemoryCopy() не выполнит возврат в клиентский вызывающий код, пока не завершится передача. В этом случае не будут сделаны никакие-вызовы callback-функций.

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

• Хендл потока (stream handle). Это значение предоставлено клиенту во время вызова функции открытия потока adi_dma_MemoryOpen().

• Указатель на структуру данных (типа ADI_DMA_2D_TRANSFER), которая определяет, как данные сохраняются в памяти места назначения.

• Указатель на структуру данных (типа ADI_DMA_2D_TRANSFER), которая определяет, как данные читаются из памяти источника.

• Ширина (в байтах) каждого отдельного копируемого элемента. Менеджер DMA использует это значение для планирования 8-, 16- или 32-битных передач.

• Адрес callback-функции, которая будет вызвана по завершении передачи. Вовлечение callback-функции зависит от значения handle службы обратных вызовов, которое было предоставлено для потока, когда он было открыт - либо при отложенном (deferred) выполнении, либо при немедленном (live) выполнении прямо в ISR аппаратного прерывания.

Если в функцию adi_dma_MemoryCopy2D() передано значение NULL для параметра адреса callback-функции, то передача произойдет синхронно, и функция adi_dma_MemoryCopy2D() не выполнит возврат в клиентский вызывающий код, пока не завершится передача. В этом случае не будут сделаны никакие-вызовы callback-функций.

Тип данных ADI_DMA_2D_TRANSFER хранит необходимые значения, описывающие двухмерную передачу. Этот тип данных содержит начальный адрес в памяти, значение XCount для количества столбцов, значение YCount для количества строк, и значения XModify и YModify, описывающая шаг итераций для столбцов и строк.

Закрытие канала в памяти. Когда memory stream больше не нужен, вызывается функция adi_dma_MemoryClose, чтобы закрыть поток. Будучи закрытым, поток должен быть заново открыт, чтобы он смог выполнять какие-то дополнительные передачи. Когда вызывается эта функция, клиент предоставляет для неё следующие параметры:

• Хендл потока (stream handle). Это значение предоставлено клиенту во время вызова функции открытия потока adi_dma_MemoryOpen().

• Флаг, указывающий, должен ли Менеджер DMA подождать перед закрытием завершения любой выполняющейся сейчас передачи, или же передача должна быть немедленно оборвана при закрытии канала.

Управление каналами DMA. Управление DMA на базе каналов позволяет жестко управлять планированием DMA. Перед использованием канала он должен быть сначала открыт, и затем сконфигурирован.

Чтобы открыть канал DMA, клиент вызывает функцию adi_dma_Open(). Клиент передает в эту функцию следующие параметры:

• Хендл (handle) Менеджера DMA, который управляет каналом.

• Идентификатор канала, channel ID (типа ADI_DMA_CHANNEL_ID), который будет идентифицировать открытый канал DMA.

• Хендл клиента (client handle) который будет передаваться в функцию обратного вызова клиента (callback). Это значение предоставляется клиентом и может что-то значить для него, и оно будет передано обратно в callback-функцию клиента, чтобы клиент мог связать это значение с потоком, вызвавшим этот callback.

• Указатель на место в памяти, где Менеджер DMA хранит хендл канала (channel handle). Значение этого channel handle определяется Менеджером DMA, и оно уникально идентифицирует канал для Менеджера DMA.

• Рабочий режим, который определяет для канала, как будут перемещаться данные. Подробнее см. ниже врезку "Одиночные передачи".

• Хендл для службы отложенных вызовов (deferred callback service), или значение NULL. Если предоставлено значение NULL, то Менеджер DMA делает так называемые live callback-и для приложения. Live callback работает в контексте аппаратного обработчика прерывания. Если предоставлен handle службы отложенных функций обратного вызова, то callback-и для канала будут использовать эту службу, чтобы выполнить отложенную обработку вызова callback-функции, после того как завершится ISR аппаратного прерывания (в этом случае callback-функция выполняется в низкоприоритетном контексте deferred callback service).

• Адрес callback-функции, которая будет вызвана для оповещения клиента о событиях. События могут быть как ожидаемыми (такие как запросы на оповещение, когда передача завершилась), так и неожиданными (такие как ошибка DMA). Когда происходит действительный вызов callback-функции (deferred или live), для неё будет предоставлено значение хендла службы обратных вызовов (callback service handle).

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

Менеджер DMA поддерживает следующие рабочие режимы для контроллера DMA процессора Blackfin:

• Одиночные передачи
• Кольцевые передачи
• Модель цепочек больших дескрипторов (Large Descriptor Chaining Model)
• Модель цепочек малых дескрипторов (Small Descriptor Chaining Model)

Режим одиночных передач (single transfer operating mode, ADI_DMA_MODE_SINGLE) выполняет отдельные, однобуферные пересылки данных. Когда используется режим одиночной передачи, клиент вызывает функцию adi_dma_Buffer(), чтобы запланировать передачу. В функцию клиент передает следующие параметры:

• Хендл канала (channel handle). Это значение было предоставлено клиенту вызовом функции adi_dma_Open().

• Начальный адрес буфера. Это значение задает адрес в памяти, откуда будут прочитаны данные (для исходящих передач), или куда данные должны быть помещены (для входящих передач).

• Конфигурационное слово для передачи. Это 16-битное значение, представляющее управляющий регистр конфигурации (DMA configuration control register) для канала DMA. Менеджер DMA подключает заголовочный файл, в котором предоставлены макросы, позволяющие клиенту быстро и просто создать слово конфигурации. Ниже перечислены только те поля слова конфигурации, которые должны быть предоставлены.

WNR (направление передачи) ADI_DMA_WNR_READ Перемещение исходящих данных.
ADI_DMA_WNR_WRITE Перемещение входящих данных.
WDSIZE (размер передаваемого элемента) ADI_DMA_WD_SIZE_8BIT Элемент данных имеет разрядность 8 бит (1 байт).
ADI_DMA_WD_SIZE_16BIT Элемент данных имеет разрядность 16 бит (2 байта).
ADI_DMA_WD_SIZE_32BIT Элемент данных имеет разрядность 32 бита (4 байта).
DMA2D (выбор размерности) ADI_DMA_DMA2D_LINEAR Одномерное (линейное) перемещение данных.
ADI_DMA_DMA2D_2D Двумерное перемещение данных.
DI_SEL (выбор, когда срабатывает прерывание данных). Поле имеет значение только для DMA2D=1. ADI_DMA_DI_SEL_OUTER_LOOP Вызов callback будет генерироваться, когда выполнится полностью вся передача (завершится внешний цикл).
ADI_DMA_DI_SEL_INNER_LOOP Вызов callback будет генерироваться при завершении каждого внутреннего цикла.
DI_EN (разрешение прерывания для данных) ADI_DMA_DI_EN_DISABLE Не будет генерироваться вызов callback.
ADI_DMA_DI_EN_ENABLE Менеджер DMA генерирует вызов callback-функции клиента, когда завершается передача.

• Значение XCount. Для одномерных передач это значение определяет количество элементов для передачи. Для двунаправленных передач это значение определяет внутренний счетчик цикла (количество столбцов).

• Значение XModify. Для одномерных передач это значение определяет инкремент/декремент адреса (шаг) для каждого последующего элемента. Для двухмерных передач это значение задает шаг инкремента/декремента адреса внутреннего цикла для каждого последующего элемента, но не включая последний элемент для каждого внутреннего цикла. После последнего элемента каждого внутреннего цикла вместо этого будет применено значение YModify, исключая самый последний элемент в передаче.

• Значение YCount. Для одномерных передач этот параметр игнорируется. Для двухмерных передач это значение представляет счетчик внешнего цикла (количество строк).

• Значение YModify. Для одномерных передач этот параметр игнорируется. Для двухмерных передач это значение представляет шаг инкремента/декремента внешнего цикла, который будет применяться по завершении каждого внутреннего цикла. Это значение будет смещением между последним элементов одной строки и первым элементом следующей строки.

Независимо от того, разрешен ли поток данных на канале, функция adi_dma_Buffer() немедленно возвращает управление в вызывающий код. Если поток данных уже разрешен на канале, то Менеджер DMA начинает передачу; иначе передаче не начнется, пока поток данных не будет разрешен вызовом функции adi_dma_Control(). Когда используется режим одиночной передачи, функция adi_dma_Buffer() может быть вызвана в любой момент, пока не идет передача на канале.

Режим кольцевой передачи (circular transfer mode, ADI_DMA_MODE_CIRCULAR) задействует возможность автобуфера контроллера DMA. С использованием режима кольцевой передачи клиент предоставляет Менеджеру DMA один непрерывный буфер, состоящий из n подбуферов, как это показано на рис. 6-1.

Когда поток данных разрешен, Менеджер DMA начнет передавать данные от начала буфера, продолжая передачу всего буфера, и автоматически зацикливаясь обратно на начало буфера снова и снова, бесконечно повторяя его передачи. Опционально клиент может заказать Менеджеру DMA генерировать вызовы callback по завершении передачи каждого подбуфера, генерировать вызовы callback по завершении передачи всего буфера, или не генерировать вызовы callback-ов.

Когда используется режим кольцевой передачи, клиент вызывает функцию adi_dma_Buffer() со следующими параметрами:

• Хендл канала (channel handle). Это значение было предоставлено клиенту вызовом функции adi_dma_Open().

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

• Конфигурационное слово для передачи. Это 16-битное значение, представляющее управляющий регистр конфигурации (DMA configuration control register) для канала DMA. Менеджер DMA подключает заголовочный файл, в котором предоставлены макросы, позволяющие клиенту быстро и просто создать слово конфигурации. Ниже перечислены поля слова конфигурации, которые должны быть предоставлены клиентом.

WNR (направление передачи) ADI_DMA_WNR_READ Перемещение исходящих данных.
ADI_DMA_WNR_WRITE Перемещение входящих данных.
DI_SEL (выбор, когда срабатывает прерывание данных). Поле имеет значение только для DMA2D=1. ADI_DMA_DI_SEL_OUTER_LOOP Вызов callback будет генерироваться только тогда, когда выполнится полностью всего буфера.
ADI_DMA_DI_SEL_INNER_LOOP Вызов callback будет генерироваться при завершении каждого внутреннего цикла.
DI_EN (разрешение прерывания для данных) ADI_DMA_DI_EN_DISABLE Не будет генерироваться вызов callback.
ADI_DMA_DI_EN_ENABLE Менеджер DMA генерирует вызов callback-функции клиента в соответствии с настройкой поля DI_SEL.

• Значение XCount. Установите этот параметр в количество элементов в одном подбуфере.

• Значение XModify. Ширина (в байтах) каждого элемента. Допустимы только значения 1, 3 и 4.

• Значение YCount. Установите этот параметр в количество подбуферов, содержащихся во всем буфере.

• Значение YModify. Этот параметр игнорируется.

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

VDK manager DMA circular buffer usage fig6 1

Рис. 6-1. Использование режима кольцевого буфера для циклической передачи.

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

Используя режим цепочки больших дескрипторов, клиент предоставляет Менеджеру DMA одну или большее количество цепочек дескрипторов, как это показано на рис. 6-2.

VDK manager DMA descriptor chain fig6 2

Рис. 6-2. Цепочка дескрипторов (Descriptor Chain).

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

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

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

• Хендл канала (channel handle). Это значение было предоставлено клиенту вызовом функции adi_dma_Open().

• Хендл типа ADI_DMA_DESCRIPTOR_HANDLE для дескриптора. Из-за того, что одна и та же функция adi_dma_Queue() используется для всех рабочих режимов DMA, основанных на дескрипторах (включая большие дескрипторы, малые дескрипторы и массивы дескрипторов), тип данных ADI_DMA_DESCRIPTOR_HANDLE действует как контейнер, который удобно представляет каждый тип дескриптора.

Для режима цепочки больших дескрипторов, дескрипторы имеют тип ADI_DMA_DESCRIPTOR_LARGE, определяющий модель больших дескрипторов. Когда вызывается функция adi_dma_Queue(), клиент может передать адрес объединения дескриптора (ADI_DMA_DESCRIPTOR_UNION), или альтернативно адрес самого дескриптора (ADI_DMA_DESCRIPTOR_LARGE) для типа данных ADI_DMA_DESCRIPTOR_HANDLE. Этот дескриптор может быть одиночным дескриптором, или первым дескриптором в цепочке дескрипторов.

Модель больших дескрипторов содержит всю информацию, необходимую Менеджеру DMA для управления работой контроллера DMA. Эта информация включает в себя:

• Указатель на следующий большой дескриптор в цепочке. Если в этом поле NULL, то данный дескриптор единственный, который клиент предоставил для канала.

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

• Конфигурационное слово для передачи. Это 16-битное значение, представляющее управляющий регистр конфигурации (DMA configuration control register) для канала DMA. Менеджер DMA подключает заголовочный файл, в котором предоставлены макросы, позволяющие клиенту быстро и просто создать слово конфигурации. Ниже перечислены поля слова конфигурации, которые должны быть предоставлены клиентом.

WNR (направление передачи) ADI_DMA_WNR_READ Перемещение исходящих данных.
ADI_DMA_WNR_WRITE Перемещение входящих данных.
WDSIZE (размер передаваемого элемента) ADI_DMA_WD_SIZE_8BIT Элемент данных имеет разрядность 8 бит (1 байт).
ADI_DMA_WD_SIZE_16BIT Элемент данных имеет разрядность 16 бит (2 байта).
ADI_DMA_WD_SIZE_32BIT Элемент данных имеет разрядность 32 бита (4 байта).
DMA2D (выбор размерности) ADI_DMA_DMA2D_LINEAR Одномерное (линейное) перемещение данных.
ADI_DMA_DMA2D_2D Двумерное перемещение данных.
DI_EN (разрешение прерывания для данных) ADI_DMA_DI_EN_DISABLE Не будет генерироваться вызов callback.
ADI_DMA_DI_EN_ENABLE Менеджер DMA генерирует вызов callback-функции клиента, когда завершается передача.

• Значение XCount. Для одномерных передач это значение определяет количество передаваемых элементов. Для двухмерных передач это значение задает счетчик внутреннего цикла (количество столбцов).

• Значение XModify. Для одномерных передач это значение определяет инкремент/декремент адреса (шаг) для каждого последующего элемента. Для двухмерных передач это значение задает шаг инкремента/декремента адреса внутреннего цикла для каждого последующего элемента, но не включая последний элемент для каждого внутреннего цикла. После последнего элемента каждого внутреннего цикла вместо этого будет применено значение YModify, исключая самый последний элемент в передаче.

• Значение YCount. Для одномерных передач этот параметр игнорируется. Для двухмерных передач это значение представляет счетчик внешнего цикла (количество строк).

• Значение YModify. Для одномерных передач этот параметр игнорируется. Для двухмерных передач, это значение определяет декремент/инкремент (шаг) адреса внешнего цикла, который будет применен после завершения каждого внутреннего цикла. Это значение будет смещением между последним элементов одной строки и первым элементом следующей строки.

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

Модель цепочек малых дескрипторов (ADI_DMA_MODE_DESCRIPTOR_SMALL) подобна модели цепочек больших дескрипторов (Large Descriptor Chaining Model). Единственное существенное отличие между этими двумя моделями в том, что в малой модели указатель на следующий дескриптор в цепочке дескрипторов составлен только из младших 16 бит адреса, а не из полного 32-битного адреса. Это означает, что все дескрипторы канала, использующие модель малых дескрипторов, должны иметь одинаковыми старшие 16 бит адреса. Другими словами, все дескрипторы малой модели для канала должны быть размещены в одном сегменте памяти размером 64 килобайта.

Это отличие отражено в типе данных ADI_DMA_DESCRIPTOR_SMALL. Чтобы избежать проблем выравнивания данных, последовательность имеет указатель на следующий дескриптор как 16-битную запись, а не 32-битную запись, с начальным адресом данных в дескрипторе, определенном как две 16-битные записи, а не как одна 32-битная запись. С выполнением двух 16-битных доступов к памяти вместо одного 32-битного доступа, можно избежать исключений нарушения выравнивания.

За исключением этих отличий модель цепочек малых дескрипторов функционально идентична модели цепочек больших дескрипторов (Large Descriptor Chaining Model).

Режим массивов дескрипторов (ADI_DMA_MODE_DESCRIPTOR_ARRAY) пока не поддерживается Менеджером DMA.

Конфигурирование канала DMA. Как только канал DMA открыт, клиент может прочитать и модифицировать его конфигурацию с помощью функции adi_dma_Control. Полный список команд, управляющих конфигурацией, предоставлен в таблице 6-6. В большинстве случаев клиент передает в функцию adi_dma_Control() следующие параметры:

• Хендл канала (channel handle). Это значение было предоставлено клиенту вызовом функции adi_dma_Open().

• Идентификатор команды (command ID). Это тип данных ADI_DMA_CMD, идентифицирующий управляемый элемент, который конфигурируется.

• Значение, зависящее от команды. Семантика этого параметра определяется идентификатором команды. Например, если предоставлена команда с идентификатором ADI_DMA_CMD_SET_DATAFLOW, то специфическое значение для неё это либо TRUE, либо FALSE, чтобы разрешить или запретить поток данных на канале. Это значение, зависящее от команды, всегда использует приведение типа от (void*).

Закрытие канала DMA. Чтобы закрыть канал DMA клиент вызывает функцию adi_dma_Close(). Клиент передает в эту функцию следующие параметры:

• Хендл канала (channel handle). Это значение было предоставлено клиенту вызовом функции adi_dma_Open().

• Флаг, показывающий, должен ли Менеджер DMA ждать завершения любой активности DMA на канале перед его закрытием, или нет.

Как только канал был закрыт, он должен быть открыт повторно функцией adi_dma_Open() перед тем, как канал можно использовать снова.

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

В дополнение к polling и callback, функции потока по памяти предоставляют возможность синхронного выполнения. При синхронном использовании функции adi_dma_MemoryCopy() и adi_dma_MemoryCopy2D() вернут управление клиенту только тогда, когда передача завершится.

Polling (опрос завершения передачи). Клиенты могут использовать функцию adi_dma_Control(), чтобы опросить определенный канал с целью определить, находится ли в процессе выполнения передача DMA. Для этого функция вызывается с командой ADI_DMA_CMD_GET_TRANSFER_STATUS. Когда выдана эта команда, Менеджер DMA проверяет состояние индивидуального канала DMA. Функция предоставляет ответ TRUE, если передача DMA еще идет, и ответ FALSE, если сейчас не происходит передача.

Обратите внимание, что потоки в памяти также могут быть опрошены для получения их статуса. Вместо передачи хендла канала (ADI_DMA_CHANNEL_HANDLE) в функцию adi_dma_Control(), клиент передает параметр хендла потока (ADI_DMA_STREAM_HANDLE, у которого осуществлено приведение типов к ADI_DMA_CHANNEL_HANDLE) в функцию adi_dma_Control().

Функция обратного вызова (callback). Callback-и наиболее часто используемый механизм, который клиенты используют с целью определить момент завершения передачи DMA. Callback-и бывают либо немедленные (live, что означает их действие в контексте обработчика аппаратного прерывания), либо отложенные (deferred, что означает их выполнение после того, как завершит работу обработчик аппаратного прерывания; в этом случае за запуск callback-функции отвечает Служба обратных вызов функций, callback service).

Когда используются MDMA, если клиент предоставил callback-функцию как параметр для функций adi_dma_MemoryCopy() или adi_dma_MemoryCopy2D(), то callback-функция будет запущена Менеджером DMA после завершения передачи.

Когда используются потоки в памяти, в клиентскую callback-функцию передаются следующие параметры:

• Хендл клиента (client handle). Это значение предоставляет клиент при вызове функции adi_dma_MemoryOpen().

• Идентификатор события (Event ID). Это значение ADI_DMA_EVENT_DESCRIPTOR_PROCESSED.

• Начальный адрес места назначения передачи.

Когда используется метод кольцевых передач (ADI_DMA_MODE_CIRCULAR), клиент использует слово конфигурации для указания частоты callback-ов. Когда указано запускать callback клиента на каждом завершении подбуфера, Менеджер DMA запускает callback-функцию клиента по завершении обработки каждого подбуфера. Это полезно в схемах с двойной буферизацией, когда используются 2 подбуфера (ping/pong).

При использовании кольцевой передачи в callback-функцию клиента передаются следующие аргументы:

• Хендл клиента (client handle). Это значение предоставляет клиент при вызове функции adi_dma_MemoryOpen().

• Идентификатор события (Event ID). Это значение ADI_DMA_EVENT_INNER_LOOP_PROCESSED, когда была завершена обработка подбуфера, или ADI_DMA_EVENT_OUTER_LOOP_PROCESSED, когда была завершена обработка всего буфера.

• Начальный адрес буфера данных.

Когда используется любой из методов передачи DMA, основанный на дескрипторах (ADI_DMA_MODE_DESCRIPTOR_LARGE, ADI_DMA_MODE_DESCRIPTOR_SMALL или ADI_DMA_DESCRIPTOR_ARRAY), клиент использует слово конфигурации дескриптора, чтобы определить, должен ли быть сгенерирован вызов callback-функции при обработке дескриптора. Когда указано использовать callback клиента по завершении дескриптора, в callback-функцию клиента передаются следующие аргументы:

• Хендл клиента (client handle). Это значение предоставляет клиент при вызове функции adi_dma_MemoryOpen().

• Идентификатор события (Event ID). Это значение ADI_DMA_EVENT_DESCRIPTOR_PROCESSED.

• Начальный адрес данных.

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

Подрежим loopback управляется командой ADI_DMA_CMD_SET_LOOPBACK.

Когда разрешен подрежим loopback (после обработки Менеджером DMA последнего дескриптора в цепочке дескрипторов, предоставленной для канала), то автоматически происходит зацикливание на первый дескриптор канала. Это эффективно создает бесконечный цикл дескрипторов, как показано на рис. 6-3. Например, с подрежимом loopback клиент может предоставить дескрипторы в момент инициализации, позволяя Менеджеру DMA обработать дескрипторы, и при этом может никогда не потребоваться необходимость повторного предоставления Менеджеру DMA дополнительных дескрипторов.

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

VDK manager DMA descriptor chain with Loopback fig6 3

Рис. 6-3. Цепочка дескрипторов с применением Loopback.

Подрежим streaming управляется командой ADI_DMA_CMD_SET_STREAMING.

При работе не в подрежиме streaming Менеджер DMA ставит контроллер DMA на паузу после обработки дескриптора, который помечен для генерации callback-а, когда он обработан. Менеджер DMA делает это потому, что контроллер DMA процессора Blackfin не предоставляет никакой информации о состоянии, показывающей, что был обработан определенный дескриптор. Если Менеджер DMA не ставил бы на паузу контроллер, то могло произойти так, что перед тем, как Менеджер DMA может распознать и обработать прерывание callback для имеющегося дескриптора, контроллер DMA может завершить обработку уже другого дескриптора. Без постановки на паузу контроллера DMA, пока Менеджер DMA обрабатывает прерывание, Менеджер DMA не может однозначно определить, какое прерывание callback с каким дескриптором связано.

Когда не происходит streaming, Менеджер DMA также ставит контроллер DMA на паузу, когда канал исчерпал свои предоставленные дескрипторы.

Подрежим streaming позволяет клиенту отменить это поведение. Когда разрешен подрежим streaming, Менеджер DMA никогда не ставит контроллер DMA на паузу; это позволяет передачам DMA происходить с максимальной пропускной способностью.

В подрежиме streaming клиенту требуется гарантировать выполнение следующих условий:

• У канала всегда есть дескрипторы для обработки, и он никогда не вылетает из последовательности дескрипторов.

• Время отклика системы достаточно мало, чтобы Менеджер DMA мог обслужить callback-прерывание для любого дескриптора, помеченного с применением callback до того, как на том же канале потребуется обработка другого callback.

Соблюдение этих условий довольно легко обеспечить в большинстве систем.

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

Менеджер DMA предоставляет 2 функции adi_dma_GetMapping() и adi_dma_SetMapping(), которые позволяют клиенту просто определить и поменять привязку каналов DMA к периферийным устройствам. Эти функции можно вызвать в любое время после инициализации Менеджера DMA, но они должны быть обработаны до того, как откроется канал.

Клиент вызывает функцию adi_dma_GetMapping(), чтобы определить идентификатор канала DMA (DMA channel ID), к которому привязано периферийное устройство. Функция adi_dma_GetMapping() принимает следующие параметры:

• Идентификатор периферийного устройства (peripheral ID). Это значение типа ADI_DMA_PMAP, привязку которого нужно определить.

• Указатель на значение ADI_DMA_CHANNEL_ID. Это значение является адресом на место в памяти, куда функция сохранит идентификатор канала (channel ID) к которому привязано указанное периферийное устройство.

Клиент вызывает функцию adi_dma_SetMapping() для установки привязки указанного channel ID к указанному периферийному устройству. Клиент должен позаботиться о том, что привязка осуществлена один-к-одному между периферийным устройством и идентификатором канала (не должно быть двойной привязки). Функция adi_dma_SetMapping() принимает следующие параметры:

• Идентификатор периферийного устройства (peripheral ID). Это значение типа ADI_DMA_PMAP указывает периферийное устройство, на которое должна быть установлена привязка канала.

• Идентификатор канала (channel ID). Это значение типа ADI_DMA_CHANNEL_ID, указывающее канал DMA, к которому должна быть сделана привязка периферийного устройства.

Прерывания. Менеджер DMA использует сервисы Менеджера Прерываний [5], чтобы сконфигурировать все прерывания, относящиеся к DMA. Все подцепления прерываний изолированы в функциях adi_dma_Open() и adi_dma_MemoryOpen(), и все отцепления прерываний происходят в функциях adi_dma_Close() и adi_dma_MemoryClose().

По умолчанию Менеджер DMA использует настройки группы векторов прерываний (interrupt vector group, IVG), как настройку, выполняемую Менеджером Прерываний. Клиент может поменять привязку каналов DMA к уровням IVG с помощью вызовов Менеджера Прерываний (подробнее про смену привязки между каналами DMA и IVG см. [5]).

Когда клиент открывает первый канал DMA, функция adi_dma_Open() подцепляет к соответствующую цепочку IVG для прерывания ошибки DMA. Обработчик ошибок DMA ничего не другого не делает, кроме как очищает соответствующую ошибку DMA и оповещает клиента о возникновении ошибки вызовом callback-функции.

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

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

Двухмерный DMA. Когда используется линейный DMA, данные перемещаются друг за другом с фиксированным шагом. Это наиболее общий тип передачи, где n элементов шириной w перемещаются из одного места, или вычитываются из периферийного устройства, чтобы быть помещенными в другое место в памяти, или выходят наружу из устройства.

Двухмерный DMA это удобная возможность, позволяющая данным передаваться нелинейным способом. Это особенно полезно в приложениях обработки видео, и может также использоваться для двойной буферизации при опросе АЦП или выводе в ЦАП. Двухмерные DMA поддерживают произвольное количество строк (YCount) и столбцов (XCount) до 64K x 64K элементов, как и значений модификации строк (YModify) и столбцов на значения до +/- 32K байт.

Когда используется канал DMA, то дескрипторы применяют для определения параметров передачи. Когда используются потоки по памяти (memory streams, или MDMA), используется тип данных ADI_DMA_2D_TRANSFER, чтобы определить параметры для передачи.

Для примера предположим, что Вы хотите запропросить блок байтов 16 x 8 (данные) из буфера кадра видео (кадр) размером N x M точек в месте кадра [6][6], и сохранить его в отдельной области памяти (данные) для обработки. После того, как данные были обработаны, значения копируются обратно в свое оригинальное место в кадре. На рис. 6-4 показана обрабатываемая область кадра.

VDK manager DMA 2D transfer example fig6 4

Рис. 6-4. Выбор блока данных 16 x 8 из кадра видео размером N x M точек.

Чтобы выбрать каждую строку блока 16 x 8, внутренний цикл требует конфигурации 2D DMA для 16 значений (XCOUNT=16) с шагом (XMODIFY) равным 1. Внешний цикл состоит из 8 значений (YCOUNT=8) и шагом (YMODIFY) равным N-15 (A + B на рис. 6-4), такой выбор сделан для инструктирования контроллера DMA перепрыгивать от конца одной строки на начало следующей.

Также можно распаковать чередующиеся (interleaved) данные (например, значения RGB для кадра видео), путем модификации значений x и y. Например, чтобы принять поток значений R,G,B,R,G,B,... из кадра N x M точек, рассмотрим рис. 6-5.

VDK manager DMA 2D transfer example fig6 5

Рис. 6-5. Захват видеопотока данных (точки R,G,B) x (размер картинки N x M).

В этом случае внутренний цикл требует конфигурации 2D DMA с 3 значениями (XCOUNT=3) и шагом (XMODIFY) равным N*M, выбранной для последовательных элементов в каждой строке (или кортеже RGB) 1-2-3, 4-5-6, и так далее (см. рис. 6-5).

Внешний цикл конфигурации 2D DMA имеет N*M значений (YCOUNT=N*M) и отрицательный шаг (YMODIFY) равный 1-2*N*M, выбранные для инструктирования контроллера DMA перескакивать от элемента 3 к элементу 4, от 6 к 7, и так далее по окончании каждого внутреннего цикла.

Управление трафиком DMA. Регистры управления периодом трафика (traffic control period registers) и регистры счетчика управления трафиком (traffic control count registers) могут управляться с использованием набора команд для установки значения и команд для считывания значения.

Определена структура данных ADI_DMA_TC_SET для установки параметра управления трафиком DMA. Он содержит поля для указания, какая команда контроллера DMA используется, какой параметр управления трафиком (DEB, DCB, DAB), и какое значение будет установлено.

Подобная структура данных ADI_DMA_TC_GET определена для считывания параметра управления трафиком DMA.

Две команды ADI_DMA_CMD_GET_TC и ADI_DMA_CMD_SET_TC используются для установки и чтения параметров управления трафиком. Подробнее про установку и чтение параметров управления трафиком см. раздел "Структуры данных" и таблицу 6-6.

[Описание API Менеджера DMA]

В этой секции предоставлены описания API-функций Менеджера DMA.

Таблица 6-1. Функции Менеджера DMA.

Функция Описание
Основные функции
adi_dma_Buffer Предоставляет одиночный или кольцевой буфер.
adi_dma_Close Закрывает канал DMA.
adi_dma_Control Управляет операциями или запрашивает операцию на канале DMA.
adi_dma_Init Инициализирует Менеджер DMA.
adi_dma_Open Открывает для использования канал DMA.
adi_dma_Queue Ставит дескриптор в очередь цепочки дескрипторов.
adi_dma_Terminate Выключает Менеджер DMA и завершает его работу.
Вспомогательные функции
adi_dma_GetMapping Получает идентификатор канала, к которому привязано указанное периферийное устройство.
adi_dma_GetPeripheralInterruptID Получает идентификатор прерывания периферийного устройства для указанного идентификатора канала.
adi_dma_SetConfigWord Устанавливает биты в слове конфигурации для цепочки дескрипторов.
adi_dma_SetMapping Устанавливает привязку идентификатора канала DMA к периферийному устройству.
Функции передач DMA по памяти (MDMA)
adi_dma_MemoryOpen Открывает для использования поток MDMA.
adi_dma_MemoryClose Закрывает поток MDMA.
adi_dma_MemoryCopy Выполняет линейное, одномерное копирование данных в памяти.
adi_dma_MemoryCopy2D Выполняет двухмерное копирование данных в памяти.
Функции очереди MDMA
adi_dma_MemoryQueueControl Управляет потоком MDMA очереди и конфигурирует его.
adi_dma_MemoryQueueOpen Открывает поток MDMA для очереди.
adi_dma_MemoryQueueClose Закрывает поток MDMA, который был открыт для очереди.
adi_dma_MemoryQueue Ставит дескриптор (дескрипторы) MDMA в очередь потока.

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

ADI_DMA_RESULT adi_dma_Buffer(
      ADI_DMA_CHANNEL_HANDLE ChannelHandle,
      void *StartAddress,
      ADI_DMA_CONFIG_REG Config,
      u16 XCount,
      s16 XModify,
      u16 YCount,
      s16 YModify);

Аргументы:

ChannelHandle Уникально идентифицирует канал DMA для буфера, это значение было возвращено при открытии канала DMA.
StartAddress Адрес начала в памяти буфера, откуда передаются данные или куда попадают данные (в зависимости от направления DMA).
Config Содержимое регистра конфигурации DMA для передачи.
XCount Общее количество слов, передаваемых в одномерном буфере или количество элементов данных на строку в двухмерном буфере.
XModify Смещение в байтах между каждым передаваемым словом (для одномерных передач 1D) или смещение в байтах между каждым элементом в строке (для двухмерных передач 2D).
YCount Количество передаваемых строк.
YModify Смещение в байтах между последним элементом данных в одной строке и первым элементом в следующей строке.

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

ADI_DMA_RESULT_SUCCESS Буфер был назначен успешно.
ADI_DMA_RESULT_BAD_HANDLE ChannelHandle не содержит допустимый хендл канала.
ADI_DMA_RESULT_BAD_MODE Канал DMA не был открыт для либо одиночной, либо для кольцевой передачи.
ADI_DMA_RESULT_ALREADY_RUNNING Находится в процессе операция DMA.

Функция adi_dma_Close() закрывает канал DMA и освобождает память конфигурации для будущего использования. В зависимости от значения аргумента WaitFlag канал будет закрыт немедленно или только после завершения текущей происходящей передачи DMA.

ADI_DMA_RESULT adi_dma_Close(
      ADI_DMA_CHANNEL_HANDLE ChannelHandle,
      u32 WaitFlag);

Аргументы:

ChannelHandle Уникально идентифицирует канал DMA для закрытия, это значение было возвращено при открытии канала DMA.
WaitFlag Если этот параметр установлен в TRUE (1), то Менеджер DMA будет перед закрытием ожидать завершения текущих передач; иначе, если параметр установлен в FALSE (0), то Менеджер DMA закроет канал немедленно.

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

ADI_DMA_RESULT_SUCCESS Канал DMA был успешно закрыт.
ADI_DMA_RESULT_BAD_HANDLE ChannelHandle не указывает на допустимый хендл канала.
ADI_DMA_RESULT_CANT_UNHOOK_INTERRUPT Не может быть отцеплен обработчик данных и/или обработчик ошибки.

Функция adi_dma_Control() управляет/запрашивает операцию на указанном канале DMA. Прототип функции:

ADI_DMA_RESULT adi_dma_Control(
      ADI_DMA_CHANNEL_HANDLE ChannelHandle,
      ADI_DMA_CM Command,
      void *Value);

Эта функция может быть использована следующими способами:

• Передается одна команда.

adi_dma_Control(ChannelHandle, ADI_DMA_CMD_SET_LOOPBACK, (void*)TRUE);

• Передается одна пара команда-значение.

ADI_DMA_CMD_VALUE_PAIR cmd = {ADI_DMA_CMD_SET_WORD_SIZE,
                              (void*)ADI_DMA_WDSIZE_32BIT};
adi_dma_Control(ChannelHandle, cmd.CommandID, cmd.Value);

• Передается (по ссылке) одна структура ADI_DMA_CMD_VALUE_PAIR.

adi_dma_Control(ChannelHandle, ADI_DMA_CMD_VALUE_PAIR, &cmd);

• Передается таблица структур ADI_COMMAND_PAIR. Таблица должна иметь следующую запись-терминатор, чтобы определить конец таблицы команд: { ADI_DMA_CMD_END, 0 }. Например:

ADI_DMA_CMD_VALUE_PAIR table = {
      {ADI_DMA_CMD_SET_LOOPBACK, (void*)LoopbackFlag},
      {ADI_DMA_CMD_SET_DATAFLOW, (void*)TRUE},
      { ADI_DMA_CMD_END, NULL }};
adi_dma_Control(ChannelHandle, ADI_DMA_CMD_TABLE,&table);

Набор команд, который может быть использован с функцией adi_dma_Control, определен а разделе "Команды DMA".

Аргументы:

ChannelHandle Уникально идентифицирует канал DMA, это значение было возвращено при открытии канала DMA.
Command Значение из перечисления ADI_DMA_CMD, задающее команду (см. раздел "Команды DMA").
Value В зависимости от значение Command, этот параметр может быть одним из следующих значений:
• Если Command == ADI_DMA_CM_VALUE_PAIR, то система выдает адрес одиночного элемента ADI_DMA_CMD_VALUE_PAIR, задающего команду.
• Если Command == ADI_DMA_CMD_TABLE, то система выдает адрес массива элементов ADI_DMA_CMD_VALUE_PAIR, указывающего одну или большее количество команд. Последняя запись в массиве должна содержать {ADI_DMA_CMD_END,NULL}.
• Для любого другого значения Command задает команду для обработки, и Value связано со значением команды. В случае, когда команда запрашивает значение параметра, это значение параметра сохраняется в ячейку памяти, на которую ссылается указатель, размещенный в значении Value.

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

ADI_DMA_RESULT_SUCCESS Функция завершилась успешно.
ADI_DMA_RESULT_BAD_COMMAND Недопустимая команда. Задана либо не существующая команда, либо в этом контексте заданная команда не разрешена.
ADI_DMA_RESULT_ALREADY_RUNNING Команда не может быть выполнена, потому что канал в настоящий момент передает данные.

Функция adi_dma_GetMapping() используется для определения привязки идентификатора канала DMA (DMA channel ID) к периферийному устройству, совместимому с DMA.

ADI_DMA_RESULT adi_dma_GetMapping(ADI_DMA_PMAP pmap,
                                  ADI_DMA_CHANNEL_ID *pChannelID);

Аргументы:

pmap Запрашиваемый идентификатор периферийного устройства (Peripheral ID).
pChannelID Ячейка в памяти, куда Менеджер DMA сохранит идентификатор канала (channel ID), к которому привязано периферийное устройство.

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

ADI_DMA_RESULT_SUCCESS Устройство было успешно идентифицировано, и была возвращена информация DMA.
ADI_DMA_RESULT_BAD_PERIPHERAL Было обнаружено плохое значение периферийного устройства.
ADI_DMA_RESULT_NOT_MAPPED Для этого устройства не обнаружена привязка к каналу DMA.

Функция adi_dma_GetPeripheralInterruptID получает идентификатор прерывания периферийного устройства (peripheral interrupt ID) для указанного идентификатора канала DMA (DMA channel ID).

ADI_DMA_RESULT adi_dma_GetPeripheralInterruptID(
      ADI_DMA_CHANNEL_ID ChannelID,
      ADI_INT_PERIPHERAL_ID *pPeripheralID);

Аргументы:

ChannelID Идентификатор канала DMA (DMA channel ID).
pChannelID Ячейка в памяти, куда сохранена структура ADI_INT_PERIPHERAL_ID, где находится идентификатор периферийного устройства.

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

ADI_DMA_RESULT_SUCCESS Не было ошибок.
ADI_DMA_RESULT_BAD_CHANNEL_ID Недопустимый идентификатор канала.

Функция adi_dma_Init() инициализирует Менеджер DMA.

ADI_DMA_RESULT adi_dma_Init(
      void *pMemory,
      const size_t MemorySize,
      u32 *pMaxChannels
      ADI_DMA_MANAGER_HANDLE *pManagerHandle,
      void *pCriticalRegionArg);

Аргументы:

pMemory Указатель на память, которую может использовать Менеджер DMA.
MemorySize Размер предоставленной памяти в байтах.
pMaxChannels Место в памяти, куда Менеджер DMA сохранит количество одновременно открытых каналов, которое он может обслужить на предоставленном объеме памяти.
pManagerHandle Место в памяти, куда Менеджер DMA сохранит хендл на себя.
pCriticalRegionArg Параметр, который Менеджер DMA передает в функцию adi_int_EnterCriticalRegion().

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

ADI_DMA_RESULT_SUCCESS Функция завершилась успешно.
ADI_DMA_RESULT_NOMEMORY Предоставлено недостаточное для инициализации Менеджера DMA количество памяти.

Функция adi_dma_MemoryClose() закрывает (останавливает) поток MDMA, освобождая все использовавшиеся для этого ресурсы.

ADI_DMA_RESULT adi_dma_MemoryClose(
      ADI_DMA_STREAM_HANDLE StreamHandle,
      u32 WaitFlag);

Аргументы:

StreamHandle Хендл на поток MDMA.
WaitFlag Если этот параметр установлен в TRUE (1), то Менеджер DMA будет перед закрытием ожидать завершения текущих передач; иначе, если параметр установлен в FALSE (0), то Менеджер DMA закроет канал немедленно.

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

ADI_DMA_RESULT_SUCCESS Функция завершилась успешно.
ADI_DMA_RESULT_BAD_HANDLE StreamHandle не указывает на допустимый хендл потока MDMA.

Функция adi_dma_MemoryCopy() выполняет одномерное (линейное, 1D) копирование памяти.

ADI_DMA_RESULT adi_dma_MemoryCopy(
      ADI_DMA_STREAM_HANDLE StreamHandle,
      void *pDest,
      void *pSrc,
      u16 ElementWidth,
      u16 ElementCount,
      ADI_DCB_CALLBACK_FN ClientCallback);

Аргументы:

StreamHandle Хендл на поток MDMA.
pDest Начальный адрес места назначения, куда копируются данные.
pSrc Начальный адрес источника, откуда копируются данные.
ElementCount Количество элементов для передачи.
ElementWidth Длина в байтах каждого копируемого элемента. Допускаются значения 1, 2 и 4.
ClientCallback Функция обратного вызова клиента, которая запускается всякий раз, когда завершается передача. Если здесь задано NULL, то вызов функции adi_dma_MemoryCopy() считается синхронным (блокирующим), т. е. в из неё не будет выполнен возврат, пока не завершится операция копирования данных.

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

ADI_DMA_RESULT_SUCCESS Функция завершилась успешно.
ADI_DMA_RESULT_BAD_HANDLE StreamHandle не указывает на допустимый хендл потока MDMA.
ADI_DMA_RESULT_IN_USE Поток MDMA в настоящий момент используется (занят передачей по памяти).

Функция adi_dma_MemoryCopy2D() выполняет двухмерное (2D) копирование памяти.

ADI_DMA_RESULT adi_dma_MemoryCopy2D(
      ADI_DMA_STREAM_HANDLE StreamHandle,
      ADI_DMA_2D_TRANSFER *pDest,
      ADI_DMA_2D_TRANSFER *pSrc,
      u32 ElementWidth,
      ADI_DCB_CALLBACK_FN ClientCallback);

Аргументы:

StreamHandle Хендл на поток MDMA.
pDest Указатель на структуру, которая описывает, как и куда будут копироваться данные в памяти.
pSrc Указатель на структуру, которая описывает, как и откуда будут копироваться данные в памяти.
ElementWidth Длина в байтах каждого копируемого элемента. Допускаются значения 1, 2 и 4.
ClientCallback Функция обратного вызова клиента, которая запускается всякий раз, когда завершается передача. Если здесь задано NULL, то вызов функции adi_dma_MemoryCopy2D() считается синхронным (блокирующим), т. е. в из неё не будет выполнен возврат, пока не завершится операция копирования данных.

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

ADI_DMA_RESULT_SUCCESS Функция завершилась успешно.
ADI_DMA_RESULT_BAD_HANDLE StreamHandle не указывает на допустимый хендл потока MDMA.
ADI_DMA_RESULT_IN_USE Поток MDMA в настоящий момент используется (занят передачей по памяти).

Функция adi_dma_MemoryOpen() открывает для использования поток MDMA. После открытия на потоке могут быть запланированы передачи MDMA.

ADI_DMA_RESULT adi_dma_MemoryOpen(
      ADI_DMA_MANAGER_HANDLE ManagerHandle,
      ADI_DMA_STREAM_ID StreamID,
      void *ClientHandle,
      ADI_DMA_STREAM_HANDLE *pStreamHandle,
      void *DCBHandle);

Аргументы:

ManagerHandle Хендл на Менеджер DMA.
StreamID Идентификатор открываемого потока MDMA.
ClientHandle Идентификатор, определенный клиентом. Менеджер DMA включает этот идентификатор во все инициируемые Менеджером DMA обмены с клиентом, особенно в вызовах callback-функции клиента.
pStreamHandle Указатель на предоставленное клиентом место в памяти, где Менеджер DMA сохраняет идентификатор, определяемый Менеджером DMA. Все последующие коммуникации, инициированные клиентом к Менеджеру DMA для этого потока MDMA будут включать в себя этот хендл.
DCBServiceHandle Хендл на службу отложенных обратных вызовов функций (deferred callback service), используемую для любых событий потока MDMA. Используемое в этом параметре значение NULL означает, что отложенные вызовы callback-функции не используются, и все callback-и вызываются немедленно в контексте обработчика прерывания DMA.

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

ADI_DMA_RESULT_SUCCESS Функция завершилась успешно.
ADI_DMA_RESULT_ALL_IN_USE Все каналы MDMA используются.
ADI_DMA_RESULT_CANT_HOOK_INTERRUPT Система не может подцепить обработчик прерывания данных или ошибки DMA.

Функция adi_dma_MemoryQueue() ставит в очередь дескрипторы MDMA для потока.

ADI_DMA_RESULT adi_dma_MemoryQueue(
      ADI_DMA_STREAM_HANDLE StreamHandle,
      ADI_DMA_DESCRIPTOR_LARGE *pSourceDescriptor,
      ADI_DMA_DESCRIPTOR_LARGE *pDestinationDescriptor);

Аргументы:

StreamHandle Хендл на поток MDMA.
pSourceDescriptor Хендл дескриптора источника.
pDestinationDescriptor Хендл дескриптора места назначения.

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

ADI_DMA_RESULT_SUCCESS Функция завершилась успешно.
ADI_DMA_RESULT_BAD_HANDLE Передан недопустимый хендл потока.
ADI_DMA_RESULT_BAD_DESCRIPTOR Передан недопустимый дескриптор.
ADI_DMA_RESULT_ALIGNMENT_ERROR Параметры приведут к ошибке выравнивания.
ADI_DMA_RESULT_BAD_XCOUNT Предоставлено недопустимое значение XCount.
ADI_DMA_RESULT_NULL_DESCRIPTOR Был передан нулевой дескриптор (NULL).
ADI_DMA_RESULT_INCOMPATIBLE_TRANSFER_SIZE У источника и места назначения разные размеры передачи.
ADI_DMA_RESULT_INCOMPATIBLE_WDSIZE У источника и места назначения разные значения WDSIZE.
ADI_DMA_RESULT_INCOMPATIBLE_CALLBACK Callback для дескриптора места назначения несовместим с дескрипторами источника.
ADI_DMA_RESULT_NO_BUFFER У канала нет буфера.

Функция adi_dma_MemoryQueueClose() закрывает поток MDMA который был открыт для очередей передач по памяти.

ADI_DMA_RESULT adi_dma_MemoryQueueClose(
      ADI_DMA_STREAM_HANDLE StreamHandle,
      u32 WaitFlag);

Аргументы:

StreamHandle Хендл на поток MDMA.
WaitFlag Задает, ожидать или нет флага завершения передач (TRUE/FALSE).

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

ADI_DMA_RESULT_SUCCESS Функция завершилась успешно.
ADI_DMA_RESULT_BAD_HANDLE Передан недопустимый хендл потока.

Функция adi_dma_MemoryQueueControl() управляет потоком MDMA или конфигурирует его.

ADI_DMA_RESULT adi_dma_MemoryQueueControl(
      ADI_DMA_STREAM_HANDLE StreamHandle,
      ADI_DMA_CMD Command,
      void *Value);

Аргументы:

StreamHandle Хендл на поток MDMA.
Command Идентификатор команды (Command ID).
Value Значение, зависящее от команды.

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

ADI_DMA_RESULT_SUCCESS Функция завершилась успешно.
ADI_DMA_RESULT_BAD_COMMAND Была передана недопустимая команда.
ADI_DMA_RESULT_ALREADY_RUNNING Команда не выполнилась, потому что канал в настоящий момент передает данные.
ADI_DMA_RESULT_BAD_HANDLE Передан недопустимый хендл потока.

Функция adi_dma_MemoryQueueOpen() открывает поток MDMA для очередей передач по памяти.

ADI_DMA_RESULT adi_dma_MemoryQueueOpen(
      ADI_DMA_MANAGER_HANDLE ManagerHandle,
      ADI_DMA_STREAM_ID StreamID,
      void *ClientHandle
      ADI_DMA_STREAM_HANDLE *pStreamHandle,
      void *DCBHandle,
      ADI_DCB_CALLBACK_FN ClientCallback);

Аргументы:

ManagerHandle Хендл на Менеджер DMA.
StreamID Идентификатор открываемого потока MDMA.
ClientHandle Аргумент ClientHandle, передаваемые во все callback-функции клиента.
pStreamHandle Указатель на место в памяти, где сохраняется StreamHandle DMA.
DCBHandle Хендл на службу отложенных обратных вызовов функций (deferred callback service).
ClientCallback Callback-функция клиента.

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

ADI_DMA_RESULT_SUCCESS Функция завершилась успешно.
ADI_DMA_RESULT_BAD_HANDLE Был передан недопустимый хендл потока или недопустимый хендл Менеджера DMA.
ADI_DMA_RESULT_ALL_IN_USE Все каналы MDMA находятся в использовании.
ADI_DMA_RESULT_CANT_HOOK_INTERRUPT Система не может подцепить обработчик прерывания данных или ошибки DMA.

Функция adi_dma_Open() открывает для использования канал DMA. Менеджер DMA удостоверяется, что канал уже не открыт, и затем инициализирует любые соответствующие структуры данных.

ADI_DMA_RESULT adi_dma_Open(
      ADI_DMA_MANAGER_HANDLE ManagerHandle
      ADI_DMA_CHANNEL_ID ChannelID
      void *ClientHandle,
      ADI_DMA_CHANNEL_HANDLE *pChannelHandle,
      ADI_DMA_MODE Mode,
      ADI_DCB_HANDLE DCBHandle,
      ADI_DCB_CALLBACK_FN ClientCallback);

Аргументы:

ManagerHandle Хендл на Менеджер DMA.
ChannelID Значение из перечисления ADI_DMA_CHANNEL_ID, идентифицирующее канал.
ClientHandle Идентификатор, определенный клиентом. Менеджер DMA включает этот идентификатор во все инициируемые Менеджером DMA обмены с клиентом, особенно в вызовах callback-функции клиента.
pChannelHandle Указатель на предоставленное клиентом место в памяти, где Менеджер DMA сохраняет идентификатор, определяемый Менеджером DMA. Все последующие коммуникации, инициированные клиентом к Менеджеру DMA для этого канала, будут включать в себя этот хендл, чтобы идентифицировать канал.
Mode Значение из перечисления ADI_DMA_MODE, указывающее на режим передачи данных, используемый для открытого канала DMA.
DCBServiceHandle Хендл на службу отложенных обратных вызовов функций (deferred callback service), используемую для указанного канала. Используемое в этом параметре значение NULL означает, что отложенные вызовы callback-функции не используются, и все callback-и вызываются немедленно в контексте обработчика прерывания DMA.
ClientCallback Адрес callback-функции, определяемой приложением. Значение, переданное для параметра ClientHandle, предоставлено приложением, когда канал был открыт.

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

ADI_DMA_RESULT_SUCCESS Функция завершилась успешно.
ADI_DMA_RESULT_ALL_IN_USE Все каналы памяти находятся в использовании.
ADI_DMA_RESULT_CANT_HOOK_INTERRUPT Система не может подцепить обработчик прерывания данных или ошибки DMA.

Функция adi_dma_Queue() запрашивает дескриптор или цепочку дескрипторов для указанного канала DMA.

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

ADI_DMA_RESULT adi_dma_Queue(
      ADI_DMA_CHANNEL_HANDLE ChannelHandle,
      ADI_DMA_DESCRIPTOR_HANDLE DescriptorHandle);

Аргументы:

ChannelHandle Идентификатор, уникально определяющий канал DMA, для которого дескриптор поставлен в очередь. Это значение было получено, когда был открыт канал DMA.
DescriptorHandle Указатель на первый дескриптор в цепочке.

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

ADI_DMA_RESULT_SUCCESS Дескриптор был успешно поставлен в очередь.
ADI_DMA_RESULT_BAD_HANDLE ChannelHandle не содержит допустимого хендла канала.
ADI_DMA_RESULT_BAD_DESCRIPTOR Хендл дескриптора равен NULL.
ADI_DMA_RESULT_ALREADY_RUNNING Не получается добавить дополнительные дескрипторы для канала, сконфигурированного в режиме Loopback с разрешенным потоком данных.

Функция adi_dma_SetConfigWord() устанавливает биты в слове конфигурации цепочки дескрипторов.

ADI_DMA_RESULT adi_dma_SetConfigWord(
      ADI_DMA_CHANNEL_HANDLE ChannelHandle,
      ADI_DMA_DESCRIPTOR_HANDLE DescriptorHandle);

Аргументы:

ChannelHandle Идентификатор, уникально определяющий канал DMA, для которого дескриптор поставлен в очередь. Это значение было получено, когда был открыт канал DMA.
DescriptorHandle Указатель на первый дескриптор в цепочке.

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

ADI_DMA_RESULT_SUCCESS Ошибок не было.
ADI_DMA_RESULT_BAD_HANDLE Хендл канала равен NULL.
ADI_DMA_RESULT_BAD_DESCRIPTOR Хендл дескриптора равен NULL.
ADI_DMA_RESULT_NON_TERMINATED_CHAIN Цепочка не имеет завершающего нулевого значения.
ADI_DMA_RESULT_BAD_DIRECTION Ошибочное значение бита WNR.
ADI_DMA_RESULT_CALLBACKS_DISALLOWED_ON_SOURCE Не разрешены callback-и.

Функция adi_dma_SetMapping() привязывает идентификатор канала DMA (DMA channel ID) к указанному периферийному устройству.

ADI_DMA_RESULT adi_dma_SetMapping(
      ADI_DMA_PMAP pmap,
      ADI_DMA_CHANNEL_ID ChannelID);

Аргументы:

pmap Идентификатор периферийного устройства (Peripheral ID), к которому привязывается канал.
ChannelID Идентификатор канала (channel ID), к которому привязывается периферийное устройство.

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

ADI_DMA_RESULT_SUCCESS Канал был успешно привязан к периферийному устройству.
ADI_DMA_RESULT_BAD_PERIPHERAL Было обнаружено плохое значение периферийного устройства.
ADI_DMA_RESULT_ALREADY_RUNNING Привязка к каналу DMA не была выполнена, поскольку канал в настоящий момент передает данные.

Функция adi_dma_Terminate() закрывает (останавливает) любую активность DMA и завершает работу Менеджера DMA.

ADI_DMA_RESULT adi_dma_Terminate(ADI_DMA_MANAGER_HANDLE ManagerHandle);

Аргумент:

ManagerHandle Хендл на Менеджер DMA.

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

ADI_DMA_RESULT_SUCCESS Процесс завершен успешно.

[Публичные структуры данных, перечисления и макросы]

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

В этой секции рассмотрены следующие вопросы:

• Типы данных
• Структуры данных
• Основные перечисления (enum)
• Значения поля ADI_DMA_CONFIG_REG
• Команды DMA

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

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

Структура данных ADI_DMA_DESCRIPTOR_UNION представляет объединение (union) типов данных малого дескриптора, большого дескриптора и массива дескрипторов. ADI_DMA_DESCRIPTOR_HANDLE это typedef, который описывает указатель на это объединение. ADI_DMA_DESCRIPTOR_HANDLE передается в функцию adi_dma_Queue(), что означает предоставить этой функции a) цепочку малых дескрипторов, b) цепочку больших дескрипторов или c) массив дескрипторов. Путем использования хендла/объединения (handle/union), требуется одна функция single adi_dma_Queue(), вместо отдельных функций для каждого типа данных дескриптора.

typedef union ADI_DMA_DESCRIPTOR_UNION
{
   ADI_DMA_DESCRIPTOR_SMALL Small;
   ADI_DMA_DESCRIPTOR_LARGE Large;
   ADI_DMA_DESCRIPTOR_ARRAY Array;
}ADI_DMA_DESCRIPTOR_UNION;
 
typedef ADI_DMA_DESCRIPTOR_UNION *ADI_DMA_DESCRIPTOR_HANDLE;

Тип данных ADI_DMA_STREAM_HANDLE идентифицирует поток памяти для Менеджера DMA. Когда он передается в функции adi_dma_MemoryXXX, этот handle уникально идентифицирует поток в памяти, с которым работает Менеджер DMA. Менеджер DMA возвратит этот хендл для приложения, когда открывается поток DMA в памяти. Все другие функции потока в памяти требуют передачи этого параметра.

Структуры данных. Структуры, которые определяют каждый тип дескриптора и регистр управления конфигурацией DMA (DMA configuration control register), доступны в заголовочном файле adi_dma.h. Имена полей следуют соглашению о наименовании в руководстве с описанием аппаратуры (Hardware Reference) для подходящего процессора.

Структура ADI_DMA_2D_TRANSFER определяет характеристики компонента источника или места назначения для двухмерного копирования в памяти.

typedef struct ADI_DMA_2D_TRANSFER
{
   void *StartAddress;
   u16 XCount;
   s16 XModify;
   u16 YCount;
   s16 YModify;
}ADI_DMA_2D_TRANSFER;

Тип ADI_DMA_CONFIG_REG определяет структуру для управляющего слова конфигурации DMA (DMA configuration control word). Дополнительно предоставлены макросы, позволяющие клиенту установить отдельные поля в слове.

Структура ADI_DMA_DESCRIPTOR_ARRAY определяет содержимое элемента массива дескрипторов.

typedef struct ADI_DMA_DESCRIPTOR_ARRAY
{
   void *StartAddress;
   ADI_DMA_CONFIG_REG Config;
   u16 XCount;
   s16 XModify;
   u16 YCount;
   s16 YModify;
   u16 CallbackFlag;
} ADI_DMA_DESCRIPTOR_ARRAY;

! Элемент дескриптора CallbackFlag определен как u16, но он должен получать только значения 0 или 1 (FALSE или TRUE соответственно). Передача значения больше 1 может дать непредсказуемые результаты.

Структура ADI_DMA_DESCRIPTOR_LARGE определяет содержимое большого дескриптора.

typedef struct ADI_DMA_DESCRIPTOR_LARGE
{
   struct ADI_DMA_DESCRIPTOR_LARGE *pNext;
   void *StartAddress;
   ADI_DMA_CONFIG_REG Config;
   u16 XCount;
   s16 XModify;
   u16 YCount;
   s16 YModify;
   u16 CallbackFlag;
}ADI_DMA_DESCRIPTOR_LARGE;

! Элемент дескриптора CallbackFlag определен как u16, но он должен получать только значения 0 или 1 (FALSE или TRUE соответственно). Передача значения больше 1 может дать непредсказуемые результаты.

Структура ADI_DMA_DESCRIPTOR_SMALL определяет содержимое малого дескриптора.

typedef struct ADI_DMA_DESCRIPTOR_SMALL
{
   u16 *pNext;
   u16 StartAddressLow;
   u16 StartAddressHigh;
   ADI_DMA_CONFIG_REG Config;
   u16 XCount;
   s16 XModify;
   u16 YCount;
   s16 YModify;
   u16 CallbackFlag;
}ADI_DMA_DESCRIPTOR_SMALL;

! Элемент дескриптора CallbackFlag определен как u16, но он должен получать только значения 0 или 1 (FALSE или TRUE соответственно). Передача значения больше 1 может дать непредсказуемые результаты.

Структура ADI_DMA_TC_SET используется для установки параметра управления трафиком DMA (DMA traffic control parameter). Поле ParameterID задает, какой тип параметра устанавливается, и это определяется с использованием перечисления ADI_DMA_TC_PARAMETER. ControllerID задает контроллер DMA для установки (там, где имеется несколько контроллеров DMA), нумерация контроллеров начинается с 0 (первый контроллер имеет номер 0). Поле Value задает значение для записи.

typedef struct ADI_DMA_TC_SET
{
   ADI_DMA_TC_PARAMETER ParameterID;
   u16 ControllerID;
   u16 Value;
}ADI_DMA_TC_SET;

Структура ADI_DMA_TC_GET используется для установки или считывания параметра управления трафиком DMA (DMA traffic control parameter). Поле ParameterID задает тип параметра, и это определяется перечислением ADI_DMA_TC_PARAMETER. ControllerID задает контроллер DMA (там, где имеется несколько контроллеров DMA), нумерация контроллеров начинается с 0 (первый контроллер имеет номер 0). Поле Value задает место, куда будет сохранено значение параметра.

typedef struct ADI_DMA_TC_GET
{
   ADI_DMA_TC_PARAMETER ParameterID;
   u16 ControllerID;
   u16 *pValue;
}ADI_DMA_TC_GET;

Основные перечисления (enum). Перечисления управляют поведением Менеджера DMA и предоставляют обратную связь с информацией о его работе.

Перечисление ADI_DMA_CHANNEL_ID содержит значения для каждого канала DMA процессора. Это значение используется в функции adi_dma_Open(), чтобы идентифицировать канал для открытия. Специфичные значения перечисления зависят от используемого целевого процессора.

Перечисление ADI_DMA_EVENT описывает типы событий, о которых может быть оповещена функция обратного вызова клиента (callback), см. таблицу 6-2. С параметром ADI_DMA_EVENT связан другой параметр pArg, используемый в паре с ним для описания события.

Таблица 6-2. ADI_DMA_EVENT

Значение Событие (Event) Сопутствующий аргумент
ADI_DMA_EVENT_DESCRIPTOR_PROCESSED Завершена обработка дескриптора или поток MDMA завершил операцию копирования. Адрес только что обработанного дескриптора, или NULL, когда событие соответствует завершению передачи потока MDMA.
ADI_DMA_EVENT_INNER_LOOP_PROCESSED Завершена обработка подбуфера. Начальный адрес кольцевого буфера.
ADI_DMA_EVENT_OUTER_LOOP_PROCESSED Была завершена обработка всего кольцевого буфера.
ADI_DMA_EVENT_ERROR_INTERRUPT Было сгенерировано прерывание ошибки DMA. NULL

Перечисление ADI_DMA_MODE определяет, как работает канал DMA для обработки перемещаемых данных. Это перечисление получает значения, показанные в таблице 6-3.

Таблица 6-3. ADI_DMA_MODE.

ADI_DMA_DATA_MODE_UNDEFINED Не определено.
ADI_DMA_DATA_MODE_SINGLE Один буфер одиночного действия.
ADI_DMA_DATA_MODE_CIRCULAR Один кольцевой буфер.
ADI_DMA_DATA_MODE_DESCRIPTOR_ARRAY Массив дескрипторов.
ADI_DMA_DATA_MODE_DESCRIPTOR_SMALL Цепочка малых дескрипторов.
ADI_DMA_DATA_MODE_DESCRIPTOR_LARGE Цепочка больших дескрипторов.

Перечисление ADI_DMA_PMAP определяет каждое встроенное в кристалл процессора периферийное устройство, которое может работать с использованием DMA. Это значение используется для определения и установки привязок встроенных в чип периферийных устройств к каналам DMA с использованием функций adi_dma_GetMapping() и adi_dma_SetMapping(). Специальные значения перечисления зависят от используемого целевого процессора.

Все публичные функции Менеджера DMA возвращают код из перечисления типа ADI_DMA_RESULT. Возможные значения этого перечисления показаны в таблице 6-4.

Таблица 6-4. Коды ADI_DMA_RESULT.

ADI_DMA_RESULT_SUCCESS Обычное успешное завершение.
ADI_DMA_RESULT_FAILED Обычное неудачное завершение.
ADI_DMA_RESULT_NOT_SUPPORTED Функция не поддерживается.
ADI_DMA_RESULT_IN_USE Ресурс сейчас находится в использовании.
ADI_DMA_RESULT_ALREADY_RUNNING В настоящий момент DMA находится в работе.
ADI_DMA_RESULT_NOT_MAPPED Периферийное устройство не привязано к каналу DMA.
ADI_DMA_RESULT_BAD_HANDLE Недопустимое значение хендла.
ADI_DMA_RESULT_BAD_DESCRIPTOR Недопустимый дескриптор.
ADI_DMA_RESULT_BAD_MODE Недопустимый режим канала.
ADI_DMA_RESULT_BAD_CHANNEL_ID Нет такого идентификатора канала.
ADI_DMA_RESULT_BAD_MEMORY_STREAM_ID Нет такого идентификатора потока.
ADI_DMA_RESULT_BAD_PERIPHERAL Нет такого значения периферийного устройства.
ADI_DMA_RESULT_NO_BUFFER У канала нет буфера.
ADI_DMA_RESULT_ALL_IN_USE Нет в наличии свободных структур каналов памяти.
ADI_DMA_RESULT_BAD_COMMAND Недопустимый элемент команды.
ADI_DMA_RESULT_BAD_DATA_SIZE Конфликт источника и места назначения DMA.
ADI_DMA_RESULT_BAD_DATA_WIDTH Недопустимый размер элемента передаваемых данных.
ADI_DMA_RESULT_NO_MEMORY Нельзя выделить память для объекта канала.
ADI_DMA_RESULT_CANT_HOOK_INTERRUPT Нельзя прицепить обработчик прерывания.
ADI_DMA_RESULT_CANT_UNHOOK_INTERRUPT Нельзя отцепить обработчик прерывания.
ADI_DMA_RESULT_BAD_SEQUENCE Недопустимая последовательность программирования.
ADI_DMA_RESULT_BAD_CONFIG_REG Недопустимое значение для регистра конфигурации.
ADI_DMA_RESULT_BAD_ALIGNMENT_ERROR Параметры приведут к ошибке выравнивания.
ADI_DMA_RESULT_BAD_XCOUNT Предоставлено ошибочное значение XCount.
ADI_DMA_RESULT_NON_TERMINATED_CHAIN Цепочка дескрипторов не завершена значением NULL.
ADI_DMA_RESULT_NO_CALLBACK_FUNCTION_SUPPLIED Для функции открытия не предоставлена callback-функция.
ADI_DMA_RESULT_BAD_CONTROLLER_ID Указан недопустимый идентификатор контроллера DMA.
ADI_DMA_RESULT_BAD_TC_PARAMETER Недопустимый параметр управления трафиком.
ADI_DMA_RESULT_BAD_DIRECTION Недопустимое направление передачи.
ADI_DMA_RESULT_INCOMPATIBLE_WDSIZE У источника и места назначения данных указаны разные значения WDSIZE.
ADI_DMA_RESULT_INCOMPATIBLE_TRANSFER_SIZE У источника и места назначения указаны разные размеры передач.
ADI_DMA_RESULT_NULL_DESCRIPTOR Передан дескриптор нулевого значения (NULL).
ADI_DMA_RESULT_CALLBACKS_DISALLOWED_ON_SOURCE Callback-и не разрешены для дескрипторов источника MDMA.
ADI_DMA_RESULT_INCOMPATIBLE_CALLBACK Callback для дескриптора назначения не совместим с дескрипторами источника.
ADI_DMA_RESULT_BAD_CHANNEL_MEMORY_SIZE Неправильный макрос ADI_DMA_CHANNEL_MEMORY (внутренняя ошибка).
ADI_DMA_RESULT_INCOMPATIBLE_IVG_LEVEL Функция не может быть вызвана из текущего уровня IVG.

Перечисление ADI_DMA_STREAM_ID содержит значения для каждого канала DMA процессора. Это значение используется функцией adi_dma_MemoryOpen(), чтобы идентифицировать какой поток открыть. Специальные значения перечисления зависят от используемого целевого процессора.

Перечисление ADI_DMA_TC_PARAMETER определяет параметры управления трафиком DMA (DMA traffic control parameter), которые можно использовать в поле ParameterID структуры данных ADI_DMA_TC_SET или ADI_DMA_TC_GET, когда Менеджеру DMA передаются команды ADI_DMA_CMD_GET_TC и ADI_DMA_CMD_SET_TC. Возможные значения показаны в таблице 6-5.

Таблица 6-5. ADI_DMA_TC_PARAMETER

ADI_DMA_TC_DCB Шина ядра DMA (DMA core bus).
ADI_DMA_TC_DEB Шина доступа DMA (DMA access bus).
ADI_DMA_TC_DAB Внешняя шина DMA (DMA external bus).
ADI_DMA_TC_MDMA MDMA round robin.

Значения поля ADI_DMA_CONFIG_REG. Эти значения используются для установки соответствующих бит в слове конфигурации DMA (DMA configuration word).

ADI_DMA_LINEAR Линейный буфер
ADI_DMA_2D Двухмерная операция DMA

ADI_DMA_DI_EN_DISABLE Запрещает callback-и при завершении.
ADI_DMA_DI_EN_ENABLE Разрешает callback-и при завершении.

ADI_DMA_DI_SEL_OUTER_LOOP Callback после завершения всего буфера (поведение по умолчанию).
ADI_DMA_DI_SEL_INNER_LOOP Callback после завершения каждого внутреннего цикла.

ADI_DMA_DISABLE Запрещает передачу DMA на канале.
ADI_DMA_ENABLE Разрешает передачу DMA на канале.

ADI_DMA_8BIT Слова шириной 8 бит.
ADI_DMA_16BIT Слова шириной 16 бит.
ADI_DMA_32BIT Слова шириной 32 бита.

ADI_DMA_READ Передача из памяти в периферийное устройство (чтение).
ADI_DMA_WRITE Передача из периферийного устройства в память (запись).

Команды DMA. Каналы DMA и потоки в памяти могут управляться через вызовы функции adi_dma_Command(). Таблица 6-6 описывает команды и их значения, которые могут быть выданы с помощью этой функции.

Таблица 6-6. Команды DMA.

Command ID Значение Описание
ADI_DMA_CMD_TABLE ADI_DMA_CMD_VALUE_PAIR * Указатель на таблицу команд.
ADI_DMA_CMD_PAIR ADI_DMA_CMD_VALUE_PAIR * Указатель на одиночную пару команды.
ADI_DMA_CMD_END NULL Обозначает конец таблицы.
ADI_DMA_CMD_SET_LOOPBACK TRUE/FALSE Разрешает / запрещает Loopback.
ADI_DMA_CMD_SET_STREAMING TRUE/FALSE Разрешает / запрещает работу потока.
ADI_DMA_CMD_SET_DATAFLOW TRUE/FALSE Разрешает / запрещает поток данных.
ADI_DMA_CMD_FLUSH недоступно Сбрасывает все буферы и дескрипторы на канале.
ADI_DMA_CMD_GET_TRANSFER_STATUS u32 * Предоставляет состояние передачи: TRUE если передача работает, FALSE если завершена.
ADI_DMA_CMD_SET_TC ADI_DMA_TC_SET * Устанавливает параметр управления трафиком (период).
ADI_DMA_CMD_GET_TC ADI_DMA_TC_GET * Получает параметр управления трафиком (счетчик).

[Ссылки]

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