Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Прерывания и таймеры в STM32
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
alex_avr2
Здравствуйте коллеги.
Мучаюсь уже который день с таймером в стм32 (контроллер стм32ф303, таймеры аналогичны тем что в ф4).

Используется таймер общего назначения 4.
Задача - вызывать прерывание по переполнению и по совпадению, в прерывании определять какое из событий произошло и принимать соответствующие действия.
Вот код настройки таймера:

Код
void pwm_init(void){
  
  RCC->APB1ENR |= RCC_APB1ENR_TIM4EN;
  
  TIM4->PSC = 0;
  TIM4->ARR = 1000;
  
  TIM4->CCR3 = 800;
  
//  TIM4->DIER = TIM_DIER_CC3IE;
  TIM4->DIER = TIM_DIER_UIE;  

  NVIC_EnableIRQ(TIM4_IRQn);
  NVIC_SetPriority (TIM4_IRQn, 5);

  TIM4->CR1 |= TIM_CR1_CEN;

}

Таймер считает до 1000. В третьем канале записано 800.

Включено тольеко прерывание по переполнению.

Вот обработчик:
Код
void TIM4_IRQHandler(void){

  if(TIM4->SR & TIM_SR_UIF){
    TIM4->SR = ~TIM_SR_UIF;  
    GPIOE->ODR |= GPIO_ODR_12;
    GPIOE->ODR &= ~GPIO_ODR_12;
  }  

  if(TIM4->SR & TIM_SR_CC3IF){
    TIM4->SR = ~TIM_SR_CC3IF;  
    GPIOE->ODR |= GPIO_ODR_10;
    GPIOE->ODR &= ~GPIO_ODR_10;
  }  
  
  GPIOE->ODR |=  GPIO_ODR_15;
  GPIOE->ODR &= ~GPIO_ODR_15;
  
}


Проверяем флаг прерывания, сбрасываем этот флаг путем записи в него нуля, и мигаем светодиодиком. Так для прерывания по переполнению и по совпадению третьего канала. В конце мигаем еще одинм светодиодиком, чтобы видет что обработчик вообще вызвался.

Но в итоге, несмотря на то что разрешено только прерывание по переполнению - выполняются оба обработчика, все светодиоды мигают.
Если разрешить только прерывание по совпадению, то ничего не меняется. Если оба одновременно - то опять ничего не меняются. Оба if выполняются друг за другом через одинаковые промежутки времени. Дебаг показывает постоянно единички во флагах CC4IF, CC3IF, CC2IF, CC1IF, UIF.

Что я делаю не так?
Хочу чтобы при переполнении мигал один светодиодик, а при совпадении - другой.

nx6310
У вас канал захвата сравнения не настроен вроде.
Golikov A.
разрешение или запрет прерывания не влияет на появление флага. Это виляет только на появление вызова в след за появлением флага. Так что поскольку происходят оба события вот и появляются оба флага. И надо уточнить, может так оказаться что для сброса флага не 0 надо писать и не в этот регистр.....
alex_avr2
Цитата
У вас канал захвата сравнения не настроен вроде.

Для выполнения прерывания достаточно лишь прописать значение в регистр сравнения, т.к. нулевые значения в регистре настройки по умолчанию настраивают канал в режим output.

Цитата(Golikov A. @ Feb 15 2013, 07:15) *
разрешение или запрет прерывания не влияет на появление флага. Это виляет только на появление вызова в след за появлением флага. Так что поскольку происходят оба события вот и появляются оба флага.

Спасибо, это опхоже то, что я хотел услышать. Не очень удобно получается, хотя может быть так и правильние.

Цитата(Golikov A. @ Feb 15 2013, 07:15) *
И надо уточнить, может так оказаться что для сброса флага не 0 надо писать и не в этот регистр.....

Да, это точно.

В процессе изучения проблемы увидел, что очень у многих сброс флагов делается неправильно, через " &= ~". Тут есть тонкость - в референсе в каждом регистре под битом пишется его тип. В случае с флагами таймера тип обозначен как "rc_w0". В начале референса есть расшифровка всех обозначений, где срези прочего написано:
Цитата
read/clear (rc_w0) Software can read as well as clear this bit by writing 0. Writing ‘1’ has no effect on
the bit value.
SSerge
Чтобы реагировать только на флаги от которых разрешены прерывания можно использовать содержимое DIER как маску.
или просто вручную (константой) маскировать флаги у которых прерывания не разрешены.
Код
void TIM4_IRQHandler(void)
{
  uint32_t tmp = TIM4->SR;
  tmp &= TIM4->DIER;
  TIM4->SR = 0;
  if( tmp & TIM_SR_UIF )    ...
  if( tmp & TIM_SR_CC1IF )  ...
  if( tmp & TIM_SR_CC2IF )  ...

или сразу uint32_t tmp = TIM4->SR & TIM4->DIER;
но тогда может выдать предупреждение
Warning[Pa082]: undefined behavior: the order of volatile accesses is undefined
alex_avr2
Цитата(SSerge @ Feb 15 2013, 15:08) *
Чтобы реагировать только на флаги от которых разрешены прерывания можно использовать содержимое DIER как маску.
или просто вручную (константой) маскировать флаги у которых прерывания не разрешены.
Код
void TIM4_IRQHandler(void)
{
  uint32_t tmp = TIM4->SR;
  tmp &= TIM4->DIER;
  TIM4->SR = 0;
  if( tmp & TIM_SR_UIF )    ...
  if( tmp & TIM_SR_CC1IF )  ...
  if( tmp & TIM_SR_CC2IF )  ...

или сразу uint32_t tmp = TIM4->SR & TIM4->DIER;
но тогда может выдать предупреждение
Warning[Pa082]: undefined behavior: the order of volatile accesses is undefined

Ага, спасибо, так и понял. В моем случае конфигурация прерываний не меняется, всегда нужны только два, так что просто ненужные флаги не проверяю и не очищаю.
Но принцип понятен.
Golikov A.
флаги должны появляться, это нужно для обработки по полингу каких либо событий. Вы же определяете на какие флаги надо реагировать вызовом функции, и внутри просто проверяете какое событие произошло по наличию флага... Все вроде логично...


ну да для регистров не реагирующих на 1, можно делать не &=(~MASK), а сразу =(~MASK), но я думаю тут уже играет роль привычка, пару лишних тактов обычно не критично, зато несколько больше переносимость кодов, да и при совместной разработке, другой программист взяв код не будет радостно кричать что нашел ошибку, и ему не понадобиться лезть в мануал проверять так ли тут все! Иногда это важнее 2 тактов...
alex_avr2
Цитата(Golikov A. @ Feb 15 2013, 19:09) *
ну да для регистров не реагирующих на 1, можно делать не &=(~MASK), а сразу =(~MASK), но я думаю тут уже играет роль привычка, пару лишних тактов обычно не критично, зато несколько больше переносимость кодов, да и при совместной разработке, другой программист взяв код не будет радостно кричать что нашел ошибку, и ему не понадобиться лезть в мануал проверять так ли тут все! Иногда это важнее 2 тактов...

Только если во время этого самого "&=(~MASK)" выставится еще какой-то флаг, то он может превратиться в тыкву и мы о нем не узнаем. Не зря разработчики СТ сделали именно такую очистку флагов, одной записью, атомарно.
Golikov A.
ваша правда! что-то я не подумал сразу о таком исходе...
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.