[i] Начальные сведения о DMA
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 - не используется.
Таблица 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 - инкремент данных источника
При использовании 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 не влияют на состояние регистра.
- Регистр SET: - RW, при записи 1-ниц устанавливаются биты в основном регистре;
- Регистр CLR: - RO, при записи 1-ниц сбрасываются биты в основном регистре.
Таблица 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 не используется, поскольку так организован вызывающий код.
#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).