В этой статье приведен перевод раздела "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_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() с новым буфером данных, и затем опять разрешить поток данных на соответствующем канале.
Рис. 6-1. Использование режима кольцевого буфера для циклической передачи.
Модель цепочек больших дескрипторов (ADI_DMA_MODE_DESCRIPTOR_LARGE) позволяет клиенту создать цепочки из дескрипторов, находящихся в любом месте памяти, где каждый дескриптор описывает отдельный рабочий блок передачи.
Используя режим цепочки больших дескрипторов, клиент предоставляет Менеджеру DMA одну или большее количество цепочек дескрипторов, как это показано на рис. 6-2.
Дескрипторы могут быть предоставлены в любое время, независимо от состояния потока данных. Менеджер 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 к клиенту после обработки.
Рис. 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 показана обрабатываемая область кадра.
Рис. 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.
Рис. 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 в соответствии с предоставленными параметрами.
Уникально идентифицирует канал 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_Close() закрывает канал DMA и освобождает память конфигурации для будущего использования. В зависимости от значения аргумента WaitFlag канал будет закрыт немедленно или только после завершения текущей происходящей передачи DMA.
Уникально идентифицирует канал 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_COMMAND_PAIR. Таблица должна иметь следующую запись-терминатор, чтобы определить конец таблицы команд: { ADI_DMA_CMD_END, 0 }. Например:
Набор команд, который может быть использован с функцией 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_GetPeripheralInterruptID получает идентификатор прерывания периферийного устройства (peripheral interrupt ID) для указанного идентификатора канала DMA (DMA channel ID).
Если этот параметр установлен в TRUE (1), то Менеджер DMA будет перед закрытием ожидать завершения текущих передач; иначе, если параметр установлен в FALSE (0), то Менеджер DMA закроет канал немедленно.
Возвращаемые значения:
ADI_DMA_RESULT_SUCCESS
Функция завершилась успешно.
ADI_DMA_RESULT_BAD_HANDLE
StreamHandle не указывает на допустимый хендл потока MDMA.
Начальный адрес места назначения, куда копируются данные.
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 в настоящий момент используется (занят передачей по памяти).
Указатель на структуру, которая описывает, как и куда будут копироваться данные в памяти.
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 в настоящий момент используется (занят передачей по памяти).
Идентификатор, определенный клиентом. Менеджер 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_Open() открывает для использования канал DMA. Менеджер DMA удостоверяется, что канал уже не открыт, и затем инициализирует любые соответствующие структуры данных.
Значение из перечисления 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.
[Публичные структуры данных, перечисления и макросы]
В этой секции определены публичные структуры данных и перечисления, используемые Менеджером 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(), вместо отдельных функций для каждого типа данных дескриптора.
Тип данных ADI_DMA_STREAM_HANDLE идентифицирует поток памяти для Менеджера DMA. Когда он передается в функции adi_dma_MemoryXXX, этот handle уникально идентифицирует поток в памяти, с которым работает Менеджер DMA. Менеджер DMA возвратит этот хендл для приложения, когда открывается поток DMA в памяти. Все другие функции потока в памяти требуют передачи этого параметра.
Структуры данных. Структуры, которые определяют каждый тип дескриптора и регистр управления конфигурацией DMA (DMA configuration control register), доступны в заголовочном файле adi_dma.h. Имена полей следуют соглашению о наименовании в руководстве с описанием аппаратуры (Hardware Reference) для подходящего процессора.
Тип ADI_DMA_CONFIG_REG определяет структуру для управляющего слова конфигурации DMA (DMA configuration control word). Дополнительно предоставлены макросы, позволяющие клиенту установить отдельные поля в слове.
! Элемент дескриптора CallbackFlag определен как u16, но он должен получать только значения 0 или 1 (FALSE или TRUE соответственно). Передача значения больше 1 может дать непредсказуемые результаты.
! Элемент дескриптора CallbackFlag определен как u16, но он должен получать только значения 0 или 1 (FALSE или TRUE соответственно). Передача значения больше 1 может дать непредсказуемые результаты.
! Элемент дескриптора 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 задает значение для записи.
Структура ADI_DMA_TC_GET используется для установки или считывания параметра управления трафиком DMA (DMA traffic control parameter). Поле ParameterID задает тип параметра, и это определяется перечислением ADI_DMA_TC_PARAMETER. ControllerID задает контроллер DMA (там, где имеется несколько контроллеров DMA), нумерация контроллеров начинается с 0 (первый контроллер имеет номер 0). Поле Value задает место, куда будет сохранено значение параметра.
Перечисление 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_MODE определяет, как работает канал DMA для обработки перемещаемых данных. Это перечисление получает значения, показанные в таблице 6-3.
Перечисление ADI_DMA_PMAP определяет каждое встроенное в кристалл процессора периферийное устройство, которое может работать с использованием DMA. Это значение используется для определения и установки привязок встроенных в чип периферийных устройств к каналам DMA с использованием функций adi_dma_GetMapping() и adi_dma_SetMapping(). Специальные значения перечисления зависят от используемого целевого процессора.
Перечисление 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_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 *
Устанавливает параметр управления трафиком (период).