STM32 Часть 10–Контроллер ПДП + Таймер 15 в режиме ШИМ
На данный момент приостановились мои работы с STM32, так как пока приоритет у STM8L, но по просьбе пользователя LeftRadio, сегодня расскажу о контроллере прямого доступа к памяти (более привычно DMA) и в качестве примера рассмотрим работу контроллера ПДП с таймером 15 в режиме ШИМ.
Попутно приглашаю всех принять участие в викторинах проводимых терраэлетроникой, мне удалось выиграть с четвертого раза :) :
Контроллер прямого доступа к памяти (ПДП)
Особенности:
ul> <li>семь независимых каналов <li>аппаратный приоритет для каналов <li>программный четырех уровневый приоритет для каждого канала <li>возможность цикличной работы <li>поддержка пересылки из памяти в память <li>число данных для передачи от 1 до 65536 <li>и т. д. </li></ul>
Функциональная схема:
Наибольший интерес представляют две таблицы. Первая таблица описывает все возможные форматы передачи между источником и приемником:
Вторая описывает соответствие сигналов периферийных модулей и каналов ПДП:
Как видим не так уж и гибко можно настраивать передачу данных (в LPC1768 более гибкий контроллер ПДП), но и этого достаточно при умелом использовании.
Работать с контроллером очень просто. Я да же не поверил что все работает как нужно когда описал и прошил :)
Согласно документации основные действия при конфигурировании любого канала:
- задать адрес приемника данных
- задать адрес источника данных
- указать количество данных для пересылки
- задать приоритет
- задать режим работы
- разрешить работу</ol> Мне кажется не плохо бы указывать первым пунктом разрешение работы модуля.
Как видим все очень просто.
Рассмотрим в качестве примера работу контроллера ПДП совместно с таймером 15.
Пример
И так цель: формировать произвольный ШИМ сигнал.
Таймер 15 может работать только в режиме “PWM edge-aligned mode” по “нашему” ОШИМ (односторонний ШИМ), т.е. изменение ширины импульса происходит только в одну сторону, а не от центра импульса как при обычном ШИМ.
Период (частота) определяется значением регистра автоперезагрузки TIMx_ARR (напомню этот регистр определяет значение при котором счетчик обнуляется) длительность импульса определяется значением в регистре TIMx_CCRx.
Имеется возможность настраивать полярность ШИМ сигнала и ещё много чего (см. доку).
Кратенько работу аналогичного таймера я уже описывал, поэтому не долго думаю и переношу код инициализации (с дополнениями):
void mcu_tim15_init(void)
{
// разрешаем татирование модуля
RCC->APB2ENR |= RCC_APB2ENR_TIM15EN;
// устанавливаем предделитель
TIM15->PSC = 10 - 1;
// задаем период ШИМ
TIM15->ARR = 255;
// начальную длительность импульса
TIM15->CCR1 = 1;
// задаем режим работы ОШИМ
TIM15->CCMR1 = TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1PE;
// разрешаем выходной сигнал
TIM15->CCER = TIM_CCER_CC1E;
TIM15->BDTR = TIM_BDTR_MOE;
// разрешаем запросы к ПДП
TIM15->DIER = TIM_DIER_CC1DE;
// разрешаем работу и автоперезагрузку
TIM15->CR1 = TIM_CR1_CEN | TIM_CR1_ARPE;
}
Примечание: обычно я так сильно не комментирую код, но по просьбам трудящихся...
По умолчанию выходной сигнал будет подключен к линии ввода-вывода CH1/PA2, но можно сделать ремап на CH1/PB14.
Настроим линию ввода-вывода:
#define TIM15_PWM1 A, 2, HIGH, ALTERNATE_OUTPUT_PUSH_PULL, SPEED_50MHZ
PIN_CONFIGURATION(TIM15_PWM1);
Ну вот осталось настроить ПДП:
const uint8_t dma_buffer[] = { 64, 128, 20, 128, 64, 20 };
//------------------------------------------------------------------------------
void mcu_dma_channel5_init(void)
{
// разрешаем тактирование ДМА1
if ((RCC->AHBENR & RCC_AHBENR_DMA1EN) != RCC_AHBENR_DMA1EN)
{
RCC->AHBENR |= RCC_AHBENR_DMA1EN;
}
// зазадем адрес приемника данных
DMA1_Channel5->CPAR = (uint32_t) & TIM15->CCR1;
// задаем адрес источника данных
DMA1_Channel5->CMAR = (uint32_t) & dma_buffer[0];
// указываем число пересылаемых данных
DMA1_Channel5->CNDTR = ARRAY_LENGHT(dma_buffer);
// разрешаем работу + режим
DMA1_Channel5->CCR = DMA_CCR1_MINC | DMA_CCR1_CIRC | DMA_CCR1_DIR
| DMA_CCR1_EN | DMA_CCR1_PSIZE_0;
}
comments powered by Disqus