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

Кто любит RISC в жизни, заходим, не стесняемся.
Ответить
Потрогал лапой паяльник
Аватара пользователя
Сообщения: 394
Зарегистрирован: Сб апр 28, 2012 16:04:14

Сообщение 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;  // понижение
Критикуешь - предлагай. Предлагаешь - делай. Делаешь - отвечай.
Реклама
Прорезались зубы
Аватара пользователя
Сообщения: 232
Зарегистрирован: Вт май 08, 2012 10:42:29

Сообщение optima »

Попробуй по входу в прерывание сразу сбросить флаг, а после все то что тебе нужно!
Реклама
Встал на лапы
Сообщения: 145
Зарегистрирован: Ср фев 01, 2012 10:55:53

Сообщение BorisSPB »

Вообще-то STM32 любят делать так:

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

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

    EXTI_ClearITPendingBit(EXTI_Line0);
  }
}
Прорезались зубы
Аватара пользователя
Сообщения: 232
Зарегистрирован: Вт май 08, 2012 10:42:29

Сообщение optima »

Ну если лишние телодвижения не напрягают можно и так!
Реклама
Эиком - электронные компоненты и радиодетали
Потрогал лапой паяльник
Аватара пользователя
Сообщения: 394
Зарегистрирован: Сб апр 28, 2012 16:04:14

Сообщение sx386 »

Записал сброс флага в начало.
Работает, но непойму почему так !

Прерывание вызывается. В нём сбрасывается флаг и продолжается выполнение обработчика прерывания.
В этот момент это же прерывание вызывается ещё раз ! И что дальше ?
Критикуешь - предлагай. Предлагаешь - делай. Делаешь - отвечай.
Реклама
Прорезались зубы
Аватара пользователя
Сообщения: 232
Зарегистрирован: Вт май 08, 2012 10:42:29

Сообщение optima »

Флаг не успевает сбросится и по завершению всех действий в прерывании, возвращается на начало прерывания!
Реклама
Встал на лапы
Сообщения: 145
Зарегистрирован: Ср фев 01, 2012 10:55:53

Сообщение BorisSPB »

Да, вот так делаешь что-то, вроде работает, а потом выясняется что это дурной тон :oops: (это я про свой способ).
На эту тему оказывается даже FAQ есть...
Потрогал лапой паяльник
Аватара пользователя
Сообщения: 394
Зарегистрирован: Сб апр 28, 2012 16:04:14

Сообщение 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]");
Критикуешь - предлагай. Предлагаешь - делай. Делаешь - отвечай.
Встал на лапы
Сообщения: 145
Зарегистрирован: Ср фев 01, 2012 10:55:53

Сообщение 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]
Потрогал лапой паяльник
Аватара пользователя
Сообщения: 394
Зарегистрирован: Сб апр 28, 2012 16:04:14

Сообщение sx386 »

да, так пожалуй будет проще

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

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

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

 173:         EXTI->PR; 
0x080006B4 6800      LDR      r0,[r0,#0x00]
Критикуешь - предлагай. Предлагаешь - делай. Делаешь - отвечай.
Друг Кота
Сообщения: 4583
Зарегистрирован: Вс дек 05, 2010 06:10:34
Откуда: ЮВ

Сообщение HHIMERA »

BorisSPB писал(а): Второй раз обращение к EXTI->PR чтобы инициировать буферизированную запись.
Ващета... для этого существуют барьеры...
sx386 писал(а):лишний такт всё же есть
В чём тайный смысл считать такты??? На коротких прерываниях так и будет... никуда не деться... а на длинных уже не существенно...
"Я не даю готовых решений, я заставляю думать!"(С)
Встал на лапы
Сообщения: 145
Зарегистрирован: Ср фев 01, 2012 10:55:53

Сообщение BorisSPB »

Эта операция не лишняя, по крайней мере в FAQ написано чтобы инициировать отложенную буферизированную запись, надо прочитать регистр.
И еще операция |= лишняя, регистр PR доступен только для чтения, запись единицы вызывает сброс флага, так что достаточно EXTI->PR = EXTI_PR_PR0;.
HHIMERA писал(а):существуют барьеры...
Что за барьеры?
Друг Кота
Сообщения: 4583
Зарегистрирован: Вс дек 05, 2010 06:10:34
Откуда: ЮВ

Сообщение 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);
  }
}

А так... при кодинге думку нужно включать... сбрасывать флаг сразу или в конце... это уже по задаче... И что толку считать такты, если оно уже не работает или потом случайно может глюкануть...
"Я не даю готовых решений, я заставляю думать!"(С)
Ответить

Вернуться в «ARM»