|
stm32F429 и прерывание от таймера |
|
|
|
Jul 22 2015, 17:49
|

Местный
  
Группа: Свой
Сообщений: 322
Регистрация: 13-12-05
Пользователь №: 12 147

|
Здравствуйте, только начал осваивать проц, и столкнулся с непоняткой, уже 3 дня сижу и не могу понять. Есть Выход Код //Trigger /*Configure GPIO pin : PE3 */ GPIO_InitStruct.Pin = GPIO_PIN_3; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_MEDIUM; HAL_GPIO_Init(GPIOE, &GPIO_InitStruct); Есть таймер 6, его настройка. Код __TIM6_CLK_ENABLE(); UV_state = 0; HAL_NVIC_SetPriority(TIM6_DAC_IRQn, 1, 0); HAL_NVIC_EnableIRQ(TIM6_DAC_IRQn); HAL_GPIO_WritePin(GPIOE, GPIO_PIN_3, GPIO_PIN_RESET); TIM6->PSC = 143; TIM6->ARR = 62499; //100 mS //TIM6->EGR = TIM_EGR_UG; TIM6->DIER = TIM_DIER_UIE; TIM6->CR1 |= TIM_CR1_CEN | TIM_CR1_ARPE; Это прерывание CODE void TIM6_DAC_IRQHandler(void) { TIM6->CR1 &= ~TIM_CR1_CEN; //Остнавливаем таймер TIM6->SR &= ~TIM_SR_UIF; //Сбрасываем флаг UIF
switch (UV_state) { case 0: TIM6->PSC = 0; TIM6->ARR = 0x707;//1799; //20 uS TIM6->CNT = 0; TIM6->CR1 |= TIM_CR1_CEN | TIM_CR1_ARPE; HAL_GPIO_WritePin(GPIOE, GPIO_PIN_3, GPIO_PIN_SET); UV_state = 1; break; case 1: TIM6->PSC = 0x008f;//143 TIM6->ARR = 0xF423;//62499; //Ñðàáîòàòü íà 100 mS TIM6->CNT = 0; TIM6->CR1 |= TIM_CR1_CEN | TIM_CR1_ARPE; HAL_GPIO_WritePin(GPIOE, GPIO_PIN_3, GPIO_PIN_RESET); UV_state = 0; break; }
} Хочу иметь импульс 20 us через 100 ms, и вроде все логично, но на выходе все перевернуто
Ну где тут можно ошибиться? Заходим по состоянию 0, устанавливаем таймер на 20 us и устанавливаем ногу в 1, чтобы в следующем прерывании ее сбросить и настроить прерывание на 100 ms и потом ее установить в 1 в новом прерывании. Почему на выходе все наоборот?
Сообщение отредактировал IgorKossak - Jul 23 2015, 16:34
Причина редактирования: [codebox] для длинного кода, [code] - для короткого!!!
|
|
|
|
|
Jul 22 2015, 18:40
|

Профессионал
    
Группа: Участник
Сообщений: 1 620
Регистрация: 22-06-07
Из: Санкт-Петербург, Россия
Пользователь №: 28 634

|
Предлагаю ещё посмотреть внимательно даташит на тему как сбрасыаать флаги прерываний в таймерах... В Вашем случае возможны потери прерываний (если другие ещё флаги потребуются). Небольшой пример из моего кода: Код void TIM3_IRQHandler(void) { const uint_fast32_t st = TIM3->SR; if ((st & TIM_SR_UIF) != 0) { TIM3->SR = ~ TIM_SR_UIF; // clear UIF interrupt request handle_timer_imterrupt(); } // проверяем другие флаги в st }
|
|
|
|
|
Jul 23 2015, 05:33
|
Гуру
     
Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454

|
какие флаги могут быть еще? Да какие угодно, проект будет жить, развиваться, появятся еще обработчики... да это просто надо взять себе за правило, что регистры для сброса прерывания записываются только одним значением, потому не надо делать &= или |= вам не нужно начальное состояние регистра, просто равно и все. Это правило! Плюс запись атомарная, в отличии от &= и |=. Если очень хочется могу в очередной раз написать как возникает проблема Цитата код должен формировать импульс, может в коде ошибаюсь Да ошибаетесь, и именно в коде  с битами ARPE, вам намекают на буферезированный режим обновления конца счетчика. То есть когда вы пишите обновить регистр вы обновляете его не мгновенно, а только когда таймер досчитает до заданного значения. Вот и получилось что когда вы пишите 100, таймер до ходит до прошлого 20, и только потом начинает считать до 100, а вы ему пишите 20, он дойдет до 100 и заменит на 20, потому у вас все по фазе и съехало...
|
|
|
|
|
Jul 23 2015, 12:28
|
Гуру
     
Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454

|
ну либо поменяйте местами присвоения, либо присвояемое, либо уберите флаг буферезированной загрузки.
то есть в случае если у вас буферезированная загрузка будет все так: допустим таймер считает до 20, досчитал, возникло прерывание в прерывании таймер пошел дальше, вы задаете значение 100, но оно не применяется за за буфера таймер досчитывает до 20, возникает очередное прерывание и он применяет ранее заданное 100 в прерывании таймер пошел дальше, вы задаете число 20, но оно не применяется из за буфера таймер досчитывает до 100, возникает очередное прерывание и он применяет ранее заданное 20 в прерывании таймер пошел дальше....
вот что у вас происходит, то есть когда вы в таймер пишите 100 это число на следующих ход, учитывайте это или отключите буфер
|
|
|
|
|
Jul 23 2015, 14:29
|
Профессионал
    
Группа: Свой
Сообщений: 1 719
Регистрация: 13-09-05
Из: Novosibirsk
Пользователь №: 8 528

|
В процессе инициализации полезно "вручную" сгенерировать update event при котором произойдёт загрузка из теневых регистров. Код TIM1->ARR = xxx; //и прочие настройки TIM1->EGR = TIM_EGR_UG; // генерируем update event для загрузки из всех теневых регистров TIM1->CR1 |= TIM_CR1_CEN; // разрешаем счёт
--------------------
Russia est omnis divisa in partes octo.
|
|
|
|
|
Jul 23 2015, 18:41
|

Местный
  
Группа: Свой
Сообщений: 322
Регистрация: 13-12-05
Пользователь №: 12 147

|
Упорство победило, если хотят играть по своим правилам, то по ним и с играем. После настройки в прерывании регистров, создаю новое прерывание и ref_register=1, в него заходим сразу после данного прерывания и тем самым обновляем теневые регистры PSC и ARR, и все заработало как нужно. Очень странно видеть, что сколько читал русскую документацию, не все объясняется, только в даташите нашел, что PSC тоже имеет теневой регистр. Настройка CODE TIM6->PSC = 143; TIM6->ARR = 62499; //100 mS TIM6->DIER = TIM_DIER_UIE; TIM6->CR1 |= TIM_CR1_CEN | TIM_CR1_OPM | TIM_CR1_ARPE;
void TIM6_DAC_IRQHandler(void) { if (ref_register == 0) { switch (UV_state) { case 0: TIM6->PSC = 0; TIM6->ARR = 0x707;//1799; //20 uS TIM6->CNT = 0; TIM6->EGR = TIM_EGR_UG; //Создать прерывание для обновления регистров ref_register = 1; //Обновить регистры TIM6->CR1 |= TIM_CR1_CEN; HAL_GPIO_WritePin(GPIOE, GPIO_PIN_5, GPIO_PIN_SET); UV_state = 1; break;
case 1: TIM6->PSC = 0x008f;//143 TIM6->ARR = 0xF423;//62499; // 100 mS TIM6->CNT = 0; ref_register = 1; //Обновить регистры TIM6->EGR = TIM_EGR_UG; //Создать прерывание для обновления регистров TIM6->CR1 |= TIM_CR1_CEN; HAL_GPIO_WritePin(GPIOE, GPIO_PIN_5, GPIO_PIN_RESET); UV_state = 0; break; } } else { TIM6->SR = 0; ref_register = 0; } }
Сообщение отредактировал IgorKossak - Jul 24 2015, 08:26
Причина редактирования: [codebox] для длинного кода, [code] - для короткого!!!
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|