Программирование ARM-контроллеров STM32 на ядре Cortex-M3. Часть 14. Использование DMA
DMA (Direct Memory Access) — технология прямого доступа к памяти. Эта технология позволяет быстро и без использования центрального процессора пересылать данные из одной области памяти в другую. При этом для такой пересылки вместо ЦП используется свой специальный контроллер, который называется контроллером DMA.
Контроллер DMA работает независимо от ЦП и параллельно с ним. Таким образом использование DMA позволяет экономить ресурсы ЦП, который во время операций пересылки данных с помощью DMA может заниматься какими-то другими полезными делами.
Несмотря на то, что ЦП и DMA работают независимо друг от друга, DMA может приостанавливать доступ ЦП к системной шине на несколько тактов в случаях когда они оба пытаются обратиться к одним и тем же адресам памяти.
В микроконтроллеры stm32 может быть встроено до 2-х контроллеров DMA — DMA1 и DMA2. Они имеют следующие особенности:
- 12 независимо конфигурируемых каналов: 7 для DMA1 и 5 для DMA2
- Возможность использования в качестве источника или приёмника данных Flash, SRAM и периферийных модулей, подключенных к шинам APB1, APB2 и AHB
- Аппаратный запрос от каждого периферийного модуля подключен к одному из 12 каналов
- Возможность генерации программного запроса по каждому каналу
- Приоритеты между запросами от разных каналов одного контроллера DMA настраиваются программно и могут иметь 4 уровня: very high, high, medium, low. В случае, если для двух каналов установлен одинаковый приоритет, более приоритетным считается канал с меньшим номером
- Независимая установка размера порции данных для источника и приёмника (байт, 16-битное полуслово или 32-битное слово)
- Поддержка кольцевого буфера (когда данные пишутся в буфер по кругу)
- Возможности передачи данных из памяти в память, из памяти в периферию, из периферии в память или из периферии в периферию
- 3 флага событий (Half Transfer, Transfer Complete и Transfer Error) логически объединённых в один запрос прерывания для каждого канала
- Программируемое количество передаваемых данных (количество порций) — до 65535 (то есть если данные передавать 32-битными словами, то максимум можно передать 65535*4 = 262140 байт, — почти 256 кбайт)
Карта запросов модуля DMA1:
Карта запросов модуля DMA2:
Как вообще работает DMA? Всё происходит следующим образом:
- В периферийном модуле происходит событие, по которому через определённый для этого периферийного модуля канал генерируется запрос к DMA (генерация запроса к DMA должна быть разрешена в настройках самого периферийного модуля)
- Контроллер DMA обрабатывает пришедший запрос в соответствии с настройками и установленным приоритетом канала, через который пришёл запрос
- Как только контроллер DMA получает доступ к периферии (выполняет передачу одной единицы информации) — он посылает сгенерировавшему запрос периферийному модулю сигнал подтверждения
- При получении сигнала подтверждения периферийный модуль снимает свой запрос
- Как только периферийный модуль снимает свой запрос — DMA контроллер отменяет сигнал подтверждения
- Если есть ещё запросы от периферии — начинает обрабатываться следующий запрос (опять же в соответствии с установленным приоритетом)
Сама передача данных состоит из трех шагов:
- Загрузка данных из регистра периферии или из памяти по адресу, записанному во внутреннем регистре текущего адреса источника (этот регистр программно недоступен). Начальный адрес, используемый для первой передачи, прописывается в регистр DMA_CPARx или в регистр DMA_CMARx (в зависимости от направления передачи)
- Сохранение загруженных данных в регистре периферии или в памяти по адресу, указанному во внутреннем регистре текущего адреса приёмника (этот регистр программно недоступен). Начальный адрес, используемый для первой передачи, прописывается в регистр DMA_CPARx или в регистр DMA_CMARx (в зависимости от направления передачи)
- уменьшение значения регистра-счётчика DMA_CNDTRx, который содержит количество оставшихся транзакций
В зависимости от настроек, после каждой транзакции модуль DMA может автоматически инкрементировать адреса источника и/или приёмника. Эта возможность настраивается для источника и приёмника независимо друг от друга установкой/сбросом битов PINC и MINC в регистре DMA_CCRx. Причём, в зависимости от установленных для источника и приёмника размеров порции данных адрес автоматически инкрементируется на 1, 2 или 4.
Если канал сконфигурированв нормальном режиме, то после обнуления счётчика транзакций новые запросы к DMA обслуживаться не будут. Чтобы включить обслуживание новых запросов — нужно сначала программно взвести счётчик (записать в регистр DMA_CNDTRx новое значение). Сделать это можно только предварительно выключив соответствующий канал DMA (при выключении канала его настройки не сбрасываются).
В кольцевом режиме (circular mode) значение счётчика автоматически устанавливается к начальному значению после выполнения последней запланированной транзакции (то есть после достижения нуля). Одновременно с этим адреса внутренних регистров текущих адресов сбрасываются к начальным адресам, прописанным в регистрах DMA_CPARx, DMA_CMARx. Кольцевой режим можно включить/выключить установкой/сбросом бита CIRC регистра DMA_CCRx.
Режим пересылки данных из памяти в память выбирается установкой бита MEM2MEM в регистре DMA_CCRx. В этом режиме контроллер DMA начинает выполнять передачу данных сразу после включения канала установкой бита EN регистра DMA_CCRx, то есть не дожидаясь внешнего аппаратного запроса. Не знаю зачем этому режиму дали такое название, я бы лучше назвал его режимом без внешнего триггера, поскольку фактически в этом режиме вы можете как и раньше пересылать данные не только из памяти в память, но и из памяти в регистры периферии, и из регистров периферии в память, и из регистров в регистры, просто теперь каждая транзакция запускается не по событию от периферии, а автоматически, пока не обнулится счётчик (или вообще бесконечно, если для канала выбран кольцевой режим).
DMA_ISR — регистр статуса прерываний. Биты этого регистра содержат флаги событий для каждого канала. Они доступны только для чтения, а сбрасываются записью 1 в соответствующий бит регистра DMA_IFCR.
- GIFx: глобальный флаг прерывания для канала x (x=1..7). Устанавливается в 1 аппаратно в случае возникновения одного из прерываний TE, HT или TC. Сбрасывается программно, записью единицы в соответствующий бит регистра DMA_IFCR.
- TCIFx: флаг окончания передачи. Устанавливается в 1 аппаратно после обнуления счётчика передаваемых данных. Сбрасывается программно, записью единицы в соответствующий бит регистра DMA_IFCR.
- HTIFx: флаг окончания передачи половины данных. Устанавливается в 1 аппаратно после отправки половины запланированных данных (когда счётчик уменьшается наполовину). Сбрасывается программно, записью единицы в соответствующий бит регистра DMA_IFCR.
- TEIFx: флаг ошибки передачи. Устанавливается в 1 аппаратно при возникновении ошибок передачи (при попытках работы с физически нереализованными или зарезервированными адресами памяти). Сбрасывается программно, записью единицы в соответствующий бит регистра DMA_IFCR.
DMA_IFCR — регистр сброса флагов статуса прерываний. Установка битов этого регистра приводит к сбросу флагов прерываний в регистре DMA_ISR. Биты регистра DMA_IFCR доступны только для записи.
- CGIFx: установка этого бита в 1 приводит к сбросу флагов GIFx, TCIFx, HTIFx и TEIFx (x=1..7 — номер канала) в регистре DMA_ISR
- CTCIFx: установка этого бита в 1 приводит к сбросу флага TCIFx (x=1..7 — номер канала) в регистре DMA_ISR
- CHTIFx: установка этого бита в 1 приводит к сбросу флага HTIFx (x=1..7 — номер канала) в регистре DMA_ISR
- CTEIFx: установка этого бита в 1 приводит к сбросу флага TEIFx (x=1..7 — номер канала) в регистре DMA_ISR.
DMA_CCRx — регистры настройки каналов (x=1..7 — номер канала).
- EN: включение/выключение канала
- TCIE: разрешение(1)/запрет(0) прерывания по событию TC (переданы все данные, счётчик обнулился)
- HTIE: разрешение(1)/запрет(0) прерывания по событию HT (передана половина данных, счётчик уменьшился наполовину)
- TEIE: разрешение прерывания по событию TE (ошибка передачи)
- DIR: направление передачи данных. 0 — читать из периферии (и писать в память), 1 — читать из памяти (и писать в периферию)
- CIRC: включение/выключение циклического режима передачи (1 — circular mode, 0 — normal mode)
- PINC: включает(1)/выключает(0) инкрементирование адреса периферии после каждой транзакции
- MINC: включает(1)/выключает(0) инкрементирование адреса памяти после каждой транзакции
- PSIZE[1:0]: определение размера единицы данных для периферии. Может принимать следующие значения:
- 00: 8 бит
- 01: 16 бит
- 10: 32 бита
- 11: зарезервировано
- 00: 8 бит
- 01: 16 бит
- 10: 32 бита
- 11: зарезервировано
- 00: Low (низкий)
- 01: Medium (средний)
- 10: High (высокий)
- 11: Very high (очень высокий)
DMA_CNDTRx — регистры-счётчики (x=1..7 — номер канала). В младшие 16 бит этих регистров прописывается количество данных для передачи (то есть сколько транзакций нужно выполнить с соответствующим каналом). Каждый из этих регистров обладает следующими особенностями:
- Значение в регистр можно прописать только когда соответствующий канал выключен
- После включения канала регистр становится недоступен для записи
- Значение в регистре автоматически декрементируется после каждой транзакции
- После того, как значение регистра станет равным нулю — новые запросы к DMA от соответствующего канала перестают обслуживаться
- Если для соответствующего канала установлен циклический режим передачи, то после обнуления регистра в него автоматически загружается начальное значение
DMA_CPARx — регистры адреса (x=1..7 — номер канала). Здесь содержатся начальные адреса регистров периферии в которую или из которой нужно передавать данные по запросу от соответствующего канала. Доступ автоматически выравнивается на границу полуслова или слова, в зависимости от установленного для периферии размера порции данных (достигается игнорированием одного или двух младших бит регистра адреса). Регистры не могут быть перезаписаны пока соответствующий канал включен.
DMA_CMARx — регистры адреса (x=1..7 — номер канала). Здесь содержатся начальные адреса областей памяти в которую или из которой нужно передавать данные по запросу от соответствующего канала. Доступ автоматически выравнивается на границу полуслова или слова, в зависимости от установленного для памяти размера порции данных (достигается игнорированием одного или двух младших бит регистра адреса). Регистры не могут быть перезаписаны пока соответствующий канал включен.
Для модуля DMA2 существуют точно такие же регистры, только x в них может принимать значения 1..5, а не 1..7 (поскольку в DMA2, в отличии от DMA1, всего 5 каналов, а не 7).
Работать с DMA достаточно просто. Всё, что от Вас требуется — это настроить соответствующий канал и далее только обрабатывать события (которых как мы помним для канала всего 3) или прерывания от них, а также, возможно, взводить счётчик передаваемых данных.
Как обрабатывать события и прерывания — решать только Вам, а вот порядок настройки канала приведён ниже:
- Установить в регистре DMA_CPARx (x — номер канала) начальный адрес регистра периферии в которую/из которой будут передаваться данные
- Установить в регистре DMA_CMARx (x — номер канала) начальный адрес области памяти в которую/из которой будут передаваться данные
- Прописать в регистре DMA_CRDTRx (x — номер канала) количество передаваемых данных (количество транзакций)
- Установить в регистре DMA_CCRx (x — номер канала) приоритет настраиваемого канала (биты PL[0:1]), направление передачи данных, режим (circular/normal), отметить нужно или не нужно инкрементировать адреса периферии и памяти после каждой транзакции, установить размеры порций данных для периферии и для памяти, а также настроить прерывания
- Включить канал, установив в 1 бит EN регситра DMA_CCRx (x — номер канала)
- Ну и конечно нужно не забыть разрешить слать запросы к DMA в настройках самого периферийного модуля.
В библиотеке StdPeriph настройку канала можно выполнить одной функцией — DMA_Init, для включения/выключения используется функция DMA_Cmd.
Примеры работы с DMA приводить не буду, их можно посмотреть в примерах работы с другими модулями (например, в примерах работы с UART или ADC), так что на этом всё.
Программирование STM32. Часть 8: DMA
Direct memory access (DMA), или прямой доступ к памяти (ПДП) используется для быстрой передачи данных между памятью и периферийным устройством, памятью и памятью, или между двумя периферийными устройствами без участия процессора. В микроконтроллере STM32F103c8 доступен один контроллер DMA1 с 7-ю каналами. DMA2 присутствует только в микроконтроллерах high-density и XL-density. Предыдущая статья здесь, все статьи цикла можно посмотреть тут: http://dimoon.ru/category/obuchalka/stm32f1.
Содержание
- Функциональное описание DMA
- Приоритеты каналов DMA
- Каналы DMA
- Выравнивание данных разной разрядности
- Особенности обращения к периферии AHB/APB
- Кольцевой режим DMA (Circular mode)
- Режим «Из памяти в память» (Memory-to-memory mode)
- Прерывания DMA
- Ошибки при передаче данных по DMA
- Каналы DMA и периферия
Функциональное описание DMA
Контроллер DMA использует системную шину совместно с процессорным ядром. Если CPU и DMA обращаются к одной о той же области памяти или одной и той же периферии, то DMA может приостановить доступ CPU к системной шине, но при этом как минимум половина пропускной способности шины резервируется за CPU. Это означает, что даже при интенсивном обмене данными по DMA процессор не зависнет наглухо.
При возникновении определенного события, периферийное устройство отправляет сигнал запроса в контроллер DMA. После этого запускается процесс обмена данными, который состоит из 3-х шагов:
- Загрузка данных из регистра периферийного устройства (если направление передачи из периферии в память) или загрузка данных из памяти (если направление передачи из памяти в периферию);
- Сохранение загруженных данных в память (если из периферии в память) или в периферийное устройство (если из памяти в периферию);
- Уменьшение значения регистра DMA_CNDTRx на единицу. Как только этот регистр станет равен нулю, то передача данных завершится.
Приоритеты каналов DMA
DMA1 в микроконтроллерах STM32F103c8 имеет 7 каналов, причем в конкретный момент времени передача данных может осуществляться только по одному из них. Однако, если активно несколько каналов, то при одновременном возникновении запросов DMA передача будет запущена для того канала, приоритет которого выше. Приведу небольшой пример. Пусть у нас 3-й канал DMA1 настроен на передачу массива данных в SPI1, а 1-й канал на прием от ADC1. Установим приоритет канала 3 больше, чем у канала 1. В этом случае, если запросы от SPI1 и ADC1 возникнут одновременно, то сначала будет обработан запрос от SPI1 (3-й канал), а уже потом от ADC1 (1-й канал). То есть одновременно включать несколько каналов DMA можно, но одновременно вести передачу может только один из них.
Приоритеты можно настраивать программно, всего 4-е градации:
- Very high priority (Очень высокий приоритет)
- High priority (Высокий приоритет)
- Medium priority (Средний приоритет)
- Low priority (Низкий приоритет)
При одинаковом уровне приоритета (например, 1-й и 3-й канал настроили на Very high priority) канал с меньшим номером будет иметь приоритет над каналом с большим номером (канал 1 будет иметь бОльший приоритет)
Каналы DMA
Каждый канал DMA имеет следующие регистры:
- DMA_CCRx — регистр конфигурации канала DMA. В нем содержатся биты конфигурации передачи данных, биты разрешения прерывания от канала и бит включения канала.
- DMA_CNDTRx — сколько кадров данных подлежит передаче (0..65535). Я намеренно употребил слово «кадр», а не «байт». Дело в том, то есть возможность настроить количество байт данных, которые передаются за одну транзакцию (настраивается в регистре DMA_CCRx), об этом поговорим далее.
- DMA_CMARx — адрес памяти. Если направление передачи из периферии в память, то сюда будем записывать данные, если обратно, то читать.
- DMA_CPARx — адрес периферийного устройства. Если направление передачи из периферии в память, то отсюда будем читать данные, если обратно, то записывать. В режиме Memory-to-memory сюда так же записывается адрес памяти.
Так, вроде все понятно: имеем 4-е регистра, с помощью которых можно настроить пересылку данных туда-сюда.
Теперь самое время поговорить о такой вещи как инкремент адреса памяти и периферии. Все примеры буду приводить для SPI. Инкремент адреса периферии чаще всего не имеет смысла, а вот инкремент памяти очень полезен. Пусть в регистр DMA_CMARx занесен адрес нулевой ячейки массива, который мы ходим отправить в SPI (вспоминаем указатели Си). После каждой отправки данных в SPI внутренний указатель памяти канала DMA будет увеличиваться на 1 элемент массива. Тут стоит отметить один важный момент: инкремент производится внутреннего указателя, который недоступен программно для чтения или записи, регистр DMA_CMARx не меняет своего значения в процессе передачи данных.
На примере SPI работать это будет вот так. В регистр DMA_CMARx занесли адрес нулевого элемента массива, который хотим отправить, в DMA_CPARx адрес регистра данных DR модуля SPI. В DMA_CNDTRx записали количество байт для передачи. Включили инкремент адреса памяти, в модуле SPI разрешили запрос к DMA на передачу данных и запустили процесс, установкой бита EN в регистре DMA_CCRx. В начальном состоянии передатчик SPI пуст, флаг пустого передатчика устанавливается в единицу, это провоцирует зарос DMA. DMA получает запрос от SPI, после этого читает байт данных из массива и записывает его в регистр DR интерфейса SPI, увеличивает внутренний указатель памяти на один элемент массива (1 байт) и уменьшает значение регистра DMA_CNDTRx на единицу. После того, как SPI выплюнет байт данных, процесс повторится. Все это будет продолжаться до тех пор, пока значение DMA_CNDTRx не станет равно нулю. После этого канал DMA завершит передачу и больше не будет реагировать на запросы от SPI.
Но это для случая, если нам надо передавать данные в периферию по одному байту. А что делать, если у нас разрядность массива 2 байта, и периферия хочет на вход 2 байта тоже?
Для таких случаев в регистре DMA_CCRx есть конфигурационные биты разрядности периферийного регистра (PSIZE) и разрядности данных в памяти (MSIZE). Они могут принимать следующие значения:
- 00: 8-bits
- 01: 16-bits
- 10: 32-bits
- 11: Reserved (эта комбинация не используется)
То есть, если мы поставим MSIZE=16 бит (2 байта), то за раз мы будем отправлять уже 2 байта, и указатель на адрес памяти будет увеличиваться на 2. А вот регистр DMA_CNDTRx все так же будет уменьшаться на единицу, так как он содержит не количество байт для передачи, а количество самих передач (транзакций). Получается, что MSIZE нужен для того, чтобы сказать DMA, на сколько байт увеличивать внутренний указатель на адрес памяти. Все верно, но MSIZE используется и еще для одной вещи.
Выравнивание данных разной разрядности
Очень часто бывают ситуации, когда разрядность приемника данных не совпадает с разрядностью источника. Например, в модуле SPI разрядность регистра данных DR равна 16 бит (2 байта, или полуслово). Однако, SPI у нас может быть настроен на передачу 8-и бит за раз и мы имеем массив данных для передачи, с разрядностью 8 бит. DMA позволяет настроить независимо разрядность передатчика и приемника данных. Как было сказано выше, с помощью битов MSIZE мы задаем разрядность данных в памяти. Но есть еще биты PSIZE, которыми надо указать разрядность регистра периферийного устройства (8, 16 или 32 бита). Если PSIZE не равен MSIZE, то DMA будет производить автоматическое выравнивание данных по следующим правилам.
Пусть разрядность источника данных 8 бит, а приемника 16. Тогда при пересылке DMA добавит 8 незначащих нулей к данным из источника и запишет их в приемник: из источника прочитали, например, 0x13, а в приемник записали 0x0013. В случае, если разрядность источника больше разрядности приемника, то DMA обрежет лишние старшие биты у данных из источника, и в приемник запишет только младшие биты: если разрядность источника 32 бита, а приемника 8 бит, то DMA прочтет из источника значение, например, 0xABCDEF12, а в приемник попадет 0x12. В принципе, все как при присвоении значений переменным в Си.
В Reference manual на микроконтроллеры STM32F1xxx в разделе про DMA есть вот такая таблица:
Рис. 1. Правила выравнивания данных DMA
Таблица из Reference manual-а может показаться довольно замысловатой (на самом деле это так и есть ).Давайте разберемся в ней на одном из случае. Например, источник данных у нас 32 бита, а приемник 16 бит:
Рис. 2. Преобразование 32-х битных значений к 16-и битным
Пусть мы пересылаем данные из одного массива в памяти в другой посредством DMA. Причем эти массивы разной разрядности. Массив-источник имеет 32 разряда и содержит следующие данные:
- элемент 0: B3B2B1B0, смещение 0x00
- элемент 1: B7B6B5B4, смещение 0x04
- элемент 2: BBBAB9B8, смещение 0x08
- элемент 3: BFBEBDBC, смещение 0x0C
Если непонятно что такое смещение и почему оно принимает именно эти значения, то необходимо почитать про организацию данных в памяти микроконтроллера и указатели языка Си.
В качестве массива это будет выглядеть вот так:
Ну и приемник данных:
А DMA будет выполнять вот такую операцию:
Думаю, что для людей, знакомых с Си, будет понятен результат такой операции:
В принципе, все то же самое справедливо и для пересылки данных из памяти в регистр периферии, только в том случае не используется инкремент адреса периферии.
Особенности обращения к периферии AHB/APB
Тут есть одна очень важная и не очевидная особенность архитектуры микроконтроллеров STM32. CPU в STM32 является 32-х разрядным, и для записи в память 8, 16 или 32-х бит существуют разные команды и разные запросы на запись. Для ОЗУ ни каких проблем не существует: мы можем выполнять 8, 16 и 32-х разрядные запросы к памяти. А вот к периферии AHB/APB можно обращаться только 32-х битными запросами. А если нам надо выполнить запись в регистр, который имеет разрядность меньше, чем 32 бита? Объясню на примере все того же SPI. Регистр данных DR у него имеет разрядность 16 бит, и старшие 16 бит 32-х разрядной шины просто не используются:
Рис. 3. Карта регистров SPI
Если в DMA мы настроим разрядность периферии PSIZE = 16 бит, и разрядность памяти MSIZE = 16 бит, то DMA продублирует младшие 16 бит в старшие и произведет 32-х битный запрос к периферии:
Т.е. из 0xABCD DMA сделает 0xABCDABCD и это значение отправится в периферию. И так как старшие 16 бит регистра DR не используются (зарезервированы), то старшие 16 бит просто проигнорируются. Так же можно настроить PSIZE = 32 бита, и тогда в регистр DR будет занесено значение 0x0000ABCD. А вот если PSIZE установить 8 бит, то DMA сделает следующее преобразование:
Таким образом, в DR будет занесено 0xABAB а не 0x00AB, как можно подумать, если не знать этих особенностей. Вот как раз из-за того, что к периферии можно обращаться только 32-битными запросами, все регистры в периферии выравнены по границе 32 бита (см. рис. 3).
Кольцевой режим DMA (Circular mode)
Думаю, все знакомы с кольцевым буфером. Его очень удобно использовать при непрерывном приеме/передаче данных. В DMA микроконтроллеров STM32 такой режим работы реализован аппаратно, и включается он битом CIRC в регистре управления DMA_CCRx. Если этот режим активирован, то после передачи всех данных по DMA (после того, как DMA_CNDTRx станет равно нулю), регистр DMA_CNDTRx заново перезагружается исходным значением и передача продолжается.
Режим «Из памяти в память» (Memory-to-memory mode)
В «обычном» режиме канал DMA ждет запроса на передачу данных от какого-либо периферийного модуля (SPI, ADC, таймер, и т.д.) Однако, канал DMA может работать и без запроса от периферии, т.е. передача начнется сразу после установки бита EN в регистре DMA_CCRx. Этот режим может использоваться для копирования одной области памяти в другую. Для этого необходимо в регистры DMA_CPARx и DMA_CMARx занести адреса массивов, над которыми необходимо выполнить операцию копирования, и установить бит MEM2MEM в регистре DMA_CCRx. Получается, что и регистру адреса периферии, и регистру адреса памяти присваиваются адреса массивов в памяти. При пересылке MEM2MEM можно использовать любой свободный канал DMA. А как выбирается направление передачи? Точно так же, как и при обмене данными с периферией: битом DIR регистра DMA_CCRx. Пример передачи из памяти в память будет в одной из следующих статей, там, где мы перейдем к практике. Стоит отметить, что нельзя использовать режим MEM2MEM одновременно с Circular mode.
Прерывания DMA
Каждый канал DMA имеет 3 прерывания:
- Half-transfer — DMA передал половину данных, удобно при потоковой передаче данных совместно с кольцевым режимом: пока передаем одну половину массива, заполняем другую.
- Transfer complete — прерывание о завершении передачи данных.
- Transfer error — прерывание об ошибке передачи.
Ошибки при передаче данных по DMA
Ошибка DMA может возникнуть при чтении/записи в зарезервированное адресное пространство микроконтроллера STM32. При возникновении ошибки соответствующий канал DMA отключается (сбрасывается бит EN) и возникает прерывание Transfer error (если разрешено).
Каналы DMA и периферия
DMA1 в микроконтроллерах STM32F103C8 имеет 7 каналов передачи данных, причем на каждом канале висит своя периферия. Приведу таблицу из Reference manual, чтоб было понятнее:
Рис. 4. Каналы DMA и соответствующие им запросы от периферийных устройств
Например, 1-й канал может обслуживать запросы от ADC1, TIM2_CH3 и TIM4_CH1, а 2-й канал от SPI1_RX, USART3_TX, TIM1_CH1, TIM2_UP и TIM3_CH3. Стоит отметить, что сами запросы должны быть разрешены в регистрах периферийных устройств, при этом, если разрешить DMA-запрос от 2-х источников, то обмен данными будет запускаться от 2-х разных запросов. С ходу не смогу привести пример, где это может быть полезно, и скорее всего такая конфигурация не имеет смысла.
На этом пока все, в следующей статье будет описание регистров DMA, а уже потом перейдем к практике. Продолжение следует.
Dma stm32 что это
В этой статье (перевод апноута AN4031 [1]) описывается применение контроллера прямого доступа к памяти (direct memory access, DMA), доступного в микроконтроллерах серий STM32F2, STM32F4 и STM32F7 Series. Функции контроллера DMA, архитектура системы, многослойная матрица шины и система памяти предоставляют широкополосную систему обмена данными между периферийными устройствами и областями памяти, с малыми задержками для использования в программном обеспечении системы.
Примечание: в этом документе STM32F2, STM32F4 и STM32F7 для краткости обозначаются как «MCU» или «микроконтроллер», и контроллер DMA обозначается просто как «DMA». В качестве примера для иллюстрации выбрана платформа STM32F4. Поведение DMA для серий STM32F2, STM32F4 и STM32F7 одинаковое, если не указано нечто другое. Перемещение данных под управлением DMA называется транзакцией или передачей. Все непонятные термины и сокращения см. в Словарике статьи [3].
При изучении этой документации следует также обращаться к руководствам MCU:
• STM32F205/215 and STM32F207/217 reference manual (RM0033)
• STM32F405/415, STM32F407/417, STM32F427/437 and STM32F429/439 reference manual (RM0090)
• STM32F401xB/C and STM32F401xD/E reference manual (RM0368)
• STM32F410 reference manual (RM0401)
• STM32F411xC/E reference manual (RM0383)
• STM32F412 reference manual (RM0402)
• STM32F446xx reference manual (RM0390)
• STM32F469xx and STM32F479xx reference manual (RM0386)
• STM32F75xxx and STM32F74xxx reference manual (RM0385)
• STM32F76xxx and STM32F77xxx reference manual (RM0410)DMA представляет собой модуль AMBA высокопроизводительной шины (advanced high-performance bus, AHB), который работает через 3 порта AHB: slave-порт для программирования DMA, и два master-порта (порты периферийных устройств и памяти), которые позволяют DMA инициировать транзакции между различными подчиненными модулями (передачи память-память, память-устройство и устройство-память).
DMA позволяет осуществлять транзакции в фоновом режиме, без вмешательства со стороны процессора Cortex-Mx (CPU). Во время этой операции основной CPU может выполнять другие задачи, прерываясь только в том случае, когда транзакция закончилась и новый блок данных целиком доступен для обработки. Большие объемы данных могут быть переданы без значительного ухудшения общей производительности системы. DMA в основном используется для реализации центрального буферизированного хранилища (обычно в system SRAM) для различных модулей периферийных устройств. Это решение менее дорогое в контексте использования микросхем и потребления энергии в сравнении с другими распространенными решениями, где каждое периферийное устройство требует создания собственного локального хранилища данных.
Свойства транзакции DMA. Передача DMA характеризуется следующими параметрами:
• Поток/канал DMA (stream/channel).
• Приоритет потока.
• Адреса источника и назначения.
• Режим передачи (transfer mode).
• Размер передачи (только когда DMA управляет потоком).
• Адрес источника/назначения инкрементируется или не инкрементируется.
• Ширина данных источника и назначения.
• Тип транзакции.
• Режим FIFO.
• Размер пакета источника/назначения.
• Режим двойной буферизации.
• Управление потоком.В MCU встроено два контроллера DMA (DMA1 и DMA2), и у каждого из них есть два порта — один порт для периферийных устройств и один порт для памяти. Оба контроллера могут работать одновременно. На рис. 1 показана блок-схема DMA.
Рис. 1. Схема контроллера DMA.
Потоки/каналы DMA. В каждом из двух контроллеров DMA имеется по 8 потоков (stream), всего в сумме получается 16. Каждый из потоков выделяется для обслуживания запросов доступа к памяти одного или большего количества периферийных устройств.
Каждый из потоков имеет всего до 8 выбираемых каналов (запросов). Этот выбор конфигурируется программно, что позволяет нескольким периферийным устройствам инициировать запросы DMA. Рис. 2 описывает выбор канала (channel) для выделенного потока (stream).
Рис. 2. Выбор канала.
Примечание: на потоке может быть одновременно активен только один канал/запрос. Больше одного разрешенного потока не должно обслуживать один и тот же запрос периферийного устройства.
Таблицы 1 и 2 показывают отображение DMA1/DMA2 запросов STM32F427/STM32F437 и STM32F429/STM32F439. Эти таблицы дают доступную конфигурацию потоков/каналов DMA против запросов периферийных устройств.
Таблица 1. Привязка запросов DMA1 периферийных устройств STM32F427/437 и STM32F429/439.
REQ Stream0 Stream1 Stream2 Stream3 Stream4 Stream5 Stream6 Stream7 Channel0 SPI3_RX — SPI3_RX SPI2_RX SPI2_TX SPI3_TX — SPI3_TX Channel1 I2C1_RX — TIM7_UP — TIM7_UP I2C1_RX I2C1_TX I2C1_TX Channel2 TIM4_CH1 — I2S3_EXT_RX TIM4_CH2 I2S2_EXT_TX I2S3_EXT_TX TIM4_UP TIM4_CH3 Channel3 I2S3_EXT_RX TIM2_UP
TIM2_CH3I2C3_RX I2S2_EXT_RX I2C3_TX TIM2_CH1 TIM2_CH2
TIM2_CH4TIM2_UP
TIM2_CH4Channel4 UART5_RX USART3_RX UART4_RX USART3_TX UART4_TX USART2_RX USART2_TX UART5_TX Channel5 UART8_TX UART7_TX TIM3_CH4
TIM3_UPUART7_RX TIM3_CH1
TIM3_TRIGTIM3_CH2 UART8_RX TIM3_CH3 Channel6 TIM5_CH3
TIM5_UPTIM5_CH4
TIM5_TRIGTIM5_CH1 TIM5_CH4
TIM5_TRIGTIM5_CH2 — TIM5_UP — Channel7 — TIM6_UP I2C2_RX I2C2_RX USART3_TX DAC1 DAC2 I2C2_TX Таблица 2. Привязка запросов DMA2 периферийных устройств STM32F427/437 и STM32F429/439.
REQ Stream0 Stream1 Stream2 Stream3 Stream4 Stream5 Stream6 Stream7 Channel0 ADC1 SAI1_A TIM8_CH1
TIM8_CH2
TIM8_CH3SAI1_A ADC1 SAI1_B TIM1_CH1
TIM1_CH2
TIM1_CH3— Channel1 — DCMI ADC2 ADC2 SAI1_B SPI6_TX SPI6_RX DCMI Channel2 ADC3 ADC3 — SPI5_RX SPI5_TX CRYP_OUT CRYP_IN HASH_IN Channel3 SPI1_RX — SPI1_RX SPI1_TX — SPI1_TX — — Channel4 SPI4_RX SPI4_TX USART1_RX SDIO — USART1_RX SDIO UART1_TX Channel5 — UART6_RX USART6_RX SPI4_RX SPI4_TX — USART6_TX USART6_TX Channel6 TIM1_TRIG TIM1_CH1 TIM1_CH2 TIM1_CH1 TIM1_CH4
TIM1_TRIG
TIM1_COMTIM1_UP TIM1_CH3 — Channel7 — TIM8_UP TIM8_CH1 TIM8_CH2 TIM8_CH3 SPI5_RX SPI5_TX TIM8_CH4
TIM8_TRIG
TIM8_COMОтображение запросов STM32F2/F4/F7 DMA разработано таким образом, что приложению дается больше гибкости для привязки каждого запроса DMA для связанного запроса периферийного устройство, и большая часть сценариев приложения покрывается мультиплексированием соответствующих потоков DMA и каналов. См. таблицы отображения DMA1/DMA2 в руководствах по используемым MCU (врезка выше «Дополнительная документация»).
Приоритет потока. У каждого порта DMA имеется арбитр для обработки приоритетов между разными потоками DMA. Приоритет потока конфигурируется программно (всего имеется 4 уровня приоритета). Если 2 или большее количество потоков DMA имеют одинаковый уровень приоритета, то используется аппаратный приоритет (поток 0 имеет приоритет над потоком 1, и т. п.).
Адреса источника и назначения. Транзакция DMA определяется адресом источника и адресом назначения. Оба этих адреса должны быть в пределах диапазонов шин AHB и APB, и адрес должен быть выровнен на размер транзакции.
Режим транзакции. DMA может осуществлять 3 разных режима передачи:
• Из периферийного устройства в память.
• Из памяти в периферийное устройство.
• Из области памяти в другую область памяти (такой режим передачи может реализовать только DMA2, и в нем не дозволяются режимы circular и direct).Размер транзакции. Должен быть определено значение размера транзакции, когда контроллером потока является DMA. Фактически это значение определяет объем данных, которые должны быть перемещены из источника (source) в место назначения (destination).
Размер транзакции определяется значением в регистре DMA_SxNDTR и шириной данных периферийного устройства. В зависимости от принятого запроса (burst или single), значение размера транзакции уменьшается на количество переданных данных.
Инкремент адреса источника/места назначения. Можно сконфигурировать DMA так, что в каждой транзакции данных будет автоматически инкрементироваться адрес источника и/или места назначения (source address, destination address).
Рис. 3. Инкремент адреса source и destination транзакции DMA.
Ширина данных источника и места назначения. Ширина (разрядность) данных может быть определена следующим образом:
• Byte (байт, 8 бит).
• Half-word (половина слова, 16 бит).
• Word (слово, 32 бита).Типы транзакций. Существуют следующие типы (режимы) передач DMA:
Circular mode : в этом режиме доступна обработка кольцевых буферов и непрерывных потоков данных (тогда регистр DMA_SxNDTR перезагружается автоматически ранее запрограммированным значением).
Normal mode : как только значение регистра DMA_SxNDTR достигнет 0, поток запрещается (бит EN в регистре DMA_SxCR становится равным 0).В этом примере DMA запускается для проигрывания через DAC небольшого буфера aEscalator8bit в циклическом (Circular) режиме. После вызова функции инициализации MX_DAC_Init сигнал генерируется на выходе канала 1 DAC автоматически, без участия процессора.
Режим DMA FIFO. У каждого потока есть независимый FIFO из 4 слов (4 * 32 бита) и программно конфигурируемый уровень порога заполнения: 1/4, 1/2, 3/4 или full. Этот FIFO используется для временного хранения данных, поступающих от источника (source), перед тем, как они передаются в место назначения (destination).
DMA FIFO может быть разрешен или запрещен программно. Если FIFO запрещен, используется режим Direct. Если FIFO разрешен, может использоваться режим упаковки/распаковки данных (data packing/unpacking) и/или пакетный (burst) режим. Конфигурируемый порог заполнения DMA FIFO определяет время запроса порта памяти DMA.
Достоинства DMA FIFO следующие:
• Уменьшается доступ к SRAM, что дает больше времени другим мастерам для доступа к матрице шины, без дополнительной конкуренции.
• Программе дозволено выполнять пакетные (burst) транзакции, которые оптимизируют полосу пропускания передачи.
• Можно упаковывать/распаковывать данные, чтобы согласовать ширину данных источника и места назначения без дополнительного доступа DMA.Рис. 4. Структура FIFO.
Размер пакета источника и места назначения. Пакетные транзакции гарантируются реализацией стеков DMA FIFO.
Рис. 5. Пакетная транзакция DMA (burst transfer).
В ответ на запрос пакета (burst request) от периферийного устройства DMA считывает или записывает некоторое количество элементов данных (элементом данных может быть слово, половина слова или байт). Это количество программируется размером пакета (burst size 4x, 8x или 16x элемента данных). Burst size на порту DMA периферийного устройства должно быть установлено в соответствии с необходимыми требованиями или возможностями периферийного устройства.
DMA burst size на порту памяти и конфигурация порога FIFO должны соответствовать друг другу. Это позволяет потоку DMA иметь достаточно данных в FIFO, когда запускается пакетная передача на порту памяти. Таблица 3 показывает возможные комбинации burst size памяти, конфигурации порога FIFO и размера данных.
Для гарантии когерентности каждая группа передач, которая формирует пакет, неделимая: транзакция AHB блокируется и арбитр матрицы шины AHB не удаляет права мастера DMA во время последовательности транзакции пакета (burst transfer sequence).
Таблица 3. Возможные конфигурации пакетной (burst) транзакции.
MSIZE Уровень
заполнения
FIFOMBURST = INCR4 MBURST = INCR8 MBURST = INCR16 Byte 1/4 1 пакет из 4 байт Запрещено Запрещено 1/2 2 пакета из 4 байт 1 пакет из 8 байт 3/4 3 пакета из 4 байт Запрещено Full 4 пакета из 4 байт 2 пакета из 8 байт 1 пакет из 16 байт Half-word 1/4 Запрещено Запрещено Запрещено 1/2 1 пакет из 4 полуслов 3/4 Запрещено Full 2 пакета из 4 полуслов 1 пакет из 8 полуслов Word 1/4 Запрещено Запрещено 1/2 3/4 Full 1 пакет из 4 слов Режим двойной буферизации. Поток с двойным буфером работает так же, как и с одним буфером, но с тем отличием, что с двойной буферизацией есть 2 указателя на память. Когда разрешен режим двойной буферизации, автоматически разрешается кольцевой режим (Circular mode), и на каждом окончании транзакции (когда регистр DMA_SxNDTR достигает 0) указатели на память переключаются. Это позволяет программе работать с одним буфером, пока второй буфер заполняется или используется транзакцией DMA.
Рис. 6. Режим двойной буферизации.
В режиме двойной буферизации есть возможность обновлять базовый адрес для порта памяти AHB на лету (DMA_SxM0AR или DMA_SxM1AR), когда поток разрешен:
• Когда бит CT (Current Target) в регистре DMA_SxCR равен 0, текущий используемый DMA целевой буфер памяти 0, поэтому может быть обновлен адрес DMA буфера памяти 1 (DMA_SxM1AR).
• Когда бит CT (Current Target) в регистре DMA_SxCR равен 1, текущий используемый DMA целевой буфер памяти 1, поэтому может быть обновлен адрес DMA буфера памяти 0 (DMA_SxM0AR).Этот пример работает на плате STM32F4DISCOVERY (микроконтроллер STM32F407) под управлением FreeRTOS. Обработчик прерывания завершения транзакции DMA1_Stream5_IRQHandler выводит из спячки задачу DACtask, которая занимается синтезом данных для свободного на данный момент буфера. По методу прямого синтеза (DDS) создаются данные синусоиды определенной частоты, которые потом проигрываются в DAC с помощью транзакций DMA. Сигнал формируется на выходе первого канала DAC (ножка порта PA4). Команда freq консоли USART2 позволяет задать произвольную частоту генерации в диапазоне от 0 до 22049 Гц.
Интересно, что автоматическое формирование сигнала на выходе DAC не прекращается, даже когда выполнение программы остановлено в отладчике. Ниже приведены основные части кода, демонстрирующие работу с DMA. Весь проект целиком для IAR версии 8.30 можно скачать по ссылке [5].
[Модуль dac.c]
В этом модуле находятся функции и переменные, относящиеся к ЦАП и синтезу формы сигнала заданной частоты.
[Модуль dma.c]
В этом модуле представлен код обработчика прерывания DMA.
[Модуль main.c]
Основной модуль программы. Здесь для упрощения оставлены только действия, касающиеся запуска потоков и генерации частоты.
Управление потоком. Контроллер потока (flow controller) это блок, который управляет длиной передачи данных, и который отвечает за остановку передачи DMA. Контроллером потока может быть либо DMA, либо периферийное устройство.
Если контролером потока является DMA, то необходимо определить значение размера транзакции в регистре DMA_SxNDTR перед тем, как разрешается соответствующий поток DMA. Когда обслуживается запрос DMA значение размера транзакции уменьшается на количество переданных данных (в зависимости от типа запроса: пакетный burst или одиночный single). Когда значение размера транзакции достигает 0, транзакция DMA завершается и поток DMA запрещается.
Если контроллером потока является периферийное устройство, то количество передаваемых элементов данных неизвестно. Периферийное устройство аппаратно показывает для контроллера DMA, когда переданы последние данные. Этот режим поддерживают только периферийные устройства SD/MMC и JPEG.
[Настройка транзакции DMA]
Для конфигурирования потока x DMA (здесь x это номер потока) должна быть выполнена следующая процедура:
1. Если поток разрешен, то он должен быть запрещен сбросом бита EN в регистре DMA_SxCR. Затем этот бит должен быть прочитан чтобы удостовериться, что не активна операция потока. Запись в этот бит лог. 0 не приведет к немедленной остановке потока (бит не станет сразу лог. 0), пока все текущие передачи не завершатся. Когда чтение бита EN покажет 0, это будет означать, что поток остановлен и готов к конфигурированию. Поэтому нужно подождать, пока не очистится бит EN, чтобы можно было начать любое конфигурирование потока. Весь набор выделенных для потока бит в регистре статуса (DMA_LISR и DMA_HISR) от предыдущей транзакции блока данных DMA должен быть очищен до того, как поток может быть снова разрешен.
2. Устанавливается регистр адреса порта периферийного устройства в регистре DMA_SxPAR. Данные будут перемещаться из этого адреса или в этот адрес в/из порта периферийного устройства после возникновения события периферийного устройства.
3. Устанавливается адрес памяти в регистре DMA_SxMA0R (и в регистре DMA_SxMA1R, если используется режим двойной буферизации). Данные будут записываться по этому адресу или считываться оттуда после возникновения события периферийного устройства.
4. В регистре DMA_SxNDTR конфигурируется общее количество элементов данных для передачи. После каждого события периферийного устройства или после каждого пакета это значение декрементируется.
5. Битами CHSEL[2:0] регистра DMA_SxCR Выбирается канал (запрос) DMA.
6. Если периферийное устройство должно быть контроллером потока, и если оно поддерживает эту возможность (доступно только для периферийных устройств SD/MMC и JPEG), то устанавливается бит PFCTRL в регистре DMA_SxCR.
7. Конфигурируется приоритет потока битами PL[1:0] в регистре DMA_SxCR.
8. Конфигурируется использование FIFO (разрешено или запрещено, порог в передачи и приеме).
9. В регистре DMA_SxCR register конфигурируется направление потока данных, режим инкремента или фиксации адреса для периферийного устройства и памяти, транзакции будут одиночные (single) или пакетные (burst), ширины данных периферийного устройства и памяти, кольцевой режим или режим двойной буферизации, и прерывания после половины или полной передачи и/или при ошибке.
10. Поток активируется установкой бита EN в регистре DMA_SxCR.
Как только поток разрешен, он может обслужить любой запрос DMA от периферийного устройства, соединенного с потоком.
[Производительность системы]
В MCU STM32F2/F4/F7 встроена архитектура нескольких главных и нескольких подчиненных блоков (multi-masters/multi-slaves):
• Несколько устройств master:
– Шины AHB ядра Cortex®-Mx
– Шина памяти DMA1
– Шина памяти DMA2
– Шина периферийного устройства DMA2
– Шина Ethernet DMA
– Шина USB high-speed DMA
– Шина Chrom-ART Accelerator
– Шина LCD-TFT• Несколько устройств slave:
– Внутренние интерфейсы Flash, подключенные к многослойной матрице шины.
– Основная внутренняя память SRAM1 и дополнительные (Auxiliary) внутренние SRAM (SRAM2, SRAM3, когда они имеются в MCU).
– Периферийные устройства AHB1, включая мосты AHB-APB и периферийные устройства APB.
– Периферийные устройства AHB2.
– Периферийные устройства AHB3 (такие как FMC, Quad-SPI, когда это имеется на линейке продуктов MCU).Устройства master и slave соединены через многослойную матрицу шины, гарантирующую конкурентный доступ его эффективное функционирование, даже когда высокоскоростные периферийные устройства работают одновременно. Эта архитектура для примера показана на следующем рисунке для случая серий STM32F405/STM32F415 и STM32F407/STM32F417.
Рис. 7. Архитектура системы STM32F405/STM32F415 и STM32F407/STM32F417.
Многослойная матрица шины. Multi-layer bus matrix позволяет устройствам master конкурентно/одновременно выполнять передачи данных, пока они адресуют разные модули slave. Базируясь на архитектуре Cortex-Mx двойных портов AHB DMA, эта структура улучшает параллелизм транзакций данных, что снижает затраты на время выполнения, повышает эффективность DMA и снижает потребление энергии.
В контексте рассмотрения матрицы шины используются следующие определения:
AHB master : главное устройство шины, который может инициировать операции чтения и записи. За определенный период времени только один master может выиграть владение шиной.
AHB slave : подчиненное устройство шины отвечает на операции чтения или записи устройства master. Устройство slave шины сигнализирует устройству master о состояниях успеха (success), отказа (failure) или ожидания.
AHB arbiter : арбитр шины гарантирует, что только один master может инициировать чтение или запись в один и тот же момент времени.
AHB bus matrix : многослойная матрица шины AHB, которая соединяет друг с другом устройства AHB master и AHB slave, с выделенным арбитром AHB для каждого слоя. Арбитраж использует алгоритм round-robin (циклический алгоритм [2]).Схема приоритетов round-robin. На уровне матрицы шин реализована циклическая (round-robin) схема обработки приоритетов для гарантии, что каждый master мог получить доступ к любому slave с очень низкой латентностью:
• Политика арбитража round-robin обеспечивает справедливое распределение полосы пропускания шины.
• Максимальная задержка ограничена.
• Квантом round-robin является 1x транзакция.Арбитры матрицы шины вмешиваются для решения конфликтов доступа, когда несколько master-устройств AHB пытаются одновременно получить доступ к одному slave-устройству AHB.
В следующем примере (рис. 8) сразу два устройства CPU и DMA1 пытаются получить доступ к SRAM1 для чтения данных.
Рис. 8. Запрос CPU и DMA1 на доступ к SRAM1.
В случае конкурентного доступа шины, как в примере рис. 8, требуется арбитраж матрицы шины. В этом случае применяется политика round-robin, чтобы решить проблему доступа: если последний выигравший master шины был CPU, то при следующем доступе выиграет доступ DMA1, и первым получит доступ к SRAM1. Затем права доступа к SRAM1 получит CPU.
В результате задержка транзакции, связанная с одним master, зависит от количества ожидающих запросов к тому же самому устройству AHB slave от других устройств master. В следующем примере (рис. 9) показана ситуация, когда сразу 5 устройств master пытаются одновременно получить доступ к SRAM1.
Рис. 9. Пять запросов устройств master на доступ к SRAM.
Латентность, связанная с DMA1 для повторного выигрыша шины и доступа к SRAM1 (для примера рис. 9) равна времени выполнения всех ожидающих запросов от других устройств master.
Задержка (latency) наблюдаемая портом DMA master в одной транзакции, зависит от типов и длин транзакций других master.
Например, если мы рассматриваем предыдущий пример DMA1 и CPU (рис. 8) с конкурентным доступом к SRAM, то задержка транзакции DMA меняется в зависимости от длины транзакции CPU.
Если доступ к шине сначала был предоставлен CPU, и CPU не выполняет одиночную операцию загрузки/сохранения данных (load/store), то время ожидания DMA для получения доступа к SRAM может расшириться от одного цикла AHB для одиночной операции load/store до N циклов AHB, где N это количество слов данных в транзакции CPU.
CPU блокирует шину AHB, чтобы сохранить владение её и снизить латентность во время нескольких операций load/store и входе в прерывания. Это улучшает отзывчивость firmware, но может привести к задержкам на выполнение транзакции DMA.
Задержка на доступ DMA1 SRAM, когда осуществляется конкуренция с CPU, зависит от типа транзакции:
• Транзакция CPU выдается по прерыванию (сохранение контекста): 8 циклов AHB.
• Транзакция CPU выдается контроллером кэша (256-битное заполнение/замещение строки кэша): 8 циклов AHB (a) .
• Транзакция CPU выдается инструкциями LDM/STM: 14 тактов AHB (b) .
– Передача до 14 регистров из памяти или в память.(a) Только для STM32F7xx.
(b) Латентность из-за транзакций, вызванных инструкциями LDM/STM, можно уменьшить, если сконфигурировать компилятор для деления нескольких инструкций load/store в отдельные инструкции load/store.На рис. 10 подробно показан случай задержки транзакции DMA из-за многоцикловой транзакции CPU, вызванной входом в обработчик прерывания. Порт памяти DMA запускается для доступа к памяти. После арбитража шина AHB не предоставляется порту памяти DMA1, потому что предоставляется для CPU. Наблюдается дополнительная задержка для обслуживания запроса DMA, она составляет 8 тактов AHB для транзакции CPU, вызванной прерыванием.
Рис. 10. Задержка запуска транзакции из-за транзакции CPU, запущенной прерыванием.
То же самое поведение наблюдается и для других устройств master (типа DMA2, USB_HS, Ethernet, . ), когда одновременно адресуется одно и то же slave-устройство с длиной транзакции, отличающейся от одного элемента данных.
Чтобы улучшить производительность доступа DMA на матрице шины, рекомендуется избегать конкуренции за шину.
[Пути транзакции DMA]
Двойной порт DMA. В MCU STM32F2/F4/F7 встроено два блока DMA. У каждого DMA есть 2 порта, порт памяти и порт периферийного устройства, которые могут работать одновременно, не только на уровне DMA, но также с другими устройствами master системы, используя внешнюю матрицу шины и выделенные пути DMA.
Одновременная операция позволяет оптимизировать эффективность работы DMA и снизить время отклика (время ожидания между запросом транзакции и передачей данных транзакции).
Рис. 11. Двойной порт DMA.
• MEM (порт памяти) может обращаться к AHB1, AHB2, AHB3 (контроллер внешней памяти, FSMC), областям SRAM, и к памяти Flash через матрицу шины.
• Periph (порт периферийных устройств) может обращаться:
– К AHB1, AHB2, AHB3 (контроллер внешней памяти, FSMC), областям SRAM, и к памяти Flash через матрицу шины.
– К мосту AHB-APB2 напрямую (без пересечения с матрицей шины).• MEM (порт памяти) может обращаться к AHB3 (контроллер внешней памяти, FSMC), областям SRAM, и к памяти Flash через матрицу шины.
• Periph (порт периферийных устройств) может обращаться только к мосту AHB-APB1 напрямую (без пересечения с матрицей шины).
Состояния транзакции DMA. В этой секции объясняются шаги транзакции DMA на уровне порта периферийного устройства, и также на уровне порта памяти.
• Для транзакции от периферийного устройства в память (см. рис. 12): в этом режиме DMA запрашивает два доступа к шине для выполнения транзакции.
– Один доступ через порт периферии, этот доступ запускается запросом от периферийного устройства.
– Другой доступ через порт памяти, который может быть запущен либо по порогу FIFO (когда используется режим FIFO), либо немедленно после чтения периферийного устройства (когда используется режим Direct).Рис. 12. Состояния транзакции периферия -> память.
• Для транзакции от памяти в периферийное устройство (см. рис. 13): в этом режиме DMA запрашивает два доступа к шине для выполнения транзакции.
– DMA ожидает доступ периферийного устройства, считывает данные из памяти и сохраняет их в FIFO для гарантии немедленной передачи данных, как только сработает запрос DMA периферийного устройства.
– Когда сработал запрос периферийного устройства, генерируется транзакция на порту DMA периферийного устройства.Рис. 13. Состояния транзакции память -> периферия.
Арбитраж запроса DMA. Как рассматривалось выше в секции «Приоритет потока», в MCU STM32F2/F4/F7 DMA встроен арбитр, который управляет запросами восьми потоков DMA на основе их приоритетов для каждого из двух портов AHB master (порт памяти и порт периферии). По этим приоритетам арбитр запускает последовательности доступа к периферии/памяти.
Когда активно больше одного запроса DMA, для DMA нужен внутренний арбитр между активными запросами, чтобы принять решение, какой запрос должен быть обработан первым.
На рис. 14 показаны два кольцевых (circular) запроса DMA, сработавших одновременно от потока DMA «request 1» и потока DMA «request 2» (запросы 1 и 2 могут быть любым запросом периферии DMA). На следующем цикле тактов AHB арбитр DMA проверяет активные ожидающие обработки запросы, и дает доступ для потока «request 1», который обладает самым высоким приоритетом.
Следующий цикл арбитража происходит во время последнего цикла данных потока «request 1». В этот момент «request 1» маскируется, и арбитр видит активным только «request 2», в результате чего на этот раз доступ резервируется для «request 2», и так далее.
Рис. 14. Арбитраж запроса DMA.
• Высокоскоростные (high-speed) / широкополосные (high-bandwidth) периферийные устройства должны иметь самые высокие приоритеты DMA. Это гарантирует, что максимальная задержка данных, ожидаемая для этих периферийных устройств, не приведет к переполнению (overrun) или недогрузке (underrun) в потоке данных.
• В случае одинаковых требований к полосе пропускания, рекомендуется назначить более высокий приоритет для периферийных устройств, работающих в режиме Slave (которые не управляют скоростью передачи данных). Меньший приоритет в этом случае назначается периферийным устройствам, которые работают в режиме Master (могут управлять потоком данных).
• Поскольку два блока DMA могут работать параллельно на базе многослойной структуры матрицы шины, запросы высокоскоростных периферийных устройств могут быть сбалансированы между двумя DMA, когда это возможно.[Мост AHB-APB]
В MCU STM32F2/F4/F7 встроено два моста AHB-APB (APB1 и APB2), к которым подключены периферийные устройства.
Двойной порт AHB-APB. Мост AHB-APB имеет двухпортовую архитектуру, которая позволяет осуществлять доступ двумя разными путями:
• Прямой путь (без пересечения с матрицей шины), который может быть сгенерирован от DMA1 к APB1 или от DMA2 к APB2. В этом случае доступ не получает пенальти от арбитра матрицы шины.
• Общий путь (через матрицу шины), который может быть сгенерирован от CPU или от DMA2, при этом нужен арбитраж матрицы шины, чтобы определить победителя доступа.Арбитраж моста AHB-APB. Из-за реализации прямого пути DMA также реализован арбитр на уровне моста AHB-APB, чтобы разрешить конкурентные запросы доступа.
На рис. 15 иллюстрируется конкурентный запрос доступа на шине AHB-APB1, генерируемый CPU (который осуществляет доступ через матрицу шины) и DMA1 (который осуществляет доступ напрямую).
Рис. 15. Конкурентный запрос на доступ моста AHB-APB1 от CPU и DMA1.
Для предоставления доступа к шине мост AHB-APB применяет политику round-robin:
• Квант round-robin равен 1x транзакции APB.
• Максимальная латентность на порту периферии DMA ограничена (1 транзакция APB).Только CPU и блоки DMA могут генерировать конкурентный доступ к шинам APB1 и APB2:
• Для APB1 конкурентный доступ может быть сгенерирован, если CPU, DMA1 и/или DMA2 одновременно запросили доступ.
• Для APB2 конкурентный доступ может быть сгенерирован, если CPU и DMA2 одновременно запросили доступ.[Как предсказать латентность DMA]
При разработке firmware приложения на основе MCU пользователь должен гарантировать, что не будут происходить ситуации недогрузки/переполнения (underrun/overrun). По этой причине важно знать точную задержку (latency) DMA для каждой транзакции, чтобы проверить, может ли внутренняя система поддерживать общую полосу пропускания, требуемую для приложения.
Время транзакции DMA по умолчанию. Как описывалось выше в секции «Состояния транзакции DMA», для выполнения транзакции DMA из периферии в память требуется два доступа к шине:
• Один доступ через порт периферии, который запускается запросом периферийного устройства. Эта операция требует:
– Арбитража запроса порта периферии DMA.
– Вычисления адреса периферии.
– Чтения данных из периферии в DMA FIFO (source, источник DMA).• Другой доступ через порт памяти, который может быть запущен порогом FIFO (когда используется режим FIFO) или немедленно после чтения периферии (когда используется режим Direct). Эта операция требует:
– Арбитража запроса порта памяти DMA.
– Вычисления адреса памяти.
– Записи загруженных данных в SRAM (destination, место назначения DMA).Когда данные перемещаются из памяти в периферию, также требуется два доступа, как описывалось выше в секции «Состояния транзакции DMA»:
• Первый доступ: DMA ожидает доступа периферии, считывает данные из памяти и сохраняет их в FIFO, чтобы гарантировать немедленную передачу данных, как только был запущен запрос DMA периферийного устройства. Эта операция требует:
– Арбитража запроса порта памяти DMA.
– Вычисления адреса памяти.
– Чтения данных из памяти в DMA FIFO (source, источник DMA).• Второй доступ: когда сработал запрос периферии, генерируется транзакция на порту периферийного устройства DMA. Эта операция требует:
– Арбитража запроса порта периферии DMA.
– Вычисления адреса периферии.
– Записи загруженных данных по адресу периферийного устройства (destination, место назначения DMA).Как основное правило, общее время транзакции потока DMA TS равно:
TS = TSP (время доступа/транзакции периферии) + TSM (время доступа/транзакции памяти)
Здесь TSP это общее время для порта периферии и транзакции, которое равно (значения tPA, tPAC, tBMA, tEDT, tBS приведены в таблице 4):
Таблица 4. Интервалы времени доступа/транзакции порта периферии в зависимости от используемого пути DMA.
Описание Через матрицу шины Прямой путь DMA К периферии AHB К периферии APB tPA: арбитраж порта периферийных устройств DMA 1 такт AHB tPAC: вычисление адреса периферии 1 такт AHB tBMA: арбитраж матрицы шины (когда нет конкуренции доступа) (1) 1 такт AHB Недоступно tEDT: эффективная транзакция данных 1 такт AHB (2)(3) 2 такта APB tBS: синхронизация шины Недоступно 1 такт AHB (1) В случае линеек серий STM32F401/STM32F410/STM32F411/STM32F412 интервал tBMA равен 0.
(2) Для FMC могут быть добавлены дополнительные такты в зависимости от используемой внешней памяти. Количество добавленных тактов AHB зависит от таймингов внешней памяти.
(3) В случае пакетной передач (burst), эффективное время передачи данных зависит от длины пакета (burst length, INC4 tEDT = 4 цикла AHB).TSM это общее время для доступа и транзакции порта памяти DMA, оно равно (значения tMA, tMAC, tBMA, tSRAM см. в таблице 5):
Таблица 5. Интервалы времени доступа/транзакции памяти.
Описание Задержка (латентность) tMA: арбитраж порта памяти DMA 1 такт AHB tMAC: вычисление адреса памяти 1 такт AHB tBMA: арбитраж матрицы шины (когда нет конкуренции) (1) 1 такт AHB (2) tSRAM: доступ к SRAM на чтение или запись 1 такт AHB (1) В случае линеек серий STM32F401/STM32F410/STM32F411/STM32F412 интервал tBMA равен 0.
(2) Следующих друг за другом доступов к SRAM (когда ни один из устройств master не обращается к тому же самому SRAM между доступами), tBMA = 0 циклов.Время передачи DMA в зависимости от конкурентного доступа. Может быть добавлена дополнительная задержка обслуживания DMA по таймингам, описанным в предыдущей секции, когда несколько устройств master пытаются одновременно получить доступ к одному и тому же устройству slave.
Для самого худшего случая времени доступа для периферии и памяти следующие факторы влияют на общее время задержки обслуживания потока DMA:
• Когда несколько устройств master одновременно обращаются к одному и тому же месту назначения AHB, это влияет на задержку DMA. Транзакция DMA не может запуститься, пока арбитр матрицы шины не предоставит доступ для DMA, как описывалось выше в секции «Схема приоритетов round-robin».
• Когда несколько устройств master (DMA и CPU) одновременно обращаются к мосту AHB-APB, время запуска транзакции DMA задерживается из-за арбитража моста, как описывалось выше в секции «Арбитраж моста AHB-APB».Ниже приведены примеры организации транзакций DMA.
Этот пример применим к MCU линеек STM32F2, STM32F405/STM32F415, STM32F407/STM32F417, STM32F427/STM32F437 и STM32F429/STM32F439.
ADC сконфигурирован в режиме triple Interleaved. В этом режиме оцифровка сигнала одного аналогового канала осуществляется на максимальной скорости (36 МГц). Прескалер ADC установлен на 2, время выборки установлено на 1.5 такта, и задержка между двумя последовательными выборками ADC режима Interleaved установлена на 5 тактов.
DMA2 stream0 передает преобразованное значение ADC в буфер SRAM. Доступ DMA2 к ADC осуществляется напрямую, без матрицы шины; однако доступ DMA к SRAM осуществляется через матрицу шины.
Таблица 6. Латентность транзакции DMA порта периферии (ADC).
Частота AHB/APB2 FAHB = 72 МГц/
FAPB2 = 72 МГц
AHB/APB = 1FAHB = 144 МГц/
FAPB2 = 72 МГц
AHB/APB = 2Время транзакции tPA: арбитраж порта DMA периферийного устройства 1 такт AHB tPAC: вычисление адреса периферии 1 такт AHB tBMA: арбитраж матрицы шины Недоступно (1) tEDT: эффективная транзакция данных 2 такта AHB 4 такта AHB tBS: синхронизация шины 1 такт AHB TSP: общее время транзакции DMA для порта периферии 5 тактов AHB 7 тактов AHB Примечание (1): DMA2 осуществляет доступ к ADC напрямую, без арбитража матрицы шины.
Таблица 7. Латентность транзакции DMA порта памяти (SRAM).
Частота CPU/APB2 FAHB = 72 МГц/
FAPB2 = 72 МГц
AHB/APB = 1FAHB = 144 МГц/
FAPB2 = 72 МГц
AHB/APB = 2Время транзакции tMA: арбитраж порта DMA памяти 1 такт AHB tMAC: вычисление адреса памяти 1 такт AHB tBMA: арбитраж матрицы шины 1 такт AHB (1) tSRAM: доступ на запись в SRAM 1 такт AHB TSM: общее время транзакции DMA для порта памяти 4 такта AHB Примечание (1): в случае множественного доступа DMA к SRAM, арбитраж матрицы шины равен 0 циклов, если в промежутке нет обращений к от других master.
В этом примере общая задержка DMA от момента срабатывания триггера ADC DMA (ADC EOC) до записи значения ADC в SRAM равна 9 тактов AHB для прескалера AHB/APB, равного 1, и 11 тактов AHB для прескалера AHB/APB, равного 2.
Примечание: когда используется FIFO, доступ к порту памяти DMA осуществляется реже, по мере достижения уровня порога FIFO, сконфигурированного пользователем.
Этот пример применим для MCU линеек STM32F2, STM32F405/STM32F415, STM32F407/STM32F417, STM32F427/STM32F437 и STM32F429/STM32F439. Пример основан на периферийном устройстве SPI1.
Конфигурируются 2 запроса DMA:
• DMA2_Stream2 для SPI1_RX: этот поток конфигурируется на самый высокий приоритет, чтобы своевременно обслужить принятые данные SPI1, и передать их из регистра SPI1_DR в буфер SRAM.
• DMA2_Stream3 для SPI1_TX: этот поток передает данные из буфера SRAM в регистр SPI1_DR.Частота AHB равна частоте шины APB2 (84 МГц), и SPI1 конфигурируется на максимальную скорость (42 МГц). Поток DMA2_Stream2 (SPI1_RX) срабатывает перед потоком DMA2_Stream3 (SPI1_TX), который будет запущен на 2 такта AHB позже.
В этой конфигурации CPU в бесконечном цикле опрашивает регистр I2C1_DR. Мы знаем, что периферийное устройство отображено на шину APB1, и что периферийное устройство SPI1 отображено на шину APB2, пути данных в системе получатся следующие:
• Прямой путь для DMA2 при доступе к APB2 (не через матрицу шины).
• Доступ CPU к APB1 через матрицу шины.Цель примера состоит в демонстрации факта, что тайминги DMA не влияют на опрос CPU шины APB1. На рис. 16 показаны тайминги DMA для режимов передачи и приема, а также время планирования для каждой операции.
Рис. 16. Время транзакции SPI full duplex DMA.
Из рис. 16 видно следующее:
• Опрос CPU по шине APB1 не влияет на латентность передачи DMA по шине APB2.
• Для транзакции потока DMA2_Stream2 (SPI1_RX) на восьмом такте AHB нет арбитража матрицы шины, поскольку предполагается, что последний master, который получил доступ к SRAM, был DMA2 (поэтому повторный арбитраж не требуется).
• Для транзакции потока DMA2_Stream3 (SPI1_TX) этот поток ожидает чтения из SRAM, записывает данные в FIFO и затем, когда произошел запуск, порт периферии DMA (destination, место назначения SPI1) начинается транзакция.
• Для потока DMA2_Stream3 выполняется фаза арбитража DMA периферии (1 такт AHB) во время цикла синхронизации шины DMA2_Stream2.Эта оптимизация всегда выполняется аналогично, когда запрос DMA сработал перед окончанием текущей транзакции запроса DMA.
[Советы и предупреждения при программировании контроллера DMA]
Последовательность запрета DMA. Чтобы отключить периферийное устройство, соединенное с запросом к потоку DMA, важно выполнить следующее:
1. Выключить поток DMA, к которому подключено периферийное устройство.
2. Подождать, пока не сбросится в лог. 0 бит EN в регистре DMA_SxCR.Только после этого можно безопасно запретить периферийное устройство. Бит разрешения запроса DMA в регистре управления периферийного устройства должен быть сброшен в лог. 0, чтобы гарантировать, что очищен любой ожидающий обработки запрос от периферийного устройства.
Примечание: в обоих случаях установится флаг прерывания завершения транзакции (Transfer Complete Interrupt Flag, TCIF) в регистре DMA_LISR или DMA_HISR), чтобы показать завершение транзакции из-за запрета потока.
Обслуживание флага DMA перед разрешением новой транзакции. Перед разрешением новой передачи пользователь должен убедиться, что очищен флаг Transfer Complete Interrupt Flag (TCIF) в регистре DMA_LISR или DMA_HISR. В качестве общей рекомендации лучше очистить все флаги регистров DMA_LIFCR перед DMA_HIFCR запуском новой передачи.
Последовательность разрешения DMA. При разрешении DMA используется следующая последовательность действий:
1. Конфигурирование подходящего потока DMA.
2. Разрешение используемого потока DMA (установка бита EN в регистре DMA_SxCR).
3. Разрешение используемого периферийного устройства. Бит разрешения запроса DMA в регистре управления периферийным устройством должен быть установлен в лог. 1.Примечание: если пользователь разрешает используемое периферийное устройство перед соответствующим потоком DMA, то может установиться флаг прерывания ошибки FEIF (FIFO Error Interrupt Flag), потому что DMA фактически не готово предоставить первые необходимые данные для периферийного устройства (в случае транзакции из памяти в периферийное устройство).
Транзакция память-память при NDTR=0. Когда конфигурируется поток DMA для выполнения передачи из памяти в память в нормальном режиме (normal mode), то как только NDTR достигает 0, установится флаг завершения транзакции (Transfer Complete). В этот момент, если пользователь установил флаг разрешения этого потока (бит EN в регистре DMA_SxCR), транзакция память-память автоматически запустится повторно с последним значением NDTR.
Пакетная передача DMA при PINC/MINC=0. Функция пакетной передачи DMA (Burst) с запретом инкремента адреса периферийного устройства (PINC) или инкремента адреса памяти (MINC) позволяет адресовать внутренние или внешние (FSMC) периферийные устройства, поддерживающие Burst (имеющие встроенные FIFO). Этот режим гарантирует, что этот поток DMA не может быть прерван другими потоками DMA во время их транзакций.
Запросы DMA с двойным отображением. Когда пользователь конфигурирует два (или большее количество) потоков DMA для обслуживания запроса одного и того же периферийного устройства, программа должна гарантировать, что текущий поток DMA полностью запрещен (путем опроса бита EN в регистре DMA_SxCR) перед разрешением нового потока DMA.
Наилучшая конфигурация DMA по пропускной способности. При использовании STM32F4xx с пониженной частотой AHB, когда DMA обслуживает высокоскоростное периферийное устройство, рекомендуется поместить стек и кучу в память CCM (Core Coupled Memory, которая может быть адресована непосредственно CPU через D-шину) вместо того, чтобы помещать их в SRAM. Это создаст дополнительный параллелизм работы CPU и DMA, осуществляющими доступ к оперативной памяти.
Приостановка транзакции DMA. В любой момент времени передача DMA может быть приостановлена до окончания, чтобы быть перезапущенной позже, или же быть запрещенной полностью.
Здесь могут быть 2 случая:
• Поток запрещает передачу без последующего возобновления передачи с той точки, где передача была остановлена. В этом случае не требуется никаких дополнительных действий, кроме как очистка бита EN в регистре DMA_SxCR для запрета потока и ожидания сброса в ноль бита EN. Как следствие:
– Регистр DMA_SxNDTR содержит количество оставшихся элементов данных на момент, когда передача была приостановлена, так что программа может определить, сколько данных было передано до того, как работа потока была прервана.
• Поток приостанавливает транзакцию, чтобы потом можно было её возобновить: для перезапуска от точки, где была остановлена транзакция, программа должна прочитать регистр DMA_SxNDTR после запрета потока (после того, как бит EN перейдет в лог. ), чтобы узнать, сколько элементов данных уже было собрано. Затем:
– Адреса периферии и/или памяти должны быть обновлены, чтобы указатели были актуально подстроены.
– Регистр SxNDTR должен быть обновлен оставшимся количеством элементов данных, которые должны быть переданы (прочитанное значение, когда поток был запрещен).
– Поток может быть заново разрешен для перезапуска транзакции с той точки, где она была остановлена.Примечание: в обоих случаях установится флаг завершения транзакции Transfer Complete Interrupt Flag (бит TCIF в регистре DMA_LISR или DMA_HISR), чтобы показать окончание транзакции из-за того, что работа потока прервана.
Преимущества контроллера DMA2 и гибкость архитектуры системы. В этой секции озвучена идея получения выгоды от гибкости, предоставляемой архитектурой STM32 и контроллером DMA. В качестве иллюстрации мы покажем, как инвертировать порты периферии DMA2 AHB и памяти, и сохранить правильное управление передачей данных периферийных устройств. Чтобы достичь этого и взять управление над обычным поведением DMA2, нужно рассмотреть рабочую модель DMA2.
Поскольку оба порта DMA2 соединены с матрицей шины AHB, и имеют симметричное соединение с slave-устройствами AHB, эта архитектура позволяет протекать трафику в одно или другом направлении через порты периферии и памяти, в зависимости от программной конфигурации.
ПО обладает гибкостью для конфигурации транзакции потока DMA2 в соответствии со своими потребностями. В зависимости от этой конфигурации один порт DMA2 AHB программируется в направлении чтения, другой в направлении записи. Таблица 8 показывает направление порта DMA AHB в зависимости от конфигурации режима транзакции.
Таблица 8. Направление порта DMA AHB в зависимости от конфигурации режима транзакции.
Режим транзакции Порт памяти DMA2 AHB Порт периферии DMA2 AHB Из памяти в периферийное устройство Направление чтения (Read) Направление записи (Write) Из периферийного устройства в память Направление записи (Write) Направление чтения (Read) Из памяти в память Теперь рассмотрим поток трафика (см. выше секцию «Состояния транзакции DMA») транзакций на порту периферии, запускаемых запросами периферийного устройства, транзакций на порту памяти, запускаемых либо по порогу FIFO (при использовании режима FIFO) или немедленно после чтения периферийного устройства (когда используется режим Direct).
Когда обслуживаются периферийные устройства с портом памяти DMA2 нам нужно позаботиться о предварительно запускаемых транзакциях (см. далее «Предварительно запущенная транзакция»), и об обработке последних данных (см. далее «Обслуживание последнего чтения данных»).
Предварительно запущенная транзакция. Как было описано ранее в секции «Состояния транзакции DMA», когда сконфигурирован режим передачи из памяти в периферийное устройство (чтение данных через порт памяти) DMA ожидает доступа периферийного устройства и считывает данные, как только поток DMA был разрешен. Один элемент данных буферируется в режиме Direct, и до 4 x 32-разрядных слов, когда разрешен DMA FIFO.
Когда обслуживаются чтения периферийного устройства через порт памяти DMA2, программа должна гарантировать, что периферийное устройство разрешено перед разрешением DMA, чтобы гарантировать правильность первого доступа DMA.
Рис. 17 иллюстрирует доступы DMA на портах памяти и периферии в зависимости от триггеров периферийного устройства.
Рис. 17. DMA в режиме транзакции из памяти в периферийное устройство.
Обслуживание последнего чтения данных. Контроллер DMA обладает функцией 4 x 32-разрядных слов FIFO на поток, что может использоваться для буферизации данных между портами AHB. Когда обслуживаются чтения периферийных устройств через порт памяти DMA, программа должна гарантировать, что 4x дополнительные слова прочитаны из периферийного устройства. Это даст гарантию, что последние достоверные данные будут переданы из DMA FIFO.
Буферизированные транзакции, когда запрещен режим Direct. Когда записываются данные через порт памяти в периферийное устройство, когда разрешен режим FIFO, программе нужно позаботиться о том, что доступ через этот порт срабатывает по запрограммированному порогу FIFO. Когда достигнут порог данных, данные передаются из FIFO в место назначения через порт памяти.
Когда происходит запись в регистр (например у GPIO нет FIFO), данные из DMA FIFO будут успешно записаны в место назначения.
И последнее, но не менее важное: когда переключается управление периферией с порта периферии на порт памяти, программе нужно пересмотреть размер транзакции и конфигурацию инкремента адреса.
Как описано выше в секции «Размер транзакции», размер транзакции определяется шириной транзакции на стороне периферийного устройства (byte, half-word, word) и количеством передаваемых элементов данных (значение, запрограммированное в регистр DMA_SxNTDR). В соответствии с новой конфигурацией DMA, когда запрограммировано инвертирование портов, может понадобиться подстроить значение регистра DMA_SxNTDR.
В этом примере DMA_S7M0AR программируется адресом регистра Quad-SPI Data, DMA_S7PAR программируется адресом буфера данных (буфер, который находится в SRAM). В регистре DMA_S7CR должно быть сконфигурировано направление потока DMA2 в режиме от периферии в память, когда происходит запись в Quad-SPI. Направление потока DMA2 должно быть сконфигурировано в режиме из памяти в периферийное устройство, когда происходит чтение из Quad-SPI.
4x дополнительных слова (32-разрядных) нужны для операции чтения, чтобы гарантировать, что последние данные были переданы наружу из DMA FIFO в SRAM.
Кусок кода для операции чтения:
Кусок кода для операции записи:
Примечание: ограничение повреждения данных, когда DMA2 обслуживается параллельно с транзакциями AHB и APB2 (см. сообщения об ошибках кристалла errata, чтобы определить, в каких STM32F2/F4 MCU это присутствует) можно обойти путем переключения портов периферии и памяти DMA2, как описывается в этой секции.
Транзакция STM32F7 DMA и обслуживание кэша, чтобы избежать некогерентности данных. Когда программа использует не кэшируемые регионы памяти для буферов источника / места назначения DMA, для них необходимо запустить очистку кэша, перед запуском работы DMA, чтобы гарантировать, что все данные были зафиксированы подсистемой памяти. При чтении данных из периферийного устройства после завершения транзакции DMA, программа должна выполнить сброс достоверности кэша (cache invalidate) перед чтением обновленного региона памяти.
Для буферов DMA желательно использовать не кэшируемые регионы памяти. Программа может использовать MPU, чтобы настроить не кэшируемый блок памяти для использования в виде общей памяти между CPU и DMA.
[Общие выводы]
Контроллер DMA разработан для обслуживания большинства случаев использования во встраиваемых приложениях, со следующими основными возможностями:
• Предоставляется гибкость выбора подходящей комбинации между 16 потоками X (по 8 потоков на каждый DMA).
• Снижается общее время задержки для транзакции DMA благодаря двухпортовой архитектуре AHB и прямому пути доступа к мостам APB, что устраняет приостановки CPU на доступе к AHB1, когда DMA обслуживает низкоскоростные периферийные устройства APB.
• Реализация стеков FIFO на DMA дает больше гибкости для конфигурирования разных размеров данных между источником и местом назначения, и ускоряет передачи, когда используется режим пакетной передачи с инкрементом (incremental burst transfer).