Прямой доступ к памяти

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

В большинстве современных микроконтроллеров, в том числе и в stm32f103c8, специально для таких случаев предусмотрен модуль прямого доступа к памяти, ПДП (англ. Direct Memory Access, DMA). Обобщая, в нашем микроконтроллере всего два вида памяти: регистры периферии и основная память. Соответственно ПДП может:

Операция копирования из периферии в периферию не доступна.

Запустить копирование можно как программно (записью в определённый регистр), так и привязать запуск DMA к какому-нибудь событию, например к окончанию преобразования ADC или приёму символа по UART.

Задумывались как работает mp3-плеер? В его состав входит flash-память, где хранятся песни. Как минимум их нужно вытащить от туда в оперативную память для последующей декодировки. Далее результат декодировки нужно подать на цифро-аналоговый преобразователь, а это опять операция копирования. Если декодировщик программный, то тратить драгоценное процессорное время на тупое копирование -- непозволительная роскошь.

Допустим по UART приходят команды, которые нужно обрабатывать. Обычно команды — это последовательности символов (NMEA, AT-команды и т.д.), поэтому пытаться обработать один единственный прибывший символ не имеет смысла, их нужно сложить в массив, а затем проанализировать. DMA можно настроить так, что бы с каждым новым его вызовом он итерировал адрес в памяти на нужную длину: 1 (uint8_t); 2 (uint16_t); или 4 байта (uint32_t). Так как массив — линейный участок в памяти, все данные будут складываться друг за другом.

Буфер однако не может быть бесконечным, поэтому DMA можно настроить на работу в циклическом режиме. Кода индекс дойдёт до края массива, он просто запишет следующее значение в начало. Такая возможность удобна ещё и тогда, когда вы работаете с несколькими каналами ADC, которые работают по очереди и складывают результаты преобразования в один единственный регистр.

Как и любая другая периферия DMA может формировать запросы на прерывания.

Конкретно в stm32f103 присутствует два модуля DMA1, которые суммарно предоставляют 12 каналов (7 на DMA1 и 5 на DMA2). Все они могут быть настроены независимо друг от друга, но есть небольшое ограничение: нельзя повесить нужную периферию на произвольный канал.

dma table

Таблица с каналами DMA1 из Reference Manual, стр. 282

В более продвинутых МК от ST наряду с каналами присутствуют потоки (англ. stream), но мы не будем их рассматривать.

Шины и DMA

Все данные передаются по шинам (англ. bus), которые пересекаются в матрице (англ. bus matrix). В STM32 модуль DMA и ядро Cortex-M3 используют одну и ту же шину, поэтому работа DMA может тормозить работу ядра. С одной стороны, это существенный недостаток, а с другой такой подход позволяет делать микроконтроллеры дешёвыми.

dma diagram

Диаграмма шин данных, документ AN2548, стр. 7.

Когда ядро считывает инструкции из flash-памяти, а DMA работает с периферией, они не мешают друг другу.

Матрица шин реализует алгоритм round-robin для распределения нагрузки. Проще говоря шина циклически перебирает всех потребителей и даёт им доступ по очереди.

Здесь сразу же может возникнуть вопрос, — «А что если несколько каналов DMA захотят работать одновременно?» Ответ довольно прост: они не смогут этого сделать. Каждому «объекту» (периферии) программно задаётся приоритет (очень высокий, высокий, средний и низкий), ориентируясь на который специальная схема-арбитр (англ. arbiter) позволит работать тому или иному каналу. В случае, если программные приоритеты равны у разных каналов, арбитр смотрит на их номера. Чем меньше номер, тем выше приоритет. Если одновременно нужно забрать данные с ADC1 и считать символ с SPI2, то последний будет ожидать освобождения шины первым каналом.

Если в МК присутствует два модуля, то DMA1 имеет приоритет над DMA2.

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

Регистры DMA

Для работы с прерываниями отведено два регистра. Устроены они аналогично, однако первый, ISR, служит для индикации, т.е. его можно только считывать, а второй, IFCR для сброса.

dma isr

Следующая группа регистров (CCRx) позволяет настроить режим работы канала.

dma ccrx

Группа регистров CNDTRx задаёт количество передаваемых данных для каждого канала, которое должна находиться в диапазоне от 0 до 65535.

И последние два регистра CPARx и CMARx задают начальный адрес (32 бита) периферии и памяти соответственно.


Назад | Оглавление | Дальше


1 Два DMA доступны только в high-density МК, а stm32f103c8 относится к medium-density.