1 / 42

Embedded Software

dr. Stefan Dulman Embedded Software Group. Embedded Software. TI2720-C. 2. Interrupts. Lab schedule. Reminder: register for the lab! (send me an email). Lecture overview. Definition & characteristics Shared-data problem Interrupt latency. What is an Interrupt?.

ilyssa
Télécharger la présentation

Embedded Software

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. dr. Stefan Dulman Embedded Software Group Embedded Software TI2720-C 2. Interrupts

  2. Lab schedule • Reminder: register for the lab! (send me an email)

  3. Lecture overview • Definition & characteristics • Shared-data problem • Interrupt latency

  4. What is an Interrupt? • Asynchronous signal from hardware • Synchronous signal from software • Indicates the need for attention • Indicates the need for execution change

  5. Why Interrupts? • Avoid wasting time in polling loops for external events • Make a system reactive and simple • Make debugging more fun  CPU I2C Switches Internal errors Timers RS232 Buttons Sensors Actuators

  6. Interrupts: Principle dev 1 IRQ contr Context switch CPU IRQ # dev N HW CALL ISR:PUSH R1 ... POP R1 RET Program: ... MOVE R1, (var-addr) MULT R1, 9 DIVIDE R1, 5 ADD R1, 32 ...

  7. Where is the interrupt code? • Intel 8051 - default locations for interrupt service routines • Interrupt vector table • Where is the interrupt vector table? • Default location (Intel 80186) • Programmable location

  8. Some questions… • Can a microprocessor be interrupted in the middle of an instruction? • Which interrupt goes first? Interrupt during another interrupt? • What happens immediately after the interrupts are enabled? • What is the status of interrupts when the processor starts?

  9. XC3S400 Block Diagram • I/O, LEDs, SSD, buttons, RS232, … • Create your own core and set of peripherals (UART, PWM, timer, decoder)

  10. Turn FPGA into a Microcontroller • High-speed designs in HW (e.g., VHDL) • XC3S400 clock 50 MHz, 400k gates ($129) • Low-speed designs in SW (e.g., C) • Need processor core that communicates with VHDL devices • No hard core provided (only in more expensive FPGAs) • So need soft core to execute programs! • Academia: zero-cost public domain VHDL soft core • Previous experience was bad (6502 core+SDCC tool chain) • So we built our own (well, SijmenWoutersen did) – X32

  11. X32 Peripheral Interrupts buttons, LEDs, SSD, switches, timers, RS232, DPC, off-board I/O ports Peripheral 0 - K CPU multiple IRQ lines per peripheral possible (e.g., tx+rx IRQ per UART) IRQ0 IRQn Interrupt Controller CPU • peripherals used at the lab: • buttons, LEDs, SSD, UART (RS232 interface to console), • DPC (digital-PWM converter to control DC motor), • digital inputs (to read motor position encoder signals A and B)

  12. X32: Interrupt Sources • CPU: divide-by-0, overflow (disable unless needed!) • Buttons, switches, I/O ports • positive AND negative edge-triggered • Timers: counter value > threshold reg • UART: rx buffer char received / tx buffer empty • Motor decoder engine: corrupt input signals

  13. IRQ . IE IE_global . (priority > exec level) servicing / interrupt stdby IE’ scheduled acknowledge X32: Interrupt Controller interrupt IRQ0 Interrupt Controller acknowledge IEk, priok, vectork vector CPU priority exec level IRQn IE_global FSM for each IRQ:

  14. X32 Interrupts • IRQ controller preprocesses multiple IRQ’s • Each device: (IRQ #, priority, associated with IRQ vector) • Vectored IRQ • Interrupts NOT disabled automatically • Automatic ISR preemption if prio IRQ > prio current ISR • Normal call saves context -> no interrupt keyword IRQ # IRQ contr CPU

  15. Exercise: ISR version of leds.c … int done = 0; intbutton_state; void delay(int ms) { inttime = X32_clock; while(X32_clock - time < ms); } … void isr_buttons(void) { // delay(200); X32_leds = X32_buttons; if (X32_buttons > 0) { button_state = X32_buttons; printf("Button %d pressed\n", button_state); } else if (button_state > 0 && X32_buttons == 0) { printf("Button %d released\n", button_state); button_state= 0; } if (X32_buttons == 0x09) done = 1; } /*------------------------------------------- * main -- do the demo *-----------------------------------------*/ int main() { SET_INTERRUPT_VECTOR( INTERRUPT_BUTTONS, &isr_buttons); SET_INTERRUPT_PRIORITY(INTERRUPT_BUTTONS,10); ENABLE_INTERRUPT(INTERRUPT_BUTTONS); ENABLE_INTERRUPT(INTERRUPT_GLOBAL); printf("Hello World!\r\n"); while (! done) { X32_display = X32_clock; } DISABLE_INTERRUPT(INTERRUPT_GLOBAL); return 0; }

  16. X32: Demo • Demo .. • (x32_projects.tgz, leds.c, leds_isr.c, buttons.c)

  17. Lecture overview • Definition & characteristics • Shared-data problem • Interrupt latency

  18. Shared-Data Problem? void isr_read_temps(void) { iTemp[0] = peripherals[..]; iTemp[1] = peripherals[..]; } void main(void) { ... while (TRUE) { tmp0 = iTemp[0]; tmp1 = iTemp[1]; if (tmp0 != tmp1) panic(); } } Book: page 92 …

  19. Shared-Data Problem? void isr_read_temps(void) { iTemp[0] = peripherals[..]; iTemp[1] = peripherals[..]; } void main(void) { ... while (TRUE) { tmp0 = iTemp[0]; tmp1 = iTemp[1]; if (tmp0 != tmp1) panic(); } } Possible Context Switch NOT ATOMIC! Book: page 92 …

  20. Finding this bug… • Can be very tricky • The bug does not occur always! • Frequency depends on • The frequency of interrupts • Length of the critical section • Problem can be difficult to reproduce • Advise: double check the access on data used by ISR!

  21. Solving the Data-Sharing Problem? void isr_read_temps(void) { iTemp[0] = peripherals[..]; iTemp[1] = peripherals[..]; } void main(void) { ... while (TRUE) { if (iTemp[0] != iTemp[1]) panic(); } }

  22. Solving the Data-Sharing Problem? void isr_read_temps(void) { iTemp[0] = peripherals[..]; iTemp[1] = peripherals[..]; } void main(void) { ... while (TRUE) { if (iTemp[0] != iTemp[1]) panic(); } } MOVE R1, (iTemp[0]) MOVE R2, (iTemp[1]) SUBSTRACT R1,R2 JCOND ZERO, TEMP_OK … … TEMP_OK: …

  23. Solution #1 • Disable interrupts for the ISRs that share the data ... while (TRUE) { !! DISABLE INT tmp0 = iTemp[0]; tmp1 = iTemp[1]; !! ENABLE INT if (tmp0 != tmp1) panic(); } The critical section is now atomic

  24. Atomic & critical section • A part of a program is atomic if it cannot be interrupted • Interrupts and program code share data • atomic can also refer to mutual exclusion • Two pieces of code sharing data • They can be interrupted • The instructions that must be atomic = critical section

  25. Be careful! static intiSeconds, iMinutes; void interrupt vUpdateTime(void) { ++iSeconds; if (iSeconds>=60) { iSeconds=0; ++iMinutes; } } long lSeconds(void) { return (iMinutes*60+iSeconds); }

  26. Be careful! static intiSeconds, iMinutes; void interrupt vUpdateTime(void) { ++iSeconds; if (iSeconds>=60) { iSeconds=0; ++iMinutes; } } long lSeconds(void) { disable(); return (iMinutes*60+iSeconds); enable(); }

  27. Function calls and enable() • enable() can be a source of bugs! int f2 () { … disable(); … enable(); … } void function1 () { … // enter critical section disable(); … temp = f2(); … // exit critical section enable(); … } should test if this is fine

  28. More on shared-data… static long intlSeconds; void interrupt vUpdateTime() { … ++lSecondsToday; … } long lGetSeconds() { return (lSecondsToday); }

  29. More on shared-data… static long intlSeconds; void interrupt vUpdateTime() { … ++lSecondsToday; … } long lGetSeconds() { return (lSecondsToday); } MOVE R1,(lSecondsToday) MOVE R2,(lSecondsToday+1) … RETURN

  30. Any issues here? static long intlSecondsToday; void interrupt vUpdateTime() { ++lSecondsToday; } long lGetSeconds() { long lReturn; lReturn = lSecondsToday; while (lReturn!=lSecondsToday) lReturn = lSecondsToday; return (lReturn); }

  31. Any issues here? volatile static long intlSecondsToday; void interrupt vUpdateTime() { ++lSecondsToday; } long lGetSeconds() { long lReturn; lReturn = lSecondsToday; while (lReturn!=lSecondsToday) lReturn = lSecondsToday; return (lReturn); } Otherwise compiler might optimize this code!

  32. Exercise: critical section /*-------------------------------------- * main -- do the demo *------------------------------------*/ intmain() { int copy1, copy2; … /* start the fireworks */ ENABLE_INTERRUPT(INTERRUPT_GLOBAL); demo_done= 0; x = y = 0; while (! demo_done) { DISABLE_INTERRUPT(INTERRUPT_BUTTONS); copy1 = x; copy2 = y; ENABLE_INTERRUPT(INTERRUPT_BUTTONS); X32_display = ((copy1&0xff)<<8) | (copy2&0xff); if (copy1 != copy2) printf("alarm: %d != %d\r\n",copy1,copy2); } DISABLE_INTERRUPT(INTERRUPT_GLOBAL); return 0; } … intdemo_done; int x, y; … void isr_buttons(void) { printf("isr: %d++\r\n",x); x++; y++; if (X32_buttons == 0x09) demo_done = 1; }

  33. X32: Demo Demo .. (x32_projects.tgz, critical.c)

  34. Lecture overview • Definition & characteristics • Shared-data problem • Interrupt latency

  35. Interrupt Latency • Quick response to IRQ may be needed • Depends on previous rules: • The longest period of time in which interrupts are disabled • The time taken for the higher priority interrupts • Overhead operations on the processor (finish, stop, etc.) • Context save/restore in interrupt routine • The work load of the interrupt itself • worst-case latency = t_maxdisabled + t_higherprio ISRs + t_myISR + context switches

  36. Example #1 EI EI DI DI ISR main IRQ ISR blocked ISR code Interrupt execution time – worst case scenario analysis

  37. Example #2 DI EI lp ISR hp ISR main hp IRQ lp IRQ blocked hp ISR actual load Interrupt execution time – worst case analysis – in the presence of a second interrupt

  38. Alternatives to disable() • Do not disable interrupts but write ingenious code • By alternating data buffers (Fig. 4.15/page 108) • By using queues (Fig. 4.16/page 109) • ISR and (main) code never access the same data • Problem: code becomes error-prone and hard to read • Rule of the thumb: • Keep it simple, just disable interrupts as long as: • keep the critical sections SHORT • keep the ISRs SHORT (to minimize latency)

  39. Avoiding interrupts #1 Void main(void) { while (TRUE) { if (useB) if (tempB[0]!=tempB[1]) … ; else if (tempA[0]!=tempA[1]) … ; useB = !useB; } } static inttempA[2]; static inttempB[2]; static booluseB = FALSE; void interrupt readTemp() { if (useB) { tempA[0]=…; tempA[1]=…; } else { tempB[0]=…; tempB[1]=…; } } Alternating data buffers example (page 108)

  40. Avoiding interrupts #2 • Make use of a circular queue (example page 109) • Interrupt “produces” temperature readings • Main code “consumes” temperature readings • Operation • Interrupt adds readings to the queue (modifies the head pointer) • Main code extracts readings from the queue (modifies the tail pointer) Queue New values Tail pointer Head pointer

  41. X32: Demo Demo .. (x32_projects.tgz: timing.c)

  42. Questions?

More Related