[i] Работа с DMA в процессорах серии К1967ВНxx
Контроллер прямого доступа в память, он же DMA (Direct Memory Access) обеспечивает механизм передачи данных без исполнения команд в ядре процессора. Это определение ни раз уже использовалось в различных источниках, в том числе и в статье, в которой рассказывается о работе данного механизма в процессорах на базе ядра Cortex-M. В этом материале будут представлены основные понятия о DMA в ЦОС-процессорах серии К1967ВНхх, поскольку блок имеет существенные различия по сравнению с тем, который используется в микроконтроллерах на Cortex.
1. Архитектура DMA
В основном, блок DMA одинаков для процессоров серии К1967, но все же есть свои особенности как для К1967ВН02BG, так и для процессоров К1967ВН044, К1967ВН04BG. В данном материале постараемся уточнить такие моменты.
Передача DMA может быть осуществлена между:
- внутренняя память процессора ↔ внутренняя память процессора;
- внутренняя память процессора ↔ внешняя память;
- внутренняя память процессора ↔ внешняя периферия;
- внешняя память процессора ↔ внешняя периферия;
- внешняя память процессора ↔ порт связи;
- порт связи ↔ порт связи;
- внутренняя память процессора ↔ внутренняя память другого процессора; (только для К1967ВН02BG)
- внутренняя память процессора ↔ хост-процессор; (только для К1967ВН02BG)
- ведущий на кластерной шине ↔ внутренняя память через AutoDMA; (только для К1967ВН02BG)
1.1. Каналы
Обычно, все привыкли к тому, что для DMA необходимо указать адрес источника, адрес приёмника, добавить управляющее слово и можно запускать цикл (так работает DMA в контроллерах на Cortex). В ЦОС-процессорах DMA реализован иначе. Здесь управляющая структура DMA отдельно задается на приём и на передачу. Управляющую структуру в терминах документации принято обозначать как TCB. Но к этому вернёмся ниже по тексту.
В К1967ВН02BG всего есть 14 каналов, в то время как в К1967ВН044 и К1967ВН04BG их 13. Приведём краткую таблицу для каждого процессора (также см. спецификации) (таблицы 1 и 2). Первые 4 канала (0-3) являются универсальными и полностью программируемыми, например, используются для пересылки память-память. Инициирование транзакции подразумевает источник запроса, то есть в случае с данными каналами, запрос можно выставлять запрос программно.
Каналы 4-7 предназначены для устройств передачи. То есть, данные из внутренней/внешний памяти отправляются в периферийный передатчик, соответственно (вероятно) условие возникновение запроса к dma - пустота передатчика.
Каналы 8-11 предназначены для устройств приёма. Все тоже самое, только в обратном направлении, а условие возникновение запроса - наличие данных в приёмнике.
Таблица 1 - Каналы DMA для К1967ВН02BG| Номер канала | Источник данных | Приёмник | Инициирование транзакции |
|---|---|---|---|
| 0-3 | Программируется TCB | Программируется TCB | Программируется. Может использовать входы nDMAR0-3. |
| 4-7 | Программируется TCB | Передатчик портов связи каналы 0-3 | По запросу от периферии. |
| 8-11 | Приёмник портов связи каналы 0-3 | Программируется TCB | По запросу от периферии. |
| 12 | Запись данных внешним ведущим устройством | Программируется TCB | Всегда, при наличии данных во внутреннем буфере. |
| 13 | Запись данных внешним ведущим устройством | Программируется TCB | Всегда, при наличии данных во внутреннем буфере. |
| Номер канала | Источник данных | Приёмник | Инициирование транзакции |
|---|---|---|---|
| 0-3 | Программируется TCB | Программируется TCB | Программируется. Может использовать запрос устройства. |
| 4-7 | Программируется TCB | Режим 1/2. Периферийное устройство/Адрес устройства задается в специальном регистре DCA | По запросу от периферии. |
| 8-11 | Режим 1/2. Периферийное устройство/Адрес устройства задается в специальном регистре DCA | Программируется TCB | По запросу от периферии. |
| 12 | Запись данных цифровым коррелятором в регистр канала | Программируется TCB | Всегда, при наличии данных во |
1.2. Запросы
Каналы 0-3 предназначены для использования программных запросов и для запроса от внешних устройств с выводов nDMAR0-3 (для К1967ВН044, К1967ВН04BG можно использовать внешние выводы для всех каналов). Каналы же 4-11 предназначены для обработки запросов от периферии. Если К1967ВН02BG всё просто: все эти каналы предназначены для работы с передатчиками/приёмника link-порта, то в случае же с К1967ВН044, К1967ВН04BG периферия представлена не только link-портами. Поэтому для того, чтобы указать DMA от какой периферии ожидать запрос. Есть специальный регистр DMACFG, состоящий из двух 32 разрядных регистров DMACFGL и DMACFGH. Об этом подробнее описано в данной статье "[i] DMA + периферийное устройство".
2. Управляющая структура TCB
Как уже было замечено выше, блок управления передачей TCB представляет из себя квадрослово (128 бит), то есть 4 регистра по 32-бита. Именно в нём представлена информация для конфигурации канала DMA.
Рисунок 1 - Схема конфигурирования DMA контроллера
Квадрослово TCB содержит 4 регистра: DI, DX, DY, DP.
2.1. Регистр DI
В регистр DI заносится адрес, который может указывать на внутреннюю и внешнюю память. В случае, если DMA программируется на передачу, то задается адрес, откуда взять данные (адрес источника), соответственно, если DMA настраивается на приём, то указывается адрес, куда положить их (адрес приёмника).
Таблица 3 - Регистр DI
| биты | поле |
Описание |
|---|---|---|
| 31..0 | DI | Содержит начальный адрес блока данных |
2.2. Регистр DX
Таблица 4 - регистр DX| биты | поле | Описание |
|---|---|---|
| 31..16 | DXC | Количество слов блока данных, которое необходимо передать |
| 15..0 | DXM | Значение модификатора, используемое для изменения адреса после каждой транзакции |
2.3. Регистр DY
Данный регистр имеет описание, аналогичное регистру DX, и используется вместе с ним, когда режим работы двумерного DMA разрешен. Если двумерный режим выключить, то необходимо оставить данное поле равным нулю.
2.4. Регистр DP
Основной регистр конфигурации управляющего слова. Здесь очень важно соблюдать определённые правила и ограничения при его программировании. Они приведены в документации. Когда канал завершает работу, поле TY переходит в состояние "канал выключен", то есть старшие биты сбрасываются.
Таблица 5 - Регистр DP
| биты | поле | Значения | Описание |
|---|---|---|---|
| 31..29 | TY |
000 - канал выключен 001 - линк порт 010 - внутренняя память (16/16) 011 - внутренняя память (22/10) 100 - внешняя память (16/16) 101 - внешнее устройство Flyby (только для К1967ВН02BG, для К1967ВН044, К1967ВН04BG - резерв) 110 - загрузочное EPROM 111 - внешняя память |
Тип обмена, выбор источника или приёмника |
| 28 | PR |
1 - высокий 0 - обычный |
Приоритет циклов обмена |
| 27 | 2D |
1 - двумерная посылка 0 - одномерная посылка |
Включение режима 2-х мерной посылки |
| 26..25 | LEN |
00 - резерв 01- слово 32 бита 10 - длинное слово 64 бита 11 - квадрослово 128 бит |
Длина передаваемых данных (операнда) в одном цикле |
| 24 | INT |
1 - разрешено 0 - запрещено |
Разрешение запроса прерывания после окончания работы канала |
| 23 | DRQ |
1 - разрешено 0 - запрещено |
Разрешение анализа от внешнего запроса/запроса от периферии |
| 22 | CHEN |
1 - разрешено 0 - запрещено |
Разрешение загрузки следующей цепочки |
| 21..19 | CHTG |
000 – канал 8 001 – канал 9 010 – канал 10 011 – канал 11 100 – канал 4 101 – канал 5 110 – канал 6 111 – канал 7 |
Канал следующей цепочки. Поле имеет значение только для каналов 4-11 |
| 18..0 | CHPT | Указатель цепочки DMA. Поле включает в себя разряды 20-2 адреса внутренней памяти, где находится значение следующего регистра TCB |
3. Пример
Рассмотрим следующий пример работы с DMA: просто скопируем массив данных из одной области памяти в другую. Работать будем с полностью программируемыми каналами 0-3. Для этого откроем описание библиотеки HAL и воспользуемся стандартной функцией для копирования данных с помощью DMA HAL_DMA_MemCopy32 (). В принципе, пример можно запускать на обоих процессорах - К1967ВН02BG и К1967ВН044/К1967ВН04BG, только необходимо подключить соответствующие библиотеки.
Запуск на К1967ВН044.
Ниже приведём листинг кода.
#include <hal_1967VN044.h>
#define N 1024
int data_tx32[N];
int data_rx32[N];
int main(void)
{
int i;
int errFlag;
for (i=0; i < N; i++)
data_tx32[i] = i;
errFlag = HAL_DMA_MemCopy32(2, &data_tx32, &data_rx32, N);
return 0;
}
Комментарии. В качестве параметров необходимо передать номер используемого канала DMA, указатель на массив передаваемых данных (сам массив предварительно инициализируется последовательностью чисел от одного до N), указатель на массив принимаемых данных, куда DMA сложит данные и количество самих данных. Функция возвращает флаг ошибки. Очень удобно, когда все делает одна функция, но для понимания работы DMA рассмотрим, что именно она делает. В первую очередь происходит объявление структуры управляющих данных DMA. И здесь кроется очень важный момент, который необходимо выделить.
uint32_t __attribute((aligned(4))) tcb_dcs[4];
uint32_t __attribute((aligned(4))) tcb_dcd[4];
Теперь посмотрим на инициализацию самой структуры. Стоит отметить тот момент, что поскольку используется один из каналов DMA общего назначения, то инициализировать нужно 2 управляющие структуры TCB: источника (где будут размещены данные для передачи) и назначения (куда DMA сложит отправленные пользователем данные). В терминах спецификации квадрослово источника именуется DCS, а квадрослово приёмника или назначения - DCD. Рассмотрим DCS:
tcb_dcs[ 3 ] = 0;
HAL_DMA_InitMemType( ( uint32_t )src, tcb_dcs[ 3 ] );
tcb_dcs[ 0 ] = ( uint32_t ) src;
tcb_dcs[ 1 ] = ( size << 16 ) | 1;
tcb_dcs[ 2 ] = 0;
tcb_dcs[ 3 ] |= TCB_NORMAL;
Для начала четвертый регистр DP сбрасывается. Затем с помощью макроса HAL_DMA_InitMemType проверяется, по какому адресу находится массив входных данных и в соответствии с ним задается поле TY регистра DP. В данном случае используется внутренняя память и поле TY=010;
#define TCB_INTMEM (0x40000000)
Затем в регистр DI заносится адрес массива данных для отправки. В регистр DX, в младшее полуслово заносим значение модификатора адреса DMA, используемое для изменения адреса после каждой транзакции, а в старшее полуслово заносим общее количество посылок, то есть размерность нашего массива для передачи. Регистр DY инициализируется нулём, поскольку двумерный DMA мы не используем. И в конце в регистр DP, к ранее заполненному полю TY, добавляем поле LEN =010, то есть указываем длину передаваемых данных операнда в одном цикле - 32 бита.
#define TCB_NORMAL (0x02000000)
Собственно, инициализация управляющей структуры назначения DMA DCD ничем не отличается, разве что в регистр DI заносится указатель на массив принимаемых данных.
tcb_dcd[ 3 ] = 0;
HAL_DMA_InitMemType( ( uint32_t )dst, tcb_dcd[ 3 ] );
tcb_dcd[ 0 ] = ( uint32_t ) dst;
tcb_dcd[ 1 ] = ( size << 16 ) | 1;
tcb_dcd[ 2 ] = 0;
tcb_dcd[ 3 ] |= TCB_NORMAL;
Теперь сконфигурированные структуры с помощью функций HAL_DMA_WriteDCS () и HAL_DMA_WriteDCD () заносятся в память по соответствующем адресам DMA.
HAL_DMA_WriteDCD( ch_number, &tcb_dcd );
HAL_DMA_WriteDCS( ch_number, &tcb_dcs );
Можно запустить программу и поставить точку останова на функции HAL_DMA_WriteDCS( ch_number, &tcb_dcs ), то есть до записи структуры на отправку. И посмотреть, как прошла конфигурация принимающего блока DCD.
Рисунок 2 - Значение сконфигурированного DCD
Красным выделен регистр - DI.
В нём лежит указатель на массив, куда будут размещены принятые данные.
Рисунок 3 - Значения указателя на массив данных
Зелёным обозначен - DX;
синим - DY;
фиолетовым - DP;
Посмотреть значение, записанное в управляющую структуру передатчика, не получится, поскольку как только конфигурационное квадрослово будет записано по адресу источника DSC2, регистры DCS и DCD тут же изменят свое значение.
Получается, как только квадрослово источника на передачу DMA помещается в соответствующий регистр DCS программируемых каналов 0-3, то и происходит выставление программного запроса к DMA.Рисунок 4 - Значение управляющих структур после завершения транзакции DMA
Это говорит о том, что используемый второй канал DMA отработал, и старшее поле TY регистра DP приняло значение 000, что соответствует выключенному каналу. И теперь можно увидеть, как DMA перенес данные из массива data_tx32 в массив data_rx32.
Рисунок 5 - Результат работы DMA
Сохранить статью в PDF