Урок 176. CMSIS. STM32F1. DMA. MEM2MEM

 

 

 

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

Подобную процедуру мы с вами уже проводили в уроке 155 и уроке 156. Только в данных уроках мы использовали для этого библиотеки HAL и LL. А в данном уроке ту же самую процедуру мы проделаем с применением уже возможностей другой библиотеки — CMSIS.

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

Прежде чем приступим непосредственно к проекту, скажу ещё, что схему мы оставим без изменений и возьмём схему прошлого урока, например, для устройства SLAVE, хотя вполне можно взять и для MASTER, так как они абсолютно одинаковые. Логический анализатор сегодня не используем

 

 

Проект сделан из будет из проекта прошлого урока для ведущего устройства с именем CMSIS_SPI_MASTER и назван был CMSIS_DMA_MEM2MEM.

Откроем проект в Keil и из файла main.c удалим пока вот эти глобальные макросы, касающиеся модуля SPI1

 

#define CS1_RESET() SET_BIT(GPIOA->ODR,GPIO_ODR_ODR4)

#define CS1_SET() CLEAR_BIT(GPIOA->ODR,GPIO_ODR_ODR4)

#define SPI1_ENABLE() SET_BIT(SPI1->CR1, SPI_CR1_SPE);

 

Функцию SPI1_Init также удалим вместе с телом.

В функции main() удалим вот эти строки

 

SPI1_Init();

CS1_RESET();

SPI1_ENABLE();

Number_7219(87654321);

delay_ms(2000);

 

Также удалим всё из бесконечного цикла и удалим объявление локальной переменной r

 

uint16_t i, r;

 

Выше функции SPI2_Init добавим функцию инициализации периферии DMA1

 

 

Добавим в тело данной функции вот этот код

 

 

Думаю, здесь объяснять особо нечего, так как те же самые действия проводятся и в LL при автогенерации, тем не менее кратко поясню.

Сначала мы настроили направление передачи — из памяти в память посредством включения бита CCR1_MEM2MEM, затем выбрали приоритет, режим DMA, также настроили инкрементирование адреса и источника и приёмника, ширину данных (16 бит) и для приёмника и для источника, а также включили глобальные прерывания от модуля DMA1.

Вызовем данную функцию в main()

 

 

Добавим два буфера, один для передачи в периферию, другой для приёма из неё

 

 

 

В функции main() заполним буфер передачи декрементированными значениями от 1024 до 1

 

 

Далее добавим вот такой код

 

 

То же самое мы делали и когда работали с LL, только сейчас это всё переписано в свете требований CMSIS. Сначала мы отключили канал 1 канал DMA1, затем очистили флаги окончания передачи и ошибки, также занесли в регистр CNDTR1_NDT количество передаваемых данных — у нас будет 1024 полуслова. Затем мы занесли адрес приёмника и источника в соответствующие регистры канала 1, потом включили прерывания по событию окончания передачи пакета данных и по возникновению ошибки, и в конце включили канал, что и является сигналом к началу передачи по шине DMA1.

Добавим глобальную переменную для флага окончания передачи

 

 

В самом низу файла добавим функцию-обработчик прерываний от DMA1

 

 

Думаю, что здесь тоже всё ясно.

Если у нас произошло прерывание, мы попадаем в данную функцию. Если в этот момент взведен флаг полного окончания передачи, то мы его очищаем и устанавливаем наш пользовательский флаг fl, а если прочитался флаг ошибки, то можно предпринять какие-то действия по выявлению данной ошибки, но мы ничего не будем предпринимать, мы лишь вставим здесь инструкцию nop. И если у нас всё же что-то пойдёт не так, то мы сюда поставим точку останова и узнаем то, что мы попали именно сюда, а дальше уж будем разбираться, что у нас за ошибка.

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

 

 

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

 

 

Если немного подождать, то счётчик наш досчитает в обратную сторону до 1.

Итак, на данном занятии мы научились управлять периферией DMA в контроллере STM32F1 в режиме MEM2MEM (передачи из памяти в память), воспользовавшись при этом функционалом библиотеки CMSIS.

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

 

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

 

Исходный код

 

 

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

Программатор недорогой можно купить здесь ST-Link V2

Индикатор светодиодный семиразрядный с драйвером MAX7219

 

 

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

 

STM CMSIS. STM32F1. DMA. MEM2MEM

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

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

*