1 interrupts and using them in c these lecture notes created by dr. alex dean, ncsu

32
1 Interrupts Interrupts and and Using Them in C Using Them in C These lecture notes created by Dr. Alex Dean, NCSU

Upload: gilbert-caldwell

Post on 16-Jan-2016

218 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: 1 Interrupts and Using Them in C These lecture notes created by Dr. Alex Dean, NCSU

1

Interrupts Interrupts and and

Using Them in CUsing Them in C

These lecture notes created by Dr. Alex Dean, NCSU

Page 2: 1 Interrupts and Using Them in C These lecture notes created by Dr. Alex Dean, NCSU

2

In These Notes . . . In These Notes . . . • Interrupts

– How they work

– Creating and debugging C interrupt routines

• Readings– M16C Software Manual, Interrupt chapter

– M16C Hardware Manual, Interrupt chapter

– C Language Programming Manual, Interrupt Processing chapter

– If not already done, read…• “Introduction to Interrupts,” Russell Massey

• “Interrupt Latency,” Jack Ganssle

• “Introduction to Interrupt Debugging,” Stuart Ball

Page 3: 1 Interrupts and Using Them in C These lecture notes created by Dr. Alex Dean, NCSU

3

Interrupts and PollingInterrupts and Polling• Consider the task of making coffee

– We need to boil water, but don’t knowexactly how long it will take to boil

• How do we detect the water is boiling?– Keep watching the pot until we see bubbles

• This is called polling

• Wastes time – can’t do much else

– Put the water in a kettle which will whistle upon boiling• The whistle is an interrupt

• Don’t need to keep watching water. Instead you can do something else until the kettle whistles.

• Much more efficient

Page 4: 1 Interrupts and Using Them in C These lecture notes created by Dr. Alex Dean, NCSU

4

Breakfast TimelineBreakfast Timeline

Start preparing breakfast:Put water in kettle and turn on burnerPut ground coffee in filter in conePut cone on cupGet milk out of fridgeGet cereal from cabinet

Resume breakfast preparation:Get bowl from cabinetPour cereal into bowlOpen milkPour milk into bowlClose milkGet spoonPut milk back in fridge

Water boils and

kettle whistles

An interrupt occursPut down whatever isin handsTurn off burnerPour boiling water intocoffee filterPick up whatever was put down

Interrupt Service Routine

Page 5: 1 Interrupts and Using Them in C These lecture notes created by Dr. Alex Dean, NCSU

5

Microcontroller InterruptsMicrocontroller Interrupts• Types of interrupts

– Hardware interrupts • Asynchronous: not related to what code the processor is currently executing

• Examples: INT0 input becomes active, character is received on serial port, or ADC converter finishes conversion

– Software interrupts • Synchronous: are the result of specific instructions executing

• Examples: BRK, INT, undefined instructions, overflow occurs for a given instruction

– We can enable and disable (mask) most interrupts as needed (maskable), others are non-maskable

• Interrupt service routine (ISR) – Subroutine which processor is forced to execute to respond to a specific

event

– After ISR completes, MCU goes back to previously executing code

Page 6: 1 Interrupts and Using Them in C These lecture notes created by Dr. Alex Dean, NCSU

6

Interrupt Processing Sequence for Enabled InterruptInterrupt Processing Sequence for Enabled Interrupt• Other code (background) is running• Interrupt trigger occurs• Processor does some hard-wired processing• Processor executes ISR (foreground), including return-from-

interrupt instruction at end• Processor resumes other code

Main Code(Background)

ISR(Foreground)

Page 7: 1 Interrupts and Using Them in C These lecture notes created by Dr. Alex Dean, NCSU

7

TMP

FLG

Hard-Wired Processor Response to InterruptHard-Wired Processor Response to Interrupt1. Finish or interrupt current instruction2. Read a special control register (at address 00000h) for interrupt source information3. Save flag register FLG in temporary FLG register:

4. Clear certain flags in FLG:• Interrupt enable - I• Debug – D• Stack pointer select – U (except for sw ints 32-63)

5. Push the temporary FLG register and PC onto stack (see left)

6. Set interrupt priority level in IPL7. Fetch interrupt vector from vector table and load

into PC• M16C62P Hardware Manual, (Interrupt)

Page 8: 1 Interrupts and Using Them in C These lecture notes created by Dr. Alex Dean, NCSU

8

Interrupt ConsiderationsInterrupt Considerations• Vectors• Saving and Restoring Context• Prioritization• Response time• Maximum interrupt rate

Page 9: 1 Interrupts and Using Them in C These lecture notes created by Dr. Alex Dean, NCSU

9

Vector Table – Where Do We Go?Vector Table – Where Do We Go?

FFFFCFFFF8FFFF4FFFF0

Reset Interrupt VectorNon-maskable Interrupt Vector

Debug Control Interrupt VectorWatchdog Timer Interrupt Vector

Reset Interrupt Service Routine

Watchdog Timer Interrupt Service Routine

Debug ControlInterrupt Service Routine

Non-maskable Interrupt Service Routine

start

start

WDT_ISR

WDT_ISR

DBC_ISR

NMI_ISR

NMI_ISRDBC_ISR

Page 10: 1 Interrupts and Using Them in C These lecture notes created by Dr. Alex Dean, NCSU

10

M16C Vectors DetailsM16C Vectors Details

• Need a table to list where the ISRs are located in memory– Each table entry is called a vector – 4 bytes holding ISR address– M16C62P Hardware manual

• Two kinds of interrupts: fixed and variable (M16C feature)– Fixed have vectors to ISRs at hardware-defined address

• Examples: undefined instruction, overflow, BRK, address match, single step, WDT, DBC, UART1, Reset

– Variable have vectors to ISRs at user-definable address• Why have two kinds?

– Flexibility for programmer, can use different ISRs in different operating modes

Page 11: 1 Interrupts and Using Them in C These lecture notes created by Dr. Alex Dean, NCSU

11

Saving and Restoring ContextSaving and Restoring Context• Problem

– Since ISR is asynchronous with main code (could happen at any time), we have no idea which registers are live (being used).

• Conceivably all* registers (R0-3, A0-1, FB, SB) could be live– The ISR needs to use some registers to do its work

• Solution 1: use stack– Before modifying any registers, ISR must push values of registers it may use onto the

stack– Before returning, pop these values back into the registers

• Solution 2: use a different register bank– Before modifying any registers, ISR must switch to use an alternate register bank– Before returning, switch back to the original register bank

• To exit ISR, use return from interrupt (REIT) instruction – Restores even more context – what processor automatically saved when responding

to interrupt• Pops FLG from stack• Pops PC from stack

– Makes CPU resume executing original code!

– Takes 6 cycles

Page 12: 1 Interrupts and Using Them in C These lecture notes created by Dr. Alex Dean, NCSU

12

PrioritizationPrioritization• Interrupt requests are considered simultaneous if they occur

between the same two clock ticks

• Interrupts are prioritized to order the response simultaneous interrupt requests– Priorities of some interrupts are fixed by the hardware design

• Reset (highest priority)

• NMI

• DBC

• Watchdog timer

• Peripheral I/O

• Single step

• Address match

– Priorities of other (peripheral) interrupts are adjustable• Value loaded into the interrupt priority level register (ILVL2-0) for that interrupt

• If there are multiple simultaneous interrupt requests with the same priority level, the hardware prioritizes them

Page 13: 1 Interrupts and Using Them in C These lecture notes created by Dr. Alex Dean, NCSU

13

Interrupt Response LatencyInterrupt Response Latency• Latency = time delay• Why do we care?

– This is overhead which wastes time, and increases as the interrupt rate rises– This delays our response to external events, which may or may not be

acceptable for the application, such as sampling an analog waveform

• How long does it take?– Finish executing the current instruction (up to 30 cycles for DIVX) or freeze

it– Push various registers on to the stack, fetch vector

• CIntResponseOvhd: Overhead for responding to each interrupt (18 to 20 cycles for M16C)

• Depends on alignment of stack pointer and interrupt vector• odd pointers are unaligned (words start at even addresses) so they take 2 cycles

each to dereference (follow to memory)

– If we have external memory with wait states, this takes longer

• Maximum 50 cycles to respond– 50 / 16 MHz = 3.125 microseconds -- > need to design for this

Page 14: 1 Interrupts and Using Them in C These lecture notes created by Dr. Alex Dean, NCSU

14

Maximum Interrupt RateMaximum Interrupt Rate• We can only handle so many interrupts per second

– FMax_Int: maximum interrupt frequency– FCPU: CPU clock frequency– CISR: Number of cycles ISR takes to execute– FMax_Int = FCPU/CISR – Note that this assumes there are no other active interrupts in the system– Example: If the ISR takes 56 cycles to execute (worst case), the maximum

interrupt rate we can handle is 24 MHz / 56 cycles = 428 kHz

• When processor is responding to interrupts, it isn’t executing our other code– UInt: Utilization (fraction of processor time) consumed by interrupt

processing– UInt = 100%*FInt* (CISR+CIntResponseOvhd)/ FCPU

– Example: If that 56-cycle ISR is being triggered at 100 kHz, UInt = 100%*100kHz*(56+20)/24 MHz = 31.7%.

• CPU looks like it’s running the other (background) code at about 16 MHz, not 24 MHz

Page 15: 1 Interrupts and Using Them in C These lecture notes created by Dr. Alex Dean, NCSU

15

Checklist for Using Interrupts in CChecklist for Using Interrupts in C• Read

– M16C Software Manual, (Interrupt)

– C Language Programming Manual, (Interrupt Processing)

• Configure MCU– Set up peripheral to generate interrupt

– Enable interrupts for system (set I bit in FLG)

• Write ISR my_isr and identify it as an ISR using#pragma INTERRUPT my_isr

• Register ISR in interrupt vector table

Page 16: 1 Interrupts and Using Them in C These lecture notes created by Dr. Alex Dean, NCSU

16

Configure Peripheral to Generate InterruptConfigure Peripheral to Generate Interrupt

• XXXic is interrupt control register for the peripheral• At least four fields – look in sfr62p.h for field names

– Interrupt level (3 bits)• Sets priority of interrupt. If 0, is disabled. Processor will not respond to

interrupts with priority level < processor interrupt priority level

• ilvl0_XXXic, ilvl1_XXXic, ilvl2_XXXic.

– Interrupt Request (1 bit) – if 1, the condition for generating an interrupt is true (can read this field even if interrupt is disabled)

• Hardware Interrupt Types– INT0-5: input signals from MCU pins

– Peripherals can also generate interrupt requests: ADC, serial, etc.

Page 17: 1 Interrupts and Using Them in C These lecture notes created by Dr. Alex Dean, NCSU

17

Interrupt Control Register for INT0-5Interrupt Control Register for INT0-5

Page 18: 1 Interrupts and Using Them in C These lecture notes created by Dr. Alex Dean, NCSU

18

Interrupt Control Register for Other PeripheralsInterrupt Control Register for Other Peripherals

Page 19: 1 Interrupts and Using Them in C These lecture notes created by Dr. Alex Dean, NCSU

19

Configure MCU to respond to the interruptConfigure MCU to respond to the interrupt• Set global interrupt enable flag I (in FLG)

– This flag does not enable all interrupts; instead, it is an easy way to disable interrupts

– Use inline assembly code to set the flag: _asm(“fset i”)or use ENABLE_IRQ macro in qsk_bsp.h

• MCU has eight interrupt priority levels (IPL bits in FLG), is 0 after reset– Set using inline assembly code

• To respond to interrupt, I flag must be 1, interrupt request bit must be 1 and interrupt priority level must be >= processor IPL

Page 20: 1 Interrupts and Using Them in C These lecture notes created by Dr. Alex Dean, NCSU

20

#pragma INTERRUPT my_isr /* or INTERRUPT/B */void my_isr(void) { /* do whatever must be done */}

Write Interrupt Service RoutineWrite Interrupt Service Routine

• Rules for writing ISRs– No arguments or return values – void is only valid type– Keep it short and simple

• Much easier to debug • Improves system response time

• Tell compiler it’s an ISR– ISR has a different stack frame compared with subroutine

• Saves all registers• Flag register saved

– Different return needed (REIT vs. EXITD)– So use #pragma INTERRUPT my_isr

• Potentially use register bank switching for faster interrupt response– Use INTERRUPT/B– Compiler inserts code to switch to register bank 1 for ISR and back to bank 0 on

return (fset B, fclr B)– This only works if interrupts can’t be interrupted (don’t set I flag while in ISR)

Page 21: 1 Interrupts and Using Them in C These lecture notes created by Dr. Alex Dean, NCSU

21

Comparing Functions and ISRsComparing Functions and ISRs

void normal_function(void) { _normal_function: count++; ENTER #00H} ADD.W #1H,0400H

EXITD

#pragma INTERRUPT isr _isr:void isr(void) { PUSHM R0,R1,R2,R3,A0,A1 count++; ENTER #00H} ADD.W #1H,0400H

POPM FB POPM R0,R1,R2,R3,A0,A1 REIT

#pragma INTERRUPT/B reg_bank_b_isr _reg_bank_b_isr: void reg_bank_b_isr(void) { FSET B count++; ENTER #00H } ADD.W #1H,0400H

POPM FB REIT

Page 22: 1 Interrupts and Using Them in C These lecture notes created by Dr. Alex Dean, NCSU

22

Register the Interrupt VectorRegister the Interrupt Vector

• Modify vector table in sect30.inc to point to our ISR so MCU vectors to our code when our interrupt occurs– Find the correct interrupt vector to replace– Replace dummy_int vector with _my_isr (address of the function)

• dummy_int is an ISR which returns immediately, doing nothing– All unused vectors are filled with this by default in sect30.inc

• Compiler prepends _ to C symbol names for uniqueness when compiling• So, we need to prepend _ when referencing C symbols (functions and variables) from asm

– Add .glb _my_isr directive to tell assembler the symbol _my_isr is defined elsewhere (“global”)

.section vector ; variable vector table

.org VECTOR_ADR

.lword dummy_int ; TIMER B1 (for user) (vector 27)

.lword dummy_int ; TIMER B2 (for user) (vector 28)

.lword dummy_int ; INT0 (for user) (vector 29)

.lword dummy_int ; INT1 (for user) (vector 30)

.lword dummy_int ; Reserved

Page 23: 1 Interrupts and Using Them in C These lecture notes created by Dr. Alex Dean, NCSU

23

Register the Interrupt VectorRegister the Interrupt Vector

• Modify vector table in sect30.inc to point to our ISR so MCU vectors to our code when our interrupt occurs– Find the correct interrupt vector to replace (e.g. vector 29)

• Note that sect30.inc for QSK62P has two variable vector tables, but only one is used (the “.else” case of “.if M60TYPE == 1” (MCU isn’t this type)

– Replace dummy_int vector with _my_isr (address of the function)• dummy_int is an ISR which returns immediately, doing nothing

– All unused vectors are filled with this by default in sect30.inc

• Compiler prepends _ to C symbol names for uniqueness when compiling• So, we need to prepend _ when referencing C symbols (functions and variables) from asm

– Add .glb _my_isr directive to tell assembler the symbol _my_isr is defined elsewhere (“global”)

.section vector ; variable vector table

.org VECTOR_ADR

.lword dummy_int ; TIMER B1 (for user) (vector 27)

.lword dummy_int ; TIMER B2 (for user) (vector 28)

.glb _my_isr

.lword _my_isr ; INT0 (for user) (vector 29)

.lword dummy_int ; INT1 (for user) (vector 30)

.lword dummy_int ; Reserved

Page 24: 1 Interrupts and Using Them in C These lecture notes created by Dr. Alex Dean, NCSU

24

Building a Program – Start with the basicsBuilding a Program – Start with the basics• Program requirements:

– Req1: When S1 is pressed, toggle the red LED

– Req2: When S2 is pressed, toggle the yellow LED

– Req3: Count the switch presses for S1 and S2

– Req4: Use interrupts for switch press detection

• All of the switches on our board are attached to port 8 (see schematic)– S1 = p8_3 => Interrupt 1

– S2 = p8_2 => Interrupt 0

– S3 = p8_1 => (see schematic)

• Button presses are “negative logic” so the interrupt will be based on the negative edge (1 -> 0) of the press.

Page 25: 1 Interrupts and Using Them in C These lecture notes created by Dr. Alex Dean, NCSU

25

Page 26: 1 Interrupts and Using Them in C These lecture notes created by Dr. Alex Dean, NCSU

26

System Tasks and Data FlowSystem Tasks and Data Flow

INT0ISR

INT1ISR

RedCount

YellowCount

Main

Global Variable

ISR Task

(does initialization,then does nothing)

Page 27: 1 Interrupts and Using Them in C These lecture notes created by Dr. Alex Dean, NCSU

27

Building a Program – Break into PiecesBuilding a Program – Break into Pieces• First break into threads, then break thread into steps• Main thread:

– First initialize system • init_switches: configure the ports connected to S1, S2 and S3 to be

inputs• init_LEDs: configure the ports connected to the LEDs to be outputs• init_ints: initialize the controller for interrupts 0 & 1

– Then do nothing• switch1_ISR thread:

– Toggle red LED– Update red_count

• switch2_ISR thread: – Toggle yellow LED– Update yellow_count

Page 28: 1 Interrupts and Using Them in C These lecture notes created by Dr. Alex Dean, NCSU

28

Start with the Basics, and Trust NothingStart with the Basics, and Trust Nothing• IT IS ALWAYS BEST TO START SIMPLE!!!!!!!

– Verify that each part of the basic system runs as you build software.

– Easier to debug – easier to exclude potential sources of problems, so bugs can be found faster

• Use an incremental approach to verify system works– Initialize ports for LEDs and switches

– Test 1: Verify LEDs work – Turn on all LEDs

– Test 2: Verify switches work – light LEDs based on switches

– Test 3: Add interrupts and test they work• Do LEDs toggle?

• Set breakpoints – do counts increase correctly?

• Use #defined symbols rather than “magic numbers” to help convey meaning of operation

Page 29: 1 Interrupts and Using Them in C These lecture notes created by Dr. Alex Dean, NCSU

29

Defining Names and ConnectionsDefining Names and Connections

#include “qsk_bsp.h”

// dir selection for GPIO#define DIR_IN (0)#define DIR_OUT (1)

// polarity selection for // interrupts#define FALLING_EDGE (0) #define RISING_EDGE (1)

int red_count; // count S1 pressesint yellow_count; // count S2 presses

void init_switches(void) { // set up GPIO bits for switches to // be inputs S1_DIR = S2_DIR = S3_DIR = DIR_IN;}void init_LEDs(void) { RED_DDR = YLW_DDR = GRN_DDR = DIR_OUT; RED_LED = YLW_LED = GRN_LED = LED_ON; RED_LED = YLW_LED = GRN_LED = LED_OFF; red_count = yellow_count = 0;}

Page 30: 1 Interrupts and Using Them in C These lecture notes created by Dr. Alex Dean, NCSU

30

Testing LEDs and SwitchesTesting LEDs and Switchesvoid init_LEDs(void) { RED_DDR = YLW_DDR = GRN_DDR = DIR_OUT; RED_LED = YLW_LED = GRN_LED = LED_ON; RED_LED = YLW_LED = GRN_LED = LED_OFF; red_count = yellow_count = 0;}

void test_switches(void) { for(;;) { // infinite loop if (!S1) RED_LED = LED_ON; else RED_LED = LED_OFF; if (!S2) YLW_LED = LED_ON; else YLW_LED = LED_OFF; if (!S3) GRN_LED = LED_ON; else GRN_LED = LED_OFF; }}

Test LEDs here. Step throughwith debugger, since LEDs would be on for less than amicrosecond at normal speed

Test switches here. Can run code at normal speedsince it echoes user behavior

Page 31: 1 Interrupts and Using Them in C These lecture notes created by Dr. Alex Dean, NCSU

31

Adding and Testing InterruptsAdding and Testing Interrupts/** Sets INT0 and INT1 to priority * level 7, triggering on falling * edge. */void init_ints(void) { // set interrupt priority level // for int0 to 7 (binary 111) ilvl0_int0ic = 1; ilvl1_int0ic = 1; ilvl2_int0ic = 1;

// set int0 to trigger on // negative edge (1->0) pol_int0ic = FALLING_EDGE;

// set interrupt priority level // for int1 to 7 (binary 111) ilvl0_int1ic = 1; ilvl1_int1ic = 1; ilvl2_int1ic = 1;

// set int1 to trigger on // negative edge (1->0) pol_int1ic = FALLING_EDGE;}

#pragma INTERRUPT switch1_isrvoid switch1_isr(void) { red_count++; if(red_count % 2) RED_LED = LED_ON; else RED_LED = LED_OFF;}

#pragma INTERRUPT switch2_isrvoid switch2_isr(void) { yellow_count++; if(yellow_count % 2) YEL_LED = LED_ON; else YEL_LED = LED_OFF;}

sect30.inc – note M60TYPE != 1.glb _switch2_isr.lword _switch2_isr ; INT0 (vector 29).glb _switch1_isr.lword _switch1_isr ; INT1 (vector 30)

Page 32: 1 Interrupts and Using Them in C These lecture notes created by Dr. Alex Dean, NCSU

32

Main FunctionMain Functionvoid main(void) {

mcu_init(); init_switches(); init_LEDs(); init_ints(); RED_LED = LED_ON; // remove once the program works test_switches(); // remove once the program works

_asm("fset i"); // enable interrupts while (1) { // can do other work here, and the LEDs will still

// toggle on a switch press, because the interrupt will // interrupt any work being done here.

} }