|
Обработчик прерывания срабатывает сразу после запуска таймера |
|
|
|
Apr 18 2014, 13:11
|

Местный
  
Группа: Участник
Сообщений: 253
Регистрация: 15-04-10
Из: Волгоград
Пользователь №: 56 658

|
Запрограммировал таймер на отчет временных интервалов: Код /* Настройка таймера TIM2 на событие: Прерывание при совпадении с р-ром TIM2_ARR */ TIM2->ARR=(8000); // загрузка рег-ра для сравнения 366/8000=0,046 Hz TIM2->PSC=(65536-1); // предделитель CK_CNT=24000000/65536=366 Hz TIM2->DIER|=(TIM_DIER_UIE); // разрешаем прерывание по срабатыванию таймера TIM2->CNT=1; TIM2->CR1|=(TIM_CR1_CEN); // Запуск Таймера
/* Разрешение прерывания TIM2 */ NVIC_EnableIRQ(TIM2_IRQn); Период србатывания ~21сек. В обработчике поставил маркер срабатывания: Код void TIM2_IRQHandler (void) { u32 i; TIM2->SR &=~(TIM_SR_UIF);// сброс ф.прерывания SWITCH_PIN(PC8); } При запуске программы почемуто сразу срабатывает прерывание. С какого это оно срабатывает , если событие не наступило? Как сделать чтобы первое срабатывание было только по совпадению с рег-ом ARR ?
|
|
|
|
3 страниц
1 2 3 >
|
 |
Ответов
(1 - 30)
|
Apr 18 2014, 15:18
|
Знающий
   
Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725

|
Цитата(MaxiMuz @ Apr 18 2014, 14:11)  При запуске программы почемуто сразу срабатывает прерывание. С какого это оно срабатывает , если событие не наступило? Как сделать чтобы первое срабатывание было только по совпадению с рег-ом ARR ? Сначала вопрос, не под отладчиком ли Вы пробуете: если не предпринять мер, а именно запретить счет таймера во время остановки при отладки, то таймер будет бежать дальше. Регистры ARR и PSC имеют теневые регистры. Команды записи модифицируют теневые регистры, которые перепишутся в рабочие, когда установится флаг обновления: Цитата It can be changed on the fly as this control register is buffered. The new prescaler ratio is taken into account at the next update event. Это означает, что новые значения регистров, которые Вы записали при инициализации, не действуют, пока не наступит событие переполнения, а оно наступает быстро, т.к. по умолчанию PSC равен нулю. Действия: - записать, что надо, прерывание еще не разрешать, - установить искусственно флаг UG в регистре EGR - это обновит PSC|ARR новыми значениями. - сбросить установившиеся флаги прерываний - только теперь разрешить прерывания и запустить таймер.
|
|
|
|
|
Apr 19 2014, 21:42
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Цитата(Golikov A. @ Apr 20 2014, 01:18)  почему = лучше чем &= уже много раз обсуждали.... Оно не лучше, оно для разных случаев. "&=" или "|=" вместо "=" - типичная ошибка при работе с write-only регистрами. Но как раз в случае STM так делать нельзя, по причине наличия такого примечания для незадействованных битов в регистрах: Reserved, must be kept at reset value. Так что только "&=" и "|=".
|
|
|
|
|
Apr 20 2014, 05:24
|

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

|
Цитата(MaxiMuz @ Apr 18 2014, 19:11)  При запуске программы почемуто сразу срабатывает прерывание. С какого это оно срабатывает , если событие не наступило? Регистр PSC обновляется только при update event. Если ARPE = 1, то ARR тоже обновляется только при update event (иначе сразу). Добавьте перед запуском таймера: Код // generate an update event to load the PSC and ARR values immediately TIM3->EGR = TIM_EGR_UG;
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Apr 20 2014, 05:53
|
Гуру
     
Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454

|
Цитата(aaarrr @ Apr 20 2014, 01:42)  Оно не лучше, оно для разных случаев. "&=" или "|=" вместо "=" - типичная ошибка при работе с write-only регистрами. Но как раз в случае STM так делать нельзя, по причине наличия такого примечания для незадействованных битов в регистрах: Reserved, must be kept at reset value. Так что только "&=" и "|=". нет оно именно лучше. если в регистре несколько битов - флагов, то &= |= срабатывая в 3 такта забрать значение, изменить, записать обратно может затереть возникший за эти три такта новый флаг, не говоря уже о чтение битов, которые предназначены только для записи. Поэтому если в регистре есть биты которые должны оставаться всегда в ресет значениях, значит это должно быть учтено при REGISTR = SBROS, в величине SBROS, но не как не означает что надо делать &=, |=.... REGISTR = (DEFAULT_VAL & (~INTERRUPT)); - правильно REGISTR &= (~INTERRUPT) ==== REGISTR = REGISTR & (~INTERRUPT); - не правильно!
|
|
|
|
|
Apr 20 2014, 09:33
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Цитата(Golikov A. @ Apr 20 2014, 09:53)  может затереть возникший за эти три такта новый флаг, Если битов несколько, и есть такая вероятность, то да, может. Цитата(Golikov A. @ Apr 20 2014, 09:53)  не говоря уже о чтение битов, которые предназначены только для записи. Тут уж что-то одно - или write-only, или w0. Но никак не одновременно. Для обсуждаемого случая "&=" является вполне корректной конструкцией.
|
|
|
|
|
Apr 21 2014, 12:31
|

Местный
  
Группа: Участник
Сообщений: 253
Регистрация: 15-04-10
Из: Волгоград
Пользователь №: 56 658

|
Цитата(aaarrr @ Apr 20 2014, 12:33)  Для обсуждаемого случая "&=" является вполне корректной конструкцией. Да , действительно , если в свойствах битов регистра " rc_w0" -означает очистка 0 , то корректнее очищать флаг: Код REG= ~(BIT_MASK); Но если используется всего один флаг , то так Код TIM2->SR &=~(TIM_SR_UIF); тоже правильно
|
|
|
|
|
Apr 22 2014, 07:44
|

Местный
  
Группа: Участник
Сообщений: 253
Регистрация: 15-04-10
Из: Волгоград
Пользователь №: 56 658

|
Цитата(AHTOXA @ Apr 20 2014, 08:24)  Добавьте перед запуском таймера: Код // generate an update event to load the PSC and ARR values immediately TIM3->EGR = TIM_EGR_UG; пробывал вот так: Код /* Настройка таймера TIM2 на событие: Прерывание при совпадении с р-ром TIM2_ARR */ TIM2->ARR=(6500); // загрузка рег-ра для сравнения 366,2109375/350=1 Hz TIM2->PSC=(65535-1); // предделитель CK_CNT=24000000/65536=366,2109375 Hz TIM2->DIER|=(TIM_DIER_UIE); // разрешаем прерывание по срабатыванию таймера TIM2->EGR = TIM_EGR_UG; TIM2->SR =~(TIM_SR_UIF);// сброс ф.прерывания TIM2->CR1|=(TIM_CR1_CEN); // Запуск Таймера
/* Разрешение прерывания TIM2 */ NVIC_EnableIRQ(TIM2_IRQn); Не работает, таймер также запускается при ресет
|
|
|
|
|
Apr 22 2014, 09:17
|

Местный
  
Группа: Участник
Сообщений: 253
Регистрация: 15-04-10
Из: Волгоград
Пользователь №: 56 658

|
Цитата(AHTOXA @ Apr 22 2014, 11:32)  Надо сгенерировать событие обновления, потом сбросить флаг, а уже потом разрешать прерывания: Код TIM2->ARR = 6500; TIM2->PSC = 65535-1; TIM2->EGR = TIM_EGR_UG; TIM2->SR = ~TIM_SR_UIF; TIM2->DIER |= TIM_DIER_UIE; TIM2->CR1 |= TIM_CR1_CEN; тоже самое Похоже что TIM2->SR =~(TIM_SR_UIF); не сбразывает сам "запрос" на прерывание
Сообщение отредактировал MaxiMuz - Apr 22 2014, 09:35
|
|
|
|
|
Apr 22 2014, 09:56
|
Знающий
   
Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725

|
Цитата(MaxiMuz @ Apr 22 2014, 10:17)  тоже самое Похоже что TIM2->SR =~(TIM_SR_UIF); не сбразывает сам "запрос" на прерывание Попробуйте еще добавить: CODE TIM2->ARR = 6500; TIM2->PSC = 65535-1; TIM2->EGR = TIM_EGR_UG; TIM2->SR = ~TIM_SR_UIF; NVIC_ClearPendingIRQ(TIM2_IRQn); TIM2->DIER |= TIM_DIER_UIE; TIM2->CR1 |= TIM_CR1_CEN;
Сообщение отредактировал KnightIgor - Apr 22 2014, 09:57
|
|
|
|
|
Apr 22 2014, 10:48
|

Местный
  
Группа: Участник
Сообщений: 253
Регистрация: 15-04-10
Из: Волгоград
Пользователь №: 56 658

|
Выясненно опытным путем с использованием документа "Cortex-M3 programming manual". Сброс флага статусного регистра Код TIM2->SR =~(TIM_SR_UIF); не приводит к сбросу самого запроса на прерывание. Чтобы сбросить запрос на прерывания делаем: 1. После загрузки временных прарметров разрешаем прерывание по срабатыванию таймера 2. генерим событие таймера UG 3. Ждем один такт и только потом сбрасиываем флаг прерывания в регистре статуса таймера 4. Запускаем Таймер 5. Очищаем Interrupt clear-pending registers (NVIC_ICPRx) 6. И только потом включаем разрешение на прерывание Код /* Настройка таймера TIM2 на событие: Прерывание при совпадении с р-ром TIM2_ARR */ TIM2->ARR=(1500); // загрузка рег-ра для сравнения ~ 366/1500=0,244 Hz TIM2->PSC=(65535-1); // предделитель CK_CNT=24000000/65536=366,2109375 Hz
TIM2->DIER|=(TIM_DIER_UIE); // разрешаем прерывание по срабатыванию таймера TIM2->EGR = TIM_EGR_UG; // генерим событие таймера __NOP(); TIM2->SR =~(TIM_SR_UIF);// сброс ф.прерывания TIM2->CR1|=(TIM_CR1_CEN); // Запуск Таймера
NVIC_ClearPendingIRQ (TIM2_IRQn);
/* Разрешение прерывания TIM2 */ NVIC_EnableIRQ(TIM2_IRQn); Если закоментить nop, то сброс события таймера не проходит. Собственно вопрос такой , если мы в конце сбрасываем бит запроса на прерывания от таймера2 , тогда уже не важно какие события произошли до этого , прерывание по идее не ожидается, правильно ? Но если я убираю команду TIM2->EGR = TIM_EGR_UG; // генерим событие таймера , то таймер сразу после разрешения прерывания запускается.
|
|
|
|
|
Apr 22 2014, 13:19
|
Частый гость
 
Группа: Участник
Сообщений: 90
Регистрация: 12-12-13
Пользователь №: 79 587

|
Цитата(MaxiMuz @ Apr 22 2014, 14:48)  1. После загрузки временных прарметров разрешаем прерывание по срабатыванию таймера 2. генерим событие таймера UG 3. Ждем один такт и только потом сбрасиываем флаг прерывания в регистре статуса таймера 4. Запускаем Таймер 5. Очищаем Interrupt clear-pending registers (NVIC_ICPRx) 6. И только потом включаем разрешение на прерывание Как-то сложно всё это получается. Попробуйте просто: 1. Запустить таймер 2. Разрешить прерывание Именно в такой последовательности.
|
|
|
|
|
Apr 22 2014, 16:51
|
Гуру
     
Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454

|
Цитата Но если я убираю команду TIM2->EGR = TIM_EGR_UG; смысл команды не сгенерить прерывание смысл команды вызвать событие и обновить регистры таймера, обновление которых происходит по событию, которое в свою очередь и генерит прерывание. Прерывание в данном случае - побочный эффект от обновления таймера. Цитата Как-то сложно всё это получается. Попробуйте просто: 1. Запустить таймер 2. Разрешить прерывание Именно в такой последовательности. и будет исходная задача, без вызова события не произойдет настройки таймера, а событие вызовет прерывание, потому сразу после разрешения прерывания в вашем случае полетите либо по таймеру работающему по старыми настройкам, либо если обновили настройки, то сразу по прерыванию...
|
|
|
|
|
Apr 23 2014, 00:28
|
Местный
  
Группа: Участник
Сообщений: 226
Регистрация: 10-07-09
Пользователь №: 51 126

|
Цитата(Golikov A. @ Apr 20 2014, 08:53)  REGISTR = (DEFAULT_VAL & (~INTERRUPT)); - правильно Да тоже неправильно...  DEFAULT_VAL равно нулю...
|
|
|
|
|
Apr 23 2014, 07:38
|
Местный
  
Группа: Участник
Сообщений: 226
Регистрация: 10-07-09
Пользователь №: 51 126

|
Цитата(Golikov A. @ Apr 23 2014, 09:23)  DEFAULT_VAL равно не нулю, а тому чему оно должно быть равно для сохранения верных значений записываемых битиков.... Тогда уже лучше написать DEFAULT_VAL_MASK, где все биты с атрибутом RES должны быть нулями, а устанавливаемые флаги единицами... а не DEFAULT_VAL... Я не ради докопаться... просто на другом форуме вопрошающий уже выдал непонимание происходящего...
Сообщение отредактировал HHIMERA - Apr 23 2014, 07:39
|
|
|
|
|
Apr 23 2014, 07:49
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Цитата(HHIMERA @ Apr 23 2014, 11:38)  Тогда уже лучше написать DEFAULT_VAL_MASK, где все биты с атрибутом RES должны быть нулями, а устанавливаемые флаги единицами... Их нельзя нулями. По мануалу нужно сохранять состояние после сброса. То есть "честное" формирование DEFAULT_VAL должно быть таким: reg_def_val = reg | <все флаги типа w0c> или reg_def_val = reg & ~<все флаги типа w1c> Не уверен, что кто-то так делает, конечно  Цитата(Golikov A. @ Apr 23 2014, 10:23)  я чет не припомню проца где это было нужно (в смысле где часть битов надо было оставлять 0, а часть 1, обычно все одинаковые) Бывает, хотя в статусных регистрах тоже не встречал.
|
|
|
|
|
Apr 23 2014, 10:29
|
Местный
  
Группа: Участник
Сообщений: 226
Регистрация: 10-07-09
Пользователь №: 51 126

|
Цитата(aaarrr @ Apr 23 2014, 10:49)  Не уверен, что кто-то так делает, конечно  Да... сомнения присутствуют... А по поводу... Цитата По мануалу нужно сохранять состояние после сброса. Примеры SPL это отвергают напрочь... т.е. всё на совести и знаниях кодера...
|
|
|
|
|
Apr 23 2014, 15:13
|
Гуру
     
Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454

|
да я тоже часто в ПЛИС делают некоторые резервные биты, которые не использую, и сам их нулю внутри автоматов, но на всякий случай, мало ли чего забуду, в описании требую такие биты в регистрах не трогать. Думаю тут также, если их трогать скорее всего ничего не будет, но мало ли что, потому и приписка такая, чтоб наверняка!
|
|
|
|
|
Apr 23 2014, 17:54
|
Местный
  
Группа: Участник
Сообщений: 226
Регистрация: 10-07-09
Пользователь №: 51 126

|
Цитата если их трогать скорее всего ничего не будет В каком-то таймере STM32... точно уже не помню... где по референсу бит OPM отсутствует... попробовал как-то его установить... на авось... а вдруг... Результат - таймер затыкался... т.е. все эти предупреждения... как бы и не на ровном месте...
|
|
|
|
|
Apr 25 2014, 11:30
|

Местный
  
Группа: Участник
Сообщений: 253
Регистрация: 15-04-10
Из: Волгоград
Пользователь №: 56 658

|
Задача своевременного запуска обработчика таймера решена. Но хочу разобраться как связан бит UG c формированием запроса не прерывание . Согласно описанию : Цитата Prescaler description The prescaler can divide the counter clock frequency by any factor between 1 and 65536. It is based on a 16-bit counter controlled through a 16-bit register (in the TIMx_PSC register). It can be changed on the fly as this control register is buffered. The new prescaler ratio is taken into account at the next update event. Т.е. чтобы вызвать появление Update event (UEV) нужно чтобы счетчик досчитал до ARR. Поэтому я перед тем как Разрешить прерывание запускаю счетчик и естественным путем вызываю Update event (UEV) , а потом сбрасываю запрос на прерывание : Код TIM2->ARR=(1); TIM2->PSC=(65535-1); TIM2->DIER|=(TIM_DIER_UIE); // разрешаем прерывание по срабатыванию таймера TIM2->CR1|=(TIM_CR1_CEN); // Запуск Таймера //TIM2->EGR = TIM_EGR_UG; // генерим событие таймера __NOP(); __NOP(); __NOP(); TIM2->SR =~(TIM_SR_UIF);// сброс ф.прерывания __NOP(); NVIC_ClearPendingIRQ (TIM2_IRQn);
/* Разрешение прерывания TIM2 */ NVIC_EnableIRQ(TIM2_IRQn); Почему тогда в этом случае , не происходит сброс запроса на прерывание ?
|
|
|
|
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0
|
|
|