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

Кто любит RISC в жизни, заходим, не стесняемся.
Ответить
Юрий48
Открыл глаза
Сообщения: 40
Зарегистрирован: Сб мар 20, 2021 23:31:54

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

Сообщение Юрий48 »

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 */
}
Как определить какой из входов сгенерировал прерывание?
Реклама
Аватара пользователя
Asmodey
Друг Кота
Сообщения: 6275
Зарегистрирован: Сб янв 28, 2006 22:47:24

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

Сообщение Asmodey »

В обработчике прерываний смотреть какие флаги в регистрах поднялись? Не?
Астролябия-сама меряет, было бы что мерять!!!
Реклама
Аватара пользователя
Eddy_Em
Собутыльник Кота
Сообщения: 2516
Зарегистрирован: Пт июл 12, 2019 22:52:01
Контактная информация:

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

Сообщение Eddy_Em »

Юрий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 по сути бывают нужны крайне редко (лично я уж забыл, пользовался ли ими когда-либо вообще!).
Linux rules! Windows must die. Здравомыслящий человек добровольно будет пользоваться мастдаем лишь в двух случаях: под дулом автомата или под влиянием анального зонда.
Я на гитхабе, в ЖЖ
Юрий48
Открыл глаза
Сообщения: 40
Зарегистрирован: Сб мар 20, 2021 23:31:54

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

Сообщение Юрий48 »

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

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

Сообщение Eddy_Em »

Юрий48, ну написано же все в RM!
Linux rules! Windows must die. Здравомыслящий человек добровольно будет пользоваться мастдаем лишь в двух случаях: под дулом автомата или под влиянием анального зонда.
Я на гитхабе, в ЖЖ
Реклама
Юрий48
Открыл глаза
Сообщения: 40
Зарегистрирован: Сб мар 20, 2021 23:31:54

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

Сообщение Юрий48 »

Eddy_Em, о каких RM идёт речь?
Реклама
Аватара пользователя
COKPOWEHEU
Говорящий с текстолитом
Сообщения: 1525
Зарегистрирован: Чт июн 10, 2010 20:11:19

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

Сообщение COKPOWEHEU »

Reference manual на ваш контроллер, очевидно
jcxz
Мудрый кот
Сообщения: 1717
Зарегистрирован: Вт авг 15, 2017 10:51:13

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

Сообщение jcxz »

Пользующиеся кубами как правило не знают что такое "Reference manual" и где его брать. :))
Аватара пользователя
Just_Fluffy
Вымогатель припоя
Сообщения: 532
Зарегистрирован: Ср июн 29, 2022 16:25:45

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

Сообщение Just_Fluffy »

Юрий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);
Белая и Пушистая
Аватара пользователя
4airy
Родился
Сообщения: 7
Зарегистрирован: Вс июл 24, 2022 11:42:22

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

Сообщение 4airy »

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

В ваш код необходимо вставить функцию, которую будет вызывать HAL при срабатывании прерывании по GPIO:

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

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { 
  if (GPIO_Pin == GPIO_PIN_13) {
     // Сработало прерывание на 13 пине.
     // Aналогичные проверки можно сделать и для остальных пинов.
  }
}
где, GPIO_Pin - пин на котором сработало прерывание.
spongebob
Грызет канифоль
Сообщения: 289
Зарегистрирован: Пт мар 20, 2009 12:25:47
Откуда: Ivanovo
Контактная информация:

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

Сообщение spongebob »

[uquote="jcxz",url="/forum/viewtopic.php?p=4262863#p4262863"]Пользующиеся кубами как правило не знают что такое "Reference manual" и где его брать. :))[/uquote]
Я пользуюсь STM32CubeIDE и прекрасно знаю что такое RM.
И не пользуюсь всякими халами и прочим, только CMSIS.
Дело не в Кубе, а в ардуриноподходе.
Аватара пользователя
electroget
Друг Кота
Сообщения: 4651
Зарегистрирован: Ср сен 30, 2020 16:51:47
Откуда: РФ

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

Сообщение electroget »

[uquote="jcxz",url="/forum/viewtopic.php?p=4262863#p4262863"]Пользующиеся кубами как правило не знают что такое "Reference manual"[/uquote]
А при чём здесь собственно "куб"? IDE появились только в этом веке. В прошлом веке для МК вообще всё на ассемблерах писалось. Но RM тогда существовали. Просто их кто-то изучал, а кто-то нет, а кто-то и вовсе не знал о их существовании.
Ответить

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