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

 
 
 
Reply to this topicStart new topic
> Таймеры в STM32
_Макс
сообщение Apr 21 2010, 11:47
Сообщение #1


Знающий
****

Группа: Участник
Сообщений: 691
Регистрация: 24-05-07
Пользователь №: 27 945



Как правильно настроить таймер, чтобы он генерировал прерывание? Несколько тысяч раз в секунду.
У меня вот такое:
Код
  TIM_TimeBaseInitTypeDef TIM2_BaseInit;
  TIM2_BaseInit.TIM_Period = 65535;
  TIM2_BaseInit.TIM_Prescaler = 0;
  TIM2_BaseInit.TIM_ClockDivision = 0;
  TIM2_BaseInit.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_TimeBaseInit(TIM2, &TIM2_BaseInit);
  TIM_ITConfig(TIM2, TIM_IT_Trigger, ENABLE);
  TIM_Cmd(TIM2, ENABLE);

Прерывание генерируется только один раз после старта, потом не проходит. Менял TIM_IT_Trigger на TIM_IT_Update, не помогло.

Почему нельзя ставить брекпоинт в обработчике прерывания? (IAR 5.41+J-Link). О прерывании узнаю по сигналу от TEventFlag в приемнике.

Спасибо!

Сообщение отредактировал _Макс - Apr 21 2010, 11:53
Go to the top of the page
 
+Quote Post
baralgin
сообщение Apr 21 2010, 11:59
Сообщение #2


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

Группа: Участник
Сообщений: 92
Регистрация: 23-12-08
Из: Кишинёв
Пользователь №: 42 680



В обработчике по выходу нужно нечто типа такого написать:
TIM2->SR = (uint16_t)(~(TIM_IT_Trigger));
Go to the top of the page
 
+Quote Post
_Макс
сообщение Apr 21 2010, 15:25
Сообщение #3


Знающий
****

Группа: Участник
Сообщений: 691
Регистрация: 24-05-07
Пользователь №: 27 945



Цитата(baralgin @ Apr 21 2010, 15:14) *
В обработчике по выходу нужно нечто типа такого написать:
TIM2->SR = (uint16_t)(~(TIM_IT_Trigger));

Что это такое? Можно не на прямую со структурой, а через функции FWLib это делать?

Сделал вот так:
Код
TIM2->SR = TIM_IT_Trigger;

Запустилось без ошибок, но не помогло.
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Apr 21 2010, 15:43
Сообщение #4


фанат дивана
******

Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



В комплекте с FwLib - куча примеров. Посмотрите пример из папочки TIM\TimeBase.


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
_Макс
сообщение Apr 21 2010, 15:57
Сообщение #5


Знающий
****

Группа: Участник
Сообщений: 691
Регистрация: 24-05-07
Пользователь №: 27 945



Цитата(AHTOXA @ Apr 21 2010, 18:58) *
В комплекте с FwLib - куча примеров. Посмотрите пример из папочки TIM\TimeBase.

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

Удивительно, что по адресу 0x4000 0000 вижу в отладчике одни нули, но ведь TIM2 сидит на этом адресе.
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Apr 21 2010, 16:16
Сообщение #6


фанат дивана
******

Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



Цитата(_Макс @ Apr 21 2010, 22:12) *
Смотрю на них, по ним и написал этот код. Но как оказалось у меня не случается ни одного прерывания, я ошибся!


Отлично. Тогда давайте по порядку.
Прерывания инициализировали? (в примере TIM\TimeBase это функция NVIC_Configuration())

Да, и не забыли ли вы создать экземпляр объекта OS::TISRW в обработчике прерывания?

----
Ещё забыл. В *.cpp файлах обработчики прерывания надо объявлять как extern "C"

Таким образом, с учётом scmRTOS будет вот так:
Код
extern "C" OS_INTERRUPT void USART1_IRQHandler()
{
    OS::TISRW ISR;
    Event.SignalISR();
}


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
_Макс
сообщение Apr 21 2010, 16:31
Сообщение #7


Знающий
****

Группа: Участник
Сообщений: 691
Регистрация: 24-05-07
Пользователь №: 27 945



Процесс:
Код
template<> OS_PROCESS void TBlinkProc::Exec()
{
  //NVIC init
  NVIC_InitTypeDef NVIC_TIM2Init;
  NVIC_TIM2Init.NVIC_IRQChannel = TIM2_IRQn;
  NVIC_TIM2Init.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_TIM2Init.NVIC_IRQChannelSubPriority = 1;
  NVIC_TIM2Init.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_TIM2Init);
  //GPIO init
  
  //TIM2 init
  TIM2_BaseInit.TIM_Period = 65535;
  TIM2_BaseInit.TIM_Prescaler = 0;
  TIM2_BaseInit.TIM_ClockDivision = 0;
  TIM2_BaseInit.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_TimeBaseInit(TIM2, &TIM2_BaseInit);
  TIM_PrescalerConfig(TIM2, SystemCoreClock / 12000000, TIM_PSCReloadMode_Immediate);
  TIM_ITConfig(TIM2, TIM_IT_Trigger | TIM_IT_Update, ENABLE);
  TIM_Cmd(TIM2, ENABLE);  
  for(;;)
  {
    //GPIO blink by TEvent
    BlinkByTIM2.Wait(0);
    //Do something
  }
}

Обработчик прерывания:
Код
extern "C" OS_INTERRUPT void TIM2_IRQHandler(void)
{
  OS::TISRW TIM2ISR;
  BlinkByTIM2.SignalISR();
}


Сообщение отредактировал _Макс - Apr 21 2010, 16:34
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Apr 21 2010, 16:48
Сообщение #8


фанат дивана
******

Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



Ага, почти порядок. Не хватает
Код
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);


А в прерывании, соответственно, проверять флаги
TIM_IT_Trigger и TIM_IT_Update (на них настроено прерывание) и сбрасывать их.

Типа:
Код
  if (TIM_GetITStatus(TIM2, TIM_IT_Trigger))
  {
    TIM_ClearITPendingBit(TIM2, TIM_IT_Trigger);
....
  }
  if (TIM_GetITStatus(TIM2, TIM_IT_Update))
  {
    TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
....
  }


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
_Макс
сообщение Apr 21 2010, 17:30
Сообщение #9


Знающий
****

Группа: Участник
Сообщений: 691
Регистрация: 24-05-07
Пользователь №: 27 945



Теперь прерывание такое:
Код
extern "C" OS_INTERRUPT void TIM2_IRQHandler(void)
{
  OS::TISRW TIM2ISR;
  BlinkByTIM2.SignalISR();
  if (TIM_GetITStatus(TIM2, TIM_IT_Trigger))
  {
    TIM_ClearITPendingBit(TIM2, TIM_IT_Trigger);
  }
  if (TIM_GetITStatus(TIM2, TIM_IT_Update))
  {
    TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
  }
}

Процесс такой:
Код
template<> OS_PROCESS void TBlinkProc::Exec()
{
  //NVIC init
  NVIC_InitTypeDef NVIC_TIM2Init;
  NVIC_TIM2Init.NVIC_IRQChannel = TIM2_IRQn;
  NVIC_TIM2Init.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_TIM2Init.NVIC_IRQChannelSubPriority = 1;
  NVIC_TIM2Init.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_TIM2Init);
  //GPIO init
  
  //TIM2 init
  TIM2_BaseInit.TIM_Period = 65535;
  TIM2_BaseInit.TIM_Prescaler = 0;
  TIM2_BaseInit.TIM_ClockDivision = 0;
  TIM2_BaseInit.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_TimeBaseInit(TIM2, &TIM2_BaseInit);
  TIM_PrescalerConfig(TIM2, SystemCoreClock / 12000000, TIM_PSCReloadMode_Immediate);
  TIM_ITConfig(TIM2, TIM_IT_Trigger | TIM_IT_Update, ENABLE);
  TIM_Cmd(TIM2, ENABLE);

  //Clock init
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);  
  for(;;)
  {
    //GPIO blink by TEvent
    BlinkByTIM2.Wait(0);
    //Do something
  }
}

Но всеравно не работает sad.gif
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Apr 21 2010, 18:20
Сообщение #10


фанат дивана
******

Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



Цитата(_Макс @ Apr 21 2010, 23:45) *
Но всеравно не работает sad.gif


Да, засадаsmile.gif
Во-первых, RCC_APB1PeriphClockCmd() надо делать в самом начале.
Во-вторых, похоже надо всё равно включать Output Compare канал.
Посмотрите пример examples\NVIC\IRQ_Channels\, там как раз то, что нужно.


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
_Макс
сообщение Apr 21 2010, 18:29
Сообщение #11


Знающий
****

Группа: Участник
Сообщений: 691
Регистрация: 24-05-07
Пользователь №: 27 945



Ура, заработало! smile.gif
Поставил в начале блока, вот так:
Код
template<> OS_PROCESS void TBlinkProc::Exec()
{
  //Clock init
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);  
  
  //NVIC init
  NVIC_InitTypeDef NVIC_TIM2Init;
  NVIC_TIM2Init.NVIC_IRQChannel = TIM2_IRQn;
  NVIC_TIM2Init.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_TIM2Init.NVIC_IRQChannelSubPriority = 1;
  NVIC_TIM2Init.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_TIM2Init);
  //GPIO init
  
  //TIM2 init
  TIM2_BaseInit.TIM_Period = 65535;
  TIM2_BaseInit.TIM_Prescaler = 0;
  TIM2_BaseInit.TIM_ClockDivision = 0;
  TIM2_BaseInit.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_TimeBaseInit(TIM2, &TIM2_BaseInit);
  TIM_PrescalerConfig(TIM2, SystemCoreClock / 12000000, TIM_PSCReloadMode_Immediate);
  TIM_ITConfig(TIM2, TIM_IT_Trigger | TIM_IT_Update, ENABLE);
  TIM_Cmd(TIM2, ENABLE);

  for(;;)
  {
    //GPIO blink by TEvent
    BlinkByTIM2.Wait(0);
    //Do something
  }
}

И записались регистры управления по адресу от 0x40000000. Включать Output Compare не понадобилось smile.gif И почему об этом нигде не написано) Так просто и столько времени. Вот изучу всю эту кухню, буду мемуары писать)

Появились вопросы:
Что такое RCC и где его найти в даташите?
Для чего нужен TIM_ClearITPendingBit() и задает ли это действие задержку и неточность в работе таймера?
Почему при входе в прерывание в счетчике TIM2.CNT каждый раз другое значение? Он ведь должен генерировать прерывание при обнулении или опустошении. Даже если имеет место задержка в несколько инструкций кода, то значение всеравно должно при каждом останове быть одним и тем же.

Сообщение отредактировал _Макс - Apr 21 2010, 18:34
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Apr 21 2010, 18:59
Сообщение #12


фанат дивана
******

Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



Цитата(_Макс @ Apr 22 2010, 00:44) *
Ура, заработало! smile.gif

Аминьsmile.gif
Цитата
Появились вопросы:
Что такое RCC и где его найти в даташите?

Это reset and clock control, описан в главе 6 Reference manual. Это общее на всё семейство описание, основной документ. Даташит только уточняет конкретные детали.
Цитата
Для чего нужен TIM_ClearITPendingBit() и задает ли это действие задержку и неточность в работе таймера?

Это сброс флага прерывания. На задержку не влияет.
Цитата
Почему при входе в прерывание в счетчике TIM2.CNT каждый раз другое значение?

Это скорее всего из-за отладчика. Попробуйте объявить отдельную переменную (volatile естественно), и при входе в прерывание копировать туда значение счётчика. А прерывание поставьте после этого присваивания.


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
_Макс
сообщение Apr 22 2010, 08:08
Сообщение #13


Знающий
****

Группа: Участник
Сообщений: 691
Регистрация: 24-05-07
Пользователь №: 27 945



Да, доверять отладчику нельзя. Сделал переменную и только после того как объявил её в файле, а не в блоке, значение стало постоянным. При объявлении в блоке значение в большинстве случаев было постоянным, но иногда отличалось. Почему так? Копирование ставил после объявления критической секции.

Хотя всеравно иногда меняется значение, но намного реже.
Go to the top of the page
 
+Quote Post

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

 


RSS Текстовая версия Сейчас: 21st July 2025 - 05:32
Рейтинг@Mail.ru


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