logo stV tomto článku budeme opět blikat diodou. Ovšem pomocí externího přerušení. Podíváme se na jeho nastavení a použití.

Externí přerušení  je třeba ve chvílích, kdy k MCU připojíme nějaký další obvod a je třeba reagovat co nejrychleji na jeho činnost (třeba tlačítko :D). Ale pozor, k řadiči externího přerušení jsou připojeny také periferie RTC, USB OTG nebo Ethernet.

Řadič externího přerušení má 23 kanálů. Je tedy možné vytvořit až 23 různých přerušení. Prvních 16 kanálů je určeno portům GPIO. Lze tedy libovolný pin libovolného GPIO připojit na jeden kanál, ale bohužel s malým omezením. Ke kanálu 0 lze připojit jen nulté piny a jen jednoho GPIO (tedy pokud na kanál 0 napojím GPIOA, pak bude přerušení na kanálu 0 generovat změna na pinu PA0, žádný jiný nultý pin), ke kanálu 1 lze připojit jen první piny a jen jednoho GPIO (tedy pokud na kanál 1 napojím GPIOF, bude přerušení na kanálu 1 generovat změna na pinu AF1, žádný jiný první pin), a tak dále až do kanálu 15. Co z toho plyne? Že pokud nastavíme generování přerušení z pinu PB2, již nelze použít k externímu přerušení pin PA2, ani PC2, ani PD2, ani žádný další pin 2 libovolného portu.

Zbytek kanálů je přiřazen následovně:

  • EXTI 16 – PVD output
  • EXTI 17 – RTC Alarm event
  • EXTI 18 – USB OTG FS Wakeup
  • EXTI 19 – Ethernet Wakeup
  • EXTI 20 – USB OTG HS Wakeup
  • EXTI 21 – RTC Tamper and TimeStamp
  • EXTI 22 – RTC Wakeup


System configuration controller (SYSCFG)

Jedná se o periferii starající se o nastavení některých dalších vlastností. Nebude podrobně probírat jaké nastavení obsahuje. Nám stačí vědět, že obsahuje část nastavení externího přerušení. Konkrétně nastavení jaký pin bude připojený na daný kanál. V základním nastavení je vždy pin portu A připojen na kanál. Tedy například ke kanálu 0 jen připojen PA0, ke kanálu 1 je připojen PA1 atd. Pomocí registrů SYSCFG_EXTICRx lze toto změnit, například aby na kanál 0 byl připojen PB0. Pro toto nastavení existují čtyři registry. Programově je to řešeno jako pole, kde příslušný registr volíme indexem. Každý registr obsahuje nastavení pro 4 kanály.
 

syscfg_exticr1
Obr. 1: Registr SYSCFG_EXTICR1.

Na obrázku 1 je vidět registr SYSCFG_EXTICR1, ale stejně vypadají i další 3 registry. Je i vidět že k určení pinu slouží 4 bity. Jejich kombinace a volba pinu je následovná:

  • 0000 - PA[x] pin
  • 0001 - PB[x] pin
  • 0010 - PC[x] pin
  • 0011 - PD[x] pin
  • 0100 - PE[x] pin
  • 0101 - PF[x] pin
  • 0110 - PG[x] pin
  • 0111 - PH[x] pin
  • 1000 - PI[x] pin

Než něco dále vysvětlovat uvedu dva příklady. Prvním nastavuji na kanál 0 pin PA0.

SYSCFG->EXTICR[0] = 0x0000;
//nebo
SYSCFG->EXTICR[0] = SYSCFG_EXTICR1_EXTI0_PA;


V druhém příkladu nastavuji na kanál 5 pin PC5.

SYSCFG->EXTICR[1] = 0x0020;
//nebo
SYSCFG->EXTICR[1] = SYSCFG_EXTICR2_EXTI5_PC;

 

EXTI registry

IMR - Interrupt mask register

Jedná se o 32bit registr, ale je využito pouze 23 prvních bitů. Každý bit odpovídá jednomu kanálu. Logická jednička na příslušné pozici povoluje generování přerušení daného kanálu.


EMR - Event mask register

Opět se jedná o 32bit registr, ale je využito jen 23 prvních bitů. Každý bit odpovídá jednomu kanálu. Jeho nastavování je stejné jako u registru IMR. Nastavením logické jedničky povolíme generování události.


RTSR - Rising trigger selection register

Opět 32bit registr s použitelnými 23 bity, kde pozice každého bitu odpovídá danému kanálu. Nastavením příslušného bitu do logické jedničky říkáme, že na daném kanálu chceme generovat přerušení při náběžné hraně.


FTSR - Falling trigger selection register

Obdobný registr jako předešlý a stejně se používá. Ovšem nastavením bitu na log 1 říkáme, že chceme generovat přerušení při sestupné hraně.

(Pozn.: Lze nastavit, aby na jednom kanálu bylo generováno přerušení na obě hrany nastavením log 1 v obou registrech – RTSR i FTSR.)


SWIER - Software interrupt event register

Opět 32bit registr s 23 použitelnými bity. Tímto registrem lze softwarově vytvořit požadavek na přerušení konkrétního kanálu.


PR - Pending register

Kupodivu opět 32bit registr s 23 použitelnými bity. Tento registr plní dvě úlohy. Při vzniku přerušení je zde nastaven bit toho kanálu, jež přerušení vyvolal. Po dokončení rutiny přerušení je ale třeba žádost o přerušení zrušit, jinak by bylo přerušení generováno ihned znova. Ovšem rušení požadavku se dělá zápisem log 1 na příslušném bitu (čekal bych log 0, ale opravdu je to log 1).


Blikáme diodou už poněkolikáté

Je to nuda, chápu. Pořád jen blikáme :D. Tentokrát, ale budeme diodu rozsvěcet a zhášet, sice tlačítkem, pomocí externího přerušení. Tak začneme (připomínám, že tlačítko je na PA0 a modrá dioda na PD15). Nastavit GPIO už umíme, takže nastavíme PD15 jako výstupní a PA0 jako vstupní.

Nejprve nastavíme řadič SYSCFG.

// Povoleni hodin pro radic SYSCFG
RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN;
// Reset radice SYSCFG
RCC->APB2RSTR |= RCC_APB2RSTR_SYSCFGRST;
RCC->APB2RSTR &= ~RCC_APB2RSTR_SYSCFGRST;
// Nastaveni v registru SYSCFG_EXTIx
SYSCFG->EXTICR[0] = SYSCFG_EXTICR1_EXTI0_PA;	// Ke kanalu 0 pripojit PA0


První část známe. Povolíme hodiny a resetujeme periferii. Dále pak zápisem do registru SYSCFG_EXTICR1 (to je registr v poli s indexem 0) nastavíme že na kanál 0 bude připojen pin PA0. Dále nastavíme registry externího přerušení.

EXTI->IMR = EXTI_IMR_MR0;		// Maskovani, povoleni kanalu 0
EXTI->RTSR = EXTI_RTSR_TR0;		// Preruseni generovat pri nabezne hrane


Zápisem do registru IMR povolujeme generování přerušení na kanálu 0. Do registru RTSR ukládáme nastavení, aby přerušení bylo generováno při náběžné hraně (pokud chcete, můžete si nastavit i reakci na sestupnou hranu).

Právě máme tedy nastaveno, že přerušení se bude generovat na PA0 (tedy kanál 0, který jsme povolili) a jen při náběžné hraně. Teď je třeba ještě povolit přerušení v NVIC.

NVIC->ISER[EXTI0_IRQn >> 0x05]  |= (0x01 << (EXTI0_IRQn & 0x1F));


Nakonec vytvořit funkci pro obsluhu přerušení, což známe už z předchozích článků.

void EXTI0_IRQHandler(void)
{
	GPIOD->ODR ^= GPIO_ODR_ODR_15;
	EXTI->PR |= EXTI_PR_PR0;

	return;
}


Takže nakonec používání externího přerušení není nijak obtížné. Je třeba nastavit jaký pin, jaký kanál, povolit přerušení v EXTI a NVIC, napsat funkci pro obsluhu a to je vlastně vše. Na závěr sem dám celý kód programu.

#include <stm32f4xx.h>

void init(void)
{
	/* GPIOA init ----------------------------------------------------------------------------*/
	// Reset portu GPIA
	RCC->AHB1RSTR |= RCC_AHB1RSTR_GPIOARST;
	RCC->AHB1RSTR &= ~(RCC_AHB1RSTR_GPIOARST);
	// Povoleni hodin pro GPIOA
	RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
	// Nastaveni modu
	GPIOA->MODER |= 0x0;	//pin 0 jako vstupní	
	
	/* GPIOD init ----------------------------------------------------------------------------*/
	// Reset portu GPID
	RCC->AHB1RSTR |= RCC_AHB1RSTR_GPIODRST;
	RCC->AHB1RSTR &= ~(RCC_AHB1RSTR_GPIODRST);
	// Povoleni hodin pro GPIOD
	RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN;
	// Nastaveni modu
	GPIOD->MODER |= GPIO_MODER_MODER15_0; //pin 15 jako výstupní
	
	/* SYSCFG init ---------------------------------------------------------------------------*/
	// Povoleni hodin pro radic SYSCFG
	RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN;
	// Reset radice SYSCFG
	RCC->APB2RSTR |= RCC_APB2RSTR_SYSCFGRST;
	RCC->APB2RSTR &= ~RCC_APB2RSTR_SYSCFGRST;
	// Nastaveni v registru SYSCFG_EXTIx
	SYSCFG->EXTICR[0] = SYSCFG_EXTICR1_EXTI0_PA;	// Ke kanalu 0 pripojit PA0
	
	/* EXTI init -----------------------------------------------------------------------------*/
	EXTI->IMR = EXTI_IMR_MR0;			// Maskovani, povoleni kanalu 0
	EXTI->RTSR = EXTI_RTSR_TR0;		// Preruseni generovat pri nabezne hrane	
	
	/* Iterrupt init -------------------------------------------------------------------------*/
	NVIC->ISER[EXTI0_IRQn >> 0x05]  |= (0x01 << (EXTI0_IRQn & 0x1F));

	return;
}

void EXTI0_IRQHandler(void)
{
	GPIOD->ODR ^= GPIO_ODR_ODR_15;	// invertuj stav na pinu 15
	EXTI->PR |= EXTI_PR_PR0;	// nuluj pozadavek na preruseni
	
	return;
}

int main(void)
{
	init();
			
	while(1);
}

 

Závěr

Odedneška umíme používat externí přerušení. Pokud pracujeme s dotykovým panelem, tak má vyvedený signál indikující, že došlo k dotyku a právě zde se dá externí přerušení například použít. O čem bude příští článek ještě nevím, ale určitě to bude zajímavé a užitečné :D.


Projekt ke stažení ZDE.


 

Komentáře  

 
0 # hexdump 2014-01-08 16:02
Ahoj, docela jsem se těšil na nový díl seriálku a nějak se to zadrhlo. Bude pokračování nebo si mám raději najít jiný zdroj informací?
Odpovědět | Odpovědět citací | Citovat
 
 
0 # Prahs 2014-02-24 22:00
Tak konečně nový díl seriálu (joudove.8u.cz/index.php?option=com_content&view=article&id=32:stm32f4tutorial-08-usart&catid=13&Itemid=152) a budu se snažit vydávat s menšími prodlevami.
Odpovědět | Odpovědět citací | Citovat
 
 
0 # Prahs 2014-01-09 19:16
Zdravím, určitě bych rád pokračoval. Omluvám se za prostoje mezi články. Hned jak mi to především škola :-* dovolí se pustím do pokračování.
Odpovědět | Odpovědět citací | Citovat
 
 
0 # hexdump 2014-01-10 12:43
Jo, tak to je dobrá zpráva :-).
Nešel by ke každému článku dát link na stažení zdrojáků?
Odpovědět | Odpovědět citací | Citovat
 
 
0 # Prahs 2014-01-10 15:40
Uvidím co dá udělat, když si v projektech udělám pořádek nejspíš bych mohl. Jen nevím zda dát ke stažení jen zdrojové soubory nebo raději celý projekt v Keilu včetně všech knihoven (tam by pak mohl být problém, že každý má jinou verzi a někdo ani Keil nepoužívá). Každopádně díky za dobrou připomínku/otáz ku :-) .
Odpovědět | Odpovědět citací | Citovat
 
 
+1 # hexdump 2014-01-10 18:21
Celý seriál je o Keilu takže by já bych se přimlouval za celý projekt. Ale to je jen můj názor.
Odpovědět | Odpovědět citací | Citovat
 
 
+3 # Prahs 2014-01-14 14:28
Tak jsem přidal ke všem dosavadním článkům celý projekt ke stažení. Kontroloval jsem projekty narychlo, tak snad tam nejsou chyby.
Odpovědět | Odpovědět citací | Citovat