Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: повторные прерывания LPC17xx
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
evgen2
Вот похожая тема В прерываниях CM0/CM3 в конце нужен ClearPending?

Имеем такой простой до невозможности код
Код
/* таймер T2  25 МГц */
   LPC_TIM2->MR0 = 782/2;           // 782 = 32 кHz
   LPC_TIM2->MCR = 3;                
   LPC_TIM2->TCR=  0x01;
   NVIC_EnableIRQ(TIMER2_IRQn);

void TIMER2_IRQHandler(void)
{    static int raz=0;
     if(raz == 0)
     {  LPC_GPIO2->FIOSET = 0x1000;raz = 1;
     } else {
       LPC_GPIO2->FIOCLR = 0x1000; raz = 0;
   }
    LPC_TIM2->IR = 1; // Clear interrupt flag
}


смотрим осциилографом, что получается:

___|___|___|___

Или наоборот

— — |— — |— — |— —

Вместо ожидаемого — — |___|— — |___|— — |___

При этом, если поставить брякпойнт на FIOSET или FIOCLR, а потом убрать и продолжить, то картина меняется
если мерять время этого второго паразита, то это будет 12-14 клоков
Однако, если перенести IR = 1; в начало
Код
void TIMER2_IRQHandler(void)
{    static int raz=0;
      LPC_TIM2->IR = 1; // Clear interrupt flag
     if(raz == 0)
     {  LPC_GPIO2->FIOSET = 0x1000;raz = 1;
     } else {
       LPC_GPIO2->FIOCLR = 0x1000; raz = 0;
   }
}


То все налаживается....

Теперь смотрю на все остальные прервывания, в том числе GPI прерывания GPIO прерывания Rising/Falling edge приходят одновременно? (2 ноги * прерывания по фронту и спаду) - там тоже получается какое-то левое повторное прерывание.. однако манипуляции с выносом очистки прерывания как можно раньше не прокатывают и, кажется, наоборот, от выноса очистки в конец количество левых прерываний уменьшается

ЗЫ: а в эмуляторе это не вылазит
_Артём_
Цитата(evgen2 @ Jan 15 2014, 01:32) *

Если память не изменяет - не нужен, но вот где это написано не помню (изменяет таки) а искать лень.

Цитата(evgen2 @ Jan 15 2014, 01:32) *
То все налаживается....
Может что такое добавить, хотя у вас не RTC...


Код
OS_INTERRUPT void OS::SystemTimer_ISR()
{
    /* Clear interrupt source */
    RTC->IFC=RTC_IFC_COMP0;
    /* Flushing instructions to make sure that the interrupt is not re-triggered*/
    /* This may be required when the peripheral clock is slower than the core */
    __DSB();
    {
    scmRTOS_ISRW_TYPE ISR;

#if scmRTOS_SYSTIMER_HOOK_ENABLE == 1
        system_timer_user_hook();
#endif
        Kernel.system_timer();
    }

}
Сергей Борщ
Цитата(evgen2 @ Jan 15 2014, 01:32) *
То все налаживается....
Угу. Это влияние конвеера. Или сбрасывайте в начале, или вставляйте барьер синхронизации после сброса флага.
evgen2
Цитата(Сергей Борщ @ Jan 15 2014, 11:54) *
Угу. Это влияние конвеера. Или сбрасывайте в начале, или вставляйте барьер синхронизации после сброса флага.


"Барьер синхронизации" - это "заклинание" __DSB(); ? Непонятно, почему ни в мануалах, ни в примерах его нет
Сергей Борщ
Цитата(evgen2 @ Jan 15 2014, 11:41) *
"Барьер синхронизации" - это "заклинание" __DSB(); ?
Ну хотя бы по диагонали просмотрите начало документа по ссылке.
Цитата(evgen2 @ Jan 15 2014, 11:41) *
Непонятно, почему ни в мануалах, ни в примерах его нет
Я вам дал ссылку как раз на мануал с примером.
evgen2
Цитата(Сергей Борщ @ Jan 15 2014, 13:50) *
Ну хотя бы по диагонали просмотрите начало документа по ссылке.
Я вам дал ссылку как раз на мануал с примером.

да хоть по диагонали, хоть на принтере распечатать да на просвет посмотреть . Может оно и влияет, если засыпать-просыпаться, а без этого - никакой разницы
Aleksandr Baranov



Due to the processor pipeline, the Cortex-M processors can be entering the interrupt sequence
at the same time as writing to the NVIC to disable the interrupt. Therefore, it is possible that an
interrupt handler might be executed immediately after it is disabled at the NVIC.

http://infocenter.arm.com/help//topic/com....r_m_profile.pdf
jcxz
Цитата(Aleksandr Baranov @ Jan 16 2014, 04:32) *
Due to the processor pipeline, the Cortex-M processors can be entering the interrupt sequence
at the same time as writing to the NVIC to disable the interrupt. Therefore, it is possible that an
interrupt handler might be executed immediately after it is disabled at the NVIC.

Мимо кассы. Так как у ТС нет запретов прерываний внутри ISR, и даже вообще обращений к NVIC внутри ISR.
swisst
Доброго дня ! на контроллере 1768 с MC0 и таймером проблем не имею.
Код
void TIMER0_IRQHandler(){
    uint32_t _interrupt_source = LPC_TIM0->IR;

    if(_interrupt_source & (1<<0)){
        LPC_TIM0->IR |= (1<<0);
                //дальше код - барьеров нет
    }
}


я бы для чистоты эксперимента объявил бы еще переменную как volatile
Код
static int raz=0;

или вовсе бы ушел от нее
Код
LPC_GPIO2->FIOPIN ^= 0x1000;
jcxz
1. Вот потому, что "дальше код", потому и не имеете rolleyes.gif
2. Операция if(_interrupt_source & (1<<0)){ бессмысленна, так как если у вас установлены ещё и другие флаги запросов в IF, то функция всё равно зациклится в непрерывных входах в ISR (ведь регистра маски прерываний в таймере вроде нету?).
3. Операция |= в LPC_TIM0->IR |= (1<<0); также бессмысленна, читайте UM.
4. volatile объявлять бессмысленно если переменная больше нигде не используется (а она больше нигде не используется).
5. Делать так: LPC_GPIO2->FIOPIN ^= 0x1000; крайне опасно, если учесть, что в основном коде (или другом ISR) могут быть операции с другими битами этого порта. Курите UM на предмет - зачем придуманы FIOSET и FIOCLR.

PS: И вообще - лучше молчать, чем давать такие "советы".
Лучше поучитесь хотя-бы у ТС как правильно реализовывать ISR-ы.
swisst
Цитата(jcxz @ Jan 16 2014, 12:48) *
1. Вот потому, что "дальше код", потому и не имеете rolleyes.gif


частота дерганья ножкой 40kHz. обработчик упростил
Код
void TIMER0_IRQHandler(){
    if(LPC_TIM0->IR & (1<<0)){

        LED3_TOG;      //LPC_GPIO2->FIOPIN ^= 0x1000;

    }

    LPC_TIM0->IR = (1<<0);
}

все работает, как и раньше. в UM ни слова о том, в каком месте сбрасывать флаг.


Цитата(jcxz @ Jan 16 2014, 12:48) *
2. Операция if(_interrupt_source & (1<<0)){ бессмысленна, так как если у вас установлены ещё и другие флаги запросов в IF, то функция всё равно зациклится в непрерывных входах в ISR (ведь регистра маски прерываний в таймере вроде нету?).
3. Операция |= в LPC_TIM0->IR |= (1<<0); также бессмысленна, читайте UM.

это не принципиально в конкретном примере. прерывания по MATCH и CAP маскируются.

Цитата(jcxz @ Jan 16 2014, 12:48) *
4. volatile объявлять бессмысленно если переменная больше нигде не используется (а она больше нигде не используется).
5. Делать так: LPC_GPIO2->FIOPIN ^= 0x1000; крайне опасно, если учесть, что в основном коде (или другом ISR) могут быть операции с другими битами этого порта. Курите UM на предмет - зачем придуманы FIOSET и FIOCLR.

я же написал - для чистоты эксперимента. иначе получается, что вы знаете о том, что переменная нигде не используется, но не знаете, что порт 2 пустой rolleyes.gif
sidy
Допустим, у меня есть следующий обработчик прерываний:
Код
void TIM1_TRG_COM_TIM11_IRQHandler(void){
  if(TIM11->SR&TIM_SR_UIF){
      TIM11->SR&=~TIM_SR_UIF;
      __disable_irq();
      TIM4->CNT=(TIM11->CNT*5.25f/168.0f)
      TIM4->CR1|=TIM_CR1_CEN;              
      __enable_irq();                      
  }
}

нужно ли мне ставить после __enable_irq(); __ISB()?
jcxz
Цитата(sidy @ Jan 16 2014, 22:13) *
нужно ли мне ставить после __enable_irq(); __ISB()?

Скажем по-другому: вам скорее всего не нужно ставить __disable_irq()/__enable_irq().
Зачем они? У вас что - в другом, более приоритетном ISR осуществляется запись в эти регистры??? smile3046.gif

Цитата(swisst @ Jan 16 2014, 18:30) *
я же написал - для чистоты эксперимента. иначе получается, что вы знаете о том, что переменная нигде не используется, но не знаете, что порт 2 пустой rolleyes.gif

Что переменная нигде не используется я знаю из static int, а то что порт больше нигде - об этом ни слова.
К тому же переменных типа int в ОЗУ можно создать ГОРАЗДО больше чем обычно имеется портов в МК. Если вы так расточительно будете подходить к ногам, что на одну ногу будете тратить целый 32-битный порт, то далеко не уедете...
sidy
Цитата(jcxz @ Jan 16 2014, 20:54) *
Скажем по-другому: вам скорее всего не нужно ставить __disable_irq()/__enable_irq().
Зачем они? У вас что - в другом, более приоритетном ISR осуществляется запись в эти регистры???

Например, если между записью в регистр CNT и пуском таймера TIM_CR1_CEN придет более приоритетное прерывание, то TIM11->CNT может сделать n-ое количество тактов и значение TIM4->CNT будет некорректным.
jcxz
Как же можно ответить ответить на Ваш вопрос, если невозможно догадаться, что у вас за регистры такие SR и CNT?
В UM на LPC17xx таковых нету.
Ну если под CNT ещё можно предположить регистр TC, то с SR вообще теряюсь в догадках....
Подозреваю что у вас не LPC17x. А в таком случае нужно указывать какой CPU имеете в виду если вопрос касается периферии и желательно указывать как она у вас сконфигурена.
sidy
Цитата(jcxz @ Jan 16 2014, 22:24) *
Как же можно ответить ответить на Ваш вопрос, если невозможно догадаться, что у вас за регистры такие SR и CNT?
В UM на LPC17xx таковых нету.
Ну если под CNT ещё можно предположить регистр TC, то с SR вообще теряюсь в догадках....
Подозреваю что у вас не LPC17x. А в таком случае нужно указывать какой CPU имеете в виду если вопрос касается периферии и желательно указывать как она у вас сконфигурена.

Да у меня STM32F407, но думаю что переферия таймеров очень похожа с LPC17x отличия только а названиях регистров.
TIM11->CNT - счетный регистр таймера
TIM11->SR - регистр статуса таймера
TIM_SR_UIF - флаг в регистре статуса, который устанавливается при прерывании
jcxz
Только в LPC флаги прерываний квтируются не записью '0', а записью '1'.
Отвечая на Ваш вопрос, думаю что вряд-ли будет проблема из-за отсутствия барьеров после квитирования флага прерывания, так как после этой операции и до выхода из ISR у вас много команд, так что сброс флага должен успеть дойти до периферии таймера до выхода из ISR.
И опять-же - что за мания такая использовать операции чтения-модификации-записи там где нужна просто запись? А остальные флаги потерять не боитесь? Да и просто - ЗАЧЕМ????
sidy
Цитата(jcxz @ Jan 16 2014, 23:39) *
И опять-же - что за мания такая использовать операции чтения-модификации-записи там где нужна просто запись? А остальные флаги потерять не боитесь? Да и просто - ЗАЧЕМ????

Немного не понял где у меня чтение-модификация-запись и как сделать просто запись? И какие флаги можно потерять?
Golikov A.
это стандартная ошибка при сбросах флагов

REG |= INTERRUPT_FLAG;

обычно эти регистры не чувствительны к одному сигналу и реагируют только на другой. в LPC, например запись 0 ничего не делает, а запись 1 сбрасывает флаг. Если в регистре лежит
0x11, а мы хотим сбросить FLAG = 0x01.
то запись REG |= FLAG равносильна REG = REG | FLAG => REG = 0x11 | 0x01 => REG = 0x11 => REG ==== 0;
то есть сбрасывая один флаг, мы случайно сбросили все остальные что были в регистрах...

именно поэтому регистр сделать не чувствителен к нулю и правильно сбрасывать

REG = FLAG => REG = 0x01 => REG ==== 0x10; То есть запись 0 в старшие биты, где стоит флаг его не тронет, снимется только младший флаг.
sidy
Понял, т.е. мы прочитали, изменили, записали в регистр число 0x11 и сбросили 0-й бит и 5ый бит.
Т.е. операция вида REG&=~FLAG тоже относится к чтения модификация запись:
REG&=~FLAG => REG=REG&(~FLAG) => REG=0x11&(~0x10) => REG=0x11&(0x01) => REG=0x01?
Golikov A.
скорее так
REG&=~FLAG => REG=REG&(~FLAG) => REG=0x11&(~0x01) => REG=0x11&(0x10) => REG=0x10?
FLAG = 01
и при сбросе 0 все вроде сработает, но есть и вторая опасность.

REG = 0x011
операция
REG&=~FLAG
не делается за 1 такт

вы получите значение регистра 0x011
на след шаге 0x011 & 0x110 = 0x010 (FLAG = 0x001, ~FLAG = 0x110)
и в конце получите
REG = 0x010
младший флаг сбрасываете, второй не трогаете (это все про сброс нулем)

но если за время этих трех тактов произошло прерывание
и регистр стал REG = 0x111,
то появившийся самый старший бит вы тоже сбросите.

а если вы сразу напишите
REG = (~FLAG)

то все будет хорошо даже если произойдет прерывание во время выполнения команды сброса.


Сергей Борщ
Цитата(sidy @ Jan 17 2014, 09:33) *
Т.е. операция вида REG&=~FLAG тоже относится к чтения модификация запись:
Ага, только REG=0x11&(~0x10) => REG=0x11&(0xEF) => REG=0x10, то есть сбросили все флаги кроме нужного
Golikov A.
Цитата(Сергей Борщ @ Jan 17 2014, 14:50) *
Ага, только REG=0x11&(~0x10) => REG=0x11&(0xEF) => REG=0x10, то есть сбросили все флаги кроме нужного


не это мы типа говорим про процы со сбросом 0, а не 1. Но смысл один, сбрасывать используя состояние регистра - нельзя!
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.