Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: STM32 Запуск DMA по внешнему событию без EXTI
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Влад Р.
Здравствуйте!
Собственно, возможно ли в STM32F0 запустить передачу посредством DMA по фронту/спаду сигнала на одном из выходов МК?
Если да, то как в таком случае необходимо сконфигурировать МК?
EXTI не годится. Как оценить время реакции (время между фронтом внешнего сигнала и началом передачи контроллером DMA)?
Посредством DMA будут передаваться данные с одного порта в/в на другой.
DeNi
По Input Capture от любого таймера, которые могут быть подключены к DMA.
Влад Р.
Цитата(DeNi @ Jul 20 2016, 15:40) *
По Input Capture от любого таймера, которые могут быть подключены к DMA.

Можете показать пример кода?
Кстати, а вообще допустимо ли с одного в/в в другой пихать или обязательно нужен промежуточный буфер?
DeNi
Код
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_BothEdge;
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStructure.TIM_ICFilter = 0;
TIM_ICInit(TIM3, &TIM_ICInitStructure);
    
TIM_DMACmd(TIM3, TIM_DMA_CC1, ENABLE);


Для таймера включить клок, сам таймер можно не запускать. Выбрать и настроить канал DMA, который работает от TIM3_CH1.

Для F0 написано что peripheral-to-peripheral допустим, а к примеру для F4 только периферия и память.
Также надо смотреть матрицу шин, может ли DMA обращаться к нужной периферии. К примеру в F4 только DMA2
имеет доступ к AHB1 и AHB2, а так как GPIO там находятся на AHB1, то в порт GPIO может писать только DMA2.
В F0 на первый взгляд должно всё работать, сам не проверял.
Влад Р.
А как в данном случае DMA понимает, что транзакцию нужно запускать по фронту/спаду на заданном канале а не по какому-либо другому событию таймера?
DeNi
Фронт/спад зависит от того как настроили вход таймера в TIM_ICInitStructure.TIM_ICPolarity, можно по фронту или по спаду, или сразу по обоим фронтам.
Также можно включить фильтр на входе таймера, чтоб помехи не вызывали ложные срабатывания.

TIM_DMA_CC1 указывает что события к DMA только от первого канала таймера, и первый канал настроили только на Input capture. Также канал DMA жестко связан
с определенным запросом от периферийного устройства, для TIM3_CH1 это 4 канал DMA, см. таблицу DMA в DS.
Влад Р.
Я имел в виду немного другое. Как задается задается тип события, по которому возникает запрос DMA? Т.е как задается, что нужно реагировать на изменение уровня на канале, а не скажем на Update Event таймера?
То, что разные каналы разных таймеров закреплены за разными каналами DMA в курсе. В любом случае спасибо! rolleyes.gif
DeNi
Для update будет TIM_DMACmd(TIM3, TIM_DMA_Update, ENABLE);
Для канала 1 и Update TIM_DMACmd(TIM3, TIM_DMA_CC1 | TIM_DMA_Update, ENABLE);
Влад Р.
Написал тестовую программку под STM32F0Discovery, чтобы проверить метод. Возможно кому-то поможет с настройкой.
Пины платы PA8 и PA9, PA10 и PA11 попарно соединены джамперами. На пинах PA8 и PA10 ловлю фронты таймером TIM1 (1 и 3 каналы таймера соответственно). Пины PA10 и PA11 вручную устанавливаю/сбрасываю.
По захвату на каждом из каналов DMA копирует младший или старший байт порта GPIOB (в зависимости от "сработавшего" канала) в старший байт порта GPIOC. В младшем и старшем байтах порта GPIOB записаны такие значения, при копировании которых загорается синий или зеленый светодиоды.
CODE
#include "stm32f0xx.h"
#include <stdint.h>

int main(void)
{
//uint8_t port = 0x01;

RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN | RCC_AHBENR_GPIOCEN | RCC_AHBENR_DMA1EN;
RCC->APB2ENR |= RCC_APB2ENR_TIM1EN;

GPIOC->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR8 | GPIO_OSPEEDER_OSPEEDR9;
GPIOC->OTYPER &= ~(GPIO_OTYPER_OT_8 | GPIO_OTYPER_OT_9);
GPIOC->PUPDR &= ~(GPIO_PUPDR_PUPDR8 | GPIO_PUPDR_PUPDR9);
GPIOC->MODER |= GPIO_MODER_MODER8_0 | GPIO_MODER_MODER9_0;

GPIOA->AFR[1] |= (2 << ((8 - 8) << 2)) | (2 << ((10 - 8) << 2));
GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR8 | GPIO_OSPEEDER_OSPEEDR9 | GPIO_OSPEEDER_OSPEEDR10 | GPIO_OSPEEDER_OSPEEDR11;
GPIOA->OTYPER &= ~(GPIO_OTYPER_OT_8 | GPIO_OTYPER_OT_9 | GPIO_OTYPER_OT_10 | GPIO_OTYPER_OT_11);
GPIOA->PUPDR &= ~(GPIO_PUPDR_PUPDR8 | GPIO_PUPDR_PUPDR9 | GPIO_PUPDR_PUPDR10 | GPIO_PUPDR_PUPDR11);
GPIOA->MODER |= GPIO_MODER_MODER8_1 | GPIO_MODER_MODER9_0 | GPIO_MODER_MODER10_1 | GPIO_MODER_MODER11_0;

DMA1_Channel2->CNDTR = 1;
DMA1_Channel2->CPAR = (uint32_t)&GPIOC->ODR + 1;
DMA1_Channel2->CMAR = (uint32_t)&GPIOB->ODR;
DMA1_Channel2->CCR |= DMA_CCR_EN | DMA_CCR_DIR | DMA_CCR_CIRC | DMA_CCR_PL ; // из CMAR в CPAR, циклическая передача, размер данных - 8 бит

DMA1_Channel5->CNDTR = 1;
DMA1_Channel5->CPAR = (uint32_t)&GPIOC->ODR + 1;
DMA1_Channel5->CMAR = (uint32_t)&GPIOB->ODR + 1;
DMA1_Channel5->CCR |= DMA_CCR_EN | DMA_CCR_DIR | DMA_CCR_CIRC | DMA_CCR_PL; // из CMAR в CPAR, циклическая передача, размер данных - 8 бит

TIM1->CCMR1 |= TIM_CCMR1_CC1S_0; // Настраиваем канал 1 на вход без ремапа, фильтр отключен
TIM1->CCMR2 |= TIM_CCMR2_CC3S_0; // Настраиваем канал 3 на вход без ремапа, фильтр отключен
TIM1->CCER |= TIM_CCER_CC1E | TIM_CCER_CC3E; // Настраиваем каналы 1 и 3 на захват фронта и включаем их
TIM1->DIER |= TIM_DIER_CC1DE | TIM_DIER_CC3DE; // Захваты по каналам 1 и 3 сгенерируют запросы DMA

GPIOB->ODR = 0x0102;

for(;;) {
GPIOA->BSRR = GPIO_BSRR_BR_11 | GPIO_BSRR_BS_9;
for (int i = 0; i < 500; i++)
__NOP();
GPIOA->BSRR = GPIO_BSRR_BR_9 | GPIO_BSRR_BS_11;
for (int i = 0; i < 500; i++)
__NOP();
}
}
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.