|
Таймеры в STM32 |
|
|
|
Apr 21 2010, 11:47
|
Знающий
   
Группа: Участник
Сообщений: 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
|
|
|
|
|
 |
Ответов
(1 - 12)
|
Apr 21 2010, 15:25
|
Знающий
   
Группа: Участник
Сообщений: 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; Запустилось без ошибок, но не помогло.
|
|
|
|
|
Apr 21 2010, 15:57
|
Знающий
   
Группа: Участник
Сообщений: 691
Регистрация: 24-05-07
Пользователь №: 27 945

|
Цитата(AHTOXA @ Apr 21 2010, 18:58)  В комплекте с FwLib - куча примеров. Посмотрите пример из папочки TIM\TimeBase. Смотрю на них, по ним и написал этот код. Но как оказалось у меня не случается ни одного прерывания, я ошибся! Удивительно, что по адресу 0x4000 0000 вижу в отладчике одни нули, но ведь TIM2 сидит на этом адресе.
|
|
|
|
|
Apr 21 2010, 16:16
|

фанат дивана
     
Группа: Свой
Сообщений: 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(); }
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Apr 21 2010, 16:31
|
Знающий
   
Группа: Участник
Сообщений: 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
|
|
|
|
|
Apr 21 2010, 16:48
|

фанат дивана
     
Группа: Свой
Сообщений: 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); .... }
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Apr 21 2010, 17:30
|
Знающий
   
Группа: Участник
Сообщений: 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 } } Но всеравно не работает
|
|
|
|
|
Apr 21 2010, 18:20
|

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

|
Цитата(_Макс @ Apr 21 2010, 23:45)  Но всеравно не работает  Да, засада  Во-первых, RCC_APB1PeriphClockCmd() надо делать в самом начале. Во-вторых, похоже надо всё равно включать Output Compare канал. Посмотрите пример examples\NVIC\IRQ_Channels\, там как раз то, что нужно.
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Apr 21 2010, 18:29
|
Знающий
   
Группа: Участник
Сообщений: 691
Регистрация: 24-05-07
Пользователь №: 27 945

|
Ура, заработало!  Поставил в начале блока, вот так: Код 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 не понадобилось  И почему об этом нигде не написано) Так просто и столько времени. Вот изучу всю эту кухню, буду мемуары писать) Появились вопросы: Что такое RCC и где его найти в даташите? Для чего нужен TIM_ClearITPendingBit() и задает ли это действие задержку и неточность в работе таймера? Почему при входе в прерывание в счетчике TIM2.CNT каждый раз другое значение? Он ведь должен генерировать прерывание при обнулении или опустошении. Даже если имеет место задержка в несколько инструкций кода, то значение всеравно должно при каждом останове быть одним и тем же.
Сообщение отредактировал _Макс - Apr 21 2010, 18:34
|
|
|
|
|
Apr 21 2010, 18:59
|

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

|
Цитата(_Макс @ Apr 22 2010, 00:44)  Ура, заработало!  Аминь  Цитата Появились вопросы: Что такое RCC и где его найти в даташите? Это reset and clock control, описан в главе 6 Reference manual. Это общее на всё семейство описание, основной документ. Даташит только уточняет конкретные детали. Цитата Для чего нужен TIM_ClearITPendingBit() и задает ли это действие задержку и неточность в работе таймера? Это сброс флага прерывания. На задержку не влияет. Цитата Почему при входе в прерывание в счетчике TIM2.CNT каждый раз другое значение? Это скорее всего из-за отладчика. Попробуйте объявить отдельную переменную (volatile естественно), и при входе в прерывание копировать туда значение счётчика. А прерывание поставьте после этого присваивания.
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|