STM32 для начинающих. Урок 6. DMA STM32.

Автор: | 01.09.2016

DMA(Direct Memory Access) — Контроллер прямого доступа к памяти. Данный контроллер позволяет оперировать данными без участия процессора. То есть, используя DMA, мы можем разгрузить наш процессор от операций с памятью, заняв его чем-то более полезным.

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

Микроконтроллеры семейства STM32F3 имеют в своем составе до 2 контроллеров DMA, которые имеют 12 линий передачи данных. То есть существует возможность организовать 12 независимых пересылок данных. Однако, следует учитывать что каждый канал соединен с соответствующей периферией согласно данной таблице:

И для DMA2:

Давайте попробуем реализовать аппаратный memcpy на DMA.То есть просто перешлем один массив в другой, настроив контроллер прямого доступа к памяти.

Рассмотрим следующий код:

Разберем данный код подробнее. В функции main, сначала вызывается функция InitRCC, о которой вы можете почитать здесь.Затем мы заполняем исходный массив в цикле. После заполнения массива, вызывается функция Init_DMA, в которой мы непосредственно настраиваем контроллер прямого доступа к памяти. Разумеется, сначала мы включаем тактирование контроллера DMA1 командой RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE). Затем необходимо настроить структуру DMA_InitTypeDef, рассмотрим её поля:

  • DMA_PeripheralBaseAddr — Адрес периферии (Так же можно указать адрес памяти),из которой или в которую будет происходить чтение/запись.
  • DMA_MemoryBaseAddr — Адрес памяти ,из которой или в которую будет происходить чтение/запись.
  • DMA_MemoryInc — Увеличивать ли адрес в памяти при работе. То есть, при каждой операции записи/чтения производить следующую операцию записи/чтения в последующий участок памяти. Удобно при записи данных в массив.
  • DMA_PeripheralInc — Увеличивать ли адрес в периферии при работе.
  • DMA_BufferSize — Размер буфера. То есть, с массивом какой длины мы будем производить операции записи/чтения.
  • DMA_M2M— Ведется ли передача из памяти в память.
  • DMA_MemoryDataSize — Размер данных в памяти.
  • DMA_PeripheralDataSize — Размер данных периферии
  • DMA_Mode — Режим работы канала. Здесь можем выбрать, включать ли циклическую запись данных. То есть, будет ли запись начата вновь в начальный элемент массива, при его заполнении.
  • DMA_Priority — Приоритет текущего канала.
  • DMA_DIR — Направление передачи. То есть периферия-память или наоборот.
Читайте также  STM32 для начинающих. Урок 5. Внешние прерывания STM32.

Заполнив данную структуру, инициализируем контроллер DMA командой DMA_Init.После этого включаем контроллер используя команду DMA_Cmd, и настраиваем прерывание окончания передачи данных DMA.

В обработчике прерывания DMA1_Channel1_IRQHandler,вызывается команда __NOP, которая поможет нам в дальнейшей отладке. После этого очищается бит окончания передачи данных командой DMA_ClearITPendingBit(DMA1_IT_TC1).

После сборки прошивки, запускаем отладку, и устанавливаем точку останова перед командой DMA_Init. В окне watch, убеждаемся в том, что исходный массив заполнен.

После этого устанавливаем точку останова в прерывании, на той самой команде __NOP. Снова заглянув в окно Watch, видим, что массив source перемещен в массив dest, чего мы собственно и добивались!

Если у Вас ещё остались какие либо вопросы по работе DMA микроконтроллера STM32, вы можете оставить их ниже, в комментариях. Лишь благодаря Вашей поддержке, наши уроки станут лучше!

На сегодня всё,спасибо за внимание!

Другие уроки цикла.


Любое копирование, воспроизведение, цитирование материала, или его частей разрешено только с письменного согласия администрации MKPROG.RU. Незаконное копирование, цитирование, воспроизведение преследуется по закону!

STM32 для начинающих. Урок 6. DMA STM32.: 10 комментариев

  1. Валентин

    У меня вопрос.
    Три строки под комментарием set flash latency что делают?
    Спасибо.

    1. DamiKK Автор записи

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

  2. Уведомление: STM32.TFT Дисплей.Библиотека для ST7735 | MKPROG.RU

  3. сергей

    Здравствуйте. Если я по дма передаю из памяти в переферию, но переферия медленная как понизить скорость передачи. Надо передать массив данных.

    1. DamiKK Автор записи

      Здравствуйте!
      Передача из памяти в периферию при помощи DMA будет осуществляться по сигналам периферии.

  4. Михаил

    А почему адрес массива берется
    dma1.DMA_PeripheralBaseAddr =(uint32_t) &source;
    так? Имени массива разве не достаточно?

    1. DamiKK Автор записи

      Знак & необходим для взятия адреса переменной в памяти.

  5. Vadim

    НЕ ВВОДИТЕ ЛЮДЕЙ В ЗАБЛУЖДЕНИЕ!!!
    dma1.DMA_PeripheralBaseAddr =(uint32_t) &source;
    ЗАПОМНИТЕ РАЗ И НАВСЕГДА!!! Имя «source» и есть указатель на память массива. На некоторых компиляторах работать будет(которые думают за вас), на некоторых нет.
    СМОТРИМ СЮДА ВНИМАТЕЛЬНО (два способа):
    1. addr = (uint32_t) source; //просто приводим уже имеющийся указатель к уинт32
    2.addr = (uint32_t) & source[0]; //а вот тут необходимо брать адрес
    А вот у регистров адрес брать НУЖНО:
    addr = (uint32_t) & ADC1->DR;

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *