210 likes | 310 Views
Robocon 2007 Electronics Quickstart!. Session 5 Interrupt and OS Prepared by KI Chi Keung [chikeung @ ust.hk] WONG Long Sing (Sam) [sam @ hellosam.net]. Today ’ s Timeline. Program Counter and Hardware Stack Interrupt Buffering for Events Multitasking. 0000. 0001. 0002. 0006.
E N D
Robocon 2007Electronics Quickstart! Session 5 Interrupt and OS Prepared by KI Chi Keung [chikeung@ust.hk] WONG Long Sing (Sam) [sam@hellosam.net]
Today’s Timeline • Program Counter and Hardware Stack • Interrupt • Buffering for Events • Multitasking
0000 0001 0002 0006 MOV A,0 ADD A,B JMP HEY SEI A,1 CLR C SUB B,C CMP B OUT 20 XOR A,9 MOV A,0 ADD A,B JMP HEY SEI A,1 CLR C SUB B,C CMP B OUT 20 XOR A,9 MOV A,0 ADD A,B JMP HEY SEI A,1 CLR C SUB B,C CMP B OUT 20 XOR A,9 MOV A,0 ADD A,B JMP HEY SEI A,1 CLR C SUB B,C CMP B OUT 20 XOR A,9 HEY Program Counter • Program Counter is an Integer register • A.k.a. as PC. • Has the address of the executing byte code • It advance by 1 step when execution is finish • Or being rewritten to some other value when CPU faces branching instruction, or calling a function • or being interrupted! 0000
0FFF int A 0FFE 0FFD int B 0FFC 0FFB char i 0FFA Rtn Addr 0FF9 0FF8 void* j 0FF7 0FF6 char i 0FF5 Rtn Addr 0FF4 int i[2] 0FF3 0FF2 0FF1 0FF0 0FF1 Hardware Stack • Hardware Stack is a piece of storage • Top located by the register - Stack Pointer, a.k.a. SP • Located at a specific position of main memory • For temporary storage, grows and shrink during execution • Local variable • Return address after calling a function • Grows towards lower address • An entire record is pushed when calling a function. • Usually, Only the top frame is used, others are ignored. 0FFF int A 0FFE 0FFD int B 0FFC 0FFB char i 0FFA Rtn Addr 0FF9 0FF8 void* j 0FF7 0FF6 char i 0FF5 0FF4 0FF3 0FF2 0FF1 0FF0 0FF6
Hardware Stack Another illustration from the Wikipedia
Heap Dynamic Allocation Stack Local Variable Global Variables Memory Arrangement Start End
Interrupt • So far we use while loop to keep on eyes on event (Switch, UART…) • This is called polling • It’s problematic • When we have a lot of events, it’s so hard to code • At the end, 99% of CPU time is used on busy waiting • Wouldn’t it be good if you are notified about an event instead? • So that CPU time is spent wisely instead of busy waiting • And this is interrupt
Interrupt • Tell the CPU that you want to be notified for an specific event. • Enabling the specific Interrupt line in register • Your interrupt service routine, a.k.a. ISR, will be called if such event occurs. • PC and Stack are modified in the same way, compare to that of calling a function • When ISR returns, execution resumes in main program
Interrupt • Interrupt is a hardware feature. All modern CPU have it. • It could never detect an in interrupt has happened, unless you tell it. • It could never prevent an interrupt from occurring, it can occur at any time • Of course unless the interrupt is disabled These characteristics will bring you a new set of problem.
Buffering for Events By using the interrupt • SendHandover all the data to be sent to the ISR • ReceiveNeed to store the data. Wait for CPU to process them i.e. You need a buffer. A temporary storage that making the transition smooth. So what is the data structure?
Buffering for Events A Queue! ISR Pop CPU Push
Buffering for Events Yeah! 勝った(我贏了)。 almost. The word Queue is just a concept. What are the implementations? • Linked List • Circular Buffer
Buffering for Events Linked list Advantage • Clean and clear concept! Has been explained for 100 times • Dynamically expandable Disadvantage • 2/3 memory overhead • No dynamic allocation, or otherwise expensive, in MCU! struct queue { char data; struct queue* next; } struct queue *head, *tail;
Buffering for Events Circular Buffer Advantage • Compact, almost no overhead • Fast to process Disadvantage • Fixed size char queue[128]; char head, tail; Head points to a free cell Tail points to the oldest occupied cell
Task Modify the echo program with output using circular buffer.
Multitasking We have a new problem. Imagine if we have many I/O queue like the UART. int main() { while (true) { // Check UART Queue // Response to computer command // Check Playstation Queue // Response to operator input // Auto Machine check Sensor // Auto Machine Calculation // Auto Machine Motor Output } }
Multitasking Won’t it be more logical if we… void UART_handler() { while (true) { // Wait for Check UART Queue // Response to computer command } } void manual_control() { while (true) { // Wait for Playstation Queue // Response to operator input } } void auto_machine_the_brain() { while (true) { // Wait for Playstation Queue // Response to operator input } }
Multitasking And that is multitasking, with the help of OS. People have written mini-OS that suitable for MCU deployment, to solve that problem.
Multitasking • There is only one processing unit. It looks like everything is running at the same time but it is not. • The CPU take care of different task from time to time. • When it change its task, it’s called Context Switching. Overhead: backup and restore all registers. • Context switching can be triggered at fixed interval (Preemptive) or task give up CPU time voluntary (Non-preemptive)
Thread Safety Traps produced by Multitasking and Interrupt • I/O device is shared. Make sure it is either shared or a task has exclusive right to use. • Interrupt/Context switch can happen at any time. Variable update and Race condition! • New task access to the same function, is the function reentrant? • Specific to AVR: you need to shutdown interrupt for accessing 16-bit SFR like Timer value. (Atomic operation problem) See http://en.wikipedia.org/wiki/Thread-safe for more
Thread Safety Non-preemptive VS Preemptive • Less responsive • but higher throughput • Less to worry about reentrancy problem