Undantag, avbrott Avsnitt 7 Undantag, avbrott Inledning Processorn befinner sig normalt i Threade-mode, utförandes ett program. Om något exceptionellt inträffar, kallar vi detta ett undantag. Eftersom undantag utförs under speciella omständigheter övergår processorn till Handler mode. Läs igenom följande i "STM32F4xx Cortex M4 programming manual": Avsnitt 2.3 (sidor 36-43), om "Exceptions" Avsnitt 4.3 (sidor 194-205), om "Nested Vectored Interrupt Controller" NVIC. Avsnitt 4.4 (sidor 206-227) översiktligt, om "System Control Block", SCB. Läs igenom följande i "STM32F407 reference manual": Avsnitt 12 (sidor 368-384), om "Interrupts and events" Avsnitt 9 (sidor 286-298) översiktligt, om "System Configuration Controller", SYSCFG. 103
Arbetsbok för MD407 Undantagsvektorer Vektortabellen beskriver hur undantagsvektorerna organiseras i minnet. Den inbördes ordningen är alltid den samma och varje vektor innehåller startadressen till undantagets hanteringsrutin, här återges bara en liten del av tabellen. Vid RESET är vektortabellen placerad i flashminne, dvs. icke skrivbart minne. Dessa kan då endast ändras genom att man programmerar om minnesinneållet. En alternativ startadress för vektortabellen kan anges i registret VTOR i SCB, vi säger då att tabellen relokerats (flyttats). I MD407 är vektortabellen relokerad till adress 0x2001C000, vilket innebär att den finns i skrivbart minne och alltså kan ändras utan speciell programmeringsutrustning. 104
Undantag, avbrott Externa avbrott Avbrott från yttre enheter kan kopplas via någon av den många IO-pinnarna hos processorn. Detta innebär alltså att det inte finns någon speciell pinne hos processorn utan praktiskt taget en godtycklig pinne kan användas som avbrottsingång. Avbrottsingångar konfigureras i tre steg SYSCFG-modulen används för att koppla en GPIO-pinne från någon port till en specifik avbrottsvektor. Detta görs via något av registren SYSCFG_EXTICRx. EXTI-modulen (External interrupt/event controller) programmeras, här måste man ettställa den bit i modulens mask-register (EXTI_IMR) som motsvarar den använda avbrottsvektorn. Man måste också programmera trigger-registren där man anger om avbrott ska generas på negativ flank (EXTI_FTSR) eller positiv plank (EXTI_RTSR) eller rentav av båda flanker. NVIC-modulen (Nested vecored interrupt controller) programmeras för att hantera avbrott från denna avbrottsvektor (NVIC_ISERx). Figur: Konfigurering "Avbrottslina" till avbrottsystemet Översikt SYSCFG Register offset 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 Register 0 SYSCFG_MEMRMP 4 SYSCFG_PMC 8 SYSCFG_EXTICR1 0xC SYSCFG_ EXTICR2 0x10 SYSCFG_ EXTICR3 0x14 SYSCFG_ EXTICR4 0x20 SYSCFG_ CMPCR Figur: Registeruppsättning SYSCFG Vi koncentrerar oss här på de register som används för avbrottshanteringen och beskriver därför först bara de övriga( MEMRMP, PMC och CMPCR) översiktligt. 105
Arbetsbok för MD407 SYSCFG_MEMRMP (0x40013800) Memory remap register Registret används för att konfigurera adressutrymmet från adress 0 och uppåt. Normalt sett används de båda BOOT-pinnarna på kretsen för detta men med detta register kan det även göras i mjukvara. För MD407 gäller att FLASH-minnet, med startadress 0x08000000 dubbelavbildas från adress 0 och uppåt. SYSCFG_PMC (0x40013804) Peripheral mode configuration register offset 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 Register 4 R_SEL ADCxDC2 SYSCFG_PMC rw rw rw rw Används för att konfigurera de fysiska egenskaperna hos Ethernet-gränssnittet (R_SEL) och välja funktion hos AD-omvandlare. Se tillverkarens anvisningar. SYSCFG_EXTICR1 (0x40013808) External interrupt configuration register 1 offset 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 Register 8 EXTI3[3:0] EXTI2[3:0] EXTI1[3:0] EXTI0[3:0] SYSCFG_EXTICR1 rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw Bitarna i alla fyra CR-registren har samma betydelse, se nedan SYSCFG_EXTICR2 (0x4001380C) External interrupt configuration register 2 offset 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 Register 8 EXTI7[3:0] EXTI6[3:0] EXTI5[3:0] EXTI4[3:0] SYSCFG_EXTICR2 rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw SYSCFG_EXTICR3 (0x40013810) External interrupt configuration register 3 offset 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 Register 0x10 EXTI11[3:0] EXTI10[3:0] EXTI9[3:0] EXTI8[3:0] SYSCFG_EXTICR3 rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw SYSCFG_EXTICR4 (0x40013814) External interrupt configuration register 4 offset 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 Register 0x10 EXTI15[3:0] EXTI14[3:0] EXTI13[3:0] EXTI12[3:0] SYSCFG_EXTICR4 rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw Bit 15:0 EXTIx[3:0]: Dessa bitar bestämmer hur en IO-pinne dirigeras till någon av de 16 avbrottslinorna EXTI0..EXTI15 genom att motsvarande fält skrivs med fyra bitar. Undantag: PK[15:8] används ej. 0000: PA[x] 0001: PB[x] 0010: PC[x] 0011: PD[x] 0100: PE[x] 0101: PF[x] 0110: PG[x] 0111: PH[x] 1000: PI[x] 1001: PJ[x] 1010: PK[x] SYSCFG_CMPCR (0x40013820) Compensation cell control register Används normalt inte men kan aktiveras för att öka stigtiden vid IO-frekvenser över 50MHz. Se tillverkarens anvisningar. Vi har alltså 16 olika avbrottslinor (EXTI0..EXTI15). Alla GPIO-pinnar med samma nummer kan dirigeras till en avbrottslina, man kan dock bara använda en i taget. dvs. GPIO-pinnar PA0, PB0, PC0 etc. kan kopplas till avbrottslina 0 (EXTI0), PA1, PB1, PC1 etc kan kopplas till avbrottslina 1 (EXTI1) osv. Utöver dessa finns det ytterligare 7 avbrottslinor, dessa är fast kopplade till olika moduler enligt följande: 106
Undantag, avbrott Irq EXTI16 EXTI17 EXTI18 EXTI19 EXTI20 EXTI21 EXTI22 Beskrivning PVD utgång fast ansluten till EXTIO16 RTC "Alarm event" fast ansluten till EXTIO17 USB OTG FS "Wakeup event" fast ansluten till EXTIO18 Ethernet "Wakeup event" fast ansluten till EXTIO19 USB OTG HS "Wakeup event" fast ansluten till EXTIO20 RTC "Tamper and TimeStamp" fast ansluten till EXTIO21 RTC "Wakeup event" fast ansluten till EXTIO22 I MD407 har STM32F407 har 7 olika avbrottsvektorer, snarare än 16, avsatts för EXTI0-EXTI15 avbrott, här har man valt att ha gemensam avbrottsvektor för EXTI5 t.om EXTI9, respektive EXTI10 t.o.m EXTI15: Irq Hanteringsrutin Beskrivning EXTI0_IRQn EXTI0_IRQHandler för IO-pinnar anslutna till avbrottslina 0 EXTI1_IRQn EXTI1_IRQHandler för IO-pinnar anslutna till avbrottslina 1 EXTI2_IRQn EXTI2_IRQHandler för IO-pinnar anslutna till avbrottslina 2 EXTI3_IRQn EXTI3_IRQHandler för IO-pinnar anslutna till avbrottslina 3 EXTI4_IRQn EXTI4_IRQHandler för IO-pinnar anslutna till avbrottslina 4 EXTI9_5_IRQn EXTI9_5_IRQHandler för IO-pinnar anslutna till avbrottslinor 5 till 9 EXTI15_10_IRQn EXTI15_10_IRQHandler för IO-pinnar anslutna till avbrottslinor 10 till 15 EXEMPEL: IO-pinne PE3 dirigeras till EXTI3 EXTI0 t.o.m EXTI3 konfigureras i SYSCFG_EXTICR1. Adressen till detta register blir (se översikt) 0x40013800 + 8. Vi får därför: #define SYSCFG_EXTICR1 0x40013808 /* Nollställ fält */ *((unsigned int *) SYSCFG_EXTICR1) &= ~0xFFF; /* PE3->EXTI3 */ *((unsigned int *) SYSCFG_EXTICR1) = 0x4000; Totalt finns det alltså 23 olika möjliga avbrottslinor i EXTI-modulen, även om inte alla används i STM32F407. Översikt EXTI Register offset 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 Register 0 EXTI_IMR 4 EXTI_EMR 8 EXTI_RTSR 0xC EXTI_FTSR 0x10 EXTI_SWIER 0x14 EXTI_PR EXTI_IMR (0x40013C00) Interrupt Mask Register 0 rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw EXTI_IMR Bit IMR[22..0]: Avbrottsmask för avbrottslina x. 0: Avbrott är maskerat (deaktiverat) 1: Avbrott är aktiverat. EXTI_EMR (0x40013C04) Event Mask Register 4 rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw EXTI_EMR Bit EMR[22..0]: Eventmask för avbrottslina x. 107
Arbetsbok för MD407 0: Event är maskerat (deaktiverat) 1: Event är aktiverat. Varje avbrottslina kan konfigureras för avbrott på positiv och/eller negativ flank. EXTI_RTSR (0x40013C08) Rising Trigger Selection Register 8 rw rw rw rwrw rw rw rwrw rw rw rw rw rwrw rw rw rw rw rw rw rwrw EXTI_RTSR Bit RTSR[22..0]: Trigg på positiv flank för avbrottslina x. 0: Trigg på positiv flank är maskerat (deaktiverat) 1: Trigg på positiv flank är aktiverat. EXTI_FTSR (0x40013C0C) Falling Trigger Selection Register 0xC rw rw rw rwrw rw rw rwrw rw rw rw rw rwrw rw rw rw rw rw rw rwrw EXTI_FTSR Bit FTSR[22..0]: Trigg på negativ flank för avbrottslina x. 0: Trigg på negativ flank är maskerat (deaktiverat) 1: Trigg på negativ flank är aktiverat. EXTI_SWIER (0x40013C10) Software Interrupt Event Register 0x10 rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw EXTI_SWIER Bit SWIER[22..0]: Om avbrott är aktiverat för lina x, kan programvara aktivera detta genom att skriva '1' till motsvarande bit i detta register. Denna bit återställs genom skrivning till EXTI_PR. EXTI_PR (0x40013C14) Pending Register 0x14 rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw EXTI_PR Bit PR[22..0]: Motsvarande bit sätts i detta register då ett triggvillkor är uppfyllt. Biten återställs genom att skrivas med '1'. 0: Trigg har uppträtt 1: Ingen Trigg. EXEMPEL: Bestäm hur avbrott ska genereras med EXTI Avbrottslina EXTI3 ska konfigureras så att avbrott genereras, och att detta sker vid negativ flank hos signalen på avbrottslinan. /* Aktivera genom att ettställa motsvarande bit i EXTI_IMR */ *((unsigned int *) 0x40013C00) = 8; /* Aktivera triggvillkor "negativ flank" */ *((unsigned int *) 0x40013C0C) = 8; 108
Undantag, avbrott NVIC Nested Vectored Interrupt Controller Upp till 81 olika avbrott hanteras av NVIC. Dessa avbrott kan ges en prioritet från 0 t.o.m 15, där 0 är den högsta prioriteten. För varje prioritet finns också ett subprioritetsfält, vilket gör att man kan skapa prioritetsgrupper där avbrotten i sin tur har en inbördes prioritet. För varje avbrott kontrollerat av NVIC finns följande funktioner: Interrupt Set Enable Registers, NVIC_ISERx Interrupt Clear Enable Registers, NVIC_ICERx Interrupt Set Pendig Registers, NVIC_ISEPRx Interrupt Clear Pending Registers, NVIC_ICPRx Interrupt Active Bit Registers, NVIC_IABRx Interrupt Priority Registers, NVIC_IPRx Software Interrupt Trigger Register, NVIC_STIR Följande tabell beskriver samtliga register i NVIC-modulen. Översikt NVIC 0x000 SETENA[31:0] NVIC_ISER0 0x004 SETENA[63:32] NVIC_ISER1 0x008 Reserverat SETENA[80:64] rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw NVIC_ISER2 0x080 CLRENA[31:0] NVIC_CER0 0x084 CLRENA [63:32] NVIC_ CER1 0x088 Reserverat CLRENA [80:64] rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw NVIC_ CER2 0x100 SETPEND[31:0] NVIC_ ISPR0 0x104 SETPEND [63:32] NVIC_ ISPR1 0x108 Reserverat SETPEND [80:64] rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw NVIC_ ISPR2 0x180 CLRPEND[31:0] NVIC_ICPR0 0x184 CLRPEND [63:32] NVIC_ICPR1 0x188 Reserverat CLRPEND [80:64] rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw rw NVIC_ ICPR2 0x200 ACTIVE[31:0] r r r r r r r r r r r r r r r r r r r r r r r r r r r r r r r r NVIC_ IABR0 0x204 ACTIVE [63:32] r r r r r r r r r r r r r r r r r r r r r r r r r r r r r r r r NVIC_IABR1 0x208 Reserverat ACTIVE [80:64] r r r r r r r r r r r r r r r r r NVIC_IABR2 0x300 IP[3] IP[2] IP[1] IP[0] NVIC_ IPR0 0x320 Reserverat IP[80] rw rw rw rw rw rw rw rw NVIC_IPR20 Varje avbrott kan hanteras individuellt och totalt åtgår alltså 4 register för att implementera varje function i NVIC. Den bit i NVIC-registren som kontrollerar respektive avbrott bestäms av avbrottets nummer i vektortabellen. 109
Arbetsbok för MD407 NVIC_ISERx: SETENA[80..0] Interrupt set-enable bit: Skrivning: 0: ingen effekt 1: möjliggör avbrott Läsning: 0: avbrott avstängt 1: avbrott möjligt NVIC_ICERx: CLRENA[80..0] Interrupt clear-enable bit: Skrivning: 0: ingen effekt 1: omöjliggör avbrott Läsning: 0: avbrott avstängt 1: avbrott möjligt NVIC_ISEPRx: SETPEND[80..0] Interrupt set pending bit: Skrivning: 0: ingen effekt 1: ändrar avbrottstatus till avvaktande (pending) Läsning: 0: avbrottstatus är inte avvaktande 1: avbrottstatus är avvaktande NVIC_ICPRx: CLRPEND[80..0] Interrupt clear pending bit: Skrivning: 0: ingen effekt 1: avlägsnar avbrottstatus avvaktande (pending) Läsning: 0: avbrottstatus är inte avvaktande 1: avbrottstatus är avvaktande NVIC_IABRx: ACTIVE[80..0] Interrupt active bit: Läsning: 0: avbrottstatus är inte inaktivt 1: avbrottstatus är aktivt NVIC_IPRx: Interrupt priority Varje prioritetsfält kan ha ett prioritetsvärde, 0-255. Ju lägre värde, desto högre prioritet för motsvarande avbrott. Processorn implementerar bara bitar [7: 4] för varje fält, bitar [3: 0] läses som noll och ignoreras vid skrivning. 110
Undantag, avbrott EXEMPEL: Bestäm bitmask och avbrottsvektor för EXTI3 Vi letar upp EXTI3 i vektortabellen (kolumn 3). Den första kolumnen anger avbrottets nummer i NVIC, dvs. 9. Kolumnen längst till höger anger avbrottsvektorns placering i vektortabellen: I detta fall identifierar vi EXTI3 som avbrott nummer 9. Bitmasken för denna bit är 0x00000200, vilket också kan skrivas (1<<9). Det sistämda skrivsättet är i bland att föredra eftersom det blir mycket tydligare vad som avses. 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 Avbrottsvektorns placering är 0x00000064. Avbrottsvektorns placering i vektortabellen är en offset. Till denna adress läggs innehållet i registret Vector Table Offset Register (VTOR). Vid RESET är innehållet i VTOR 0, och minnesområdet från adress 0 är i sin tur speglat av det interna FLASH-minnet. I MD407 har monitor-programmet flyttat vektortabellen till adress 0x2001C000, dvs. läs- och skrivbart minne, vilket innebär att avbrottsvektorer kan dynamiskt. EXEMPEL: Initiera avbrottsvektor En funktion för hantering av avbrott kan inte ha några parametrar eller returvärden, dvs. deklareras: void irq_handler( void ); Adressen till avbrottsrutinen ska placeras på den aktuella avbrottsvektoradressen, dvs. (VTOR)+vektor offset. En typriktig initiering av avbrottsvektorn blir då: *((void (**)(void) ) avbrottsvektor ) = irq_handler; 111
Arbetsbok för MD407 EXEMPEL: Aktivera NVIC för EXTI3 För att möjliggöra avbrott från EXTI3-linan vidare in till processorn måste den bit som motsvarar EXTI3 i Set Enable registret sättas till '1'. Biten bestäms av avbrottets nummer, i detta fall identifierar vi EXTI3 som avbrott nummer 9 (se vektortabellen). Bitmasken för denna bit är 0x200 i det första av de tre Set Enableregistren, vilket också kan skrivas (1<<9). Det sistämda skrivsättet är i bland att föredra eftersom det blir mycket tydligare vad som avses. *((unsigned int *) 0xE000E100) = (1<<9); För att överhuvudtaget acceptera avbrott måste processorns avbrottsmask nollställas. För sådana operationer finns instruktionen CPS (Change Processor State). Se sidan 173 i "Programming Manual". Uppgift 41 Skriv C-funktionerna: void enable_interrupt( void ); som får processorn att acceptera avbrott och: void disable_interrupt( void ); som får processorna att ignorera avbrott (maskera). Slut Uppgift 41 Vid avbrottshanteringen ska ett aktiverat avbrott återställas, detta gör man genom att kvittera avbrottet i dess ursprung. EXEMPEL: Återställ avbrott för EXTI3 Detta avbrott återställs genom att '1' skrivs till motsvarande bit i EXTI Pending Register: *((unsigned int *) 0x40013C14) = (1<<3); Laborationskort med avbrottsvippor Laborationskortet IRQ Flip Flop kan användas för att generera externa avbrott till MD407. Två olika avbrotten aktiveras manuellt via strömställare, en tredje typ av avbrott kommer från en pulsgenerator och ger periodiska avbrott med valbar frekvens 10Hz eller 100 Hz. Aktiverade avbrott kan återställas manuellt, via en strömställare, eller programvarumässigt. 112
Undantag, avbrott Uppgift 42 Prova IO-enheten IRQ flip flop, för att fungera korrekt i nästkommande uppgifter ska du ansluta den till GPIOE, pin 0-7. Aktivera de olika avbrottsvipporna genom att klicka på strömställarna till vänster, strömställaren nederst, i mitten av kortet, återställer vipporna. Indikator IRQ1 Signal IRQ1 Signal IRQ1 Starta periodiska avbrott Indikator IRQ2 Indikator någon IRQ aktiv Bygel, IRQ aktiv nivå Indikator periodiskt IRQ Avbrottsfrekvens (10 eller 100 Hz) Återställ alla IRQ Programmerarens bild av laborationskortet: Slut Uppgift 42 113
Arbetsbok för MD407 Uppgift 43 Skriv en enkel applikation som använder PE3 hos MD407 som avbrottsingång och som registrerar varje avbrott, med en enkel räknare, och i huvudprogrammet skriver ut antalet avbrott till en visningsenhet. Applikationen ska vara komplett med startup, main, initieringsfunktioner och avbrottshantering: void irq_handler ( void ) { Om avbrott från EXTI3: inkrementera count; kvittera avbrott från EXTI3 } void enable_interrupt( void ) { } void app_init ( void ) { Sätt upp PD0-7 som utport för visningsenhet Aktivera klockan för SYSCFG; Koppla PE3 till avbrottslina EXTI3; Konfigurera EXTI3 för att generera avbrott; Konfigurera för avbrott på negative flank Sätt upp avbrottsvektor } Konfigurera de bitar i NVIC som kontrollerar den avbrottslina som EXTI3 kopplats till void main(void) { app_init(); enable_interrupts(); while(1){ utport = count; } } Bygg projektet, testa med simulator. Slut Uppgift 43 114