Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Таймеры в STM32
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > ARM, 32bit
_Макс
Как правильно настроить таймер, чтобы он генерировал прерывание? Несколько тысяч раз в секунду.
У меня вот такое:
Код
  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 в приемнике.

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

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

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

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

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

Удивительно, что по адресу 0x4000 0000 вижу в отладчике одни нули, но ведь TIM2 сидит на этом адресе.
AHTOXA
Цитата(_Макс @ 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();
}
_Макс
Процесс:
Код
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();
}
AHTOXA
Ага, почти порядок. Не хватает
Код
  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);
....
  }
_Макс
Теперь прерывание такое:
Код
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
AHTOXA
Цитата(_Макс @ Apr 21 2010, 23:45) *
Но всеравно не работает sad.gif


Да, засадаsmile.gif
Во-первых, RCC_APB1PeriphClockCmd() надо делать в самом начале.
Во-вторых, похоже надо всё равно включать Output Compare канал.
Посмотрите пример examples\NVIC\IRQ_Channels\, там как раз то, что нужно.
_Макс
Ура, заработало! 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 каждый раз другое значение? Он ведь должен генерировать прерывание при обнулении или опустошении. Даже если имеет место задержка в несколько инструкций кода, то значение всеравно должно при каждом останове быть одним и тем же.
AHTOXA
Цитата(_Макс @ Apr 22 2010, 00:44) *
Ура, заработало! smile.gif

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

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

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

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

Хотя всеравно иногда меняется значение, но намного реже.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.