24432

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

Дата последнего изменения: 02.08.2021 10:24:31

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

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

  • адреса источника и приёмника;
  • количество передаваемых данных (цикл DMA);
  • размерность передаваемых данных;
  • инкремент адресов источника и приёмника после передачи каждого значения.
После передачи очередной порции данных, адреса источника и приемника данных могут либо инкрементироваться, либо оставаться неизменными. Инкремент необходим, когда передается/принимается массив данных. Неизменный адрес необходим при считывании/записи в регистр, например, когда выбран адрес регистра данных АПЦ или ЦАП.

Пересылаемые данные могут быть:

  • 8-разрядные (байт);
  • 16-разрядные (полуслово);
  • 32-разрядные (слово).

1. Каналы DMA

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

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

Например, необходимо передать 100 значений из массива в массив. Если выставить параметр R_power = 6  (26 = 64), то канал передаст 64-е значения и разрешит провести арбитраж. Далее:

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

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

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

Аналогично, для контроллера ЦАП, адресом назначения DMA выбирается регистр "DAC_DATA", а событием, по которому происходит передача слова, выбирается событие таймера CNT == ARR (запрос к 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ВЕ4У, 1986ВЕ9x, 1986ВЕ1Т и 1986ВЕ3Т сигналы dma_req[С] и dma_sreq[С] от определенных периферийных контроллеров жестко привязаны к каналам DMA. Подключение сигналов запросов dma_req[С] и dma_sreq[С] от периферии к каналам DMA для микроконтроллеров серии 1986ВЕ9х приведено в таблице 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ВЕ9х, то самый приоритетный - это UART1_TX. Приоритет по умолчанию можно увеличить, задав каналу высокий приоритет. Для задания высокого приоритета используется регистр CHNL_PRIORITY_SET, в который необходимо записать "1" в бит по индексу канала. Для возвращения приоритета в обычное состояние (низкий приоритет), используется регистр CHNL_PRIORITY_CLR - запись "1" в бит по индексу канала. Чтение регистра CHNL_PRIORITY_SET возвращает текущее состояние приоритета канала: 0 - приоритет по умолчанию (низкий приоритет), 1 – высокий приоритет.

В МК 1986ВЕ8Т, 1923ВК014 и «Электросила» сигналы запросов 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 из библиотечного файла «MDR32F9Qx_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Е3Т

Следует обратить внимание, что в микроконтроллерах 1986ВЕ1Т и 1986ВЕ3Т не вся память ОЗУ доступна для контроллера 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, а также в статье «Расположение функций в ОЗУ, программирование 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

Теги

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