Страница 1 из 1

STM32L все прерывания срабатывают по 2 раза

Добавлено: Сб апр 19, 2014 13:40:04
sx386
STM32L

Все прерывания срабатывают по 2 раза
Абсолютьно все !!! И по изменению уровня и таймеров.

Вот пример на кнопку:

Код: Выделить всё


/* PA0 : инициализация прерывания кнопки 
   ----------------------------------------- */

void button_0_int_init (void) {
  
  // настроика порта
  GPIO_InitTypeDef GPIO_InitStructure;
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  GPIO_Init (GPIOA, &GPIO_InitStructure);
  
  // настроить прерывание на вывод 1 линии B  
  SYSCFG->EXTICR [0] |= SYSCFG_EXTICR1_EXTI0_PA; 
 
  // выполнение по изменению напряжения
  EXTI->RTSR |= EXTI_RTSR_TR0;  // повышение
 
  // настроить прерывание на вывод 0 
  EXTI->IMR |= EXTI_IMR_MR0;

  // приоритет прерывания
  NVIC_SetPriority (EXTI0_IRQn, 1);
  
  // разрешение выполнение прерывания
  NVIC_EnableIRQ (EXTI0_IRQn); 
}  

   
/* прерывание кнопок : PB0
   ----------------------------------------- */

void EXTI0_IRQHandler (void) { 

   power_button ++;
   
   // очистка флага прерывания
   EXTI->PR |= EXTI_PR_PR0; 
}
А если ставлю срабатывать во 2 уровням, то срабатывае 4 раза.

Код: Выделить всё

EXTI->RTSR |= EXTI_RTSR_TR0;  // повышение
EXTI->FTSR |= EXTI_FTSR_TR0;  // понижение

Re: STM32L все прерывания срабатывают по 2 раза

Добавлено: Сб апр 19, 2014 14:14:29
optima
Попробуй по входу в прерывание сразу сбросить флаг, а после все то что тебе нужно!

Re: STM32L все прерывания срабатывают по 2 раза

Добавлено: Сб апр 19, 2014 14:54:11
BorisSPB
Вообще-то STM32 любят делать так:

Код: Выделить всё

void EXTI0_IRQHandler(void)
{
  if(EXTI_GetFlagStatus(EXTI_Line0) != RESET)
  {
    /* set UserButton Flag */
    setUserButtonFlag(); 

    EXTI_ClearITPendingBit(EXTI_Line0);
  }
}

Re: STM32L все прерывания срабатывают по 2 раза

Добавлено: Сб апр 19, 2014 20:12:55
optima
Ну если лишние телодвижения не напрягают можно и так!

Re: STM32L все прерывания срабатывают по 2 раза

Добавлено: Вс апр 20, 2014 01:13:28
sx386
Записал сброс флага в начало.
Работает, но непойму почему так !

Прерывание вызывается. В нём сбрасывается флаг и продолжается выполнение обработчика прерывания.
В этот момент это же прерывание вызывается ещё раз ! И что дальше ?

Re: STM32L все прерывания срабатывают по 2 раза

Добавлено: Вс апр 20, 2014 08:27:23
optima
Флаг не успевает сбросится и по завершению всех действий в прерывании, возвращается на начало прерывания!

Re: STM32L все прерывания срабатывают по 2 раза

Добавлено: Вс апр 20, 2014 10:59:12
BorisSPB
Да, вот так делаешь что-то, вроде работает, а потом выясняется что это дурной тон :oops: (это я про свой способ).
На эту тему оказывается даже FAQ есть...

Re: STM32L все прерывания срабатывают по 2 раза

Добавлено: Вс апр 20, 2014 12:41:02
sx386
FAQ Question

When I cleared the interrupt as the last instruction in the ISR, the ISR code is called immediately upon exit half the time. Is there a possibility of race condition ?

FAQ Answer
The core (Cortex-M3) generates bufferable write transfer. This mean that the CPU consider that the data is written from an AHB point of view while the APB write transfer is managed by the AHB2APB bridge and could be written later. In this case the CPU left the interrupt routine while the interrupt is not yet cleared the cpu will re-enter again on the interrupt handler. To avoid this race condition :
1) ISR routine has to clear the interrupt peripheral flag when just entering in the routine to avoid interrupt missing.
2)ISR routine has to Implement a write to the APB peripheral register ( to clear the peripheral flag) then followed by a read access to the same register/flag. This operation will force the write buffer to complete the effective write and will stall the CPU until the effective write of the bit in the register. Therefore it is independent from the AHB/APB ratio prescaler.
Here an example :
STR R1, [R0, #0] ; Store R1 register peripheral register ( or using bit-banding peripheral address)
LDR R2, [R0, #0] ; Load the peipheral register; This will hold the CPU until the effective write of R1.
Use Cortex-M3 Bit-banding feature for interrupt clearing since it is an atomic operation and NVIC pending interrupts will be ignored during this operation, however Read-Modify-Write is not.
Пытаюсь сделать как написано, но выдаёт:
Error[Og005]: Unknown symbol in inline assembly: "EXTI_BASE"
Error[Og005]: Unknown symbol in inline assembly: "EXTI_PR_PR0"
Error[Og005]: Unknown symbol in inline assembly: "EXTI_PR_OFFSET"

Код: Выделить всё

 // сбросим флаг прерывания (иначе никогда из него не выйдем
   asm ("LDR R0, =EXTI_BASE");
                    
   // cброс выполняется записью бита
   asm("MOV R1, #EXTI_PR_PR0");
   asm("STR R1, [R0, #EXTI_PR_OFFSET]");

Re: STM32L все прерывания срабатывают по 2 раза

Добавлено: Вс апр 20, 2014 14:42:35
BorisSPB
Пока не проверял, но думаю достаточно сделать так:

Код: Выделить всё

void EXTI0_IRQHandler (void) { 

   // очистка флага прерывания
   EXTI->PR |= EXTI_PR_PR0; 
   EXTI->PR;

   power_button ++;
   
}
Второй раз обращение к EXTI->PR чтобы инициировать буферизированную запись. Компилятор обязан вставить чтение EXTI->PR так как регистр volatile и в итоге в ассемблере должно получиться то что надо.
Попробовал, получилось следующее (у меня EXTI_Line1):

Код: Выделить всё

0x080006AC 482F      LDR      r0,[pc,#188]  ; @0x0800076C
   171: { 
   172:   EXTI->PR = EXTI_Line1; 
0x080006AE B510      PUSH     {r4,lr}
0x080006B0 2102      MOVS     r1,#0x02
0x080006B2 6001      STR      r1,[r0,#0x00]
   173:         EXTI->PR; 
0x080006B4 6800      LDR      r0,[r0,#0x00]

Re: STM32L все прерывания срабатывают по 2 раза

Добавлено: Пн апр 21, 2014 15:58:01
sx386
да, так пожалуй будет проще

Код: Выделить всё

 // очистка флага прерывания
   EXTI->PR |= EXTI_PR_PR0; 
   EXTI->PR;
хотя лишний такт всё же есть:

Код: Выделить всё

 173:         EXTI->PR; 
0x080006B4 6800      LDR      r0,[r0,#0x00]

Re: STM32L все прерывания срабатывают по 2 раза

Добавлено: Пн апр 21, 2014 17:12:00
HHIMERA
BorisSPB писал(а): Второй раз обращение к EXTI->PR чтобы инициировать буферизированную запись.
Ващета... для этого существуют барьеры...
sx386 писал(а):лишний такт всё же есть
В чём тайный смысл считать такты??? На коротких прерываниях так и будет... никуда не деться... а на длинных уже не существенно...

Re: STM32L все прерывания срабатывают по 2 раза

Добавлено: Пн апр 21, 2014 17:16:01
BorisSPB
Эта операция не лишняя, по крайней мере в FAQ написано чтобы инициировать отложенную буферизированную запись, надо прочитать регистр.
И еще операция |= лишняя, регистр PR доступен только для чтения, запись единицы вызывает сброс флага, так что достаточно EXTI->PR = EXTI_PR_PR0;.
HHIMERA писал(а):существуют барьеры...
Что за барьеры?

Re: STM32L все прерывания срабатывают по 2 раза

Добавлено: Пн апр 21, 2014 18:15:02
HHIMERA
http://infocenter.arm.com/help/index.js ... index.html
Эта операция не лишняя, по крайней мере в FAQ написано чтобы инициировать отложенную буферизированную запись, надо прочитать регистр.
В общем... там задержки в любом виде хватит... Вот пример из SPL... и не заморачиваются...

Код: Выделить всё

/**
  * @brief  This function handles External line 0 interrupt request.
  * @param  None
  * @retval None
  */
void EXTI0_IRQHandler(void)
{
  if(EXTI_GetITStatus(EXTI_Line0) != RESET)
  {
    /* Toggle LED1 */
     STM_EVAL_LEDToggle(LED1);

    /* Clear the  EXTI line 0 pending bit */
    EXTI_ClearITPendingBit(EXTI_Line0);
  }
}

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