Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Не срабатывает внешнее прерывание
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Rash
Всем привет.

Столкнулся с такой проблемой в STM32F407: Если сделать критическую секцию для внешнего прерывания, то если его отключить на время выполнения кода, а потом опять включить, но за время выполнения кода пришло внешнее прерывание, то при последующем включении внешнего прерывания, прерывание не сработает. Т.е. получается будет пропущенное прерывание на время его отключения. Как сделать чтобы при включении внешнего прерывания его сработавший флаг был активен?

Код инициализации
CODE
#define TEST_IRQ_PIN GPIO_Pin_14
#define TEST_IRQ_GPIO_PORT GPIOE
#define TEST_EXTI_Line EXTI_Line14
#define TEST_IRQChannel EXTI15_10_IRQn
#define TEST_EXTI_PortSource EXTI_PortSourceGPIOE
#define TEST_GPIO_PinSource GPIO_PinSource14


// отключение обработки внешнего прерывания
#define ENTER_NOIRQ_REGION() { ITStatus exti_status = EXTI_GetIRQStatus(TEST_EXTI_Line); \
EXTI_Disable_IRQ(TEST_EXTI_Line); \

// включение обработки прерывания
#define LEAVE_NOIRQ_REGION() if(exti_status != RESET) \
EXTI_Enable_IRQ(TEST_EXTI_Line); \
}


GPIO_InitStructure.GPIO_Pin = TEST_IRQ_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(TEST_IRQ_GPIO_PORT, &GPIO_InitStructure);

RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
SYSCFG_EXTILineConfig(TEST_EXTI_PortSource, TEST_GPIO_PinSource);

EXTI_InitStructure.EXTI_Line = TEST_EXTI_Line;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);

NVIC_InitStructure.NVIC_IRQChannel = TEST_IRQChannel;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);


Такой вид имеет код приложения
Код
ENTER_NOIRQ_REGION();
           ...
   Копирование данных
           ...
LEAVE_NOIRQ_REGION();
Golikov A.
если флаг прерывания есть, то оно сработает, и пока флаг не снимите будет долбить. Потому если было внешнее прерывание и оно было замечено и был поставлен флаг, то после разрешения прерываний как оно может не сработать? Вы точно разрешая прерывания никакие флаги не сбрасываете на всякий случай?
Rash
да сам удивлён такой ситуации. Штрихуешь выключения/включение внешнего прерывания на время выполнения необходимого кода и всё работает как часы. Флаги ни какие больше не сбрасываю, в коде на момент отключения внешнего прерывания копирование из одного буфера в другой, ни какой работы с внешней периферией.
adnega
Не нашел исходников EXTI_Disable_IRQ() и EXTI_Enable_IRQ().
Может там PendingBit сбрасывается (скорее всего при разрешении)?
Rash
Код
static inline void EXTI_Enable_IRQ(uint32_t EXTI_Line)
{
  EXTI->IMR |= EXTI_Line;
}

static inline void EXTI_Disable_IRQ(uint32_t EXTI_Line)
{
  EXTI->IMR &= ~EXTI_Line;
}

static inline ITStatus EXTI_GetIRQStatus(uint32_t EXTI_Line)
{
  if ((EXTI->IMR & EXTI_Line) != (uint32_t)RESET)
    return SET;

  return RESET;
}
Golikov A.
а можно проследить в момент разрешения флаг стоит, а после?
то есть попробуйте посохранять значение флага перед и после операций, просто надо понять он в какой то момент пропадает или это прям железный глюк типа флаг есть а прерывания нет...

может сделали такое гадство, что
EXTI->IMR |= EXTI_Line;
сбрасывает и флаг заодно?
Rash
Я пробовал читать этот флаг перед EXTI->IMR |= EXTI_Line; и ставил даже __DSB() между чтением, потом проверял если флаг был установлен, вызвать прерываний программно, но флаг ни разу установленным не оказался.
Golikov A.
погодите.
Так если флага нет, то и прерывания не будет.
То есть у вас происходит внешнее прерывание и флага не ставиться? Ну тогда его действительно не произойдет. Надо понять почему флаг не ставиться...
Rash
попытаюсь вкратце объяснить. По внешнему прерыванию опрашивается внешний приёмопередатчик, так вот он перестают опрашиваться если пропустил от него хоть одно прерывания (по которому высчитывается его статус). Если ручками при отладке установить бит нужного прерывания в EXTI_SWIER, то сработает обработчик и всё пойдёт как раньше, опять до критического совпадения.
Golikov A.
вот сейчас мне вдруг подумалось
вы включение и маскирование прерывания не перепутали?

вы не выключаете реакцию, а выключаете маску, кажется...

то есть прерывание остается включенным но не отмечаемым, а должно быть прерывание отмечаемым, но выключенным

или это я глупость сказал?
scifi
Цитата(Rash @ Dec 2 2014, 22:46) *
Т.е. получается будет пропущенное прерывание на время его отключения.

Если взглянуть на блок-схему EXTI, то ровно так оно и должно работать: регистр маскирования не пропускает сигнал со входа в регистр Pending Request.

Цитата(Rash @ Dec 2 2014, 22:46) *
Как сделать чтобы при включении внешнего прерывания его сработавший флаг был активен?

Опять же, если взглянуть на блок схему, то напрашивается вывод, что прерывание надо маскировать на уровне NVIC. Другие способы не просматриваются.
adnega
Цитата(scifi @ Dec 3 2014, 14:34) *
прерывание надо маскировать на уровне NVIC. Другие способы не просматриваются.

+1
Так и никак иначе.
Запрещать и разрешать через NVIC->ICER и NVIC->ISER.
Rash
Я понял, спасибо за разъяснение.
Но если работать через NVIC, то получается если запретить EXTI15_10_IRQn, то не работать будут сразу 5 прерываний объединённых в эту группу. Не критично конечно, но не приятно, нужно на будущее учесть. В STM с внешними прерываниями какая то урезанность, например: на два одинаковых бита различных портов нельзя сделать прерывания (PA2 и PB2).
Ещё такой вопрос если мне нужно определить включено ли сейчас прерывание, нужно читать регистр ISER или также можно ISPR?
т.е. мне нужно прочитать состояние прерывания, запомнить его, выполнить операцию и вернуть обратно статус.
scifi
Цитата(Rash @ Dec 3 2014, 20:20) *
Но если работать через NVIC, то получается если запретить EXTI15_10_IRQn, то не работать будут сразу 5 прерываний объединённых в эту группу. Не критично конечно, но не приятно, нужно на будущее учесть.

Ну да, всегда будут какие-то ограничения.
Но никто не отменял творческий подход: если есть свободный таймер, к примеру, то можно его входы использовать для внешних прерываний.
Rash
Объясните, пожалуйста, смысл регистров NVIC ISPR и ICPR?
scifi
Цитата(Rash @ Dec 4 2014, 00:12) *
Объясните, пожалуйста, смысл регистров NVIC ISPR и ICPR?

Уж я-то точно не стану объяснять. Могу предоставить ссылку: STM32F3 and STM32F4 Series Cortex®-M4 programming manual.
Там английским по белому написано. Читайте на здоровье.
Rash
читал и на английском и на русском, смысл что флажок устанавливаться при ожидании прерывания, А ожидании чего? мне не ясен
adnega
Цитата(Rash @ Dec 4 2014, 10:40) *
читал и на английском и на русском, смысл что флажок устанавливаться при ожидании прерывания, А ожидании чего? мне не ясен

Это флаг отложенного прерывания. Если появился запрос на прерывание, то устанавливается флаг - PendingBit для этого источника.
Обработка этого прерывания наступит когда NVIC обработает все более высоко-приоритетные прерывания. Данные флаги можно устанавливать и сбрасывать программно - для усиления "творческого подхода" при решении задачи. При запрещении и разрешении прерывания PendingBit не изменяется. Поэтому можно запретить обработку прерывания на некоторое время и потом разрешить. Если за это время произошло прерывание, то как только разрешим обработку - NVIC в порядке очереди вызовет обработчик. Если обработка прерывания была запрещена надолго, то повторные запросы на прерывание от этого источника потеряются.
Rash
спасибо всем, вроде разобрался
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.