Перейти к содержанию
    

STm32F4 Возникает неразрешенное прерывание по заднему фронту

Прерывание EXTI по изменению состояния на ноге. Разрешено прерывание по переднему фронту, однако иногда возникает прерывание по заднему. Может быть причиной то, что задний фронт затянут до 5 мкс?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Только что, Алексей ВМ сказал:

Прерывание EXTI по изменению состояния на ноге. Разрешено прерывание по переднему фронту, однако иногда возникает прерывание по заднему. Может быть причиной то, что задний фронт затянут до 5 мкс?

Дребезг

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

На осцилле все чисто, на ногу идет сигнал с триггера Шмитта.

Изменено пользователем Алексей ВМ

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 минуту назад, Алексей ВМ сказал:

На осцилле все чисто, на ногу идет сигнал с триггера Шмитта.

ну значит - такой осцилл  :unknw:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 hour ago, Алексей ВМ said:

Прерывание EXTI по изменению состояния на ноге. Разрешено прерывание по переднему фронту, однако иногда возникает прерывание по заднему. Может быть причиной то, что задний фронт затянут до 5 мкс?

На прошлой неделе я тоже словил нечто подобное.

Я тоже использовал прерывания от внешнего устройства по EXTI. По невнимательности я забыл в main() перед главным циклом разрешить прерывания (__enable_interrupt()). Более того, я эту ошибку не сразу просёк! Девайс работал но как-то странно. Прерывания возникали и обработчик прерывания их даже отрабатывал. Но отрабатывал не каждое, а примерно одно из ста. Я тупил над кодом несколько минут. Копал, но не в том месте. Надо было сразу пойти в main(). Как только я прописал эту строку, девайс сразу начал функционировать как и ожидалось. Но для себя я отметил, что с прерываниями EXTI у STM32F0xx что-то не в порядке. Почему-то они умудряются каким-то образом "просачиваться".

Я не знаю, с чем это связано. Понятно, что надо бы по хорошему покопаться поглубже, но пока руки не доходят (как обычно -- всяких дел выше крыши). Боюсь, что придётся отложить это интереснейшее исследование до Новогодних каникул.

Параметры для повторения: проц STM32F030F4, питание 3.3 В, тактовая частота ядра 48 МГц. Прерывание от внешнего (цифрового, не аналогового!) устройства возникает каждые 60 мс. Фронт -- спадающий (из "1" в  "0"). Внешнее устройство висит на SPI1, тактовая частота SPI -- 3 или 6 МГц (не помню!) Всё чрезвычайно просто -- устройство ставит прерывание на ногу процу, проц обслуживает устройство по SPI. В девайсе задействован ещё USART1, работает только на передачу (TX). Передача байтов происходит тоже по прерываниям (не через DMA.)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В моем случае все прерывания от переднего фронта возникают, только к ним добавляются ещё прерывания и от заднего фронта. Кроме того, используется ещё множество прерываний от таймеров, уарта и тп, все работает адекватно.

Изменено пользователем Алексей ВМ

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А точнр это прерывание по заднему, а не двойное из-за несброшенного флага по переднему?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В обработчике прерывания от EXTI флаг сбрасывается. Прерывание от EXTI запускает таймер, который генерит импульс с программируемой задержкой и программируемой же длительности на другой ноге. На этой ноге всегда присутствуют импульсы от переднего фронта и иногда от заднего, причем сдвиг импульса относительно фронта меняется в соответствии с заданной задержкой. Например, задали задержку 5 мс  - после переднего фронта через 5 мс генерится импульс, и иногда с той же задержкой генерится импульс по заднему фронту, длина импульса всегда правильная, заданная. Грешу на то, что задний фронт затянут, но тут должен срабатывать гистерезис на ноге чипа, по идее.

Изменено пользователем Алексей ВМ

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

27 минут назад, Алексей ВМ сказал:

В обработчике прерывания от EXTI флаг сбрасывается.

А после этого сброса выполняется какая-нить команда синхронизации: DSB или DMB или ISB?

Если нет, то вполне возможно что входите Вы по несброшенному флагу, как заметил VladislavS. И обнаружить это легко зафиксировав времена входов по какому-нить таймеру.

 

Цитата

Прерывание от EXTI запускает таймер, который генерит импульс с программируемой задержкой и программируемой же длительности на другой ноге. На этой ноге всегда присутствуют импульсы от переднего фронта и иногда от заднего, причем сдвиг импульса относительно фронта меняется в соответствии с заданной задержкой. Например, задали задержку 5 мс  - после переднего фронта через 5 мс генерится импульс, и иногда с той же задержкой генерится импульс по заднему фронту, длина импульса всегда правильная, заданная. Грешу на то, что задний фронт затянут, но тут должен срабатывать гистерезис на ноге чипа, по идее.

Вообще с такими временами (5 мс) сделано у Вас не совсем правильно. По идее делать нужно примерно так:

1) Изначально разрешаем прерывание по фронту; 2) в ISR по фронту, запрещаем прерывание по фронту, разрешаем по спаду; 3) в ISR по спаду, запрещаем прерывание по спаду, разрешаем прерывание по истечению некоторого таймаута по таймеру (время выберем такое, чтобы было заведомо меньше длительности высокого уровня сигнала, но больше времени дребезга); 4) в таймерном ISR запрещаем прерывание по таймеру, разрешаем по фронту (как в п.1); и далее - с пункта 2. Вот так должно работать надёжно.

Если заранее известна длительность низкой фазы сигнала, то можно пп. 2 и 3 объединить, убрав прерывание по спаду и запустив сразу после фронта отсчёт таймаута по таймеру.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

18 minutes ago, jcxz said:

А после этого сброса выполняется какая-нить команда синхронизации: DSB или DMB или ISB?

Нет, не выполняется. Не совсем понимаю, о чем речь - ISR стандартная -

 

void EXTI0_IRQHandler(void) {
    /* Make sure that interrupt flag is set */
    if (EXTI_GetITStatus(EXTI_Line0) != RESET) {
        /* Do your stuff when PD0 is changed */
        
        
        /* Clear interrupt flag */
        EXTI_ClearITPendingBit(EXTI_Line0);

        // Запуск таймера
    }
}
 
18 minutes ago, jcxz said:

Вообще с такими временами (5 мс) сделано у Вас не совсем правильно. По идее делать нужно примерно так:

1) Изначально разрешаем прерывание по фронту; 2) в ISR по фронту, запрещаем прерывание по фронту, разрешаем по спаду; 3) в ISR по спаду, запрещаем прерывание по спаду, разрешаем прерывание по истечению некоторого таймаута по таймеру (время выберем такое, чтобы было заведомо меньше длительности высокого уровня сигнала, но больше времени дребезга); 4) в таймерном ISR запрещаем прерывание по таймеру, разрешаем по фронту (как в п.1); и далее - с пункта 2. Вот так должно работать надёжно.

Если заранее известна длительность низкой фазы сигнала, то можно пп. 2 и 3 объединить, убрав прерывание по спаду и запустив сразу после фронта отсчёт таймаута по таймеру.

Проблема в том, что сигнал подразумевается без дребезга, иначе, конечно, все придется делать по другому. Задача просто сформировать импульс по чистому цифровому сигналу.

 

Забыл упомянуть - время между фронтами EXTI всегда больше длительности генерируемого импульса - срабатывание от EXTI во время работы таймера (генерации импульса) исключены.

 

С другой стороны,  нужно исключить вероятность появления дребезга, спасибо за наводку.

 

Изменено пользователем Алексей ВМ

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

10 минут назад, Алексей ВМ сказал:

Нет, не выполняется. Не совсем понимаю, о чем речь - ISR стандартная -

"Стандартная ISR" со стандартным багом :)  :  сбрасывать флаг прерывания нужно сразу поле его обнаружения, а не как у Вас - где-то в хвосте ISR. Писали уже не раз про этот фиче-баг в STM32. Или использовать ISB после сброса флага. А лучше - и то и другое (переместить в начало и добавить ISB).

Подумайте сами почему. У Вас же не AVR всё-таки.....

 

Цитата

Прерывания по спаду мне не нужны - Вы предлагаете их использовать только для исключения ложного срабатывания?

Ну да. Точно так же борятся с дребезгом контактов кнопок. Там тоже таймер как бы и не нужен. Ну если конечно Вас этот дребезг не устраивает.

 

Цитата
Забыл упомянуть - время между фронтами EXTI всегда больше длительности генерируемого импульса - срабатывание от EXTI во время работы таймера (генерации импульса) исключены.

Значит можно упростить, обойдясь без прерывания по спаду, добавив только таймаут (как я писал выше) - "мёртвую зону".

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2 minutes ago, jcxz said:

"Стандартная ISR" со стандартным багом :)

В моем посте приведена вся моя ISR - после проверки условия сразу сбрасываем флаг и запускаем таймер. Больше в ней ничего нет. Насчет дребезга поисследую, спасибо, но изначально дребезг в этой схеме не подразумевался ))

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

3 минуты назад, Алексей ВМ сказал:

В моем посте приведена вся моя ISR - после проверки условия сразу сбрасываем флаг и запускаем таймер. Больше в ней ничего нет. Насчет дребезга поисследую, спасибо, но изначально дребезг в этой схеме не подразумевался ))

Значит написать надо примерно так:

if (EXTI_GetITStatus(EXTI_Line0) != RESET) {
  EXTI_ClearITPendingBit(EXTI_Line0);
  __ISB();
  /* Do your stuff when PD0 is changed */
  /* Clear interrupt flag */
  // Запуск таймера
}

Но таймаут всё равно нужен для стабильной работы.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А разве не надо сбрасывать флаг  в любой ситуации. Иначе есть вероятность, что Вы при выходе из прерывания снова в него будете влетать до бесконечности. Не знаю что там библиотеках индюшка понаписал, но я это делаю просто вот так:

 

EXTI->PR|=(1<<12);                                         // clear pending interrupt PA12

__ISB();

...

 

Изменено пользователем vlad_new

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...