Presentation is loading. Please wait.

Presentation is loading. Please wait.

An Embedded Software Primer

Similar presentations


Presentation on theme: "An Embedded Software Primer"— Presentation transcript:

1 An Embedded Software Primer
David E. Simon

2 Chapter 4: Interrupts Microprocessor Architecture Interrupt Basics
The Shared-Data Problem Interrupt Latency 3/5/2006

3 Microprocessor Architecture
Most microprocessors and their assembly languages are generally similar to one another. An assembly language is a more easily readable form of the instructions that a microprocessor actually works with. The assembly language is translated into binary numbers by a program called an assembler before execution. When translating C, most of the statements are converted into multiple assembly instructions by the compiler. Each microprocessor family will have a different assembly language (e.g. the Intel 8085, 8051 etc.) however the individual microprocessors in the same family generally have the same assembly language. Microprocessors typically have a set of (general-purpose) registers that can store data values. 3/5/2006

4 Microprocessor Architecture (contd.)
The registers are used before performing any data operations like arithmetic. For the following sections assume the microprocessor has the registers R1, R2, R3 …….etc. Apart from the above registers, microprocessors normally contain special registers like: Program Counter: Contains the address of the next instruction to be executed. Stack Pointer: Contains address of the top of the processor stack. Accumulator: Used by the microprocessor to do arithmetic operations. 3/5/2006

5 Microprocessor Architecture (contd.)
Some assembly language conventions: The variables in the instruction are normally read from right to left. e.g. MOVE R1, R2 will move the contents of register R2 to register R1 A variable-name in an instruction refers to its address. MOVE R5, Temperature is read “move the address of Temperature to register R5” A variable in parentheses refers to the value of the variable. MOVE R5, (Temperature) will place the value of Temperature in register R5. Anything following a semicolon is a comment. 3/5/2006

6 Microprocessor Architecture (contd.)
Some important instructions include: Arithmetic: ADD R2, R3 add contents of R3 to R2 Bit-oriented: NOT R5 invert all the bits of R5 Jump (unconditional): Will unconditionally jump to an instruction specified by a label. Labels are followed by colons. ADD R2, R3 NOT R2 JUMP NO_ADD ADD: ADD R2, R5 ; Comments come here NO_ADD: MOVE R7, R2 ; R7 contains the final result The instruction adds contents of R3 to R2, inverts the result in R2, jumps unconditionally to the NO_ADD label (the instruction ADD R2, R5 never gets executed) and stores the result in R7. 3/5/2006

7 Microprocessor Architecture (contd.)
Conditional Jump: Executes a jump if a certain condition is true. SUBTRACT R2, R3 JCOND ZERO,NEXT . NEXT: Here jump is executed if result of the subtraction is zero. PUSH and POP: These are stack instructions. PUSH adjusts the stack pointer and adds data to the stack while POP retrieves the data and adjusts the pointer. CALL: Used to execute functions and subroutines. Followed by a RETURN instruction for getting back. CALL SUBTRACT_THESE MOVE R7,R2 SUBTRACT_THESE: SUB R2,R3 RETURN 3/5/2006

8 Interrupt Basics Interrupts are triggered when certain events occur in the hardware. e.g. when a serial chip has sent data to a microprocessor and wants it to read it from its pin, it sends an interrupt to the processor, usually by sending a signal to one of the processor’s IRQ (interrupt request) pins. On receiving an interrupt, the microprocessor stops its current execution, saves the address of the next instruction on the stack and jumps to an interrupt service routine (ISR) or interrupt handler. The ISR is basically a subroutine written by the user to perform certain operations to handle the interrupt with a RETURN instruction at the end. It is a good practice to save register state and reset the interrupt in ISRs. ISRs are similar to a CALL except that the call to the ISR is automatically made. 3/5/2006

9 Interrupt Basics (contd.)
The following shows an e.g. of an ISR Task Code ISR ... MOVE R1, R7 MUL R1, 5 PUSH R1 ADD R1, R2 PUSH R2 DIV R1, JCOND ZERO, END ;ISR code comes here SUBTRACT R1, R POP R2 POP R1 END: MOVE R7, R1 RETURN 3/5/2006

10 Interrupt Basics (contd.)
Saving and Restoring the Context As the above code demonstrated, the task code has no idea of the changes taking place in registers like R1 or R2 in the ISR. Hence if R1 is modified by the ISR, we might get an incorrect final result. Due to limited number of registers, the ISRs and task codes usually have to work with same registers. To solve this problem it is common practice to save the register contents onto the stack (saving the context) and restoring them at the end of the ISR (restoring the context). This is mandatory to prevent any bugs from appearing due to interrupts 3/5/2006

11 Interrupt Basics (contd.)
Disabling Interrupts Most microprocessors allow programs to disable interrupts. In most cases the program can select which interrupts to disable during critical operations and which to keep enabled by writing corresponding values into a special register. Nonmaskable interrupts however cannot be disabled and are normally used to indicate power failures or other serious event. Certain processors assign priorities to interrupts, allowing programs to specify a threshold priority so that only interrupts having higher priorities than the threshold are enabled and the ones below it are disabled. 3/5/2006

12 The Shared-Data Problem
In many cases the ISRs need to communicate with the task codes through shared variables. Fig. 4.4 from Simon shows the classic shared-data problem. The code continuously monitors two temperatures and sets off an alarm if they are different. An ISR reads the temperatures from the hardware. The interrupt might be invoked through a timer or through the temperature sensing hardware itself. Now, consider that the temperatures are 70 degrees and an interrupt occurs after iTemp0 = iTemperatures[0] is executed. The temperatures now become 75 degrees. Hence on returning from ISR, iTemp1 will be assigned 75 and an alarm will be set off even though the temperatures were the same. Fig. 4.5 compares the values iTemperatures[0] and iTemperatures[1] directly without making a local copy. However as the assembly code for this code in Fig. 4.6 shows if an interrupt occurs between the two MOVES, this translates into the same problem as Fig. 4.4 and the alarm goes off when it shouldn’t have. 3/5/2006

13 The Shared-Data Problem (contd.)
3/5/2006

14 The Shared-Data Problem (contd.)
Characteristics of the Shared-Data Bug The problem in both the above figures (4.4 and 4.5) is due to the shared array iTemperatures. These bugs are very difficult to find as they occur only when the interrupt occurs in between the first 2 MOVE instructions, other than which code works perfectly. Solving the Shared-Data problem The problem can be solved by disabling the interrupts during the instructions that use the shared variable and re-enabling them later. The following modification to Fig. 4.4 (or 4.5) solves the problem. while (TRUE) { disable(); ; Disable interrupts iTemp0 = iTemperatures[0]; iTemp1 = iTemperatures[1]; enable(); ;Re-enable interrupts ... ;Remaining code same as in Fig. 4.4 } In assembly DI and EI are used to disable and enable interrupts respectively. 3/5/2006

15 3/5/2006 “Atomic” and “Critical Section” Few Examples
A part of a program is “atomic” if it cannot be interrupted. Hence the code between disable() and enable() above is atomic. Atomic might also be used for codes that only disable interrupts working with the same data. Hence if interrupts not working with the temperature variable (like pressure, time etc.) are left enabled code is still considered atomic and free of bugs. Few Examples Consider an ISR that updates iHours, iMinutes and iSeconds every second through a hardware timer interrupt. The function to calculate the time can be written as follows: long iSecondsSinceMidnight (void) { long lReturnVal; disable(); lReturnVal = (((iHours*60) + iMinutes) * 60) + iSeconds; enable(); return (lReturnVal); } A problem in the above code arises when the function is called from a critical section that has disabled interrupts. The function will incorrectly enable interrupts on return. Fig solves this problem. 3/5/2006

16 The Shared-Data Problem (contd.)
The volatile Keyword Fig from Simon fixes the shared-data problem without disabling interrupts by reading the seconds twice. 3/5/2006

17 The Shared-Data Problem (contd.)
However certain compilers will optimize the code. It will read lSecondsToday in one or more registers and instead of updating the value before saving it to lReturn it will read the value from the register every time instead of from memory. Some compilers might also remove the while-loop during optimization causing the same bug as in Figs 4.4 and 4.5. This is prevented by declaring lSecondsToday as volatile. This warns the C compiler that the variable might change due to interrupts or other routines and not to optimize code pertaining to it. static volatile long int lSecondsToday; 3/5/2006

18 Interrupt Latency Make ISRs short
Interrupt latency is the amount of time taken to respond to an interrupt. This depends on several factors:- Longest period during which the interrupt is disabled Time taken to execute ISRs of higher priority interrupts Time taken for the microprocessor to stop the current execution, do the necessary ‘bookkeeping’ and start executing the ISR Time taken for the ISR to save context and start executing instructions that count as a ‘response’ The third factor is measured by knowing the instruction execution times from the processor manual, when instructions are not cached. Make ISRs short Factors 4 and 2 are controlled by writing efficient code that are not too long. Factor 3 depends on hardware and is not under software control. 3/5/2006

19 Interrupt Latency (contd.)
Disabling Interrupts Disabling interrupts increases interrupt latency so this period should be kept as short as possible. Consider the scenario in which two different task codes disable interrupts for 125 and 250 µs resp. In this case the max. time taken to start executing an ISR will be 250 µs and not µs because ISR is started as soon as the interrupts are re-enabled in either one of the atomic sections. Alternatives to Disabling Interrupts As disabling interrupts increases latency, some alternatives might be required in certain situations. Fig (Simon) uses two array sets iTemperaturesA and iTemperaturesB and a variable (fTaskCodeUsingTempB) to ensure that the ISR always works with the array not being used by the task code. However the while-loop might have to run twice if the task checks the wrong array the first time. 3/5/2006

20 Interrupt Latency (contd.)
Fig uses a queue. The ISR writes data at the head of the queue and increments iHead by 2 while the task code starts reading from the tail of the queue. These alternatives are not robust and even minor changes might introduce bugs and hence should only be used as the last option. 3/5/2006


Download ppt "An Embedded Software Primer"

Similar presentations


Ads by Google