Для быстрого обмена данными между периферией и памятью без участия ядра активируйте нужный канал через регистр CCR. Укажите направление передачи, размер данных и режим приоритета. Например, для USART1 в режиме приема настройте DMA1_Channel5:
DMA1_Channel5->CCR |= DMA_CCR_DIR; – чтение из периферии.
DMA1_Channel5->CCR |= DMA_CCR_PSIZE_0 | DMA_CCR_MSIZE_0; – размер слова 8 бит.
DMA1_Channel5->CCR |= DMA_CCR_PL_1; – высокий приоритет.
Перед запуском задайте адреса источника и приемника:
DMA1_Channel5->CPAR = (uint32_t)&USART1->DR;
DMA1_Channel5->CMAR = (uint32_t)buffer;
Количество передач указывается в CNDTR. Для 64 байт:
DMA1_Channel5->CNDTR = 64;
Разрешите прерывания по завершению или ошибке через CCR и активируйте канал:
DMA1_Channel5->CCR |= DMA_CCR_TCIE | DMA_CCR_EN;
Обработчик прерывания очищает флаг в ISR и выполняет необходимые действия с данными.
Работа с прямым доступом к памяти в микроконтроллерах ST
Инициализация периферии
Для активации модуля включите тактирование через регистр RCC->AHBENR. Например, для DMA1 на STM32F103 установите бит DMA1EN:
RCC->AHBENR |= RCC_AHBENR_DMA1EN;
Конфигурация канала передачи
Задайте параметры в структуре DMA_Channel_TypeDef:
DMA1_Channel1->CCR =
DMA_CCR_MINC | // Инкремент адреса памяти
DMA_CCR_DIR | // Направление: из памяти в периферию
DMA_CCR_TCIE; // Прерывание по завершении
DMA1_Channel1->CNDTR = 128; // Количество передаваемых элементов
DMA1_Channel1->CPAR = (uint32_t)&USART1->DR; // Адрес периферии
DMA1_Channel1->CMAR = (uint32_t)buffer; // Адрес буфера
Приоритет устанавливается битами PL[1:0] в регистре CCR. Для максимальной скорости передачи выберите значение 0b11.
Для старта передачи активируйте канал:
DMA1_Channel1->CCR |= DMA_CCR_EN;
Передача информации между памятью и модулями через прямой доступ
Активация канала
Включите нужный канал, установив бит EN в регистре CCRx (DMA_CCR). Например, для канала 1:
DMA1_Channel1->CCR |= DMA_CCR_EN;
Перед этим убедитесь, что остальные параметры (направление, приоритет, размер данных) заданы.
Конфигурация регистров
Укажите адреса источника и приемника в PAR (DMA_CPAR) и MAR (DMA_CMAR). Для отправки из массива в USART:
DMA1_Channel4->CPAR = (uint32_t)&USART1->DR;
DMA1_Channel4->CMAR = (uint32_t)buffer;
Задайте количество элементов в CNDTR (DMA_CNDTR):
DMA1_Channel4->CNDTR = sizeof(buffer);
Выберите режим: циклический (DMA_CCR_CIRC) или однократный. Для непрерывной работы:
DMA1_Channel4->CCR |= DMA_CCR_CIRC;
Разрешите прерывания, если требуется обработка завершения или ошибок. Установите биты TCIF и TEIF в регистре ISR (DMA_ISR), затем активируйте их в CCR (DMA_CCR_TCIE, DMA_CCR_TEIE).
Работа с прерываниями при передаче данных через контроллер
Для обработки событий завершения передачи или ошибок активируйте соответствующие биты в регистре CR канала. Например, для включения прерывания по завершению установите флаг TCIE, а для ошибок – TEIE.
Перед запуском канала убедитесь, что обработчик зарегистрирован в таблице векторов. В Cortex-M это делается через NVIC_EnableIRQ(). Пример для канала 1:
NVIC_SetPriority(DMA1_Channel1_IRQn, 0);
NVIC_EnableIRQ(DMA1_Channel1_IRQn);
В обработчике проверяйте флаги статуса в регистре ISR. Для канала 1 биты TCIF1 (завершение) и TEIF1 (ошибка) очищаются записью 1 в соответствующие позиции IFCR.
Пример кода обработчика:
void DMA1_Channel1_IRQHandler(void) {
if (DMA1->ISR & DMA_ISR_TCIF1) {
// Действия при успешной передаче
DMA1->IFCR |= DMA_IFCR_CTCIF1;
}
if (DMA1->ISR & DMA_ISR_TEIF1) {
// Реакция на ошибку
DMA1->IFCR |= DMA_IFCR_CTEIF1;
}
}
Для минимизации задержек избегайте сложных операций в обработчике. Если требуется обработка данных, используйте флаги и переносите логику в основной цикл.
При работе с кольцевым буфером проверяйте флаг HTIF (половина передачи) для двойной буферизации. Это позволяет обрабатывать данные параллельно с заполнением следующей части буфера.