48250

[i] Начальные сведения о DMA

Дата последнего изменения: 21.11.2025 15:51:51
Материал из настоящей статьи, относящийся к микросхемам К1986ВЕ92QI и К1986ВЕ1QI, распространяется в том числе на микроконтроллеры К1986ВЕ92FI, К1986ВЕ92F1I, К1986ВЕ94GI и К1986ВЕ1FI, К1986ВЕ1GI.

DMA (Direct Memory Access) - специализированный контроллер, предназначенный для пересылки данных без использования ядра микроконтроллера. Использование DMA позволяет не тратить процессорное время на отслеживание готовности данных в периферийных блоках и последующую их пересылку. Ядро инициализирует DMA и переходит к выполнению других задач, пока не возникнет прерывание от DMA, сигнализирующее о том, что заданное количество данных было передано.

Как и при любой пересылке данных, для запуска обмена с использованием DMA необходимы следующие параметры:

  • адреса источника и приёмника;
  • разрядность передаваемых данных;
  • количество передаваемых данных (цикл DMA);
  • инкремент адресов источника и приёмника после передачи каждого значения.

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

  • Инкремент адреса необходим, когда передается или принимается массив данных, расположенных по последовательным адресам.
  • Фиксированный адрес необходим при чтении и записи данных в регистр, например, когда выбран адрес регистра данных АПЦ или ЦАП, или при чтении и записи данных в FIFO.

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

  • 8 бит (байт);
  • 16 бит (полуслово);
  • 32 бита (слово).

1. Каналы DMA

Для выполнения нескольких "параллельных" задач по пересылке данных в контроллере DMA реализовано 32 независимых канала. Одновременно передачи может осуществлять только один канал. Каждый канал настраивается отдельно на выполнение конкретной задачи. Таким образом, возможно одновременно запустить и копирование массивов данных в памяти, и считывание данных из АЦП, и запись данных в ЦАП и многое другое. Все это будет работать "параллельно" (благодаря арбитражу активные каналы попеременно осуществляют передачи DMA).

Для реализации совместной "параллельной" работы нескольких каналов в контроллере DMA предусмотрен механизм смены текущего канала при исполнении цикла обмена - арбитраж. В настройках каждого канала количество передач до арбитража задает параметр R_power. Количество передач до арбитража может быть задано меньшим, чем полный цикл обмена канала DMA. Значение этого параметра является степенью 2, т.е. возможны 1, 2, 4, 8, 16, 32, 64, 128, 256, 512 и 1024 непрерывные передачи, которые не могут быть прерваны процедурой арбитража.

Например, необходимо передать 100 значений из массива в массив. Если установить R_power = 6, то контроллер DMA выполняет передачи активного канала до осуществления 64 (26) передач. После этого осуществляется процедура арбитража:

  • Если нет запросов от более приоритетных каналов, то текущий канал закончит передачу оставшихся 36 значений. После этого канал разрешит арбитраж и вызовет аппаратное прерывание от DMA - завершение цикла DMA;
  • Если есть запросы от более приоритетных каналов, то DMA обработает эти приоритетные каналы. Канал, настроенный на передачу 100 значений, выставит запрос на обработку и будет ожидать арбитраж, в ходе которого DMA вернется к исполнению канала и будут переданы оставшиеся 36 значений.

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

1.1 Источники и приемники данных 

В отличие от простого цикла копирования, DMA может не просто выполнять пересылку данных, а делать это по определённому событию.

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

Аналогично, для контроллера ЦАП адресом назначения канала DMA выбирается регистр данных ЦАП, а событием, по которому происходит передача слова, выбирается событие периода таймера  общего назначение (запрос к DMA по событию совпадения счётчика CNT и основания счёта ARR). Тогда с помощью DMA можно получить равномерный вывод сигнала в ЦАП по таймеру. Форма сигнала для вывода в ЦАП в данном случае обычно прописывается массивом, который выбирается в качестве источника данных для DMA. Размер массива указывается в параметре - "количество передаваемых данных". По окончанию передачи массива возникает прерывание от DMA - окончание цикла DMA.

1.2 Запросы к DMA от периферийных устройств

Передача одного значения называется одиночной передачей, а передача 2R_power данных - блочной передачей.
Периферийные блоки могут запрашивать блочные и одиночные передачи, используя внутренние сигналы dma_req[С] и dma_sreq[С]. С - номер канала, т то есть каждый канал имеет отдельные сигналы от периферии.

dma_req[C] - запрос на блочную передачу DMA. Когда от периферии приходит запрос dma_req[С], контроллер DMA выполняет 2R_power передач, далее контроллер DMA ожидает новый запрос dma_req[С] или dma_sreq[С] от периферии. Если в цикле DMA осталось выполнить меньше количество передач, чем 2R_power, то выполняется оставшееся количество передач, чтобы закончить цикл DMA.

dma_sreq[C] - запрос на одиночную передачу DMA. Когда от периферии приходит запрос dma_sreq, контроллер DMA выполняет 1 передачу, далее контроллер DMA ожидает новый запрос dma_sreq[С] от периферии.

Обработку одиночных запросов от dma_sreq[C] можно отключить/включить - для этого используются регистры CHNL_USEBURST_SET / CHNL_USEBURST_CLR. При выключенной обработке одиночных запросов от dma_sreq[C] будут обрабатываться только запросы от dma_req[C].

В МК К1986ВЕ92QI, К1986ВЕ1QI, К1986ВК234, К1986ВК025 и MDR1206FI сигналы dma_req[С] и dma_sreq[С] от определенных периферийных контроллеров жестко привязаны к каналам DMA. Например, подключение сигналов запросов dma_req[С] и dma_sreq[С] от периферии к каналам DMA для микроконтроллера К1986ВЕ92QI приведено в таблице 1.

Таблица 1 – Распределение запросов от периферийных контроллеров по каналам DMA
Номер канала   Источник dma_sreq Источник dma_req
0 UART1_TX UART1_TX
1 UART1_RX UART1_RX
2 UART2_TX UART2_TX
3 UART2_RX UART2_RX
4 SSP1_TX SSP1_TX
5 SSP1_RX SSP1_RX
6 SSP2_RX SSP2_TX
7 SSP2_RX SSP2_RX
8 ADC1_EC -
9 ADC2_EC -
10 TIMER1 -
11 TIMER2 -
12 TIMER3 -
13 - -
- -
31 - -


Каналы 13 - 31 являются программными, поэтому для установления запроса на выполнение передачи должен быть установлен соответствующий каналу бит в регистре CHNL_SW_REQUEST. Необходимо отметить, что запрос на передачу аппаратного канала также можно выставить программный путём с помощью регистра CHNL_SW_REQUEST.

У каждого канала есть свой приоритет, и он определяется индексом канала. 0-ой канал имеет самый высокий приоритет, далее приоритет следует в порядке убывания. Если посмотреть распределение каналов DMA для К1986ВЕ92QI, то самый приоритетный - это UART1_TX. Приоритет по умолчанию можно увеличить, задав каналу высокий приоритет. Для задания высокого приоритета используется регистр CHNL_PRIORITY_SET, в который необходимо записать "1" в бит по индексу канала. Для возвращения приоритета в обычное состояние (низкий приоритет), используется регистр CHNL_PRIORITY_CLR - запись "1" в бит по индексу канала. Чтение регистра CHNL_PRIORITY_SET возвращает текущее состояние приоритета канала: 0 - приоритет по умолчанию (низкий приоритет), 1 – высокий приоритет.

В МК К1986ВК01GI сигналы запросов dma_sreq[C] и dma_req[C] от периферийных устройств могут мультиплексироваться между каналами, что позволяет гибко настроить приоритет работы DMA с периферийными контроллерами.

1.3 Арбитраж каналов DMA 

На рисунке 1 показана структурная схема работы каналов DMA с осуществлением арбитража.

Рисунок 1 – Структурная схема работы каналов DMA с осуществлением арбитража

Пояснения к рисунку 1:
  • всего есть 32 канала DMA;
  • приоритет каналов убывает от 0-го канала к 31-му;
  • каналы передают данные блоками по 2R_power, между которыми осуществляется арбитраж - смена канала;
  • DMA передача - это передача одного слова данных заданной размерности;
  • цикл DMA - это общее количество данных, которое необходимо передать. Задается параметром N_minus_1;
  • для передачи следующей порции данных необходим запрос на обслуживание канала DMA - DMA Request. По этой причине более приоритетный канал С-1 отдает управление каналу С – так как запрос к С-1 еще не установлен к моменту арбитража. Поэтому исполнение переходит к каналу С, и только на следующем арбитраже канал С-1 передаст оставшееся слово;
  • под DMA Request подразумевается запрос по сигналам sreq[C], req[C] или программный запрос;
  • каждый канал управляется своей структурой, состоящей из 4-х 32-битных слов;
  • последнее слово резервное и не используется;
  • два слова в структуре задают адрес источника и приемника данных;
  • все настройки обмена задаются в слове Control:
    • общее количество передач задается полем N_minus_1 при запуске. Далее это значение используется для вычисления текущего адреса передаваемых данных и уменьшается контроллером DMA при передаче каждого слова; 
    • младшие 3 бита Control задают режим работы канала. По окончанию цикла DMA это поле сбрасывается контроллером DMA в 0, что означает режим STOP - канал работу закончил.

1.4 Управляющие данные канала DMA

Каждый канал управляется своей структурой, которая состоит из 4-х 32-разрядных слов:
  • Source End Pointer - конечный адрес источника данных;
  • Destination End Pointer - конечный адрес приемника данных;
  • Control - параметры обмена;
  • Reserved - не используется.
Параметры цикла DMA канала находятся в слове Control. Это слово меняется в процессе работы канала, и по этому слову можно узнать, сколько осталось данных для передачи и закончил ли работу канал. Именно это слово должно быть восстановлено начальными значениями при перезапуске цикла DMA. В таблице 2 приведено описание слова Control.

Таблица 2 – Описание полей слова Control
Биты Поле Значения Описание
31..30 dst_inc b00 - байт 
b01 - полуслово 
b10 - слово 
b11 - ноль/нет инкремента
Инкремент адреса приемника
29..28 dst_size Размерность данных приемника, всегда равна src_size! 
27..26 src_inc Инкремент адреса источника
25..24 src_size Размерность данных источника
23..21 dst_prot_ctrl b001 - Привилегированый доступ 
b010 - Буферизируется 
b100 - Кэшируется
Флаги привилегий приемника
20..18 src_prot_ctrl Флаги привилегий источника
17..14 R_power b000 - 1 передача Передач до арбитража
b001 - 2 передачи
b010 - 4 передачи
b1010 - 1024 передачи
13..4 N_minus_1 0 - 1024 Передач в цикле DMA
3 next_useburst b0 - sreq и req Переопределение CHNL_USEBURST_SET[C] в режиме 
с изменением конфигурации
b1 - req
2..0 cycle_ctrl b000 - STOP Режим работы
b001 - Основной
b010 - Авто-запрос
b011 - Пинг-понг
b100/b101 - Реконфигурация с памятью
b110/b111 - Реконфигурация с периферией

Контроллер DMA вычисляет адрес текущей передачи из конечного адреса по следующей формуле:
Addr = data_end_ptr - (n_minus_1 << src_inc), где src_inc - инкремент данных источника
Размерность данных приемника всегда должна быть равна размерности данных источника: src_size == dst_size
Управляющие структуры каналов должны быть расположены в памяти друг за другом и представлять собой массив структур. Когда DMA будет обрабатывать канал, например, 5-й, то он будет считывать и изменять 5-ю структуру в массиве. Указатель на начало массива структур должен быть прописан в регистре CTRL_BASE_PTR.

При использовании SPL этот массив структур уже определен в файле «MDR32F9Qx_dma.c» как массив структур DMA_ControlTable[64]. Массив DMA_ControlTable[64] имеет вдвое большую длину - 64 структуры, а каналов всего 32. Вторая половина (с 32-го индекса) является альтернативным массивом структур, и адрес этого массива можно считать в регистре ALT_CTRL_BASE_PTR. Регистр ALT_CTRL_BASE_PTR доступен только на чтение и устанавливается автоматически при задании регистра CTRL_BASE_PTR.

Альтернативная структура может использоваться, например, в режиме работы ping-pong. В этом режиме по окончании цикла основной структуры DMA переключится на исполнение альтернативной структуры, затем, по окончании цикла альтернативной структуры DMA снова перейдёт к выполнению основной структуры и так далее. Получается, что один и тот же канал работает то с одной управляющей структурой, то с другой. По окончании цикла каждой структуры будет вызвано прерывание, и пока DMA выполняет обмен по текущей структуре, необходимо заново проинициализировать следующую структуру. Такой подход позволяет организовать непрерывную пересылку данных с помощью DMA с минимальными затратами процессорного времени.

Режим ping-pong может пригодиться, например, для вывода сигнала в ЦАП. Пока DMA выводит сигнал по основной структуре, ядро высчитывает и заполняет данные сигнала для альтернативной структуры. По завершении цикла DMA переключится на альтернативную структуру, и ядро может заполнять сигнал для основной структуры и так далее.

2. Регистры блока DMA

Полное описание регистров представлено в спецификации. В данной статье будут рассмотрены только основные моменты работы с регистрами DMA. Особое внимание следует уделить параметрам ReadOnly (RO) и WriteOnly (WO). Далее по тексту ниже, где атрибуты не указаны, доступ разрешен и на запись, и на чтение - Read-Write (RW).

Доступ к большинству регистров блока DMA реализованы с помощью дополнительных регистров с приставками SET и CLR, которые позволяют осуществлять установку и сброс отдельных бит в основном регистре. Запись нулей в регистры SET и CLR не влияют на состояние регистра.
  1. Регистр SET: - RW, при записи 1-ниц устанавливаются биты в основном регистре; 
  2. Регистр CLR: - RO, при записи 1-ниц сбрасываются биты в основном регистре.
Перечень регистров DMA приведён в таблице 3. В таблице указано только название основного регистра, обозначением (S/C) показано, что доступ обеспечивается через регистры-маски SET и CLR.

Таблица 3 - Перечень регистров контроллера DMA
Название регистра Описание
STATUS Отражает состояние контроллера, RO
CFG Бит Master_enable - включает работу блока DMA. Но весь регистр WO, при чтении возвращается 0.
CTRL_BASE_PTR Задает указатель на массив первичных и вторичных управляющих структур каналов.
ALT_CTRL_BASE_PTR Возвращает указатель на массив альтернативных управляющих структур каналов, RO. Значение высчитывается из CTRL_BASE_PTR и количества каналов в блоке DMA.
WAITONREG_STATUS Состояние сигналов запроса на обработку к каналам DMA, RO
CHNL_SW_REQUEST Запись 1 в бит канала вызывает программный запрос на обработку канала, WO.
CHNL_USEBURST (S/C) Бит канала: 0 - обработка запросов sreq и req, 1 - только req.
CHNL_REQ_MASK (S/C) Бит канала: 0 - работа канала разрешена, 1 - работа канала запрещена.
CHNL_ENABLE (S/C) Запись 1 в бит канала запускает работу канала. После окончания цикла, бит аппаратно сбрасывается в 0.
CHNL_PRI_ALT (S/C) Бит канала: 0 - канал использует первичную структуру, 1 - альтернативную. Можно указать вручную. В режимах работы, использующих обе структуры, бит переключается аппаратно.
CHNL_PRIORITY (S/C) Бит канала: 0 - обычный приоритет, 1 - повышенный.
ERR_CLR Бит 0: Возвращает наличие ошибки при работе DMA. Запись 1 сбрасывает ошибку.

3. Пример программного копирования данных в FIFO контроллера Ethernet

В данном пункте приводится пример работы с DMA из библиотечного файла «MDR32FxQI_eth.c». В данном примере пакет данных с помощью DMA записывается в FIFO контроллера Ethernet.

3.1 Инициализация DMA

Перед использованием DMA необходимо его предварительно настроить. Функция предварительной инициализации DMA приведена в фрагменте кода 1. В данной функции задаются только основные параметры DMA. Далее, при вызове функции обмена параметры управляющей структуры перенастраиваются. Для пересылки данных используется 15 канал DMA - DMA_Channel_SW2, запросы выставляются программным путём с помощью регистра CHNL_SW_REQUEST.

Фрагмент кода 1 – Функция предварительной инициализации контроллера DMA
#define DMA_Channel_SW2           ((uint8_t)(15))
void ETH_DMAPrepare(void)
{
    // Локальная управляющая структура канала DMA
    DMA_CtrlDataInitTypeDef DMA_PriCtrlStr;
    // Структура инициализации DMA
    DMA_ChannelInitTypeDef DMA_InitStr;
    // Подача тактирования на DMA
    RST_CLK_PCLKcmd(RST_CLK_PCLK_DMA, ENABLE);
    // Сброс настроек DMA
    DMA_DeInit();
    // Инициализация управляющей структуры по умолчанию       
    DMA_StructInit(&DMA_InitStr);
    // Настройка DMA - выбор основной управляющей структуры   
    DMA_InitStr.DMA_PriCtrlData = &DMA_PriCtrlStr;
    DMA_InitStr.DMA_Priority = DMA_Priority_High;
    DMA_InitStr.DMA_UseBurst = DMA_BurstClear;
    DMA_InitStr.DMA_SelectDataStructure = DMA_CTRL_DATA_PRIMARY;
    // Инициализация DMA
    DMA_Init(DMA_Channel_SW2, &DMA_InitStr);
}

3.2 Функция записи в FIFO через DMA

Адрес FIFO (адрес назначения), как и адрес массива данных (источника), задается вызывающим кодом вместе с количеством передаваемых данных. Функция записи в FIFO контроллера Ethernet приведена во фрагменте кода 2, далее приведена дополнительная информация к коду:
  • запись в FIFO осуществляется всегда по одному адресу, поэтому для приемника не задается смещение адреса;
  • для обмена выбран канал 15;
  • для того чтобы передать весь пакет максимально быстро повышается приоритет данного канала и значение R_power выбирается максимальное - арбитраж через 1024 передачи. Размер же пакета может быть меньше данного значения, но не больше (контролируется вызывающим кодом);
  • выставляется режим Авто-запроса для автоматического формирования запросов передачи данных к DMA;
  • прерывание от DMA не используется, поскольку так организован вызывающий код.
Фрагмент кода 2 – Функция записи в FIFO контроллера Ethernet с использованием DMA
#define DMA_Channel_SW2 ((uint8_t)(15))

// Доступ к глобальному массиву управляющих данных каналов
extern DMA_CtrlDataTypeDef DMA_ControlTable[DMA_Channels_Number * (1 + DMA_AlternateData)];
 
void ETH_DMAFrameTx(uint32_t * DstBuf, uint32_t BufferSize, uint32_t * SrcBuf)
{
    __IO uint32_t * ptrControltable;
    uint32_t tmpval;
    // Высший приоритет
    MDR_DMA->CHNL_PRIORITY_SET |= 1 << DMA_Channel_SW2;
    // Настройка управляющей структуры     
    DMA_ControlTable[DMA_Channel_SW2].DMA_SourceEndAddr = (uint32_t)SrcBuf + 4*(BufferSize-1);
    DMA_ControlTable[DMA_Channel_SW2].DMA_DestEndAddr = (uint32_t)DstBuf;
    DMA_ControlTable[DMA_Channel_SW2].DMA_Control = DMA_DestIncNo | DMA_SourceIncWord |
                                                    DMA_MemoryDataSize_Word |
                                                    DMA_Mode_AutoRequest |
                                                    DMA_Transfers_1024 |
                                                    ((BufferSize - 1) << 4);
    // Разрешение работы канала - DMA ожидает запрос для запуска
    DMA_Cmd(DMA_Channel_SW2, ENABLE); // MDR_DMA->CHNL_ENABLE_SET = (1 << DMA_Channel);
    // Подача DMA Request - старт цикла DMA
    DMA_Request(DMA_Channel_SW2); // MDR_DMA->CHNL_SW_REQUEST = (1 << DMA_Channel);
    // Получение указателя на поле Control канала
    ptrControltable = (uint32_t *) &DMA_ControlTable[DMA_Channel_SW2].DMA_Control;
    // Ожидание окончания цикла
    while( 1 )
    {
        tmpval = (*ptrControltable) & 0x7;
        if(tmpval == 0) // режим STOP?
            break;
    }
    // Выключение канала DMA
    DMA_Cmd(DMA_Channel_SW2, DISABLE); // MDR_DMA->CHNL_ENABLE_CLR = (1 << DMA_Channel);
}

4. Работа с DMA в К1986ВЕ1

Следует обратить внимание, что в микроконтроллере К1986ВЕ1QI не вся память ОЗУ доступна для контроллера DMA, а только AHB-Lite SRAM 16KB, начинающаяся с адреса 0x2010_0000 (спецификация, раздел «Организация памяти»). Это необходимо учитывать при выборе источника и приёмника, а также при размещении массива управляющих структур.

В SPL массив управляющих структур DMA_ControlTable[] объявлен с атрибутом __attribute__((section("EXECUTABLE_MEMORY_SECTION"))), позволяющим разместить данный массив в определённую область памяти МК. Данный атрибут необходимо указать в конфигурационном файле компоновщика для соответствующего региона памяти.

Например, в среде Keil конфигурационный файл компоновщика (scatter file) автоматически создается при сборке проекта, если в опциях проекта установлена галочка «Linker -> Use Memory Layout from Target Dialog». Конфигурационный файл создается в поддиректории «Objects» и называется именем проекта с расширением *.sct. Для работы с DMA необходимо убрать галочку с опции «Use Memory Layout from Target Dialog», чтобы данный файл не обновлялся при каждой сборке (рисунок 2), а также в сам файл дописать строку с указанием атрибута массива управляющих структур для региона памяти ОЗУ AHB-Lite SRAM 16KB, как показано в фрагменте кода 3.

Фрагмент кода 3 – Размещение структуры с атрибутом "EXECUTABLE_MEMORY_SECTION" в регион памяти IRAM2
RW_IRAM2 0x20100000 0x00004000 {
  *.o (EXECUTABLE_MEMORY_SECTION)
  .ANY (+RW +ZI)
}
Рисунок 2 - Настройка конфигурационного файла компоновщика в опциях проекта

Подробная информация про конфигурационный файл компоновщика приведена на официальном сайте Keil, а также в статье «[i] Расположение функций в ОЗУ, программирование EEPROM».

5. Первоначальная инициализация DMA для работы с прерываниями

После включения МК некоторые периферийные блоки могут выставить запросы к DMA. При этом, если канал DMA, к которому установлен запрос, будет выключен, то контроллер DMA оповестит об этом ядро путём выставления запроса прерывания (спецификация, правила осуществления DMA передач при «запрещенных» каналах, правило №19). Таким образом DMA показывает запросы от периферии, которые поступают на выключенные каналы. Если данный механизм оповещения не требуется в проекте, то его можно отключить. Для этого необходимо:
  • запретить обработку запросов по dma_req[C] и dma_sreq[C] во всех каналах DMA, кроме требуемых, установив соответствующие биты в регистре «CHNL_REQ_MASK_SET»;
  • разрешить работу всех каналов DMA, установив все биты в регистре «CHNL_ENABLE_SET»;
  • разрешить работу контроллера DMA путём установки бита «master_enable» в регистре «DMA_CFG»;
  • сбросить отложенное прерывание от DMA с помощью вызова функции NVIC_ClearPendingIRQ(DMA_IRQn).
Сохранить статью в PDF

Теги

Была ли статья полезной?