Взято тут. |
Подивимося, як користуватися цією можливістю на дещо надуманому прикладі -- мигатимемо світлодіодом у перериванні від TIM1, який буде підлеглим для TIM4.
На відміну від зовнішнього тактування, розглянутого раніше, тут використано тактування від внутрішніх тригерів -- ITRx.
На відміну від зовнішнього тактування, розглянутого раніше, тут використано тактування від внутрішніх тригерів -- ITRx.
Як і раніше, почати слід із ініціалізації тактування портів та таймерів:
RCC->APB2ENR |= RCC_APB2ENR_IOPCEN; // Дозволяємо тактування порту C RCC->APB1ENR |= RCC_APB1Periph_TIM4; // Дозволяємо тактування TIM4 RCC->APB2ENR |= RCC_APB2Periph_TIM1; // Дозволяємо тактування TIM1 // PC8 -- blue LED GPIOC->CRH &= ~GPIO_CRH_CNF8; GPIOC->CRH |= GPIO_CRH_MODE8;
Процедура обробки переривання -- така ж, як в попередньому пості:
void TIM1_UP_TIM16_IRQHandler(void) { if( TIM1->SR & TIM_SR_UIF ) // Перевіряємо джерело { TIM1->SR &= ~TIM_SR_UIF; //Очищаємо прапорець переривання GPIOC->ODR^=(GPIO_Pin_8); //Змінюємо стан світлодіода } }
Потім налаштовуємо TIM4:
TIM4->PSC = 0; // Подільник -- 1 (0+1) TIM4->ARR = 24000 ; // На частоті 24МГц, тік -- раз на 1 мс // MMS: Master mode selection --> // 010: Update - The update event is selected as a trigger output (TRGO). TIM4->CR2 &= ~( TIM_CR2_MMS_0 | TIM_CR2_MMS_2 ); TIM4->CR2 |= ( TIM_CR2_MMS_1 );
Новою частиною є налаштування бітів MMS регістра CR2 -- вказується, що за переповнення слід генерувати сигнал тригера для підлеглого таймера -- TRGO.
Таймер буде генерувати тактовий сигнал для підлеглого таймера раз на
мілісекунду -- подільник 1 (нагадаємо, він отримується додаванням 1 до
вмісту PSC), оновлення кожних 24000 тіки, при частоті 24МГц.
Взагалі, варіанти MMS для таймерів STM32F100 і таймерів загального використання STM32F303, наступні:
- 000 -- Reset, біт UG з TIMx_EGR, встановлення котрого примусово створює подію оновлення, служить джерелом TRGO.
- 001 -- Enable, запуск таймера служить сигналом. Використовується для синхронного запуску кількох таймерів.
- 010 -- Update, використаний нами -- оновлення таймера генерує TRGO (не плутати із Reset -- примусовим оновленням!)
- 011 -- Compare Pulse, генерується, коли чергова подія оновлення готується встановити відповідний прапорець переривань, CC1IF (навіть якщо він вже був встановленим).
- 100/101/110/111 -- Compare, сигнал на OC1/2/3/4REF відповідно, служить командою подати TRGO.
Для просунутих таймерів STM32F303, які мають два TRGO, згадані вище біти MMS такі ж, але присутнє ще 4-бітове поле MMS2 -- в TRGO2 є всі режими TRGO1 (мають той же код, що і 3-бітовий вище, із нульовим старшим бітом) та ряд додаткових режимів:Для TIM1 -- підлеглого (slave), конфігурація трохи складніша, але починається звично:
- 1000/1001 -- Compare для додаткових каналів, OC5/6REF
- 1010..1111 -- Compare Pulse, всілякі хитрі комбінації захоплення для 4-6 каналів, див. документацію (типу обох фронтів сигналу 4-го каналу, або зростання 4-го і спад 6-го, і т.д.).
TIM1->PSC = 0; // Подільник -- 1 (0+1) TIM1->ARR = 1000; // Переривання -- раз на 1с TIM1->DIER |= TIM_DIER_UIE; // Дозволяємо переривання
Параметри підібрано так, щоб переривання виникало раз на секунду.
Наступним кроком слід вказати, звідки отримувати тактові імпульси:
// TS[2:0]: Trigger selection, 011: Internal Trigger 3 (ITR3) -- TIM4 TIM1->SMCR &= ~( TIM_SMCR_TS_2 ); TIM1->SMCR |= ( TIM_SMCR_TS_1 | TIM_SMCR_TS_0 );
Щоб зрозуміти код вище, нам знадобиться таблички із документації, із назвою "TIMx internal trigger connection". Для TIM1, єдиного просунутого таймера STM32F100RBT6B, вона зовсім коротенька:
Тобто, TIM4 може бути під'єднаним до ITR3 TIM1.
Нарешті, встановлюємо вже обговорені в попередньому пості біти SMS:
// 111: External Clock Mode 1 - // Rising edges of the selected trigger (TRGI) clock the counter. TIM1->SMCR |= TIM_SMCR_SMS;
Все, можна запускати таймери та насолоджуватися миганням світлодіода:
TIM1->CR1 |= TIM_CR1_CEN; // Дозволити slave-таймеру працювати NVIC_EnableIRQ(TIM1_UP_TIM16_IRQn); // Дозволити відповідне переривання TIM4->CR1 |= TIM_CR1_CEN; // Дозволити master-таймеру працювати
main.c
#include <stm32f10x.h> #ifdef __cplusplus extern "C"{ #endif void TIM1_UP_TIM16_IRQHandler(void) { if( TIM1->SR & TIM_SR_UIF ) // Перевіряємо джерело { TIM1->SR &= ~TIM_SR_UIF; //Очищаємо прапорець переривання GPIOC->ODR^=(GPIO_Pin_8); //Змінюємо стан світлодіода } } #ifdef __cplusplus } #endif int main(void) { RCC->APB2ENR |= RCC_APB2ENR_IOPCEN; // Дозволяємо тактування порту C із // світлодіодами плати STM32VLDiscovery // PC8 -- blue, PC9 -- green // TIM1 та TIM4 використовуються в пості "Таймери STM32 -- внутрішні тригери/CMSIS" RCC->APB1ENR |= RCC_APB1Periph_TIM4; // Дозволяємо тактування TIM4 RCC->APB2ENR |= RCC_APB2Periph_TIM1; // Дозволяємо тактування TIM1 GPIOA->CRL &= ~GPIO_CRL_CNF7_0; // 10 -- AF PP (Alternative function -- push-pull) GPIOA->CRL |= GPIO_CRL_CNF7_1; GPIOA->CRL |= GPIO_CRL_MODE7; //Встановити обидва біти MODE для піна 1 -- швидкість 50MHz // PC8 GPIOC->CRH &= ~GPIO_CRH_CNF8; GPIOC->CRH |= GPIO_CRH_MODE8; //------------------------------------------------------------------------- // TIM1 смикатиметься TIM4. TIM4->PSC = 0; // Подільник -- 1 (0+1) TIM4->ARR = 24000 ; // На частоті 24МГц, тік -- раз на 1 мс // MMS: Master mode selection --> // 010: Update - The update event is selected as a trigger output (TRGO). TIM4->CR2 &= ~( TIM_CR2_MMS_0 | TIM_CR2_MMS_2 ); TIM4->CR2 |= ( TIM_CR2_MMS_1 ); TIM1->PSC = 0; // Подільник -- 1 (0+1) TIM1->ARR = 1000; // Переривання -- раз на 1с TIM1->DIER |= TIM_DIER_UIE; // Дозволяємо переривання // TS[2:0]: Trigger selection, 011: Internal Trigger 3 (ITR3) -- TIM4 TIM1->SMCR &= ~( TIM_SMCR_TS_2 ); TIM1->SMCR |= ( TIM_SMCR_TS_1 | TIM_SMCR_TS_0 ); // 111: External Clock Mode 1 - // Rising edges of the selected trigger (TRGI) clock the counter. TIM1->SMCR |= TIM_SMCR_SMS; TIM1->CR1 |= TIM_CR1_CEN; // Дозволити slave-таймеру працювати NVIC_EnableIRQ(TIM1_UP_TIM16_IRQn); // Дозволити відповідне переривання TIM4->CR1 |= TIM_CR1_CEN; // Дозволити master-таймеру працювати //------------------------------------------------------------------------- while(1) { } }
Завершальне слово
Скачати проект із кодом для цього, попереднього ("Таймери STM32 -- зовнішнє тактування/CMSIS") та наступного ("Таймери STM32 -- Автоматична зупинка/CMSIS") постів можна тут.
Код, який стосується лише цього посту, можна знайти у файлі main_internal_trig.c, в директорії app/ проекту (не включений у проект CoIDE -- щоб не конфліктувати із int main(), котрий містить все зразу).
Немає коментарів:
Дописати коментар