Кто любит RISC в жизни, заходим, не стесняемся.
Ответить

Как определить какой вход сгенерировал прерывание?

Ср июл 20, 2022 00:28:20

STM32CubeMX создал такой код:
Код:
void EXTI15_10_IRQHandler(void)
{
  /* USER CODE BEGIN EXTI15_10_IRQn 0 */
 
  /* USER CODE END EXTI15_10_IRQn 0 */
  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_13);
  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_14);
  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_15);
  /* USER CODE BEGIN EXTI15_10_IRQn 1 */

  /* USER CODE END EXTI15_10_IRQn 1 */
}

Как определить какой из входов сгенерировал прерывание?

Re: Как определить какой вход сгенерировал прерывание?

Ср июл 20, 2022 03:59:13

В обработчике прерываний смотреть какие флаги в регистрах поднялись? Не?

Re: Как определить какой вход сгенерировал прерывание?

Ср июл 20, 2022 10:00:22

Юрий48, а вот не нужно калом пользоваться. Достаточно документацию почитать. Если у вас F103, то есть регистры EXTI_EMR и EXTI_IMR, дающие возможность маскировать прерывания и события. Есть регистры EXTI_RTSR и EXTI_FTRS, позволяющие задать, на какой фронт реагировать: восходящий или нисходящий. А в EXTI_PR будут установлены в 1 те биты, которые события сработали.
Кроме того, прерывания на каждый бит этих регистров мультиплексируются от разных групп ног (скажем, PA0, PB0 и т.п. управляются младшим битом). Чтобы узнать, от какого порта GPIO сработало прерывание, можно воспользоваться регистром AFIO_EXTICRx (тоже, между прочим, в документации все есть).
За биты 10..15 отвечают регистры с x=3 и 4. Регистр GPIO обозначается группой из четырех бит. Т.е. если сработало EXTI_15_10, смотрим, что там у нас в EXTI_PR: ага, установлен бит 12 → прерывание сработало от 12-го пина какого-то регистра GPIO. Смотрим, что там в младшем квартете AFIO_EXTICR4, ага, там 0x2 → сработало прерывание от PC12. Вуаля!

Ну, точней несколько наоборот: чтобы задать, что вы в обработчике прерывания ждете события от PC12, вы должны в младший октет AFIO_EXTICR4 занести двойку. К сожалению, нет возможности настроить прерывания, скажем, сразу на PA12, PB12, PC12… Надо выбрать что-то одно. Правда, у STM32 достаточно богатая периферия, так что EXTI по сути бывают нужны крайне редко (лично я уж забыл, пользовался ли ими когда-либо вообще!).

Re: Как определить какой вход сгенерировал прерывание?

Ср июл 20, 2022 22:04:24

Eddy_Em, спасибо за разъяснения. В отладчике кейла пробую посмотреть, что делается в EXTI_PR при нажатии кнопок и ничего не увидел там меняющегося, хотя в регистре GPIOB_IDR реакция на нажатие кнопок адекватная. Решил поиграться с этим регистром в программе. Но не могу к нему обратиться, просто не знаю, как правильно сделать запись (не смешно). Сразу хочу спросить: а можно ли где посмотреть этот синтаксис, какая логика составление этих записей. Вообще то надо определять время нажатия кнопок, поэтому прерывание настроено на срабатывание по обоим фронтам. То есть надо не только определить какая кнопка сработала, но и что было - нажатие или отпускание - фронт. Понятно, что надо опрашивать регистр в цикле. Учитывая мой уровень знаний, лучшим вариантом было бы привести конкретный код, например, определения срабатывания конкретной кнопки.

Re: Как определить какой вход сгенерировал прерывание?

Ср июл 20, 2022 22:10:35

Юрий48, ну написано же все в RM!

Re: Как определить какой вход сгенерировал прерывание?

Ср июл 20, 2022 22:22:30

Eddy_Em, о каких RM идёт речь?

Re: Как определить какой вход сгенерировал прерывание?

Чт июл 21, 2022 10:49:04

Reference manual на ваш контроллер, очевидно

Re: Как определить какой вход сгенерировал прерывание?

Чт июл 21, 2022 12:08:42

Пользующиеся кубами как правило не знают что такое "Reference manual" и где его брать. :))

Re: Как определить какой вход сгенерировал прерывание?

Чт июл 21, 2022 13:24:26

Юрий48, из какой то сетевой шпаргалки (кажется, для F103), но EXTI вроде везде +/- одинаков....
Спойлер
Код:
/*******************
 * EXTI
 *******************/
/*
   AFIO->EXTICR[0..3]
   ----------
      В контроллере EXTI есть 19 линий внешних прерываний.
      Первые 16 мультиплексируются на биты физических портов МК, два оставшихся - на прерывания от
         PVD (программируемый датчик напряжения питания), RTC Alarm event и USB Wakeup event.
      На линию EXTI0  мультиплексируется бит  0 портов A,B,C,D,E,F,G
      На линию EXTI1  мультиплексируется бит  1 портов A,B,C,D,E,F,G
      .......
      На линию EXTI15 мультиплексируется бит 15 портов A,B,C,D,E,F,G
      За мультиплексирование отвечают регистры EXTICR1, EXTICR2, EXTICR3, EXTICR4 домена AFIO.
      В CMSIS они сгруппированы в массив EXTICR[0..3], но битовые константы оперируют литералами EXTICR1..EXTICR4
      AFIO->EXTICR[0..3]
      Регистор EXTICR[0] отвечает за биты  0,  1,  2,  3
      Регистор EXTICR[1] отвечает за биты  4,  5,  6,  7
      Регистор EXTICR[2] отвечает за биты  8,  9, 10, 11
      Регистор EXTICR[3] отвечает за биты 12, 13, 14, 15
      Соответствено, что бы  настроить мультиплексирование соответствующего бита порта в контроллер EXTI, необходимо
      включить тактирование альтернативных функций AFIOEN:     RCC->APB2ENR |= RCC_APB2ENR_AFIOEN;
         EXTIx[3:0]: EXTI x configuration,
         где   x=0..3 для регистра AFIO_EXTICR1;
            x=4..7 для регистра AFIO_EXTICR2;
            x=8..11 для регистра AFIO_EXTICR3;
            x=12..15 для регистра AFIO_EXTICR4.
         Биты (битовые поля) модифицируются программно и используются для выбора источника сигнала для линии
         внешнего прерывания EXTIx, x=0..15. В зависимости от значения битового поля, используется вход одного
         из портов ввода/вывода микроконтроллера (GPIO):
         0000: PA[x] вывод микроконтроллера;
         0001: PB[x] вывод микроконтроллера;
         0010: PC[x] вывод микроконтроллера;
         0011: PD[x] вывод микроконтроллера;
         0100: PE[x] вывод микроконтроллера;
         0101: PF[x] вывод микроконтроллера;
         0110: PG[x] вывод микроконтроллера.

      В CMSIS уже есть готовые константы для битовых полей:
      AFIO_EXTICRx_EXTInn - маска битов для прерывания nn в регистре EXTICRx
      AFIO_EXTICRx_EXTInn_PA - v
      AFIO_EXTICRx_EXTInn_PB - v
      AFIO_EXTICRx_EXTInn_PC - v
      AFIO_EXTICRx_EXTInn_PD - v
      AFIO_EXTICRx_EXTInn_PE - v
      AFIO_EXTICRx_EXTInn_PF - v
      AFIO_EXTICRx_EXTInn_PG - готовые битовые маски для портов A..G
         (помним nn=0..3->x=1, nn=4..7->x=2, nn=8..11->x=3,nn=12..15->x=4)

   Регистры контроллера внешних прерываний EXTI

   EXTI->IMR       Interrupt mask register - Регистр маски прерываний
   ---------
   MR18   MR17   MR16
   MR15   MR14   MR13   MR12   MR11   MR10   MR9      MR8
   MR7      MR6      MR5      MR4      MR3      MR2      MR1      MR0
   ----------
   Разрешение или запрет контроллеру EXTI генерацию прерываний (для каждой линии имеется отдельный бит разрешения).
      MRx: Interrupt Mask on line x, x=0..17 - Бит, разрешающей генерацию прерываний от соответствующей линии EXTI:
         0: не формируются запросы на прерывание от соответствующей линии EXTIx;
         1: разрешается формировать запросы на прерывание от соответствующей линии EXTIx.

   EXTI->EMR       Event mask register - Регистр маски событий пробуждения
   ---------
   MR18 ..... MR0
   ----------
      Разрешение или запрет контроллеру EXTI генерацию событий (для каждой линии имеется отдельный бит разрешения).
      MRx: Event mask on line x, x=0..18 - Бит, разрешающей генерацию событий от соответствующей линии EXTI:
         0: не формируются сигналы события от соответствующей линии EXTIx;
         1: разрешается формировать сигналы события от соответствующей линии EXTIx

   EXTI->RTSR      Rising trigger selection register  - Регистр выбора линий EXTI, запускаемых нарастающим входным сигналом.
   EXTI->FTSR       Falling trigger selection register - Регистр выбора линий EXTI, запускаемых спадающим входным сигналом.
   ----------
   TR18 ..... TR0
   ----------
      TRx: Rising trigger event configuration bit of line x=0..18 - Бит определяет, что на входной линии x
         контроллера EXTI требуется обнаруживать нарастающий фронт сигнала:
         0: отключён запуск нарастающим фронтом (как для прерываний, так и для событий) для данной линии;
         1: включён запуск нарастающим фронтом (как для прерываний, так и для событий) для данной линии.
      TRx: Falling trigger event configuration bit of line x, x=0..18 - Бит определяет, что на входной линии x
         контроллера EXTI требуется обнаруживать спадающий фронт сигнала:
         0: отключён запуск спадающим фронтом (как для прерываний, так и для событий) для данной линии;
         1: включён запуск спадающим фронтом (как для прерываний, так и для событий) для данной линии.

   EXTI->SWIER      Software interrupt event register - Регистр для программной генерации прерываний и событий EXTI.
   ----------
   SWIER18   ..... SWIER0
   ----------
      SWIERx: Software interrupt on line x, x=0..17
         Запись 1 в этот бит, когда он содержит 0, приводит к установке соответствующего отложенного
         бита в регистре EXTI_PR (если разрешено регистром маски EXTI_IMR). Если прерывания для
         данной линии разрешены, генерируется запрос на прерывание.
         Бит сбрасывается при сбросе соответствующего бита в регистре EXTI_PR, который, в свою
         очередь, сбрасывается записью 1 в этот бит.

   EXTI->PR      Pending register - Регистр отложенных прерываний
   --------
   PR18 ..... PR0
   ----------
      PRx: Pending bit - Бит отложенного прерывания:
         0: не генерировалось запросов на прерывание;
         1: произошла генерация запроса на прерывание.
         Этот бит устанавливается при обнаружении отслеживаемого фронта входного сигнала на внешней линии.
         Бит сбрасывается путём записи 1 в этот бит.

   Вектора прерываний (описаны в startup_stm32f103xb.s):
   EXTI0_IRQHandler      Прерывание от линии 0 EXTI
   EXTI1_IRQHandler      Прерывание от линии 1 EXTI
   EXTI2_IRQHandler      Прерывание от линии 2 EXTI
   EXTI3_IRQHandler      Прерывание от линии 3 EXTI
   EXTI4_IRQHandler      Прерывание от линии 4 EXTI
   EXTI9_5_IRQHandler      Прерывание от линий [9:5] EXTI
   EXTI15_10_IRQHandler   Прерывание от линий [15:10] EXTI
      Внутри обработчика прерывания необходимо проверить, какая линия была виновником вызова прерывания.
      Это делается проверкой битов в регистре EXTI_PR.
      Так же необходимо сбросить бит прерывания, записав в этот бит 1.

   Кроме разрешения прерывания в регистрах контроллера EXTI еше необходимо разрешить соответствующие прерывания
   в контроллере NVIC: NVIC_EnableIRQ(nnn);
   Тут nnn - имя вектора прерываний (определены в stm32f103xb.h)
      PVD_IRQn              - PVD through EXTI Line detection Interrupt
      EXTI0_IRQn            - EXTI Line0 Interrupt
      EXTI1_IRQn            - EXTI Line1 Interrupt
      EXTI2_IRQn            - EXTI Line2 Interrupt
      EXTI3_IRQn            - EXTI Line3 Interrupt
      EXTI4_IRQn            - EXTI Line4 Interrupt
      EXTI9_5_IRQn          - External Line[9:5] Interrupts
      EXTI15_10_IRQn        - External Line[15:10] Interrupts
*/

// обработчик прерывания
void EXTI15_10_IRQHandler(void) {
   if (EXTI->PR & EXTI_PR_PIF12) {
      EXTI->PR |= EXTI_PR_PIF12;
   // нужное нам действие
   }
}

// настройка прерывания
   //GPIO_B12 - key
   RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;
   GPIOB->CRH &= ~(GPIO_CRH_MODE12_Msk | GPIO_CRH_CNF_Msk); // input
   GPIOB->CRH |= GPIO_CRH_CNF12_1;   // with pull resistor
   GPIOB->ODR |= GPIO_ODR_ODR12;   // pull to UP
   // EXTI
   RCC->APB2ENR |= RCC_APB2ENR_AFIOEN;
   AFIO->EXTICR[3] &= ~AFIO_EXTICR4_EXTI12;      // мапим EXTI12
   AFIO->EXTICR[3] |=  AFIO_EXTICR4_EXTI12_PB;      // на порт B (GPIO_B_12)
   EXTI->IMR |= EXTI_IMR_IM12;      // прерывание от IO_B12
   EXTI->RTSR |= EXTI_RTSR_RT12;   // по нарастающему фронту (Rising)
   EXTI->FTSR |= EXTI_FTSR_FT12;   // по спадающему фронту (Falling)
   NVIC_EnableIRQ(EXTI15_10_IRQn);

Re: Как определить какой вход сгенерировал прерывание?

Вс июл 24, 2022 12:05:22

Отвечу на первоначальный вопрос, если конечно еще актуально.

В ваш код необходимо вставить функцию, которую будет вызывать HAL при срабатывании прерывании по GPIO:
Код:
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
  if (GPIO_Pin == GPIO_PIN_13) {
     // Сработало прерывание на 13 пине.
     // Aналогичные проверки можно сделать и для остальных пинов.
  }
}

где, GPIO_Pin - пин на котором сработало прерывание.

Re: Как определить какой вход сгенерировал прерывание?

Ср сен 07, 2022 10:12:09

Пользующиеся кубами как правило не знают что такое "Reference manual" и где его брать. :))

Я пользуюсь STM32CubeIDE и прекрасно знаю что такое RM.
И не пользуюсь всякими халами и прочим, только CMSIS.
Дело не в Кубе, а в ардуриноподходе.

Re: Как определить какой вход сгенерировал прерывание?

Ср сен 07, 2022 10:23:52

Пользующиеся кубами как правило не знают что такое "Reference manual"

А при чём здесь собственно "куб"? IDE появились только в этом веке. В прошлом веке для МК вообще всё на ассемблерах писалось. Но RM тогда существовали. Просто их кто-то изучал, а кто-то нет, а кто-то и вовсе не знал о их существовании.
Ответить