реклама на сайте
подробности

 
 
> STM32F051 Таймер и прерывания
Влад Р.
сообщение Jan 22 2014, 20:50
Сообщение #1


Частый гость
**

Группа: Свой
Сообщений: 87
Регистрация: 9-12-10
Пользователь №: 61 511



Всем привет!

Пишу под STM32F051.
На контакте PC1 при помощи таймера общего назначения TIM16 формирую сигнал, где положительный полупериод имеет фиксированную длительность 1 мс, а а длительность отрицательного возрастает в арифметической прогрессии от 3 мс и до... большого числа, не столь важно. Отрицательный полупериод формируется первым, переключение уровня осуществляется в обработчике прерывания таймера, которое должно вызываться !ТОЛЬКО! по переполнению таймера (с установкой флага UIF в регистре SR). Обратное переключение осуществляется уже в основной функции программы без вызова прерывания.

Однако, прерывание вызывается еще в ряде случаев. В обработчике видно. что флаг UIF в регистре SR сброшен. Иногда в обработчике отладчик показывает установленный флаг CC1IF в регистре SR. Если вход в обработчик произошел не из-за переполнения таймера, то необходимо обнулять весь регистр SR, иначе происходит следующее: корректно формируется отрицательный полупериод только первый раз, в последующих периодах длительность отрицательного полупериода составляет порядка 2 мкс.
Это может происходить по причине неустановки правильного конечного значения счета или же еще по какой-то неизвестной мне причине.

Если в обработчике прерывания обработать указанное ниже условие, то программа отработает корректно.

Код
void TIM16_IRQHandler(void)
{
  // Что вызывает прерывние, если в регистре DIER установлен только бит TIM_DIER_UIE?
  if (!(TIM16->SR & TIM_SR_UIF)) {                              // То самое "магическое" условие
    TIM16->SR = 0;
    return;
  }
  NVIC_DisableIRQ(TIM16_IRQn);                                  // Запретить обработку прерываний от таймера TIM16
  GPIOC->ODR ^= GPIO_ODR_1;                                     // Инвертировать значение на порту PC1 - установить высокий уровень
  TIM16->SR &= ~TIM_SR_UIF;                                     // Сбросить флаг прерывания
}


Из-за чего происходят сбои в случае удаления этого условие и по какой причине может вызываться прерывание?

CODE
#include "stm32f0xx.h"

void main(void)
{
uint16_t delay = 2999;

RCC->AHBENR |= RCC_AHBENR_GPIOCEN; // Тактируем порт в/в C
RCC->APB2ENR |= RCC_APB2ENR_TIM16EN; // Тактируем таймер TIM16

// Настраиваем пин выхода
GPIOC->MODER &= ~GPIO_MODER_MODER1; // Срасываем настройки режима работы пина
GPIOC->MODER |= GPIO_MODER_MODER1_0; // Режим выхода
GPIOC->OTYPER &= ~GPIO_OTYPER_OT_1; // Режим двухтактного выхода
GPIOC->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR1_0; // Выходная частота - 10 МГц
GPIOC->PUPDR &= ~GPIO_PUPDR_PUPDR1; // Отключаем подтягивающие резисторы пинов
GPIOC->ODR &= ~GPIO_ODR_1; // Установить низкий уровень

TIM16->PSC = 47; // Настраиваем таймер TIM16 на период 1 мкс
TIM16->EGR = TIM_EGR_UG; // Сгенерировать событие для загрузки нового значения предделителя
TIM16->SR &= ~TIM_SR_UIF; // Сбросить флаг прерывания
TIM16->CR1 = TIM_CR1_OPM; // Установить режим "одного импульса"
TIM16->DIER = TIM_DIER_UIE; // Включить прерывание по переполнению счетчика таймера TIM16
NVIC_SetPriority(TIM16_IRQn, 1);

while (1) {
TIM16->ARR = delay; // Установить начальную длительность отрицательного полупериода - 3 мкс
delay += 100; // Увеличивать каждый отрицательный полупериод импульса на 0,1 мкс
TIM16->CR1 |= TIM_CR1_CEN; // Включить таймер TIM16
NVIC_EnableIRQ(TIM16_IRQn); // Разрешить обработку прерываний от таймера TIM16
while (NVIC->ISER[0] & (1 << TIM16_IRQn)); // Ожидаем отключения прерываний от таймера TIM16 (после выхода из обработчика)
TIM16->ARR = 999; // Установить постоянную длительность положительного полупериода - 1 мкс
TIM16->CR1 |= TIM_CR1_CEN; // Включить таймер TIM16
while (!(TIM16->SR & TIM_SR_UIF)); // Дождаться конца задержки
TIM16->SR &= ~TIM_SR_UIF; // Сбросить флаг прерывания
GPIOC->ODR ^= GPIO_ODR_1; // Инвертировать значение на порту PC1 - установить низкий уровень
}
}

void TIM16_IRQHandler(void)
{
// Что вызывает прерывние, если в регистре DIER установлен только бит TIM_DIER_UIE?
if (!(TIM16->SR & TIM_SR_UIF)) { // То самое "магическое" условие
TIM16->SR = 0;
return;
}
NVIC_DisableIRQ(TIM16_IRQn); // Запретить обработку прерываний от таймера TIM16
GPIOC->ODR ^= GPIO_ODR_1; // Инвертировать значение на порту PC1 - установить высокий уровень
TIM16->SR &= ~TIM_SR_UIF; // Сбросить флаг прерывания
}


Сообщение отредактировал Влад Р. - Jan 23 2014, 06:47
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов (1 - 3)
Golikov A.
сообщение Jan 23 2014, 05:26
Сообщение #2


Гуру
******

Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454



где то в соседней теме кто-то бился с таймерам. Там было сказано что для правильной работы машины прерываний надо не только сбрасывать, но еще и читать регистр статуса прерываний.
убирая условие вы убираете чтение из регистра, может в этом отгадка? А прерывание можно вызывать и руками....


кстати

TIM16->SR &= ~TIM_SR_UIF; // Сбросить флаг прерывания
так сбрасывать флаг нельзя, надо
TIM16->SR = ~TIM_SR_UIF; // Сбросить флаг прерывания
Go to the top of the page
 
+Quote Post
Влад Р.
сообщение Jan 23 2014, 06:41
Сообщение #3


Частый гость
**

Группа: Свой
Сообщений: 87
Регистрация: 9-12-10
Пользователь №: 61 511



Цитата(Golikov A. @ Jan 23 2014, 07:26) *
где то в соседней теме кто-то бился с таймерам. Там было сказано что для правильной работы машины прерываний надо не только сбрасывать, но еще и читать регистр статуса прерываний.
убирая условие вы убираете чтение из регистра, может в этом отгадка? А прерывание можно вызывать и руками....

Спасибо за участие в обсуждении, а ссылочкой на тему не поделитесь? Попробовал просто читать регистр SR в обработчике, но это результата не дало - задержка не выдерживается, отрицательный уровень держится около 2 мкс. Странно то, почему это условие вообще выполняется при входе в обработчик, ведь прерывание должно вызываться только при установленном флаге UIF. wacko.gif

Цитата(Golikov A. @ Jan 23 2014, 07:26) *
TIM16->SR &= ~TIM_SR_UIF; // Сбросить флаг прерывания
так сбрасывать флаг нельзя, надо
TIM16->SR = ~TIM_SR_UIF; // Сбросить флаг прерывания

Почему так нельзя сбрасывать флаг? Всегда так сбрасываю биты в регистрах.

UPD: одназначно установил, что вход в прерывание осуществляется либо по взведению бита UIF (как и задумывалось), либо бита CC1F. Почему взводится бит CC1F? И самое главное почему из-за этого вызывается прерывание??? blink.gif

Сообщение отредактировал Влад Р. - Jan 23 2014, 08:07
Go to the top of the page
 
+Quote Post
Golikov A.
сообщение Jan 23 2014, 08:01
Сообщение #4


Гуру
******

Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454



вот где то тут
http://electronix.ru/forum/index.php?showt...118023&st=0


почему так нельзя снимать флаг:
недавно где то уже писал, но куда то все уехало...

биты в обычных регистрах так можно сбрасывать, а это регистр статуса прерывания биты в нем появляются сами собой.

REG &= (~flag) => REG = REG & (~flag);
последовательно это выглядит так
пусть рег и флаг 8 бит
REG = 0x11
flag = 0x01
хотим сбросить 1 флаг

проц берет значение REG = 0х11
потом берет ~flag == 0хFE
потом считает & == (0x11 & 0xFE) == 0x10
и в конце в REG = пишет 0x10 и флаг как бы сброшен.

Но за время пути в регистре мог появится еще один флаг и он стал 0x31
а вы в него пишете 0x10, и сбросите не только 0х01, но и 0х20

именно поэтому регистры статуса прерывания делают нечувствительными к записи в них 1, и реагируют они только на 0 (кстати иногда наоборот, флаг 1 сбрасывается).


в нашем случае регистр 0х11, вы сразу пихаете в него флаг ~0х01 == 0xFE, и каким бы ни был регистр и как бы он не поменялся, вы убираете только младший бит. Флаги прерывания могут появится в любой момент, даже если прерывание глобально запрещено, флаг появится.
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 27th July 2025 - 19:07
Рейтинг@Mail.ru


Страница сгенерированна за 0.01367 секунд с 7
ELECTRONIX ©2004-2016