Tics Realtime -----


 
Home Services Products Tutorials Contact Us
- - - - -

Tics Realtime Definitions

active task

Refers to the task that is currently running. Multi-tasking kernels need to know the identity of the currently running task so that it can know where to save the task's context when the kernel performs a task switch. For example, a global variable called ActiveTcb might point to the tcb of the active task. The kernel would save the active task's context on the active task's stack (i.e. the current stack)

application

Another name for program.

assert, asserted

Designates the active state of an electrical signal. For example, raising a normally 0 volt CPU input control pin to 5 volts asserts the line. Similarly, pulling down a normally 5 volt CPU input control pin to 0 volts asserts the line. In either of the above examples, the line is said to be asserted. When an input put is asserted, it performs its function. For example, asserting the interrupt pin on the x86 generates an interrupt.

block, blocked task

A task is blocked when it attempts to acquire a kernel entity that is not available. The task will suspend until the desired entity is available. A task is blocked when: it attempts to acquire a semaphore that is unavailable, or when it waits for a message that is not in its queue, or while it waits for a pause to expire, or when, in a time-slicing environment, its time-slice has expired, to give a few examples.

boot code, boot up, boot loader

The startup code that is stored in ROM; this code runs at power-on / reset time. "Bootup" refers to this process. Derived from the old story about a man trying to pull himself up by his own boot straps. Note that code in ROM is also referred to as "firmware". In some embedded systems the entire software set resides in ROM; in others, the the ROM only contains enough code to load the rest of the program in from another source (hard disk drive, another computer via a network, etc.). Once the boot code has loaded the rest of the program into memory, it jumps to the first instruction of the loaded code, and its job is done. The typical PC works this way (the ROM has boot code that loads the OS from a disk drive). See loader for more details about program loading.

 
break, breakpoint

A program breaks when a breakpoint is reached. A breakpoint is an instruction address at which a debugger has been commanded to stop program execution, and execute the debugger so that the user can enter debugger commands. At some point after breaking the user typically executes a debugger command like "continue" which continues program execution from the point at which the program was stopped.

busy waiting, polling
The process by which code repetitively checks for a condition. The following code exhibits busy waiting.

	while (TRUE)  {
		if (switchDown) {
			lampOn();
			break;
		}
	}

The code stays in the loop until the condition is met. Contrast with event driven code.

context, context switching

A CPU's context typically refers to all its registers (including IP and SP) and status register(s). When a task switch occurs, its context is saved, and the context of the next task to run is restored. The saving of the current task's context and the restoring of the context of the next task to run is called a context switch. (Special Note: In a more complete sense context also includes the task's local variables and its subroutine nesting information (for example, the task may be 7 subroutine calls deep when the context switch is made, and when the task is eventually resumed the task's code must be able to return from all 7 subroutines). The local variables and subroutine nesting level are preserved by giving each task its own private stack when the task is created, since subroutine return information and local variables are stored on the stack.).

cooperative scheduling

A group of tasks run cooperatively when each must voluntarily relinquish control so that other tasks can run. In other words, a task will run forever, thus starving other tasks, unless it voluntarily gives up control. Control can be relinquished explicitly by a yield, pause, or suspend; or implicitly by waiting for an event. Contrast with priority based preemptive scheduling and time-slicing.

crash

A system is crashed when the CPU has halted to due a catastrophic error, however, the word can be used in the same sense has hung.

cyclical executive, cyclical kernel, cyclical scheduling, foreground/background
See also the article A Cyclical Executive for Small Systems. Cyclical (also referred to as round robin) scheduling is done without an operating system per se by simply calling one "task" (typically a C function) after another in an infinite loop as shown below.

void main(void)
{
	for (;;) {
		task0();
		task1();
		task2();
		/* and so on... */
	}
}

In this scenario, each task must do its work quickly, save its state if necessary, and return back to the main loop. The advantages with this approach are small size, no kernel required, requires only 1 stack, and easy to understand and control. The disadvantages are no priorities, tasks must retain their states, more responsibility is placed on the programmer, and the possibility of excessive loop latency when there are many tasks. High priority events generate interrupts and are handled in the background by isr's. This technique is sometimes referred to as foreground/background.

debugger

A debugger is a software program used to break program execution at various locations in an application program after which the user is presented with a debugger command prompt that will allow him to enter debugger commands that will allow for setting breakpoints, displaying or changing memory, single stepping, and so forth.

deadlock

The term can have various meanings, but typically, a deadlock is a condition in which a task will remain forever suspended waiting for a resource that it can never acquire. Consider a system comprised of a keyboard and a display, with a separate semaphore for each. In order for a task to interact with the user it must acquire the "console" (keyboard and display) and therefore must acquire both the keyboard and the display semaphores. If more than one task decides to interact with the user at the same time a condition can arise where taskA acquires the keyboard semaphore and taskB acquires the display semaphore. Now taskA will wait forever for the display semaphore and taskB will wait forever for the keyboard semaphore. The solution in this example is to treat the keyboard and display as a single resource (console). Deadlocks can occur for a variety of reasons, but the end result is typically the same: the task will wait forever for a resource that it can never acquire.

differential timer management

A method of managing timers such that only 1 timer count is decremented regardless of the number of pending timers. Consider 3 pending timers with durations of 50 ms, 20 ms, and 5 ms respectively. The timers are sorted and stored in a list with the lowest timer first: 5, 20, 50. Then the timer durations are replaced with the difference of the timer duration and the preceding duration, i.e., 5, 20, 50, is replaced with 5, (20-5), (50-20), which equals 5, 15, 30. This allows for only the first duration (5 ms in this example) to be decremented. Thus, when the first duration of 5 decrements down to 0, there are only 15 ms required to meet the 20 ms duration, and when the 50 ms duration is to be started, already 5 + 15 = 20 ms have expired, so only a count of 30 ms is required. This technique is attractive because the timer counts are typically decremented inside the timer isr and time inside any isr should be kept to a minimum.

download

Refers to the transfer of executable code from a host to a target, typically using an RS-232 serial line, parallel printer cable, or Ethernet. Download either requires an ICE, or the target must have resident software (e.g., FLASH) that can read the incoming data, translate it if necessary (the file format may be ASCII hex for example) and load the code into RAM memory. If the target board has no resident software, then an ICE is required. 

dynamic priorities

Priorities that can be changed at run-time. Contrast with fixed priorities.

dynamic RAM (DRAM)

RAM that requires a periodic refresh (i.e., a write) to maintain data integrity.

event, event driven code

Code that remains dormant until an event occurs. The following is an example.

	while (TRUE) {
		msg = waitMsg(MOTOR_ON);
		freeMsg(msg);
		turnMotorOn();
	}

Until the message MOTOR_ON is received, the function waitMsg will suspend the current thread of execution until the message is received. The receipt of the message is the event that causes the ask to be scheduled and eventually run. Contrast with busy waiting.

exception

A software interrupt generated by the CPU when an error or fault is detected.

fairness

A concept which dictates that if a task runs too long, its priority is lowered so that other tasks can get their fair share of the CPU. This concept is repugnant to real-time principles and is used chiefly in multi-user systems with the intent of disallowing one user from monopolizing the CPU for long compiles and the like.

fault

A fault is an exception that is generated when the current instruction needs help before it can be executed. For example, supposed in a virtual memory system, a memory access is made to a page that is not in memory. In this case, a fault is generated which vectors to an isr that will read in the page. The fault exception is different in the way it returns from interrupt in that control is returned to the instruction that caused the fault, not the following instruction as with a normal interrupt. This allows the instruction to access the memory again, and this time succeed.

fixed block memory allocation

A memory allocation/deallocation scheme in which a number of memory pools of fixed sized blocks is created. For example, 3 pools are created as follows: pool 1 contains 100 64 byte blocks, pool 2 contains 50 256 byte blocks, and pool 3 contains 10 1K byte blocks. When a user wants memory he takes and returns blocks from/to a pool. For example, if the user needed a 256 byte block of memory he would take a block from pool 2. Similarly, if he needed a 100 byte block he would still have to take a block from pool 2 even though bytes are wasted. The advantage is no fragmentation and high speed.

fixed priorities

Priorities that are set once, typically at compile time, and unalterable at run-time. Contrast with dynamic priorities.

FLASH Memory
Unlike DRAM and SRAM, FLASH memory retains the data values stored in it when power is turned off. In self-booting embedded systems, the program code is stored in FLASH. When power is applied, the hardware is designed to jump to a known FLASH address, at which the first instruction of the program is stored, and program execution begins. Writing to FLASH memory is quite slow compared to SRAM and DRAM, so embedded systems also include SRAM or DRAM for data storage and manipulation; in addition, FLASH is more expensive than standard memory. Writing to FLASH is a complicated process; you just can't write to an address like you would with normal memory. FLASH memory requires you to write a sequence of values to special FLASH addresses to unlock the FLASH for writing. Once the sequence has been written, FLASH memory can be written to in the normal way. This is a useful and necessary feature. Consider what might happen if a bug caused part of FLASH to be overwritten - the system would no longer boot up, because of FLASH corruption. Requiring the sequence of writes first makes the possibility of FLASH corruption remote. FLASH can be written to under program control (i.e., a program that you write that is downloaded to your embedded system via ICE) by using a FLASH programmer.

FLASH programmer
A hardware box that connects to the PC via the printer port, Ethernet, or similar communications channel and talks to vendor supplied software that runs on the PC. The software allows for writing and reading of FLASH chips. The FLASH programmer is equipped with a socket that allows the user to insert FLASH chips for reading and writing (writing is also referred to as FLASH "programming").

 
fragmentation

In a kernel or language which allows for memory allocation and deallocation, the available free memory can eventually become fragmented, i.e., non-contiguous, if memory is allocated from one large pool. For example after allocating and deallocating many different size blocks of memory, there may be 12K available, but it is not contiguous, and therefore, if software needs 12K it cannot use it, even though it is available. Contrast with fixed block memory allocation.

hang, hung

A system is hung when it does not respond to external input (e.g. keyboard) but has not completely crashed. A hung system is typically spinning in an endless loop.

hard real-time

Hard real-time refers to the strict definition of real-time. See real-time.

hardware interrupt latency

The time it takes for the isr to be entered, once the processor interrupt pin is asserted.

HEX file, ASCII HEX file

Most linkers have the ability to generate a hex file. This is an ascii readable (you can view it with your text editor) version of the executable file. The hex file is useful when you need to write a loader program.

hook, chain

Intercept an interrupt by saving the current interrupt vector and writing a new interrupt vector. When the new interrupt service routine is finished it calls the old interrupt service routine before returning.

host

See target.

in-circuit emulator, ICE

An ICE is essentially a hardware box that connects a PC to an embedded system. Typically the ICE vendor or a third party supplies debug software that  turns the PC into a debugging station. The ICE requires an IO port (typically  the parallel printer port) on the PC and an industry standard JTAG connector and JTAG support on the target board; if you do not design JTAG support into your target system, then an ICE cannot be used (unless you build your own custom ICE). Breakpoints, single stepping, variable display,  etc. are all supported. One of the most important features provided by the ICE is the ability to download software into the target system memory. The ICE allows for trapping the following types of activities: read/write to an address range, read/write a specific value from an address range, setting a breakpoint in ROM, mapping emulator memory to target board memory, and other similar features. It also turns the host (a PC for example) into a debug station with supplied software. This allows for debugging of the target board even though the target does not have a keyboard, screen, or disk. For more information, see articles 1, 2, and 3.

idleTask

A kernel owned task that is created and scheduled during system initialization. It runs at the lowest possible priority. The idle task has the lowest possible priority and runs only when no other tasks are scheduled. When any other task is scheduled, the idle task is preempted. The idle task is typically a "do nothing" tight loop. Its only purpose is to run when no other tasks run. It is a convenience mechanism in that no special kernel code is required to handle the case of all tasks being idle; the kernel sees the idle task like any other task. The key is that the idle task has a lower priority than any other task, and even though it is scheduled to run and occupies a place in the ready queue, it will not run until all other tasks are idle. And, conversely, when any other task is scheduled, the idle task is preempted.

instantiate, instantiation

To start multiple instances of a task.

intercept

Identical to hook except that the old isr is not called before returning.

interrupt, interrupt vector
Most microprocessor chips have a pin designated as the "interrupt" pin. The interrupt pin can be enabled or disabled by software (however the special NMI interrupt cannot be disabled by software). The CPU checks the interrupt pin after the execution of each machine code instruction. When the CPU detects that the interrupt pin is asserted and interrupts are enabled, the typical microprocessor (1) halts, (2) saves the current instruction pointer and the processor status register on the stack, and (3) jumps to the location of an interrupt service routine (isr). How the address of the isr is determined is CPU dependent. Some CPU's have multiple interrupt pins, and each pin refers to a reserved memory location where the isr address can be found. For example, consider an imaginary 16 bit CPU with 8 interrupt pins numbered I0 through I7, which refer to interrupt numbers 0 through 7, and an interrupt vector table starting at address 0. The addresses of the isr's for interrupt pins I0 through I7 would be located at addresses 0, 2, 4, 6, 8, 10, and 12. The dedicated interrupt pin approach works fine until more than 8 interrupts are desired. The 8086 handles this problem by relegating the handling of the interrupt signals to a special interrupt controller chip like the 8259A. The 8086 has only 1 interrupt pin. When the interrupt pin is asserted, the 8086 determines which device generated the interrupt by reading an interrupt number from the interrupt controller. The interrupt number is converted to an interrupt vector table index by multiplying the interrupt number by 4 because each entry in the 8086 interrupt vector table requires 4 bytes (2 bytes for the CS register and 2 bytes for the IP register). Although the 8259A interrupt controller handles only 8 incoming interrupt lines, the 8259A's can be cascaded to handle more interrupts. Interrupts allow a system to react immediately to important events (depression of an EMERGENCY STOP button for example).

interrupt controller
(The following explanation uses the 8259A as an example interrupt controller). Sometimes many interrupts are required. Most CPU's with dedicated interrupt pins have no more than 8 interrupt pins, so that no more than 8 incoming interrupts can be handled. A way around this problem is to handle interrupts with an interrupt controller chip. Typically interrupt controller chips can be cascaded so that even though a single interrupt controller chip handles only 8 incoming interrupts, a cascade of 4 can handle 32 incoming interrupts. The typical arrangement is for the hardware device (an Ethernet chip for example) to signal an interrupt by asserting one of its output pins which is directly connected to one of the interrupt controller's interrupt pins. The interrupt controller then signals the CPU by asserting the one and only CPU interrupt pin. The CPU then begins a special interrupt bus cycle with the interrupt controller and obtains the interrupt number which is converted into an index into an interrupt vector table, which enables the CPU to jump to the proper isr for the interrupt. If other interrupts are asserted while the CPU is handling an interrupt, the interrupt controller waits until it receives a signal from the CPU called and EOI (end of interrupt) before interrupting the processor again. The EOI signal is generally asserted with a software IO output instruction. Note however, that if more than one interrupt is generated on the same interrupt controller pin while the CPU is processing an interrupt, then all but the first waiting interrupt on that pin will be lost. Note also that when using an interrupt controller the interrupts can be individually enabled or disabled (another word for disabled is "masked"). So, for an interrupt to make it from the interrupting device, through the interrupt controller, through the CPU and finally to the isr, the individual interrupt must be enabled at the interrupt controller and the interrupts at the CPU must be enabled also. Interrupts on the CPU are enabled or disabled with a software instruction; interrupts on the interrupt controller are enabled/disabled by setting or clearing a bit in one of the interrupt controller registers. The interrupt controller is typically accessed through memory mapped IO. For more information see interrupts.

interrupt service routine, isr

A routine that is invoked when an interrupt occurs.

interrupts and CPU flags register, IRET instruction

It is necessary to save the flags on entering an isr and restore them on exit, otherwise, the isr may change the flags, which can cause problems. The 8086 automatically saves flags on the stack prior to calling the isr, and restores the flags before returning using the IRET instruction. The reason for saving the flags can be understood by considering the following code fragment.

	; Assume that AX = 0.

	CMP AX,0
	JE LABEL7

The CMP instruction executes, and because AX = 0, the Z bit in the flags register is set by the CPU. Let us say that after the compare instruction, an interrupt occurs and the isr is jumped to which executes the following instruction.

	; Assume BX = 1.

	CMP BX,0

The above instruction will clear the Z bit because BX is not 0. The isr will eventually return to the instruction above JE LABEL7. If a standard RET instruction is used instead of IRET, the flags will not be restored, and the instruction JE LABEL7 will not perform the jump as it should because the Z bit was cleared in the isr. For this reason flags must be saved before entering an isr and restored prior to returning from an isr.

interrupt vector table, interrupt service routine (isr), software interrupt

Some CPU's handle with an interrupt vector table. On the 8086, the interrupt vector table is a 1K long table starting at address 0, which will support 256 interrupts numbered 0 through 255. The numbers 0 through 255 are referred to as "vector numbers" or "interrupt numbers". The table contains addresses of interrupt service routines, which are simply subroutines that are called when the interrupt occurs. The only difference between an interrupt service routine and a subroutine is that on entry to the isr the CPU flags are stored on the stack in addition to the return address; for an explanation of why the flags must be saved, see the definition. This means that an interrupt service routine must return with a special return instruction (IRET on the 8086) that pops the CPU flags off the stack and restores them before returning. On the 8086, an address is specified by a segment and an offset, and therefore each interrupt vector table entry uses 4 bytes; two bytes for the CS register and 2 bytes for the IP register (IP is the lower word in the vector table and CS is the higher word). An interrupt service routine can be invoked by software using the 8086 INT instruction, which in addition to the return address pushes the CPU flags onto the stack. An interrupt service routine can also be invoked by software using a standard CALL instruction as long as the CPU flags are first pushed onto the stack. For details of how an interrupt is generated and serviced, see interrupts.

kernel, multi-tasking kernel, real-time kernel, RTOS

Software that provides interfaces between application software and hardware and in general controls and programs all system hardware. A multi-tasking kernel provides for multi-tasking in the form of threads, processes, or both. A real-time kernel provides is a multi-tasking kernel that has predictable worst case tasks switch times and priorities so that high priority events can be serviced successfully.

linker, locator, program sections

The compiler/assembler translates high level language code into a binary machine language file called an object file. The start address for the code in the object file is always address 0. The linker program allows multiple object files to be combined into a single executable file. Since each object file starts at address 0, the linker must reassign addresses so that there are no conflicts. The linker also resolves references. For example, if fileA.c calls a function named functionB that is defined in fileB.c, the compiler leaves the address of functionB blank in fileA.obj. When the linker links fileA.obj and fileB.obj together into one executable file, the linker fills in the correct address for functionB. Any blank addresses that remain blank after linking are flagged as "unresolved external references" by the linker. Embedded systems linkers also have a "locate" feature. This allows the programmer the ability to tell the linker where to locate code in memory. This feature is necessary because, for example, certain pieces of code reside be at certain addresses. For example, the boot code must be at the start address that the microprocessor jumps to on power-up. See reset for details. The locator also allows the programmer to name sections of his code and locate the contents at specific addresses. For example, in each of the C/C++ files (call them fileA.c, fileB.c, and fileC.c) that contain code that is to reside in FLASH the programmer might code something like this at the top of the file.

// Each of the C files should contain the following line at the top of the file.
#pragma section FLASH

// Write C/C++ code here that is to be located in FLASH.
Then in his linker/locator command file that will be submitted to the linker, he might code something like this:
FILES fileA.obj fileB.obj fileC.obj ; These are the files to link together.
LOCATE FLASH AT 9000000H            ; Locate program section "FLASH" starting at 90000000h.

How the above is done will vary from linker to linker.

 

loader
A program that reads an executable file and loads it into memory. When you type an EXE program name at the DOS prompt you are actually invoking the loader program, which reads the EXE file, loads it into memory, then jumps to the start address of the program to begin program execution. Loader input files are not limited to EXE files. For example, embedded systems loaders typically read an ascii hex file from a remote host via an network connection. The hex file is preferred because it is easier to read and process. The hex file however, takes more time to load because ascii to binary conversion must be performed on each data item, which is  why operating systems like DOS and Unix load binary executable files (no ascii conversion required).

 

machine language (machine code), assembly language, high level language

Machine language, or machine code, is the binary language that the microprocessor executes. For example, the Intel x86 instruction to disable interrupts is a byte with the following binary value 11111010. The machine code instruction for a short jump is two bytes long. The first byte is 11101011 and the second byte represents how far to jump from the address of current instruction (displacement). This second byte is added to the address of the current instruction (which is contained in the program counter register, (PC), also called the instruction pointer register (IP)). In order the jump forward or backward, the second byte of the short jump instruction is a signed number. Here is a small machine language program.

        Memory
        Address    Instruction    Comment
        0000h      11111010       ; Disable interrupts.
        0001h      11101011       ; First byte of jump instruction.
        0002h      00000000       ; Second byte of jump instruction (displacement).    

Now lets see how this program executes. First we must set the program counter register (PC) to 0 so that the microprocessor will execute the instruction at address 0. Let's assume that when the microprocessor powers up it automatically sets the program counter register to address 0, so that after power up we execute the disable interrupt instruction at address 0. After the instruction is executed, the program counter is incremented by 1 so that it points to the next instruction at address 0001h. The processor fetches the instruction at address 0001h and finds that it is a short jump instruction. The processor knows that the byte after the jump instruction byte contains the displacement for the jump, so it reads the displacement value at address 0002h, which is 0,  and adds it to the current contents of the program counter register. However, since the displacement is 0, the contents of the program counter register will remain at 0001h. Since the microprocessor always fetches the next instruction at the address contained in the program counter, it will again fetch the instruction at address 0001h which is again the jump instruction. The microprocessor will execute this endless loop forever.

An assembler is a program that translates English language instructions into binary code. The above machine language program would be written in assembly language as shown below.

       CLI                  ; Disable interrupts (clear interrupt flag).
LABEL:
       JUMP SHORT  LABEL    ; Jump back to myself.

If the above code were put into a file and submitted to the assembler program, the assembler would output an "object" file that would essentially be the binary code shown above.

High level languages like C take the assembler one step further in that for each C statement one or more machine code instructions are generated. For the most part, the assembler generates one machine language statement for each assembly statement. Note that some C compilers actually generate assembly language that is then passed to an assembler to generate machine code.

memory map - hardware, memory mapped IO

Most modern microprocessor systems use "memory mapping" to allow the microprocessor easy access to external hardware. Memory mapping means that all hardware in the system, not just standard memory, can be accessed through standard microprocessor reads and writes. A simple memory map is shown below. So for example, referring to the table below, any reads or writes in the range 0000h to FFFFh address DRAM. Note that the "type" of memory for DRAM is "R/W" which means we can read or write DRAM. If we read from address 2000ch we will read a byte whose 8 bits represent the states of the 8 DIP switches (this memory type is read only). Writing out a binary 11111111h to address 20004h will light up all 8 of the bank # 1 LED's, and writing a 00000001h will turn them all off except for the last one. Note also that the hardware engineer could have designed the system so that writing a 11111111h to the LED bank would turn them all off. The memory map is generated by the hardware engineer and is typically included in his design document.

Microprocessor Address        Type         Hardware

0000h  to  FFFFh              R/W          DRAM 
10000h to 1FFFFh              R            FLASH
20000h                        W            Motor control register 
20004h                        W            LED bank # 1 (8 LED's)
20008h                        W            LED bank # 2 (8 LED's) 
2000ch                        R            DIP switch (8 rocker switches)

memory map - software
A software memory map is a file generated by the linker. Also called a map file, it lists all the global symbols (global data and subroutine names) and the addresses assigned to each. Typically, other items are also included like program section information.

 
monitor

Refers to a kernel, or a very minimal kernel used for debugging, typically written by the programmer for a particular project, or supplied on ROM from the board manufacturer.

message

A data structure that is passed to a task by placing a pointer to the structure into a queue. The queue is a doubly linked list that is known to the task. Kernel functions are supplied to remove messages from the queue.

message aliasing

A technique by which the sender of the message changes the "sender" field in the message structure before sending it so that the receiver of the message will reply to a task other than the actual sender.

messages vs. mail

Messages are queued, mail is not. New mail data may optionally over-write old, which is advantageous for certain applications. Consider taskA that updates a display and receives the latest data on a periodic basis from taskB. Assume further that the system is busy to the point that taskB sends taskA two data updates before taskA can resume execution. At this point the old data is useless, since taskA only displays the latest value. In this situation, queuing (using messages) is undesirable, and mail with over-write enabled is preferred.

multi-processing

A term that describes an environment in which 2 or more CPU's are used to distribute the load of a single application.

multi-tasking
A term that describes an environment in which a single computer is used to share time with 2 or more tasks. Contrast with multi-user. For more information and implementation details see articles 1, and 2.

multi-user

A term that describes a single computer that is connected to multiple users, each with his own keyboard and display. Also referred to as a time-sharing system. Contrast with multi-tasking.

non-maskable interrupt (NMI)
A non-maskable interrupt, or NMI, is a microprocessor pin that operates just like the standard interrupt pin with one major exception - it cannot be turned off. There is no way to disable it. I.e., the instruction   that disables interrupts only works for the standard interrupt pin; NMI ignores it. This is useful in emergency situations. Let's say that our embedded system can sense when we lose power. Assume also that we have some important things to do  before we lose power totally (like save important data). We estimate that we have about 100 milliseconds to save data. This is a good application for the NMI interrupt, because even if the software has disabled interrupts, NMI will ignore it and jump to the NMI isr so that we can save our data before we lose power.

non-reentrant, reentrant code

Non-reentrant code cannot be interrupted and then reentered. Reentrancy can occur for example, when a function is running and an interrupt occurs which transfers control to an interrupt service routine, and the interrupt service routine calls the function that was interrupted. If the function is not reentrant, the preceding scenario will cause problems, typically a crash. The problem typically occurs when the function makes use of global data. To illustrate, consider a function that performs disk accesses and uses a global variable called "NextSectorToRead", which is set according to a parameter passed to the function. Consider the following scenario. The function is called with a parameter of 5, and "NextSectorToRead" is set to 5. The function is then interrupted and control is transferred to an isr which calls the function with a parameter of 7, which results in "NextSectorToRead" being set to 7. The sector is read, control is returned to the isr, the isr performs a return from interrupt, and the function resumes with an erroneous value of 7 instead of 5 in "NextSectorToRead". This problem can be avoided by only using stack variables.

object file
The object file is the designation given to the file that is generated by a compiler or assembler. The compiler/assembler translates a file containing high level language into machine code and stores it in an object file. The compiler/assembler assumes that it has an infinite amount of memory and that all of it is available. It begins locating instructions at address 0 and moves up in memory from that point as reads down through the source code and generates machine code. Starting the code at address 0 has some problems associated with it. First, not all microprocessors allow code at address 0. For example the x86 family stores its vector table at 0. Second, most programs are comprised of more than one source file, which causes complications. Compiling each of the source files into an object file creates a conflict in that each object file claims that code starts at address 0. These problems are resolved by a program call a linker (see linker for details).

page

A unit of memory, typically around 4K, which is used as the smallest granule of memory in virtual memory systems.

polling
Polling refers to the process of constantly checking for an event; a switch closure for example. Polling is accomplished by looping. Simple polling is not good in the sense that no other work  (outside of interrupts) can be done. A simple real-time embedded systems architecture referred to as "foreground/background", or "cyclical executive" is a form of intelligent polling. In this architecture a foreground loop constantly checks for events like button presses and processes them, while in the background interrupts service important events.

preemption - causes of
Preemption occurs when a dormant higher priority task becomes ready to run. A dormant higher priority task can become "ready to run" in a variety of ways. If time-slicing is enabled, (which is rarely the case in properly designed real-time systems), preemption occurs when the task's time-slice has expired. Preemption can also occur when a message is sent to a task of a higher priority than the active task. Consider the following. The active task, taskB, invokes waitMsg to wait for a particular message named START. Since the message START is not in taskB's message queue (i.e., no task has sent taskB a message named START), taskB will be suspended until such time as the message START is received. Once taskB is suspended, the highest priority waiting task, (the task at the front of the ready queue), is removed from the ready queue, (call it taskA which is of a lower priority than taskB) and it becomes the new active task. Now if taskA sends taskB a message named START, the kernel will suspend taskA, and resume taskB since taskB has a higher priority and it now has a reason to run (it received the message that it was waiting for). Task preemption can also occur via interrupt. If a message is sent from within an isr to a task with a higher priority than the active task, (which was interrupted to run the isr), then on exiting the isr, control should not return to the interrupted task, but rather to the higher priority task to which the message was sent.

preemptive, preemption

Preemption occurs when the current thread of execution is stopped and execution is resumed at a different location. Preemption can occur under software (kernel) or hardware (interrupt) control. See priority based preemptive scheduling.

priority

A number attached to a task that determines when the task will run. See also scheduling.

priority based preemptive scheduling

A multi-tasking scheduling policy by which a higher priority task will preempt a lower priority task when the higher priority task has work to do. Contrast with cooperative scheduling and time-sliced scheduling.

priority inversion

An inappropriately named condition created as follows. Consider three tasks: taskA, taskB, and taskC, taskA having a high priority, taskB having a middle priority, and taskC having a low priority. taskA and taskB are suspended waiting for a timer to expire, and therefore taskC runs. taskC then acquires semaphoreA, and is subsequently preempted by taskA before it releases semaphoreA. taskA then attempts to acquire semaphoreA, and blocks since the semaphore is in use by taskC. taskB now runs, because it is of a higher priority than taskC and its timer has expired. Now, taskB can run until it decides to give up control, creating a condition where a high priority task (taskA) cannot run because a lower priority task has a resource that it needs. taskA will remain blocked until the lower priority task runs and releases the semaphore. This situation can be avoided by proper coding, or by using a server task instead of a semaphore.

process

A process is a single executable module that runs concurrently with other executable modules. For example, in a multi-tasking environment that supports processes, like Microsoft Windows, a word processor, an internet browser, and a data base, are separate processes and can run concurrently. Processes are separate executable, loadable modules as opposed to threads which are not loadable. Multiple threads of execution may occur within a process. For example, from within a data base application, a user may start both a spell check and a time consuming sort. In order to continue to accept further input from the user, the active thread could start two other concurrent threads of execution, one for the spell check and one for the sort. Contrast this with multiple .EXE files (processes) like a word processor, a data base, and internet browser, multi-tasking under Microsoft Windows for example.

program space

The range of memory that a program can address.

protection violation

Through a scheme involving special hardware and kernel software, tasks can be restricted to access only certain portions of memory. If a program attempts to jump to a code location outside its restricted area or if it attempts access data memory outside its restricted area, a protection violation occurs. The protection violation generates an interrupt to an interrupt service routine. The interrupt service routine will typically terminate the task that caused the violation and schedule the next ready task. When the interrupt service routine returns, it returns to the next ready to run task. Special hardware is needed because each code or data access must be checked. This is essentially done through special hardware tables that kernel software can write to. For example, when a task is created, the kernel assigns a hardware table to the task (each task is assigned a different hardware table). The kernel then writes into this table the lower limit and the upper limit of memory that the task is allowed to access. When a task starts, a special hardware register is set to point to the hardware table for the task so that the special memory management hardware (which may be on the CPU chip, or external to it) will know which table to use when making access checks. Each time the task accesses memory, the memory management hardware checks the requested memory access against the allowable limits, and generates a protection violation if necessary.

read only memory, ROM

Memory that can only be read; it cannot be written. See FLASH as an example. Note that although FLASH is writable as well as readable, it is still referred to ROM or FLASH ROM. True ROM is read only. A true ROM is typically manufactured in large quantity at low cost for high volume manufacturing where write-ability is typically not useful anyway. A ROM is typically used to store boot code and startup data like the model number etc. The model number and similar data is often used by generic ROM software that handles many different models of the product.

real-time

In a strict sense, real-time refers to applications that have a time critical nature. Consider a data acquisition and control program for an automobile engine. Assume that the data must be collected and processed once each revolution of the engine shaft. This means that data must be read and processed before the shaft rotates another revolution, otherwise the sampling rate will be compromised and inaccurate calculations may result. Contrast this with a program that prints payroll checks. The speed at which computations are made has no bearing on the accuracy of the results. Payroll checks will be generated with perfect results regardless of how long it takes to compute net pay and deductions. See also hard real-time and softRealtime.

real-time kernel, RTOS

A real-time kernel is a set of software calls that provide for the creation of independent tasks, timer management, inter-task communication, memory management, and resource management.

real-time Operating System

A real-time kernel plus command line interpreter, file system, and other typical OS utilities.

relinquish, voluntarily relinquish control

The process by which the active task voluntarily gives up control of the CPU by notifying the kernel of its wish to do so. A task can voluntarily relinquish control explicitly with a yield, pause, or suspend; or implicitly with waitMsg, waitMail, etc. and the actual system calls will vary from kernel to kernel. When the active task relinquishes control, the task referenced by the node at the front of the ready queue becomes the new active task.

ready queue

The ready queue is a doubly linked list of pointers to tcb's of tasks that are waiting to run. When the currently active task relinquishes control, either voluntarily, or involuntarily, (for example by an interrupt service routine which schedules a higher priority task), the kernel chooses the task at the front of the ready queue as the next task to run.

real-time responsive

Describes a task switching policy that is consistent with real-time requirements. Specifically, when ever it is determined that a higher priority task needs to run, it runs immediately. Contrast this with a policy in which the higher priority task is scheduled when it is determined that it must run, but the active lower priority task continues to run until a system scheduler task interrupts it and then switches to the higher priority task.

reset, power-on reset
When power is applied to the microprocessor, a microprocessor "reset" occurs. What the processor does on reset differs from processor to processor. A typical scenario is as follows.  When the microprocessor senses a reset, it generates a reset interrupt. When the interrupt occurs, the processor jumps to an interrupt service routine (isr) whose address is located in the vector table entry reserved for reset. A simple vector table is shown below.

Microprocessor Memory Address        Contents of Microprocessor Memory Address
0000                                                   5080       // Reset
0004                                                   6020       // Divide by zero
0008                                                   8092       // Timer

Microprocessor address 0000 contains the address of the subroutine (isr) that will be jumped to when reset occurs. So, on power-up, address 5080 is jumped to, i.e., instruction execution begins at address 5080. But don't we have a problem here? On power up, all memory is blank, and there will be no code at address 5080, right? Wrong. If we design our hardware system so that microprocessor address 5080 is actually the first address of FLASH, then all is OK, as long as we have preprogrammed the FLASH with our program. This is referred to as memory mapping.

resource

A resource is a general term used to describe a physical device or software data structure that can only be accessed by one task at a time. Examples of physical devices include printer, screen, disk, keyboard, tape, etc. If, for example, access to the printer is not managed, various tasks can print to the printer and inter-leave their printout. This problem is typically handled by a server task whose job is to accept messages from various tasks to print files. In this way access to the printer is serialized and files are printed in an orderly fashion. Consider a software data structure that contains data and the date and time at which the data was written. If tasks are allowed to read and write to this structure at random, then one task may read the structure during the time that another task is updating the structure, with the result that the data may not be time stamped correctly. This type of problem may also be solved by creating a server task to manage access to the structure.

resume

To run again a suspended task at the point where it was suspended. Formally, the process by which the active task is suspended and a context switch is performed to the previously suspended task.

round robin, round robin scheduling

A multi-tasking scheduling policy in which all tasks are run in their turn, one after the other. When all tasks have run, the cycle is repeated. Note that various scheduling policies are run in round robin fashion, e.g., cooperative scheduling, time-sliced scheduling, and cyclical scheduling. Cyclical and round robin scheduling are used inter-changeably.

dynamic scheduling

A scheduling mechanism that allows for creating and scheduling new tasks and changing task priorities during execution. See also scheduling and static scheduling.

source file
A high level language text file. For example files containing C code, assembly code, C++ code, JAVA code are all examples of files that contain source code. Compare with machine code (also called object code).

static scheduling

A scheduling mechanism in which all tasks and task priorities are described and bound at compile-time; they cannot be changed during execution. See also scheduling and dynamic scheduling.

schedule, scheduling

A task can be in any of the following states: (1) dormant (inactive, usually waiting for an event - a message for example), (2) waiting to run (a task that was non-existent or dormant was scheduled to run), (3) running (on a single CPU system, only one task at a time can be in the running state. A dormant task is scheduled by notifying the kernel/OS that the task is now ready to run. There are various scheduling policies: see cooperative scheduling, time-sliced scheduling, cyclical scheduling, and priority based preemptive scheduling. For software implementation details see the article HowTasks Work - Part 2.

semaphore

This term has several meanings. In its simplest form, it is a global flag - a byte of global memory in a multi-tasking system that has the value of 1 or 0. In multi-tasking systems, however, a simple global flag used in the normal manner can cause time dependent errors unless the flag is handled by a special test and set instruction like the 80x86 XCHG instruction. A semaphore is typically used to manage a resource in a multi-tasking environment - a printer for example. See XCHG for a code example. In another form, the semaphore may have a count associated with it, instead of the simple flag values of 1 or 0. When the semaphore is acquired, its count is made available to the caller, and can be used for various purposes. For example, consider a system that has three printers numbered 1, 2, and 3. A semaphore could be created with a count of 3. Each time the semaphore is acquired its count is decremented. When the count is 0, the semaphore is not available. When the semaphore is released, its count is incremented. In this way a pool of 3 printers can be shared among multiple tasks. The caller uses the semaphore count value returned to him to determine which numbered resource (e.g., printer 1, 2 or 3) he is allowed to use. Numerous variations on this theme can be created. Compare also with server task. The advantage of a server task is that it does not block the calling task if the resource is not available, thus avoiding priority inversion. In general semaphores should be avoided; furthermore they are unnecessary in a message based OS. The server task approach to resource management is preferred over semaphores as it is cleaner and less error prone.

serial line analyzer, datascope

A piece of test equipment that is connected in series with a serial line for the purpose of displaying and monitoring two way serial communications. The term usually refers only to RS-232 serial lines.

server task

A task dedicated to the management of a specific resource. A server task accepts requests in the form of messages from other tasks. For example, a server task could be created to manage access to a single printer in a multi-tasking environment. Tasks that require printing send the server a message that contains the name of the file to print. Note that the server task approach does not block the calling task like a semaphore will when the resource is unavailable; instead the message is queued to the server task, and the requesting task continues executing. This is an important consideration when is a concern.

single step

A debugger command that allows an application program to execute one line of the program, which can either be a single assembly language instruction, or a single high level language instruction. There are typically two distinct single step commands - one that will single step "into" subroutine calls, and one that will step "across" them (i.e., enter the routine, but do not show its instructions executed on the screen). The latter command is useful, otherwise many unwanted levels of subroutines would be entered while single stepping.

soft real-time

Refers to applications that are not of a time critical nature. Contrast with hard real-time. See also real-time.

static RAM (SRAM)

RAM that, unlike DRAM, does not requires a periodic refresh (write) to maintain data integrity. Unlike FLASH, however, if power is removed, memory data is lost.

stress testing

The process by which a software system is put under heavy load and demanding conditions in an attempt to make it fail.

subroutine nesting, subroutine nesting level

Refers to the scenario in which subroutineA calls subroutineB which calls subroutineC... which calls subroutineN. This is relevant for real-time systems because if a task is 7 subroutines deep, and the task is preempted, the return addresses must be preserved so that when the task is later resumed, it can return back up the chain. The most practical way of preserving subroutine nesting is by assigning each task its own stack. This way when a task is resumed, the SP is first set to the task's stack.

suspend, suspension

The immediate cessation of a thread, preceded by the saving of its context.

synchronization

Sometimes one task must wait for another ask to finish before it can proceed. Consider a data acquisition application with 2 tasks: taskA that acquires data and taskB that displays data. taskB cannot display new data until taskA fills in a global data structure with all the new data values. taskA and taskB are typically synchronized as follows. (1) taskB waits for a message from taskA, and since no message is available, taskB suspends. When taskA runs and updates the data structure, it sends a message to taskB which schedules taskB to run, at which time it displays the new data, then again waits for a message, and the scenario is repeated.

target, target board, host
Refers to the situation where two computers are involved in the software development process - one computer to develop software (edit, compile, link, etc.), referred to as the host, (typically a PC), and one computer to run the software, referred to as the target. The target is the actual product on which the software is to run. In most common situations, the host and target are the same. For example, a word processor is developed on the PC and runs as a product on the PC. However, for various real-time and embedded systems, this is not the case. Consider a small single board computer that controls a robot arm. The software cannot be developed on this board because it has no keyboard, display, or disk, and therefore, a host computer, like a PC, is used to develop the software. At some point, when it is believed that the software is ready for testing, the software is compiled and linked to form an executable file, and the file is downloaded to the target, typically over an RS-232 serial connection. Debugging on the target is typically done with an ICE.

task

A thread of execution that can be suspended, and later resumed.

task collisions, time dependent error

Data corruption due to preemption. Consider a preemptive multi-tasking environment in which tasks use a global flag to gain access to a printer. The following code will not have the desired effect.

tryAgain:
	CMP flag,1	; Printer available?
	JE tryAgain	; No, then try again.
	MOV flag,1	; Printer was available. Set it as busy.
	...use printer...
	MOV flag,0	; Set printer as available.

The problem is that after the CMP instruction, the current task can be preempted to run another task which also checks the flag, sees that it is available, sets the flag, does some printing, and is then preempted to run the original task, which resumes at the JE instruction. Since the 80x86 flags register (not to be confused with the flag variable), which contains the status of the last CMP instruction, is restored with the original task's context, the JE will fail, since the flag was 0. The original task will now acquire the flag and interleave its printing with the other task's printing. This problem can be overcome by using a read-modify-write instruction like XCHG or by managing the printer with a server task. Time dependent errors can also occur when preemption is used with non-reentrant code. Consider a graphics library that is non-reentrant. If taskA calls a non-reentrant graphics function and is then preempted to run taskB which calls the same function, errors will result. Sometimes the non-reentrancy problem is not so obvious. Consider a non-reentrant floating software library that is called invisibly by the compiler. For example the statement y = 5.72 * x; would make a call to the floating point software multiplication function. If the current task were preempted while executing this instruction, and the next task to run also performed a multiply, then errors can again result. Note that floating point time-dependent errors could still occur even if a floating point chip was used instead of a floating point software library. An error could occur if the floating point CPU's context context is not saved by the kernel.

task control block, tcb

A task control block is a data structure that contains information about the task. For example, task name, start address, a pointer to the task's instance data structure, stack pointer, stack top, stack bottom, task number, message queue, etc.

task instance, generic task, instance data

A single generic task can be created to handle multiple instances of a device. Consider 5 analog channels that must be read and processed every "n" milliseconds, the number "n" being different for each channel. A generic task can be created that is channel independent through the use of instance data. Instance data is a C structure that in this case contains information specific to each channel, i.e., the IO port address of the channel, the sample interval in milliseconds, etc. The task code is written so that it references all channel specific data through the instance data structure. When the task is created a pointer to the task's task control block is returned. One of the fields of the task control block is a user available void pointer named "ptr". After starting the task, the "ptr" field is set to an instance data structure that contains the sample rate, IO port address, etc. for that task instance.

for (i = 0; i < 5; i++) {
	tcb = makeTask(genericAnalogTask, i);
	tcb->ptr = &InstanceDataArray[i];
	startTask(tcb);
}

The code above shows how 5 instances of the same task are created, and each given a unique identity via tcb->ptr which points to the instance data.

void genericAnalogTask(void) {
	typeAnalogData * d;
	
	d = (typeAnalogData *) ActiveTcb->ptr;

	while (TRUE) {
		pause(d->sampleIntervalInMs);
		readAndProcessChannel(d->channelIOPortAddress);
	}
}

The code above shows what the generic task might look like. For further information see the example.

thread

A thread is a task that runs concurrently with other tasks within a single executable file (e.g., within a single MS-DOS EXE file). Unlike processes, threads have access to common data through global variables.

thread of execution

A sequence of CPU instructions that can be or have been executed.

timer

Most modern microprocessors have built in timers. A timer works like a stop watch. For example, a timer could be set to zero, and set to count up to 10,000 after which an interrupt is generated, the counter reset to zero, and the count started again. This is referred to as setting the timer counter in repeat or continuous mode. Many other system dependent features are generally available. For example, the timer may have an option that will allow the counter to start based upon an external signal going high and stopping on the external signal going low, after which an interrupt is generated. This would allow for timing of external events.

 
time-slice, time-slicing, time-sliced scheduling, time-sharing

Each task is allotted a certain number of time units, typically milliseconds, during which it has exclusive control of the processor. After the time-slice has expired the task is preempted and the next task at the same priority, for which time-slicing is enabled, runs. This continues in a round-robin fashion. This means that a group of time-sliced high priority tasks will starve other lower priority tasks. For example, in a 10 task system, there are 3 high priority tasks and 7 normal priority tasks. The 3 high priority tasks have time-slicing enabled. As each high priority task's time-slice expires, the next high priority task is run for its time slice, and so on. The high priority tasks are run forever, (each in its turn until its time-slice expires), and the low priority tasks will never run. If however, all high priority task waits for an event, (for example each pauses for 100 ms), then lower priority tasks can run. The behavior of tasks in a time-slicing environment is kernel dependent; the behavior outlined above is only one of many possibilities, but is typically the way time-sliced tasks should behave in a real-time system. Some kernels may implement the concept of fairness to handle this situation, however, fairness is repugnant to real-time principles as it compromises the concept of priority.

trace

An ICE command that will save the most recent "n" instructions executed. The trace can also be conditional, e.g., trace only those instructions that access memory between 0 and 1023.

trace buffer

A buffer in ICE memory that stores the last "n" instructions executed. It is useful while debugging as it shows a history of what has occurred.

virtual memory

A technique in which a large memory space is simulated with a small amount of RAM, a disk, and special paging hardware. For example, a virtual 1 megabyte address space can be simulated with 64K of RAM, a 2 megabyte disk, and paging hardware. The paging hardware translates all memory accesses through a page table. If the page that contains the memory access is not loaded into memory a fault is generated which results in the least used page being written to disk and the desired page being read from disk and loaded into memory over the least used page.

XCHG (80x86 XCHG instruction), protected flag, read-modify-write

The 80x86 XCHG instruction can be used in a single processor, preemptive multi-tasking environment to create a flag that is shared between different tasks. A simple global byte cannot be used as a flag in this type of environment since tasks may collide when attempting to acquire the flag. The XCHG instruction is typically used as follows:

tryAgain:
	MOV AL,1
	XCHG AL,flag
	CMP AL,0
	JNE tryAgain

flag is a byte in RAM. If the flag is 1, then the XCHG instruction will place a 1 into AL. If AL is 1 after the XCHG then the loop must continue until finally AL is 0. When AL is 0 the following is known: (1) The flag was 0 and therefore available, and (2) the flag is now 1 due to the exchange, meaning that the flag has been acquired. The effect is that with a single instruction, a task can check, and possibly acquire the flag, thus eliminating the possibility of a collision with another task.

When using multiple processors with the flag in shared RAM, the above solution will not work, since although the instruction is indivisible for the processor that executes it, it is not indivisible with respect to the shared RAM data bus, and therefore, the shared RAM bus arbitration logic must provide a method by which one processor can lock out the others while the XCHG executes. This is typically done with the 80x86 LOCK instruction as shown below.

tryAgain:
	MOV AL,1
	LOCK
	XCHG AL,flag
	CMP AL,0
	JNE tryAgain

Note that the LOCK instruction provides information only. It is up the shared RAM bus arbitration logic to incorporate the LOCK* pin into its logic. Newer processors like the 80386 incorporate the LOCK implicitly into the XCHG instruction so the LOCK instruction is unnecessary.

yield, yielding

The process by which a task voluntarily relinquishes control (via a kernel call) so that other tasks can run; the task will run again in its turn (according to its priority).


Copyright © 2000, Tics Realtime