Na FreeHostingu Endora běží desítky tisíc webů. Přidejte se ještě dnes!

Vytvořit web zdarma

Na FreeHostingu Endora běží desítky tisíc webů. Přidejte se ještě dnes!

Vytvořit web zdarma

logo stV tomto článku se podíváme na poměrně užitečnou věc a to přerušení. Přerušení je nedílnou součástí číslicové elektroniky a jeho použití značně ulehčuje ošetření některých situací nebo vykonání určitých úkonů v co nejkratším čase od vzniku požadavku.

Jak se přerušení chová je dáno jádrem ARM a proto přesnější popis přerušení najdeme v dokumentaci k jádru ARM. NVIC se dá volně přeložit jako řadič vektorů vnořených přerušení. To znamená že ARM umožňuje nastavovat priority konkrétním přerušením, podle kterých jsou vykonávány.

STM32F4xx využívá 82 kanálů přerušení a všem přerušením lze nastavit prioritu od 0 do 16 (jsou využity 4 bity pro prioritu (ARM umožňuje využít 8 bitů pro prioritu, ale u STM32F4xx nejsou využity všechny)).

Nastavení priorit má výhodu v tom, že se vždy vykonává rutina přerušení s vyšší prioritou. Důležité je poznamenat, že čím nižší číslo priority, tím větší má přerušení prioritu. Tedy pokud nastane přerušení A s prioritou 1 a po nějakém čase i přerušení B s prioritou 0, tak se rutina pro přerušení A pozastaví a pokračuje se v ní až po vykonání přerušení B. Naopak přerušení se stejnou nebo menší prioritou čekají na dokončení již probíhající rutiny přerušení.

Podívejme se na strukturu, kterou budeme využívat pro nastavení registrů (ta se nachází v souboru core_cm4.h):

typedef struct
{
  __IO uint32_t ISER[8];                 /*!< Offset: 0x000 (R/W)  Interrupt Set Enable Register           */
       uint32_t RESERVED0[24];
  __IO uint32_t ICER[8];                 /*!< Offset: 0x080 (R/W)  Interrupt Clear Enable Register         */
       uint32_t RSERVED1[24];
  __IO uint32_t ISPR[8];                 /*!< Offset: 0x100 (R/W)  Interrupt Set Pending Register          */
       uint32_t RESERVED2[24];
  __IO uint32_t ICPR[8];                 /*!< Offset: 0x180 (R/W)  Interrupt Clear Pending Register        */
       uint32_t RESERVED3[24];
  __IO uint32_t IABR[8];                 /*!< Offset: 0x200 (R/W)  Interrupt Active bit Register           */
       uint32_t RESERVED4[56];
  __IO uint8_t  IP[240];                 /*!< Offset: 0x300 (R/W)  Interrupt Priority Register (8Bit wide) */
       uint32_t RESERVED5[644];
  __O  uint32_t STIR;                    /*!< Offset: 0xE00 ( /W)  Software Trigger Interrupt Register     */
}  NVIC_Type;

 

 

ISER – Interrupt Set Enable Register

Pomocí tohoto registru povolujeme konkrétní přerušení. Každá periferie má své číslo přerušení (nebo i více pokud může generovat více přerušení), které najdeme v souboru stm32f4xx.h na řádcích 147 až 239. Takže například přerušení z časovače TIM7 má číslo 55. Pro povolení tohoto přerušení musíme nastavit 55. bit v registru ISER. Ten je řešen jako pole o velikosti 8x32 bit. Takže potřebujeme nastavit 55-32 = 23 bit v ISER[1].

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

 

ICER - Interrupt Clear Enable Register

S tímto registrem se zachází úplně stejně jako s registrem ISER. Jeho funkce je opačná. Nastavením příslušeného bitu přerušení zakážeme. Například pro zakázání přerušení od časovače TIM7 napíšeme:

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

 

ISPR - Interrupt Set Pending Register

Opět zacházení s registrem obdobné jako s předchozími registry. Díky tomuto registru mužeme „uměle“ generovat přerušení od libovolné periferie i když daná periferie, přerušení negenerovala.

 

ICPR - Interrupt Clear Pending Register

Opět zacházení s registrem obdobné jako s předchozími registry. Naopak od ISPR registru, pomocí tohoto registru můžeme rušit požadavky na přerušení. Takže pokud probíhá přerušení A a v pořadí čeká přerušení B, může pomocí tohoto registru přerušení B zrušit.

 

IABR - Interrupt Active bit Register

V tomto registru je vždy aktivní ten bit, jemuž odpovídá přerušení, které právě probíhá. Opět čtení nebo zápis je obdobný předchozím registrům.

 

IP - Interrupt Priority Register

Pomocí tohoto registru nastavujeme prioritu přerušení. I když se jedná o pole 240x8 bit, není celá šířka využita. Přerušeních je pouze 82 a prioritu lze nastavit jen 4 bity (horní 4 bity bytu, spodní 4 bity jsou ignorovány). Index pole odpovídá číslu přerušení. Takže pokud bychom chtěli dát nejnižší prioritu přerušení z časovače TIM7, napsali bychom:

NVIC->IP[TIM7_IRQn] = 0xF0;

 

Blikáme diodou s přerušením

Teď si rozblikáme diodu, ale nebudeme sledovat stav časovače. Místo toho povolíme přerušení a diodu budeme rozvěšet/zhášet v rutině přerušení.
K tomu použijeme příklad z minula. Nastavení GPIO je shodné (tedy piny 12, 13, 14 a 15 jako výstupní). Nastavení časovače je obdobné:

// Rreset casovace TIM7
RCC->APB1RSTR |= RCC_APB1RSTR_TIM7RST;
RCC->APB1RSTR &= ~RCC_APB1RSTR_TIM7RST;

// Povolení hodin pro casovac TIM7
RCC->APB1ENR |= RCC_APB1ENR_TIM7EN;

// Nastaveni
// Pozn.: casovac TIM6 je 16bit
TIM7->CR1 |= TIM_CR1_ARPE;   // Povoleni prednacteni auto-reload
TIM7->ARR = 65523;           // Auto-reload hodnota, pri ktere se ma citac resetovat
TIM7->PSC = 1281;            // Delicka hodinoveho signalu
TIM7->EGR = TIM_EGR_UG;      // Aktualizace (update event)
TIM7->SR = 0x0000;           // Vrácení status bitu na log 0
TIM7->DIER |= TIM_DIER_UIE;	 // povoleni generováni preruseni
TIM7->CR1 |= TIM_CR1_CEN;    // Spusteni casovace TIM6

// Povoleni preruseni
NVIC->ISER[TIM7_IRQn >> 0x05]  |= (0x01 << (TIM7_IRQn & 0x1F));

Změna je jen malá. Povolení generování signálu přerušení v registru TIM7_DIER. Dále je také potřeba povolit přerušení od časovače v registru NVIC. Tím jsme povolili generování přerušení. Vytváření funkcí, které se budou vykonávat při přerušení, je velice jednoduché. Stačí vytvořit funkci void s názvem přerušení, který najdeme v souboru startup_stm32f4xx.s (tam jsou vytvořeny všechny vektory přerušení) a vložit ji před funkci main:

void TIM7_IRQHandler(void)
{
	if(TIM7->SR & TIM_SR_UIF)    
	{
			if(GPIOD->ODR & GPIO_ODR_ODR_15)
					GPIOD->ODR &= ~GPIO_ODR_ODR_15;
			else
					GPIOD->ODR |= GPIO_ODR_ODR_15;
			TIM7->SR = 0x0000;                   // Vrácení status bitu na log 0
	}
}

 

Tato funkce se vykoná vždy, když nastane přerušení. To v našem případě nastane přibližně každou sekundu. Nesmíme zapomenou nulovat bity ve status registru TIM7_SR, jinak by další přerušení bylo generováno okamžitě po skončení prvního přerušení. Samotná funkce main pak vypadá stejně jako v minulém příkladě, jen smažeme obsah cyklu while.

while(1);

 

Závěr

Dnes jsme si ukázali jak jednoduše povolit a nastavit přerušení od periferie. Příště si ukážeme jak povolit a nastavit externí přerušení. Tedy přerušení generována při náběžné nebo sestupné hraně na nějakém GPIO portu/pinu.


Projekt ke stažení ZDE.


 

Komentáře  

 
0 # Clarence 2018-12-22 16:51
I benefit from looking through your websites. Thank you!


my web blog ... Dr Extenda: http://marirea-penisului-ro.eu/drextenda.html
Odpovědět | Odpovědět citací | Citovat