STM Урок 210. LL. STM32F4. DMA. MEM2MEM



Продолжаем программирование линейки контроллеров STM32F4 с использованием библиотеки LL.

В данном уроке мы попытаемся поработать с периферией DMA контроллера STM32F4. Мы попробуем скопировать некоторое количество информации из одной области памяти в другую (MEM2MEM).

Над данной темой мы уже работали в уроке 156, когда работали с линейкой STM32F1. Но, так как в DMA линейки контроллеров STM32F4 присутствует очень много отличий, в чём мы убедились в прошлом уроке, то считаю, что урок такой нужен и наверняка может возникнуть ситуация, когда нам потребуется скопировать данные из одного буфера в другой, не нагружая при этом АЛУ контроллера. Благодаря тому, что с данной темой мы уже знакомы, а также и с DMA серии контроллеров F4 тоже знакомы, то урок не будет большим и справиться с задачей нам не составит особого труда.

Схема наша осталась прежней — отладочная плата STM32F429I-Discovery

 

 

Проект за основу мы возьмём из прошлого урока с именем LL_SPI_ILI9341_DMA, так как нам потребуется дисплей для вывода информации, и назовём его LL_DMA_MEM_TO_MEM.

Откроем наш проект в Cube MX, перейдём во вкладку MemToMem раздела DMA и добавим поток, оставив приоритет низким. Передавать мы будем 16-разрядные значения (HalfWorld), Fifo будем использовать (его тут и не отключишь), также буфер Fifo мы будем использовать только наполовину, так как у нас такие значения, инкрементировать мы будем и источник и приёмник, а Brust Size оставим одиночным

 

 

А вот у SPI мы приоритет потока DMA повысим, чтобы копирование данных не мешало работе дисплея ибо у него номер потока больше и, следовательно, приоритет ниже

 

 

Включим прерывания для нашего нового потока, приоритеты здесь можно не трогать, так как прерывание мы обрабатываем очень быстро, мы там только флаги устанавливаем

 

 

Сгенерируем проект, откроем его в Cube IDE и посмотрим инициализацию нашего нулевого канала, которую нам сгенерировал Cube MX. Нам интересны изменения по сравнению с серией F1, а также с потоком DMA, работающим с шиной SPI, к которой подключен наш дисплей.

Наш новый нулевой поток инициализируется в функции MX_DMA_Init, в которой сначала включается тактирование DMA2, потом также выбирается канал, как он выбирался и в случае с потоком Stream4.

 

 

Далее с помощью вызова функции LL_DMA_SetDataTransferDirection произойдёт установка бита 1 в битовом поле DIR того же регистра, посредством чего включится направление передачи данных из памяти в память.

Затем устанавливается самый низкий приоритет с помощью вызова функции LL_DMA_SetStreamPriorityLevel, засчёт чего сбрасываются все биты поля PFCTRL.

При помощи вызова функции LL_DMA_SetMode устанавливается режим NORMAL сбросом всех битов CIRC и PFCTRL.

С помощью вызова двух других функций LL_DMA_SetPeriphIncMode и LL_DMA_SetMemoryIncMode включаются биты PINC и MINC, засчёт чего настраивается режим адресации и источника и приёмника.

При помощи функции LL_DMA_SetPeriphSize мы устанавливаем размер элемента буфера в 16 бит. Тем самым устанавливается нулевой бит поля PSIZE.

С полем MSIZE та же ситуация. Устанавливается бит 0 засчёт вызова функции LL_DMA_SetMemorySize.

Далее при помощи вызова функции LL_DMA_EnableFifoMode устанавливается бит DMDIS регистра FCR. Тем самым включается режим использования FIFO и отключается режим Direct.

Посредством вызова функции LL_DMA_SetFIFOThreshold настраивается использование половины буфера FIFO с помощью установки бита 0 поля FTH.

Далее устанавливается одиночный (не пакетный) режим передачи через буфер FIFO для приёмника данных посредством вызова функции LL_DMA_SetMemoryBurstxfer. Засчёт этого сбрасываются все биты поля MBURST регистра CR.

Засчёт вызова следующей функции LL_DMA_SetPeriphBurstxfer происходит то же самое с битами PBRUST, что действует уже на адрес источника.

Затем устанавливаются группы приоритетов и сами приоритеты глобальных прерываний от потоков DMA. Но это тема отдельного урока.

Вот и вся инициализация. Дальше дело за нами.

Добавим глобальные буферы для источника и приёмника и пользовательский флаг

 

 

Из бесконечного цикла функции main() удалим весь пользовательский код.

 

 

В данной функции также удалим из объявления локальную переменную j

 

uint16_t i,j;

 

Добавим также символьный массив для строки, которая будет затем выводиться на экран дисплея

 

 

Останавливаем поток DMA

 

 

Теперь нам надо инициализировать локальные прерывания.

Здесь, в принципе всё также как и с потоком 4, только вместо него у нас поток 0.

Сбросим флаги прерываний по окончанию передачи и по ошибке

 

 

Зададим количество передаваемых элементов

 

 

Зададим адреса источника и приёмника, указав адреса наших буферов

 

 

Разрешим прерывания по окончанию передачи и по ошибке

 

 

Пока канал не стартуем, у нас ещё буфер не готов.

Добавим пользовательский обработчик прерывания по окончанию передачи, в котором сбросим соответствующий флаг прерывания и установим свой пользовательский

 

 

На данную функцию прототип добавим в файле stm32f4xx_it.c

 

 

Также среагируем на событие в обработчике прерывания от канала DMA2_Stream0_IRQHandler

 

 

Если у нас установился флаг окончания передачи, то мы вызовем свой пользовательский обработчик, а если флаг ошибки, то просто его сбросим.

Вернёмся в функцию main() файла main.c и изменим ориентацию экрана, чтобы он стал горизонтальным, а также установим цвет, фон и размер шрифта

 

 

Заполним буфер источника декрементирующимися значениями от 1024 до 1

 

 

Запустим поток DMA и выведем на дисплей значения элементов приёмного буфера

 

 

Соберём код, прошьём контроллер и посмотрим результат передачи

 

 

 

 

Данные успешно передались через поток DMA.

Итак, в данном уроке мы ещё глубже познакомились с аппаратной реализацией периферии DMA в контроллере STM32F4, а также на практике подтвердили свои знания, воспользовавшись при этом функционалом библиотеки LL.

Всем спасибо за внимание!

 

 

Предыдущий урок Программирование МК STM32 Следующий урок

 

Исходный код

 

 

Отладочную плату можно приобрести здесь STM32F429I-DISCO

 

 

Смотреть ВИДЕОУРОК (нажмите на картинку)

 

STM LL. STM32F4. DMA. MEM2MEM

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

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

*