Sei sulla pagina 1di 110

KR-51

Real-Time Kernel for the 8051 family

Reference manual

September 2005
Information in this document is subject to change without notice and does not represent a
commitment on the part of the manufacturer. The software described in this document is
furnished under license agreement or nondisclosure agreement and may be used or copied in
accordance with the terms of the agreement. It is against the law to copy the software on any
medium except as specifically allowed in the license or nondisclosure agreement. No part of this
manual may be reproduced or transmitted in any form or by any means, electronic or mechanical,
including photocopying, recording, or information storage and retrieval systems, for any purpose
other than the purchaser’s personal use, without prior written permission.

Every effort was made to ensure the accuracy in this manual and to give appropriate credit to
persons, companies and trademarks referenced herein.

Copyright 2000, 2005 RAISONANCE SAS. All rights reserved

Microsoft® and Windows™ are trademarks or registered trademarks of Microsoft Corporation.


PC® is a registered trademark of International Business Machines Corporation.
Raisonance is a registered trademark of RAISONANCE S.A.S.
KR-51 Contents

CONTENTS

1. OVERVIEW 7

1.1 Introduction ..................................................................................................................................8


1.2 Organisation of the manual .........................................................................................................8
1.3 General description of tasks ........................................................................................................9
1.3.1 A first example : 2 LEDs ..........................................................................................................10
1.4 The multitasking capability .......................................................................................................11
1.5 KR-51 specification.....................................................................................................................11
1.6 Simple Example ..........................................................................................................................13
1.7 Available versions .......................................................................................................................14
1.8 List of the files supplied..............................................................................................................15
1.9 Program development tools .......................................................................................................15

2. TASK DESCRIPTION 17

2.1 Task definition ............................................................................................................................18


2.2 Task states ...................................................................................................................................19
2.3 Priorities and register banks......................................................................................................20
2.4 Clock frequency groups .............................................................................................................21
2.5 Waiting for an event ...................................................................................................................22
2.5.1 Time-outs...................................................................................................................................22
2.5.2 The SIGNAL .............................................................................................................................23

3. THE SCHEDULER 25

3.1 Description ..................................................................................................................................26


3.2 The kernel CLOCK ....................................................................................................................27
3.2.1 THE POOLER...........................................................................................................................27
3.2.2 The INITIATOR........................................................................................................................28
3.3 Task execution.............................................................................................................................28
3.4 The RECEIVER .........................................................................................................................28
3.5 Direct pooling..............................................................................................................................28
3.5.1 Principle.....................................................................................................................................28
3.6 Interrupt handling......................................................................................................................29
3.6.1 Implementation ..........................................................................................................................29
3.6.2 Register banks............................................................................................................................29
3.6.3 Kernel and parallel interrupt priority.........................................................................................30
3.6.4 Response time............................................................................................................................30
3.6.5 Permissible delay .......................................................................................................................31
3.6.6 Tasks/interrupts interface ..........................................................................................................31
3.7 Possible actions on IE and IP registers .....................................................................................32
3.8 Task lifetime................................................................................................................................32
3.9 Notes and suggestions.................................................................................................................33

4. IMPLEMENTATION 35

-3-
Contents KR-51

4.1 Installation...................................................................................................................................36
4.1.1 Invocation ..................................................................................................................................36
4.1.2 KR-51 files description..............................................................................................................36
4.2 Implementation...........................................................................................................................37
4.2.1 General ......................................................................................................................................37
4.3 Task declaration .........................................................................................................................38
4.3.1 Significance of the different keywords......................................................................................39
4.3.2 Kernel settings ...........................................................................................................................39
4.4 Saving stacks and local variables ..............................................................................................41
4.4.1 Stack storage..............................................................................................................................41
4.4.2 The external stack capability (external versions) ......................................................................41
4.5 The set-up utility program.........................................................................................................44
4.6 Task editing .................................................................................................................................45
4.7 The DEBUG versions .................................................................................................................45
4.7.1 General ......................................................................................................................................45
4.7.2 Recommendations .....................................................................................................................45
4.7.3 Quick reference to return codes in the DEBUG utility program ...............................................46

5. LIST OF SERVICES 47

5.1 Three types of services................................................................................................................48


5.1.1 System services..........................................................................................................................48
5.1.2 Information services ..................................................................................................................48
5.1.3 Utility services...........................................................................................................................48
5.2 Quick reference to the services ..................................................................................................48
5.3 Parameter passing convention...................................................................................................49
5.4 Values returned by services .......................................................................................................49
5.5 KR_CREATE (System Function) .............................................................................................50
5.6 KR_DELETE (System Function)..............................................................................................51
5.7 KR_DEL_ABS (System Function) ............................................................................................52
5.7.1 Possible problems with KR_DEL_ABS....................................................................................53
5.8 KR_DEL_REL (System function).............................................................................................56
5.9 KR_SENDSIG (System function)..............................................................................................56
5.10 KR_WAITSIG (System function) ...........................................................................................57
5.11 KR_DELSIG (or KR_DELSIG_REL)....................................................................................57
5.12 KR_DELSIG_ABS ...................................................................................................................57
5.13 KR_PAUSE (System function) ................................................................................................58
5.14 List of the information services ...............................................................................................59

6. SEMAPHORES 61

6.1 Description ..................................................................................................................................62


6.2 Semaphore representation .........................................................................................................63
6.2.1 Semaphores with time-outs (external versions only).................................................................63
6.2.2 Normal semaphores ...................................................................................................................63
6.3 Implementation...........................................................................................................................65
6.4 Notes and suggestions.................................................................................................................65
6.5 Semaphores and task groups (external versions).....................................................................65
6.6 Semaphores and task synchronisation......................................................................................66
6.7 Resources used ............................................................................................................................66

7. MAILBOXES 67

-4-
KR-51 Contents

7.1 Description ..................................................................................................................................68


7.2 Available services........................................................................................................................68
7.3 Notes and suggestions.................................................................................................................70
7.4 Resources used ............................................................................................................................70

8. THE MEMORY ALLOCATOR (KRX) 71

8.1 Description ..................................................................................................................................72


8.2 Available services........................................................................................................................72
8.2.1 MEM_ALLOC ..........................................................................................................................72
8.2.2 MEM_FREE..............................................................................................................................73
8.2.3 PRECAUTIONAY MEASURES..............................................................................................73

9. THE CALENDAR 75

9.1 Description ..................................................................................................................................76


9.2 Available services........................................................................................................................77
9.3 Implementation...........................................................................................................................80

10. THE INTERNAL VERSION : KRY 81

10.1 Description ................................................................................................................................82


10.2 Resources used ..........................................................................................................................82
10.3 Example .....................................................................................................................................83
10.4 Performances ............................................................................................................................83

11. THE EXTERNAL VERSIONS: KRX / KRH 85

11.1 Description ................................................................................................................................86


11.2 Resources used ..........................................................................................................................86
11.3 Example .....................................................................................................................................87
11.4 Performances ............................................................................................................................88

12. APPENDICES 89

12.1 TELEMEAS application (recorder) .......................................................................................90


12.2 Revision History......................................................................................................................108

13. INDEX 109

-5-
Contents KR-51

-6-
KR-51 1. Overview

1. OVERVIEW

1.1 Introduction

1.2 Organisation of the manual

1.3 General description of the tasks

1.4 The multitasking capability

1.5 KR-51 specification

1.6 Simple example

1.7 Available versions

1.8 List of the files supplied

1.9 Code generation tools

-7-
1. Overview KR-51

1.1 Introduction
The KR-51 executive is a real time kernel for the 8051 microcontroller family. Placed in the
heart of an application, it provides efficient task scheduling by driving :
• task activation : initiate, waiting or termination.
• task relationships.
KR-51 is easy to implement and permits the programmer to concentrate on each task
independently. KR-51 recognises tasks written in either assembly, PL/M-51 or the C-51 language
and provides support for any compatible derivatives of the 8051, except the 83C751 and 83C752.

KR-51 consists of two parts :


• the scheduler, which is the task scheduling program.
• the services or functions that can be called by tasks to send various requests to the
scheduler.

1.2 Organisation of the manual


The chapters describe the operation of the Kernel in increasing levels of detail :

1. OVERVIEW : Corresponds to this chapter.

2. TASK DESCRIPTION : Gives a static description of the tasks.

3. THE SCHEDULER : Describes the dynamic characteristics of the scheduler.

4. IMPLEMENTATION : Indicates how to use KR-51 and associate it with tasks written in a
high level language or assembly language.

5. LIST OF THE SERVICES : Describes the kernel’s services.

6. SEMAPHORES : Describes how the flag capability ensures resource sharing between
tasks.

7. MAILBOXES : Describes the mailbox services. Mailboxes represent a powerful task


communication module.

8. THE MEMORY ALLOCATION : Permits dynamic allocation of the external memory


space.

9. THE CALENDAR : Conversion to/from various formats.

-8-
KR-51 1. Overview

1.3 General description of tasks


A task is a void function, which has no parameters, returns no value, and implements part of the
user’s application. A typical declaration is shown in the example below :

Example : task declaration


void taski (void) task 5;

However, a task can affect its own process or that of related tasks, but always via the scheduler to
which the requests have to be sent. Requests can be :
• to run another task.
• to move a task to the idle state for a given time or to wait for an event.
• for task synchronisation or communication...
Note that task lifetime varies. It can be :
• "permanent" : the task will initiate at the beginning of the application and will never
terminate, although it can be suspended for a short duration
• "temporary" : the task is initiated for a given action.
• "periodic" : the task is initiated in a cyclic fashion at regular or irregular time intervals.

-9-
1. Overview KR-51

1.3.1 A first example : 2 LEDs


Let’s see the following program:
#include <krdcl.h> // Declarations for the services

#define _TSKLED1_ 1 // Reference task #1


#define _TSKLED2_ 2 // Reference task #2

at 0x91 sbit LED1; // LED 1 driven by P1.1


at 0x92 sbit LED2; // LED 2 driven by P1.2

void main (void)


{
kr_init();
kr_create(_TSKLED1_); // Creates and runs task 1
kr_create(_TSKLED2_); // Creates and runs task 2
while (1); // Loop for ever
}

void tskled1 (void ) task _TSKLED1_ //Task 1


{
while (1)
{
LED1 = !LED1; // Toggles P1.1
kr_del_abs(7); // Waits for 7 ticks
}
}

void tskled2 (void ) task _TSKLED2_ //Task 2


{
while (1)
{
LED2 = !LED2; // Toggles P1.2
kr_del_abs(23); // Waits for 23 ticks
}
}

This program has to be compiled and linked with LX51. For example:

RC51 2led
LX51 2led.obj, KRX.LIB

The two permanent tasks will run forever, and the LEDS will blink :
• at the base frequency divided by (2*7) for the task 1.
• at the base frequency divided by (2*23) for the task 2.
The base frequency can to be set in RIDE. A typical value would be 1 kHz, which allocates time
in 1 milli-second intervals.

-10-
KR-51 1. Overview

1.4 The multitasking capability


Strictly speaking, KR-51 does not support either the parallel operation or time slicing
functionality used for multi-user systems.

In fact, a parallel organisation requires a multiprocessor physical architecture. KR-51 has been
designed to operate on a standalone microcontroller only, on which only one instruction runs at a
given time within a single task).

KR-51 uses the time-slicing capabilities applicable to any 1-processor based system with an
interrupt handler.

In a multi-user computing system, CPU time is ‘sliced’ between different users at such a rate that
each user is unaware of the other users. To the system, each user is merely a ‘task’. Although
time slicing offers numerous advantages, it is often unsuitable for applications concerned with
process control. It is difficult to use the 8051 where a great number of different tasks must be
performed, each with often a short lifetime.

KR-51 thus provides time-slicing capabilities that have been modified for optimised use of the
resources available on the 8051 microcontroller.

In particular the concept of task is almost identical to that of an interrupt service routine:

Each task is specified by a configurable priority level between 0 and 3. As for interrupts, the
priority level feature permits context overlay on the stack, as only the initiated highest priority
task takes control of the CPU.

A task is given a time slice only if it is in the waiting state, or if a higher priority task takes
control of the CPU.

In principle KRX and KRH, which use external RAM, could support a more dynamic task
management scheme where, for example, the task's priority or group can be changed during
execution. However, the current version does not support these capabilities.

1.5 KR-51 specification


The features used have been selected to best suit the 8051. The kernel was coded for the best
possible balance of conflicting requirements. Here is a list of some of the requirements :
• execute a great number of tasks without leaving some out
• run the highest priority tasks within the minimum delay (minimum context switch time)
• provide reliable time management : a task that generates a square wave signal must create
fixed frequency edges. A slight offset caused by the execution of a highest priority task is
possible, but offsets should not accumulate
• limit and minimal CPU time assigned to the kernel.
• limit the number of resources used by the kernel (restrictions on internal RAM use).
• provide a variety of system functions (task communication via MAILBOXES .. etc.).
• provide resource sharing (via flags).
• provide interrupt handling and TASK/INTERRUPT interface.
• ensure low latency for high priority interrupts
• best suit the resources available in the application (availability of an external RAM
(XDATA) or not...).

-11-
1. Overview KR-51

• accept development tools used : compilers, assemblers,.. and support the usual parameter
passing conventions.
• offer easy configuration by the user.
• ensure easy debugging and provide DEBUG capabilities.

-12-
KR-51 1. Overview

1.6 Simple Example


For a tele-metering application, the tasks can be split as follows :
• measurement acquisition.
• formatting, calculation and storage of the measurements.
• perpetual calendar/clock.
• phone line management : monitoring, dialing,...
• set-up dialog
• send file handshake management.
• local keyboard read.
• backup battery control.

These tasks are specified by :


• a priority level. Some can be delayed for several milliseconds or even several seconds;
others must be executed quickly.
• a scheduling mode. Some tasks (such as perpetual calendar management) occur at regular
intervals; while others follow an asynchronous or sequential logic e.g. measurement
processing follows the measurement and will generate an alarm which will initiate phone
dialing ...
• the rate of occurrence : some tasks are initiated once a day, others every 10 milliseconds.
In this example, a compiler for a high level language provides a static structure for data and
algorithms, whereas KR-51 determines the dynamic characteristics.

-13-
1. Overview KR-51

1.7 Available versions


KR-51 is available in several versions with each optimised for specific requirements.

The first choice relates to the use of either the IDATA (internal RAM) or XDATA (external
RAM) memory space. Access to the internal RAM is more rapid but the space is limited,
however access to the external RAM is slower but the available space is large (64 K).

• KRY refers to a kernel, which uses internal RAM and is well suited to applications with a
limited number of tasks or no XDATA space. KRY can be used for tasks written in the ‘C’
language if the ‘SMALL’ memory model is used during compilation (no external stack).
• KRX and KRH require 256 and 1024 bytes of external memory space respectively, but no
internal RAM. They offer more capability and support more tasks than KRY but are
slightly slower.

The second important choice relates to the inclusion of a ‘semaphore’ capability. Without
semaphores the KR-51 module is more rapid and uses less RAM, as the processes and resources
required by this feature are ignored. (Semaphores are used to share resources between tasks: e.g.
to control access to sensitive global variables or peripherals).

The table below summarises the characteristics of the libraries.

Version xdata Maximum number Notes


Requirement of tasks
KRY.LIB None 7* for small applications

KRX.LIB 256 bytes 29 the most popular version


KRH.LIB 1 Kbytes 125 for larger applications

* Note that the KRY.LIB creates automatically a task to manage the tasks of group 1 (even if
there is not). So only 6 tasks are still available.

Each collection of libraries includes 4 sub-versions :


• The standard version (for example KRX.LIB)
• The DEBUG versions that include Debug capabilities. Performance is sometimes reduced
to gain reliability. Parameter consistency checks are performed at function invocation and,
if any abnormality is detected, a trap is executed to try to recover correct operation of the
program. The libraries that contain DEBUG information are given a ‘D_’ prefix (e.g.
D_KRX.LIB).
• The SEMAPHORE versions include semaphore capabilities and have a ‘S’ suffix (e.g.
KRXS.LIB).
• The versions which include both the DEBUG and the SEMAPHORE capabilities have a
‘D_’ prefix and an ‘S’ suffix (e.g D_KRXS.LIB).

Note:
During development, the DEBUG versions are recommended, but they may later be replaced
if performance is too low.

-14-
KR-51 1. Overview

1.8 List of the files supplied


KR-51 is supplied with :
• the 12 libraries corresponding to the versions described above in the ..\LIB directory.
• Header files needed for ‘C’, PL/M or assembler in the ..\INC directory.
• the TUTORIAL directory contains some applications showing some specific features of
the kernel : signals, semaphores...
• the README.DOC file that contains additional information which are not featured in this
manual.

1.9 Program development tools


KR51 requires the LX51 linker and RC51 ‘C’ compiler programs from Raisonance, and the
RIDE Integrated Development Environment is recommended to simplify project management.

-15-
1. Overview KR-51

-16-
KR-51 2. Task Description

2. TASK DESCRIPTION

2.1 Task definition

2.2 Task states

2.3 Priorities and register banks

2.4 Clock frequency groups (KRX)

2.5 Waiting for events

-17-
2. Task Description KR-51

2.1 Task definition


For the KR-51 scheduler, a task is specified by :
• a reference : This corresponds to an identification number used with kernel function calls.
• a descriptor : Indicates the task's priority, current state and events triggers (including
semaphore release). Note - For KR-51, the task's priority is associated with a register bank
used during the task execution.
• a group: each task is assigned a "GROUP" which corresponds to a time base (or clock
frequency).
• a task code (a function) : specified by the address of the code to be executed.
• a stack size: when a task enters the Waiting state, the stack contents are stored (swapped).
However, the storage size must be previously defined.
• an external stack size (KRX and KRH versions) : when a task enters the waiting state, the
automatic variables are stored in the ‘external stack’. However, the storage size must be
previously defined.
• an appearance (or creation) time : when a task is initiated, the time when it should be
executed is specified. If a delay or "time-out" is required, this time is regarded as the
starting point, which helps to avoid clock skews caused by offsets. Similarly, if more than
one task with equal priority is in the READY state, the oldest is selected.

These values are not all directly accessible by tasks. However, they help to understand how the
scheduler operates internally. They are initialised at the beginning of the application, using the
task declaration table in CODE space (see "Implementation" section).

-18-
KR-51 2. Task Description

2.2 Task states


The task's state is contained in the descriptor. It can be :
• UNVALIDATED if the task has never been set, or if it has already been executed to
completion.
• READY if the task is ready to be initiated.
• WAITING if the task is waiting for an event : it may have been initiated but suspended for
a given duration. When the event occurs, the task returns to the READY state.
• SUSPENDED if the task has been initiated but pre-empted during execution by a task of
higher priority.
• RUNNING if the task is currently running.
A non-existent task is regarded as UNKNOWN. It may be an illegal reference. Context switching
occurs via the kernel or by system calls.

Remarks:
Each task may be either UNVALIDATED, READY or WAITING state. However, for a given
priority level, there may be only one (or possibly zero) task in the SUSPENDED state.
One task only can be in the RUNNING state.

-19-
2. Task Description KR-51

2.3 Priorities and register banks


The priority of the task is indicated in the descriptor and can be in the range 0 to 3. A task of
priority 3 is a highest priority task, and will be initiated using register bank 3. If more than one
task is simultaneously in the READY state, the highest priority task in the ‘run’ queue, that is
ready to run will be the first executed. Register bank 3 (address : 18h-1Fh) is also used by the
kernel itself. It corresponds to that of the highest priority tasks and if a task of priority 3 is
currently running, the register bank select bits (RS1 and RS0) not modified.

• One SUSPENDED task only per level is allowed.


• Each priority level is associated with a register bank. More precisely, priority level i
corresponds to bank Rbi and the four register banks correspond to the four priority levels.
The association of register banks with a priority level avoids the need to save and restore
registers when the context is switched.
• An interrupt priority level is usually associated with a register bank. (Interrupt handling is
discussed hereafter).
• If a priority level and associated register bank is not used, the bank can be used by a
service routine associated with an asynchronous interrupt.

-20-
KR-51 2. Task Description

2.4 Clock frequency groups


Four clock rates (or two for KRY) hereafter referred as GROUPS are available and each task is
associated with one of the four (or two) groups.
The clock rate is reduced by successive divisions : the scheduler pools tasks of group 0, and
every n1 clocks, creates the clock corresponding to group 1 which initiates that group's pooling
task. Similarly, every n2 clocks of group 1, a clock is generated for group 2, and so on...

An advantage of the clock frequency group feature is that the scheduler does not have to pool
systematically all tasks.

n1, n2 and n3 dividers are referred to as DIVIDE_1, DIVIDE_2 and DIVIDE_3. They are
PUBLIC symbols of NUMBER type to be defined by the user when configuring the system (see
"IMPLEMENTATION" section).

Dividers can be used for generating clocks, which vary from milli-seconds to minutes.

-21-
2. Task Description KR-51

2.5 Waiting for an event


A trigger can be a TIMEOUT, a SIGNAL or a combination of "TIMEOUT" and "SIGNAL" or a
flag release. See section 7 for further information on flag capabilities.

2.5.1 Time-outs
The task is SUSPENDED for a given number of clocks by calling KR_DEL_ABS or
KR_DEL_REL function.

KR_DEL_ABS and KR_DEL_REL functions are fully described in the "List of services"
section. Note that these functions are frequently used when working with a real time kernel.

Remarks:
Systematic suspension of a task by calling this function with a constant parameter causes task
initiation at a regular time rate. A typical example is in the construction of a perpetual
calendar.

Time-outs are expressed as signed 8 bits words. A time-out is hence limited to 127 clock cycles
(or ticks) of the previous group.

Example 1 : In the ‘C’ language the following macro permits simulation of a time-out function
with a time parameter in the form of a 16-bit word :

#define delay16(time)
{
static unsigned n; \
unsigned n1; \
n = time; \
while (n) \
{ \
n1 = (n<125) ? n : 125; \
n -= n1; \
kr_del_abs(n1); \
} \
} /* End of macro delay16 */

COMMENTS:
The '\' character is used to represent the end of a line and allows a macro definition to appear
over several lines.

-22-
KR-51 2 Task Description

2.5.2 The SIGNAL


The task waits for a signal from another task. The signal is a simple inter-task communication
and synchronisation tool. Practically, a signal is a flag (a bit in the task's descriptor). It goes high
(assigned) to indicate a WAITING task (waiting for a signal or event). It goes low (de-asserted)
when the signal is sent by another task.

The KR_WAITSIG function causes a task to enter the ‘Wait for signal’ state.

The KR_SENDSIG function causes sending of a signal to a user-specified task.

Finally, the KR_DELSIG function causes a task to move to the ‘Wait for a signal’ OR ‘time-out’
state. When one of the events occurs the task is activated.

Kr_sendsig, kr_waitsig and kr_delsig functions are fully described in chapter 5 (list of the
services).

Other features :
• Sending a signal to a task that is not waiting for a signal has no effect.
• Similarly, sending a series of signals will probably have the same effect as sending a
signal.
• Signal is an easy-to-use task synchronisation feature.
• Signals are reset at initialisation by a call to KR_INIT.

-23-
2. Task Description KR-51

-24-
KR-51 3. The scheduler

3. THE SCHEDULER

3.1 Description

3.2 The CLOCK

3.3 Task execution

3.4 The Receiver

3.5 Direct pooling

3.6 Interrupt handling

3.7 Possible actions on IE and IP registers

3.8 task lifetime

3.9 Notes and suggestions

-25-
3. The scheduler KR-51

3.1 Description
This chapter describes the dynamic characteristics of the scheduler and a full understanding is
essential to make best use of the services provided by KR-51.

KR-51 contains a function library for task services and a scheduler. The scheduler consists of the
following functional modules :
SCHEDULER 1. CLOCK
2. POOLER
3. INITIATOR
4. RECEIVER

The CLOCK occurs at regular time intervals.

The CLOCK calls the POOLER, which determines if any time-out has occurred or if tasks
waiting for a flag release can be moved to the READY state.

If a task is ready to be initiated, the INITIATOR causes its correct placement and initiation.

Finally, the RECEIVER takes control, when a task terminates or moves to the Waiting state.

-26-
KR-51 3. The scheduler

3.2 The kernel CLOCK


The CLOCK function is initiated at regular intervals via the TIMER 0 interrupt service routine.
Each clock (or tick) causes :
• increment of the clock timer (which is used as a time reference for time--out management).
• reloading of timer 0 to the user defined value. The reloading mode adopted eliminates any
cumulative.
• and finally, initiation of the POOLER by the CLOCK (except if timer 0 interrupt was itself
delayed by a previous execution of POOLER).

Remark:
For the versions with external RAM, several CLOCKS are used in cascade (divisions in
series), as if there were several schedulers. However, the secondary clocks are not built into
the scheduler module : they consist of tasks that are initiated by the INITIATOR module and
are only used to place other tasks in the READY state. The POOLER module will recover
them at next pooling cycle.

3.2.1 THE POOLER


The POOLER examines all tasks that are defined in the group, to determine if some tasks in the
Waiting state (waiting for a time-out or a signal flag release) may move to the READY state.
During the analysis phase, it identifies the READY task with the highest priority. It then calls the
INITIATOR if this task has a higher priority than the currently active task.

If more than one task with equal priority is ready to be initiated, only the "oldest" will be
selected. A task's ‘creation time’ corresponds to the time when the task moves to the READY
state.

At similar priority levels and ages, the final selection is performed as follows: generally, the first
task in the READY queue will be selected.

The POOLER places the READY tasks in the READY queue. The READY queue is then
examined to select the task to be initiated.

Tasks of GROUP 0 only (for which the clock corresponds to the timer overflow) are moved to
the READY state by the POOLER. The predefined tasks TASK_CL1, TASK_CL2 and
TASK_CL3 cause pooling of tasks of group 1, 2 and 3 respectively.

The pre-defined tasks bear the following numbers :

Task Task Number for Task Number for Task number for the
the KRY version the KRX version KRH version
TASK_CL1 7 29 125
TASK_CL2 -- 30 126
TASK_CL3 -- 31 127

-27-
3. The scheduler KR-51

Remarks :

All TASK_CLi predefined tasks have priority 3.

When initiated, TASK_CLi can move one task (or more) of the GROUP to which it belongs to
the READY state. The initiation will be performed only at the next TIMER0 interrupt unless the
"DIRECT POOLING" mode has been activated.

3.2.2 The INITIATOR


The INITIATOR saves the context (PSW, ACC, B, DPH, DPL and stack level) of the task that
was previously running, then initiates the new task using the register bank allocated to its priority
level.

The task is executed at the last INITIATOR instruction, which is a RETI. The task is thus placed
outside of the interrupt service structure to allow a scheduler cycle to be performed at the next
clock and also to permit asynchronous interrupts.

3.3 Task execution


Once initiated, a task runs until it terminates, waits for an event or a flag release or is deleted by
itself or by another task. It can also be interrupted by a higher priority task following the
scheduler phase. In this case, it remains in the SUSPENDED state, but its context is saved and
then to be retrieved when the higher priority task terminates. The context contains the return
address and also the topmost section of the stack that contains the return addresses of the nested
calls, as well as the automatic local variables.

3.4 The RECEIVER


A task terminates, if a "ret" instruction is executed from within the task or if the kr_delete
function is called with the identity of the task as a parameter. The RECEIVER then takes control
of the execution. It retrieves the context of the suspended task (of lower priority) and reinitiates
it. The following section describes how to chain the RECEIVER to the POOLER and thereby
immediately reinitiate another READY task.

3.5 Direct pooling

3.5.1 Principle
Waiting, task pooling and initiation occurs only during the timer 0 interrupt service routine,
hence at each timer 0 overflow or ‘clock’. If, when a task moves to the Waiting state, no lower
priority task is SUSPENDED, a READY task will be initiated only at the next clock. For part of
a clock cycle, it may occur that no task is executed, although several tasks are READY. To
eliminate these dead times, the POOLER is initiated by setting the TF0 bit independently from
the CLOCK in the following cases :
• at any task termination (automatically at the end of the RECEIVER execution).
• at signal sending, semaphore release, initiation of a daughter task.
This mechanism has no effect on the time management as direct pooling is distinguished from a
real timer 0 overflow.

-28-
KR-51 3. The scheduler

3.6 Interrupt handling

3.6.1 Implementation
In addition to TIMER0, KR-51 recognises any other unmasked interrupt source. These so called
parallel (// below) or asynchronous interrupts can be handled without difficulty, provided you
proceed carefully with :
• the use of register banks.
• the delay that KR-51 may cause to interrupt handling.
• the delay that may be caused by the interrupt handling
• the priority level hierarchy.

Attention : the priority level for parallel interrupts must be higher than or equal to that of the
scheduler.

3.6.2 Register banks


One of the fundamental rules of the KR-51 kernel consists in associating a register bank with a
task's priority level. Tasks of priority 3 are hence automatically associated with bank 3, those of
priority 2 with bank 2 and so on...

Usually, a register bank is also associated with a particular interrupt priority level.
Consequently, to avoid unnecessary swapping of a task's registers, a register bank should be
reserved for parallel interrupts, and tasks with the corresponding priority level should not be
declared.

Consequently, a register bank must be associated exclusively with :


• a task's priority level
• an interrupt level (for a parallel interrupt)

Moreover, bank 3 for priority level 3, must be allocated only to tasks as it is also used by the
SCHEDULER.
The table below gives some examples of how to use register banks.
Example A Example B Example C
Bank 3 Tasks priority3 Tasks priority 3 Tasks priority3
(used by KR51) + KR 51 +KR 51 +KR 51
Bank 2 Tasks priority2 Ints // priority1 Ints // priority2
Bank 1 Tasks priority1 Tasks priority1 Ints // priority1
Bank 0 Tasks priority0 Tasks priority0 Task priority0

In example A, the 4 banks are available so that the kernel can process 4 priority levels.

In example B, one bank is reserved for the parallel (//) interrupts. Three priority levels are
available for the kernel.

In example C, 2 banks are reserved for the parallel (//) interrupts. Two priority levels are still
available for tasks. In this case, the device is assumed to have 4 priority levels.

-29-
3. The scheduler KR-51

3.6.3 Kernel and parallel interrupt priority


At initialisation (KR_INIT function), TIMER 0 interrupt, which is associated with the KR51
kernel, is given the default priority level (0). It is recommended not to change this priority level.
Parallel interrupts must have a priority level equal to or higher than that of TIMER0 interrupt. A
parallel interrupt may interrupt the kernel.

3.6.4 Response time


This paragraph is concerned with only to delays caused by the KR51 kernel. Delays caused by
the other enabled user interrupts should also be considered.

An interrupt of a priority identical to that of the scheduler can be delayed for at most the kernel’s
execution time. The maximum duration depends on the number of tasks, but also of the task's
state.

An interrupt of higher priority will run with delays defined by the manufacturer of the
microcontroller, unless the interrupts were disabled in the kernel by resetting EA bit. Interrupts
are disabled under the following conditions :

• to reload TIMER 0 and eliminate the risk of offset, the scheduler blocks interrupts for 14
CPU clock cycles.
• In the KR_TST (semaphore "test and set") function call, the flag is manipulated with the
interrupts disabled. Flag manipulation may last for up to 12 CPU clock cycles.
• In the KR_DEL_ABS, KR_DEL_REL, KR_DELETE function calls, task switching is also
performed with the interrupts disabled, but lasts only 7 CPU clock cycles.
• utility services such as MAILBOXES can also block interrupts for a short time. See the
description of these services for further details.

-30-
KR-51 3. The scheduler

3.6.5 Permissible delay


At timer 0 reloading, the scheduler CLOCK includes the time expired since the previous
overflow. The maximum permissible delay is equal to the clock duration. If exceeded, the
following clock will then be offset by 65536 CPU clock cycles.

Practically, it is recommended to limit the duration of the parallel interrupts. If an important


interrupt processing session is to be initiated, it should be performed as a task (see following
paragraph).

3.6.6 Tasks/interrupts interface


A parallel interrupt can initiate some kernel functions such as :
• information queries.
• initiate task (kr_create).
• send signal to task.
• functions related to MAILBOXES.

However, parallel interrupts may not terminate a task by calling kr_delete. Similarly, the use of
semaphores is reserved for tasks because an interrupt routine cannot be moved to the idle state.
Practically, these prohibited functions can still be called via a task initiation to go from the
"parallel interrupt" mode to the more powerful "task" mode.

-31-
3. The scheduler KR-51

3.7 Possible actions on IE and IP registers


KR_51 does not require exclusive access to interrupt control registers. The strategy applied is :
• the user can enable/disable the interrupts and can also give them different priority levels.
• KR-51 does not initialise and never changes the register(s) which set(s) interrupt priority
(IP or IPO/IP1). The scheduler is hence initialised with the lowest priority level.
However, the TIMER0 interrupt and the interrupt associated with the direct pooling initiation (if
any) should be maintained at lowest priority level.

3.8 Task lifetime


This section describes the dynamic properties of the scheduler by analysing the various phases in
the lifetime of task T1. The mechanisms are now detailed from the viewpoint of T1.

• At RESET, the scheduler initialisation procedure moves the task to the UNVALIDATED
state.
• If task T1 is permanent (or repetitive), the application’s initialisation routine must be used.
If not, the initiation is performed later at the request of another task, or during the parallel
interrupt service routine.
• The initiation moves the task to the READY state, until it is selected by the POOLER. The
INITIATOR then moves it to the RUNNING state.
• The task may temporarily leave the RUNNING state, if a higher priority task pre-empts it.
The TASK remains in the SUSPENDED state to allow the higher priority task(s) to be
executed. When the task that interrupted it terminates (or enters the WAITING state), task
T1 moves to the RUNNING state.
• If T1 is waiting for an event or calls a shared resource protected by a semaphore, T1
becomes WAITING, allowing another task of equal priority to be activated.
• T1 is maintained in the WAITING state until the event occurs. At detection of the event by
the POOLER, T1 moves to the READY state (as for the first initiation).
• A Task continues, alternating between the "RUNNING", "WAITING", "SUSPENDED"
and "READY" states. It can also be "INTERRUPTED" (for short times) by the activation
of a parallel interrupt or scheduler (TIMER0 overflow).
• Finally, non-permanent tasks can be terminated (killed by themselves of by another task)
and hence return to the UNVALIDATED state.

-32-
KR-51 3. The scheduler

3.9 Notes and suggestions


Variables may be overlaid, when using a real time kernel. To eliminate this risk, the following
rules should be observed :
• in the parallel interrupt services routine, working registers : PSW, ACC, B, DPL and DPH
should be saved. With PL/M-51 and C-51 compilers, these values are automatically stored,
when a function is declared with the "INTERRUPT" attribute.
• common resources such as variables internal peripherals, tasks and mailboxes should be
used only if they are protected by semaphores, or if the "volatile" feature of these
resources is controlled and does not pose any problem.
• if tasks are written in assembly language, the scheduler function calls that may suspend the
current task (kr_del_abs, kr_tst, etc...) should be used carefully as various registers may be
corrupted.
Hence, the following lines should not be written :

;example of bad practice


inc R6
mov R7,#3 ;passage of the parameter "delay" in R7
lcall KR_DEL_ABS ;call to the kernel service KR_DEL_ABS
mov A,R6 ;R6 lost! (KR_DEL_ABS uses R6)

Generally, kernel services (as with any RC51 or PL/M-51 function) may modify the values
in the currently working registers : R0...R7, ACC, B, PSW, DPL and DPH. As a
consequence, storing values in them for later retrieval is bad practice.

-33-
3. The scheduler KR-51

-34-
KR-51 4. Implementation

4. IMPLEMENTATION

4.1 Installation

4.2 Implementation

4.3 Task declaration

4.4 Saving stacks and local variables

4.5 The set-up utility program

4.6 Task editing

4.7 The DEBUG versions

-35-
4. Implementation KR-51

4.1 Installation

4.1.1 Invocation
KR-51 is installed with RKit51 software. To use KR-51, you need a valid serial number.

4.1.2 KR-51 files description


The supplied files are :
• the KR-51 libraries in the \LIB directory,
• the "INCLUDE" files, in the \INC directory, that corresponds to the programming
language used :
KRDCL.H for the ‘C’ language.
KRDCL.H51 for the MA-51 assembler.

• the examples in the \EXAMPLES\RTOS directory.

The INCLUDE files must be inserted at the beginning of the application files. For programmers
using RC51, the following control should be placed at the beginning of each file :
#include "KRDCL.H" /* Prototypes of the functions of KR-51 */
#include "REG51.H" /* SFR of the 8051 */
...

These files contain :


• the constant definitions (especially the codes returned by the information services).
• the pre-defined types (especially for task declaration).
• the kernel service prototypes.

-36-
KR-51 3. The scheduler

4.2 Implementation
The text presented hereafter further the different cases.

4.2.1 General
To construct a KR-51 based application, proceed as follows :
1. Ensure the linker is configured to use the Kernel libraries (either KRY,KRx or KRH) via
Project | Options | LX51 | Kernel in RIDE.
2. Define the tick rate and the value of the dividers.
3. Write a "main" task initialisation procedure: kernel should be initialised by a call to
KR_INIT. If you use mailboxes, MAIL_RESET() should also be called.
4. Write the tasks specific to the application.
5. Compile and link the project.

-37-
4. Implementation KR-51

4.3 Task declaration


The keywords task, group, priority, stack and stackx allow direct implementation of the tasks
under RC-51.

Example :
void fmenu() task _menu_ group 1 priority 3 istack 3 xstack 4
...

In this example the fmenu function is a task, with the following


attributes :
Tsk Number : _menu_
Group 1
Priority : 3
istack and xstack settings correspond to the space allocated
to save the internal and external
stacks respectively. See the section «Saving stacks».

Tasks written in another language

It is possible to write tasks in another language (e.g. from the MA-51 Assembler). To allow the
linker to take into account this task, you must declare it with the external attribute in a ‘C’ source
module. If the application comprises of several ‘C’ modules, the task declaration must be carried
out only once.

code
...
PUBLIC FLCD: ;task code is written in Assembler
mov A,NUMBER
LABEL1:
...
mov R7,TEMPO1
lcall kr _del_abs ;task is put to sleep
...

/* Task declaration in a ‘C’ module */

extern void flcd () task _TLCD_ group 2 priority 0


// This task is written in assembler and will be accepted
// by the linker and the kernel.
// ATTENTION: This external declaration must appear only once!!
...

The parameters NUM_TASK and NUM_TASKi (number of tasks for each group) are processed
by the linker and the Compiler. They do not have to be defined by the user.

-38-
KR-51 3. The scheduler

4.3.1 Significance of the different keywords

Keyword Significance Note


task Indicates to the linker that mandatory parameter
the function must be dealt
with as task.

Must be followed by a
constant value
corresponding to the task
number
group Must be followed by a optional parameter
constant corresponding to default value = 0
group to which the task
belongs
priority indicates the task priority optional parameter
default value = 0
(1)
istack indicates the memory used optional parameter
to save the stack default value = 16 bytes
(8 for KRY)
xstack (1) indicates the memory used optional parameter
to save the stack default value = 16 bytes
Ignore for KRY
(1)
: refer to the section ‘Implementation - Saving stacks and local variables’.

4.3.2 Kernel settings


The kernel options have the following default values :

Parameter Description Default Notes


value
TIMO_INIT Tick rate 1000 i.e. 1 ms @ 12MHz
(= reload value)
DIVIDE_1 Group 1 divisor 100 i.e. 0.1 s @ 12MHz
DIVIDE_2 Group 2 divisor 10 i.e. 1 s @ 12MHz
DIVIDE_3 Group 3 divisor 60 i.e. 1 min @ 12MHz

The quickest way to change these parameters is to select Options | Project | LX51 | Kernel from
RIDE.

Moreover you can set KR_XLEN which is the size of HR_XTOP segment (in xdata memory).
The default value is 1024.

Example:

$if(1)
PUBLIC KR_XLEN
KR_XLEN EQU 512

RKRXDEF?XD segment XDATA

-39-
4. Implementation KR-51

rseg RKRXDEF?XD
PUBLIC KR_XTOP
KR_XTOP: ds KR_XLEN

$endif

END

QUESTIONS

1. How do we calculate the number of CPU cycles/tick to be able to get 16usec per tick?
The clock goes at 16Mhz, so one CPU cycle takes 1/16=0.0625µs . Therefore we'll have
16/0.0625=256 cycles in 16µs. So we should set 256.
This is the theoretical value, but it may lead to problems. see below.

2. What is a smallest CPU cycles/tick that could be set?


The minimum value allowed is 200. If you enter a smaller value, RIDE uses 200. (the maximum
is 65535)
This limitation exists because the kernel takes about 200 cycles to analyse the tasks list when
there is only one group 0 task. If you used a smaller value, the CPU would spend all its time
managing the system, and the task would never be executed. (or some ticks would be skipped)

This is really a theoretical minimum, usable only if you have a few tasks of group 0.

When actually using the kernel in an application, the number of tasks grows, mailboxes and
semaphores are created, etc. All these things take time to be managed and the CPU time needed
for the system itself gets bigger. In practice, we advise to use at least a value of 500 if you want
to avoid problems.

That is why even if you set a value of 256, you may still have trouble. It all depends on the
complexity of the application.

In fact, when you want to perform such precisely timed operations (let's say, below 100µs
between ticks, if you have a 16MHz crystal), the best is to use another timer with a higher
interrupt level and a dedicated ISR. You can still use the kernel for the slower tasks.
Indeed, managing an OS takes time, you can't avoid it.

The number of clock by CPU cycles depends on the derivative you are using. The standard 51
takes 12 clock cycles per CPU cycle.

-40-
KR-51 3. The scheduler

4.4 Saving stacks and local variables

4.4.1 Stack storage


The management of return addresses of interrupted tasks requires information to be placed on top
of the stack. The "size" corresponds to a space reserved in XDATA (or IDATA for KRY) for
data storage. The return address need not be included in this size.

To calculate the stack size :


• if the task code does not invoke any sub-program (except kernel function calls), a size of 0
is sufficient.
• data storage occurs at "SUSPEND" calls where a task is moved to the WAITING state.
Sub-programs that do not use this function can be ignored.
• RC51 and PL/M-51 do not stack variables before a function call, (except for reentrant
functions) and only the function return addresses should be considered.
• Enter the required size after the keyword istack in the task declaration.

Example :
void ftime task _time_ priority 2 istack 2 xstack 0
{
while (1) {
if(++second==60) { inc_minute(); second = 0;}
kr_del_abs(100); /* assuming 100 Ticks per second */
}
}
void inc_minute()
{
if (++minute==60) minute = 0;
}
/* A 0 byte size is sufficient for the stack saving. The call to
inc_minute function is not taken into account */

The stack information is stored in an XDATA segment, using the KR_XTOP symbol to indicate
the start address and KR_XLEN for the size. The KR_XTOP segment is allocated automatically
by the kernel.

The default value of the size of this segment is 1024 bytes. To change this size, you can :
• Change the value from the kernel dialog box in RIDE
• Change the value either in an Assembler module or in a ‘C’ module using the following
syntax :
- Assembler: PUBLIC KR_XLEN
KR_XLEN NUMBERxx // xx is the size
- C: #pragma defj(KR_XLEN = xx) // xx is the size

The number of bytes, N, to reserve should be at least the sum of the declared sizes for the stack
spaces :
+ (NUM_TASK * 4) where NUM_TASKS is the total number of tasks declared by the user,
+ 16 bytes,
+ the bytes used for external stack storage (see next section)
to which the size of the space for the memory allocator (if used) should be added (see section 8).

4.4.2 The external stack capability (external versions)

-41-
4. Implementation KR-51

This section explains the concept of dynamic external stack management used by the ‘C’
compiler. You can skip the remaining part of the section if your tasks are written in assembly, or
in the ‘C’ language and compiled with the SMALL memory model where no external stack is
used.
Although the "SMALL" model may be used, it is logical to compile tasks in the "LARGE"
model, if you use kernel KRX versions in order to benefit from the external stack.
The reference manual for the RC-51 compiler gives a description of the external stack feature.

4.4.2.1 External stacks


If printf is used when ‘Use external stack’ is set, the buffer used for formatting is located into
external stack.
External stacks are saved at invocation of a SUSPEND function (kr_del_abs, kr_tst,
kr_waitsig...). The stack is saved and then automatically restored when reinitiating the task. The
swapping procedure is performed internally and does not pose any problem, except that the
external stack storage size to be assigned to each task.
The maximum size for automatic variable storage should be determined before calling a kernel
SUSPEND function. The example below explains how to determine the maximum size (which
must be placed after the keyword xstack).

pragma auto
float f1=12; /*static variable*/

void fcounter() task _counter_ istack 4 xstack 4


/*task counter*/
{
int i; /*int = 2 bytes used for this automatic variable*/
for (i=0;i<=5,i++)
{
printf ("fct=fcompteur : compteur=%2.2",i)
fct2 ();
kr_del_abs (5);/*timeout of 5 ticks*/
}
return ()
}

void fct2 ()
{
char c; /*automatic variable char = 1 byte used*/
for (c='0';c<='5',c++)
{
printf ("fct=fcompteur : counter=%c",c)
fct3();
kr_del_abs (5); /*timeout of 5 ticks*/
}
return();
}

void fct3 (char c2)


{ /*no automatic variable in this function*/
printf ("fct=fct3") /*but one parameter passed (c2)*/
/*this parameter will be stored in external stack*/
kr_del_abs (5); /*timeout of 5 ticks*/
printf ("%6.6f %c",sin(f1),c2);
}

-42-
KR-51 3. The scheduler

Caution : via the putchar function, the printf function may indirectly call a kernel suspend
function. The TELEMEAS example supplied (and printed out at the end of the manual)
illustrates this case.

Sufficient reservation (for internal and external stacks) should then be performed to include the
possible kernel suspend function calls from printf.

In example above, the external stack storage requires a minimum of 4 bytes as in the ‘worst
case’, the counter task may be suspended within fct3 function.

Before calling a suspend function within fct3, the following information should be stored in the
external stack :
• i value, in fcounter (int=2 bytes)
• c value, in fct2 (char=1 byte)
• the value of the parameter transmitted between fct2 and fct3 (here a char i.e. 1 byte).
The minimum size to be reserved for the external stack is hence the sum of the 3 preceding
values, which is 4 bytes.

These 4 bytes should be included when determining the size of KR_XTOP and KR_LEN (see
previous section).

Remarks:
As for the stack storage, it is advisable to reserve some additional bytes for the external stack
storage in case hand calculations are too small. A size of 0 for the external stack is appropriate
for the following cases :
- tasks written in assembly language
- tasks written in the ‘C’ language but compiled in the ‘SMALL’ memory model.

-43-
4. Implementation KR-51

4.5 The set-up utility program


For a KR-51 based application, the typical start-up process consists of the following initialisation
procedures :

Primary start-up

Application variable set-up

Kernel set-up

Internal peripheral set-up

"Permanent" task initiation

Kernel Activation

Base loop

The primary start-up procedure consists in initialising the Stack Pointer register (SP) and resetting
internal RAM (not essential but recommended). The configuration parameters are often placed in
the compiler’s set-up utility programs and hence need be of no great concern to most
programmers.

For the RC-51 compiler, the application variables set-up can also be performed automatically.
Practically, some variables will still need to be set up.

Initialisation the kernel is achieved by calling the KR_INIT function. In the KR_INIT function
call, timer 0 is configured, the interrupts enabled (EA and ETO) and tasks moved to the
UNVALIDATED state. Finally, in the KRX version, the pre-defined tasks (CLOCK of GROUPS
1, 2 and 3) are initiated. Note that timer 0 is not initiated : the first clock will occur only after
65536 CPU clock cycles, unless anticipated by the user (by entering FFh in the TH0 bit for
example).

The internal peripheral set-up procedure applies to the peripherals used by the application : serial
port,.. except for timer 0 and its interrupt.

The permanent task initiation procedure (refers to tasks that occur at fixed intervals) is performed
by the KR_CREATE function.

Finally, the base loop is executed, if no task is running it often consists of a simple loop (sjmp$). A
background function may be inserted in the procedure, if the register bank used is not the same as
that of any tasks or interrupts.

-44-
KR-51 3. The scheduler

4.6 Task editing


The examples of tasks provided should be read, before creating any original programs. It is
appropriate to remind the reader of some rules :
• the service prototypes and type definition placed in the INCLUDE files should be used :
*.h51 in Assembler, *.h in RC-51.
• to identify the tasks, constants should be defined (using #define in the ‘C’ language or equ
in assembly language) with meaningful. These constants should then be used at function
calls.
• direct memory addressing of registers should be performed with care since this could lead
to inappropriate accesses. The RB control in the MA-51 macro assembler, or the ‘using’
keyword in the RC-51 compiler is recommended.

4.7 The DEBUG versions

4.7.1 General
The DEBUG utility program offers the four following features :
• consistency checks are performed for easier debugging. The debug libraries are indicated
by a ‘D_’ prefix. The use of the DEBUG capability modifies the kernel’s performance and
increases code size.
• an error number is placed in the KR_ERR1 bytes, and a parameter, which is often a task
number, in KR_ERR2. These bytes are placed in DATA for the KRY version and in
XDATA for the KRX version. A summary of the errors is given later.
• a KR_TRAP function is initiated, if an abnormality in the scheduler module or a service is
detected. The "TRAP" function should be written by the programmer and given the
PUBLIC attribute. An example is provided in the KRX directory.

A simple trap exception function may be declared as follows :

void KR_TRAP(void)
{
EA = 0; //disable interrupts
while(1);
}

• a trace of the maximum value of the SP register is stored in SP_MAX byte in DATA
space. SP_MAX is updated in the CLOCK and INITIATOR phases. If SP is less than 8,
the KR_TRAP function with error code 1 is initiated. For microcontrollers with 256 bytes
of internal RAM, KRY will generate a trap exception if SP>248.
• the return address of the abnormal kernel function is loaded in the DPTR 16-bit register.

4.7.2 Recommendations
If you have any problems in implementing an application that uses the kernel, the DEBUG utility
program will be of great help, although it reduces kernel performances. If you have the SIMICE-
51 simulator (or the PCE5130C emulator) integrated in RIDE, you can open the ‘Kernel’ view
while debugging.

-45-
4. Implementation KR-51

4.7.3 Quick reference to return codes in the DEBUG utility program


The next quick reference tables apply to both internal (KRY) and external versions (KRX).
Functions are discussed in more detail in chapter 5.

Function KR_ERR1 KR_ERR2 Notes


"CLOCK" or 1h stack overflow
"INITIATOR"
Stack overflow

Function KR_ERR1 KR_ERR2 Notes


KR_CREATE 10h Task ref. unknown task
11h Task ref. not unvalided state
KR_DELETE 12h Task ref. unknown task
KR_SENDSIG 13h Task ref. unknown task
KR_DEL_ABS
KR_DEL_REL
KR_WAITSIG
KR_DELSIG
KR_PAUSE
System functions

Systems KR_ERR1 KR_ERR2 Notes


KR_GETSTATUS 14h Task ref. unknown task
KR_GETPRIORITY 15h Task ref. unknown task
KR_GETEVENTS 16h Task ref. unknown task
KR_GETTASKCUR -
KR_GETPRIORITYCUR -
Information requests

Function KR_ERR1 KR_ERR2 Notes


KR_TST 17 Flag ref. flag addr>127
KR_FREE 18 Flag ref. flag addr>127
19 Flag ref. flag already released
Semaphores

Function KR_ERR1 KR_ERR2 Notes


(see ‘mailboxes’ section for
further information )
MAIL_READ 8Fh mailbox N° read from an empty mailbox
MAIL_SEND 8Eh mailbox N° write on a full mailbox
any service related to 81h mailbox N° unknown mailbox
mailboxes 8Dh mailbox N° incoherent mailbox
Mailboxes

-46-
KR-51 5. List of services

5. List of Services

5.1 Three types of service

5.2 Quick reference to the services

5.3 Parameter passing convention

5.4 Values returned by the services

5.5 KR_CREATE (System Function)

5.6 KR_DELETE (System Function)

5.7 KR_DEL_ABS (System Function)

5.8 KR_DEL_REL (System Function)

5.9 KR_SENDSIG (System Function)

5.10 KR_WAITSIG (System Function)

5.11 KR_DELSIG (System Function)

5.12 KR_DELSIG_ABS (System Function)

5.13 KR_PAUSE (System Function)

5.14 List of the Information services

-47-
5. List of services KR-51

5.1 Three types of services


A "service" is a kernel function that can be called by a running task. Three types of services are
available :

5.1.1 System services


Provide the interface between user tasks and the real-time kernel. They react in ways which
depend on task scheduling (initiation, stop, send signal,..). System service functions are self-
protected against kernel state variable overlay (a risk involved in task or interrupt overlays). If
necessary, these functions can disable interrupts by clearing the EA bit in the SFR called IE.

5.1.2 Information services


Correspond to functions that return information relative to the kernel or a specific task. The
information can be used in the task binding or debugging procedures.

5.1.3 Utility services


Correspond to special functionality not directly built into the kernel, such as MAILBOX
management. The utility services are described in a separate section along with semaphore
services.
Each service description includes :
• their prototype in the ‘C’ language.
• an explanation of the effects on system status.

5.2 Quick reference to the services


System Information Utility
KR_CREATE KR_GETSTATUS MAIL_SEND
KR_DELETE KR_GETPRIORITY MAIL_READ
KR_SENDSIG KR_GETEVENTS MAIL_FLUSH
KR_DEL_ABS KR_GETTASKCUR
KR_DEL_REL KR_GETPRIORITYCUR MAIL_RESET
KR_WAITSIG MAIL_TEST
KR_DELSIG_ABS
KR_DELSIG_REL MEM_ALLOC
KR_TST MEM_FREE
KR_TST_TOUT
KR_FREE_TOUT
KR_FREE TIME_2STRUCT
KR_PAUSE TIME_2LONG

-48-
KR-51 5. List of services

5.3 Parameter passing convention


The parameter passing convention is compatible with the RC-51 compiler and the MA-51 macro
assembler from RAISONANCE. Most of the services have only one parameter of 1 byte, which
is passed via register R7.

5.4 Values returned by services


The system functions kr_delsig_abs, kr_delsig_rel and kr_tst_tout return a value in R7. The other
systems functions return no value (void type in the ‘C’ language).

The KR_TRAP function is initiated in the DEBUG versions, if an abnormality is encountered.


Information query services and some utility services return a byte located in both the
accumulator (A) and register R7.

-49-
5. List of services KR-51

5.5 KR_CREATE (System Function)

Function: Put a task into the READY state

Prototype: void kr_create (unsigned char task_id);

Return value: None

Remarks: The initiation or creation of task_id task causes switching


from the UNVALIDATED to the READY state. The task
does not run immediately, even if it is of higher priority than
the initiated task unless followed by a direct call to the
POOLER.

In the standard version, the task's current state, which should


be UNVALIDATED, is not checked.

In the DEBUG version, an exception (call to KR_TRAP) is


set and no action is performed, if the task is UNKNOWN or
not in the UNVALIDATED state.

Error code (debug): Error codes (DEBUG) :

10H Unknown task KR_ERR2 : reference of the task.

11H non compatible state (non UNVALIDATED).


KR_ERR2 : reference of the task.

Suggestions:
If a task can be initiated by more than one task, it should be regarded as a "shared resource" and
be initiated using a semaphore.

-50-
KR-51 5. List of services

5.6 KR_DELETE (System Function)

Function: Deletes a task.

Prototype: void kr_delete (unsigned char task_id);

Return value: None

Remarks: Kr_delete causes abnormal, or forced, termination of a task


and its use should be regarded as exceptional.

The deleted task moves immediately to the UNVALIDATED


state and if the task is currently active its execution stops. If
the task was interrupted, it is extracted from the running
queue and execution will not resume after completion of the
interrupt handler.

The scheduler stops kr_delete from being interrupted for a


time that may exceed 100 CPU cycles for the KRX version
with many tasks in the READY state.

Error code (debug): None

kr_delete SHOULD NOT be called from a hardware interrupt service routine.

Suggestions: :
To abort a task, the kr_delete call is not necessary. A simple "return" is by far better.
The DEBUG version will generate an exception (code 12H) only if the task is unknown.

-51-
5. List of services KR-51

5.7 KR_DEL_ABS (System Function)

Function: Moves a task to the idle state for a given time duration

Prototype: void kr_del_abs (unsigned char time);


or void kr_delay (unsigned char time);

Return value: None

Remarks: Moves the current task into the WAITING state for the
number of clocks specified by the ‘time’ parameter.

The TIME duration is derived from the CLOCK module (or


task's group for the KRX version). See also section "Task
description/Waiting for an event".

The time taken as a reference is not the current time, but the
time when current task was placed in the READY state.
Exact timing is hence ensured.

KR-51 manages delays resulting from the initiation of higher


priority tasks or an interrupt of lower priority tasks. If a
current task is initiated with a delay of 4 clocks and
kr_del_abs (10) is called, a delay of 6 (10-4) clocks is
applied, calculated from actual time. Delays should not
cumulate.

Error code (debug): None

In the time diagram below, it is assumed that to end the task, KR_DEL_ABS (10) function is
systematically used.

10 ticks 10 ticks 10 ticks 10 ticks

TASK SCHEDULING

Task creation Task initiation

Task ready Task execution

LEGEND

-52-
KR-51 5. List of services

KR_DEL_ABS may be used anywhere in a task, as dynamic entry point management is


employed. After the delay has expired, execution continues with the statement/instruction
immediately after the KR_DEL_ABS function call.

A typical use of the KR-DEL_ABS function is in the construction of timed tasks without
"offsets". However, it is often necessary to move an instruction to the Wait for a time-out state
(starting from current time). In this case, KR_DEL_REL should be used. This function is
described in next section.

5.7.1 Possible problems with KR_DEL_ABS


Normally, you need not know any more about how the kernel handles the KR_DEL_ABS
function. However, for more complex applications, the concept of a task delay (or advance)
based on current time should be more thoroughly understood.

A way to visualise the process consists in representing the current time (number of clocks) by the
position on the circumference of a circle (in the form of a bold radius line in the diagrams
below). Times are counted with "modulo 256" and passes in an anti-clockwise direction.

Similarly, a "timer" is associated with each task (represented in the form of a fine radius line in
the diagrams). At each clock, a comparison between the current time and the task's timer value is
performed by the scheduler.

In the example below, tasks 1 and 2 are both waiting for a time-out and at the next clock the
following occurs :
• the scheduler detects that task 2 (delayed) must be moved to the READY state, which will
be effectively performed even if task initiation is delayed.
• it detects that task 1 (in advance) must remain in the WAITING state.

Task 1 current time


(in advance) Task 2
(delayed)

0 (mod 256)

This representation also permits a better understanding of why the KR_DEL_ABS function has a
signed number (-128 to +127) as a parameter.

KR_DEL_ABS accepts a negative argument, which can be useful in some specific cases. e.g.
KR_DEL_ABS (-5)

A "reset" compared with task's creation time is thus performed.

This image being explained, let us end with 2 examples where KR_DEL_ABS involves more
complex interpretations.

-53-
5. List of services KR-51

current time
Task 1 counter Task 1 counter

0 (mod 256) 0 (mod 256)

CPU not available


to initiate task 1
fig 2 : task 1 in the READY state
fig 1 : task 1 in the WAITING state

Task 1counter
New value of
task1 counter

0 (mod 256)
0 (mod 256)

current time current time

fig 3 : task 1 in the RUNNING state fig 4 : task 1 in the WAITING state

1)
Let us image that a task (task 1 in example above) is to be initiated every 10 clocks, which can be
easily obtained by systematically ending the task using the following sequence :

KR_DEL_ABS (10) /*in the ‘C’ language*/

Let us assume that a task placed in the READY state is not initiated immediately and is delayed
for more than 128 + 10 = 138 consecutive clocks because the CPU being occupied by tasks or
interrupts of higher priority. Figures 1 and 2 illustrate this case.

When the CPU is released so that it may initiate task 1 (figure 3), task 1 moves to the RUNNING
state and then terminates by a KR_DEL_ABS(10) function call as always.

The new reference value for the timer associated with task 1 is calculated as above explained
(=old value + 10). It is represented on figure 4.

At the next kernel clock (see figure 4), task 1 will then be regarded as being in ADVANCE,
although in fact it has 128 clocks of "delay". It will consequently not be moved to the READY
state, before the absolute counter exceeds task 1 counter value. In this case, the equivalent to a
"half-turn" (=128 clocks) is "lost", before resuming with normal task scheduling. Consequently,
the kernel handles any delay, provided it does not exceed 128 clocks.

-54-
KR-51 5. List of services

2)
A similar but more difficult problem may occur due to cumulative delays (in the previous
example, a delay has been generated only once).

Let us imagine for example a sequence in the form KR_DEL_ABS (2) for a function of long
duration compared with the clock time base.

If, in addition, the CPU is pre-empted from time to time by higher priority tasks, an increasing
delay between current time and task's counter value (-2, then -7, then -12....) occurs. If this delay
reaches -128, a "half-turn" (128 clocks) is lost in the task scheduling, which differs significantly
from the expected result, i.e. a regular schedule of task sequence every 2 clocks.

Practical conclusion :
Both previous examples correspond to rare situations where task splitting is badly optimised.
Note that an essential rule is that the higher priority tasks or interrupts should be of the shortest
duration.

Similarly, the second example represents a case where the CPU is "used up", which should of
course be avoided. When a task is to be initiated at regular time intervals, the first condition to
observe is that the task's duration does not exceed the time interval between two consecutive
initiations.

Remark : If you must work with tasks of a long duration with respect to the time base and of
equal priority (which is not recommended), the KR_PAUSE function should be used.

-55-
5. List of services KR-51

5.8 KR_DEL_REL (System function)

Function: Puts a task to SLEEP for a given duration

Prototype: void kr_del_rel (unsigned char time);

Return value: None

Remarks: Moves the current task to the WAITING state for the TIME
duration. The TIME duration is specified in number of clocks
in the CLOCK module (or task's group in the KRX version).
See section "Task description/Waiting for an event".

In contrast to the kr_del_abs function, the time taken as a


reference is the current time. A kr_del_rel function call erases
any trace of task delays starting from the last time when it
was declared as READY.

KR_DEL_REL reloads the value of the timer associated with


the task using the following value : current timer (or timer
associated with its group) + TIME. The task will hence be re-
declared "READY" in "TIME" clocks.

Error code (debug): None

5.9 KR_SENDSIG (System function)

Function: Sends a signal to a task.

Prototype: void kr_sendsig (unsigned char task_id);

Return value: None

Remarks: Sends a signal to the task indicated by task_id. This signal is


ignored, if the specified task is not waiting for the signal. If it
is, and if the task is not waiting for another event, it moves to
the READY state. It can hence be selected during the next
pooling session.

Error code (debug): Task existence checks are performed.

-56-
KR-51 5. List of services

5.10 KR_WAITSIG (System function)

Function: Moves a task to the Wait for a signal state (WAITING).

Prototype: void kr_waitsig (void);

Return value: None

Remarks: A flag in the current task descriptor is set. Later another task
may call KR_SENDSIG, which resets the flag and causes the
present task to be moved to the READY state.

Error code (debug): Task existence checks are performed.

5.11 KR_DELSIG (or KR_DELSIG_REL)

Function: Moves a task to the Wait for a signal state (WAITING), but
the wait is limited by a time-out.

Prototype: char kr_delsig (unsigned char time);

char kr_delsig_rel (unsigned char time);

Return value: 0 if the time-out has elapsed before a signal was received

!=0 otherwise

The returned value is placed in R7

Remarks: Identical to KR_WAITSIG, but the ‘time_out’ flag is also set.


The task will leave the WAITING state (and move to the
READY state) if either of "TIMEOUT" or "SIGNAL" event
occurs. The delay is a relative delay. See kr_del_abs and
kr_del_rel for further details.

Error code (debug): Task existence checks are performed.

5.12 KR_DELSIG_ABS
Identical to KR_DELSIG_REL but in this case the delay is an absolute delay, referring to the
task’s creation time (see kr_del_abs and kr_del_rel for further details).

-57-
5. List of services KR-51

5.13 KR_PAUSE (System function)

Function: Moves a task to the READY state, if another task of equal


priority is also ready (to take control). Equivalent to
KR_DEL_REL(0).

Prototype: void kr_pause ();

Return value: 0 if the time-out has elapsed before a signal was received

!=0 otherwise

The returned value is placed in R7

Remarks: When two tasks of long duration and similar priority must be
activated, the first initiated task takes control of the
processor, prohibiting the execution of the next task because
of its duration. Time slicing is the usual solution to this
problem but is not supported by KR-51. The KR_PAUSE
function is an economic and efficient alternative: you only
need place kr_pause calls in the tasks and the arbitration
occurs automatically. If, at function call, no task of equal
priority is ready, the return to the task is immediate and
KR_PAUSE has no effect.

At the call to KR_PAUSE, the task's creation time is


modified and given the current timer value (as if the task
were just initiated). This permits ‘refresh’ of the task, which
is required by the "oldest first" principle. However, this time
change feature creates a time offset and prohibits task calls
at regular time intervals by KR_DEL_ABS function. If these
offsets pose a problem, a solution consists of interleaving
two tasks : the first task occurs at fixed time and calls the
second task, which performs KR_PAUSE calls.

Error code (debug): None

-58-
KR-51 5. List of services

5.14 List of the information services


The function prototypes, state designation and other definitions are contained in the INCLUDE
files.

kr_getstatus:
char kr_getstatus (unsigned char task_id)

Returns the state of task_id task in 1 byte.

The state can be : UNKNOWN (255), READY (0), WAITING (4), UNVALIDATED (8),
SUSPENDED (12) RUNNING (1).

kr_getpriority:
char kr_getpriority (unsigned char task_id)

Returns the priority of task_id task as value between 0 and 3.

kr_getevents:
event kr_getevents (unsigned char task_id)

Returns the list of the events waited by task_id task. It is 1 byte. Bits 4, 5 and 6 respectively
indicate whether a signal, a timeout or a flag release is waited for (a timeout and a flag may not
be waited for simultaneously). Type event is declared in file ‘krdcl.h’.

kr_gettaskcur:
unsigned char kr_gettaskcur ( )

Returns the number of the current task.

kr_getprioritycur:
char kr_getprioritycur ( )

Returns the priority level (0...3) of the current task.

-59-
5. List of services KR-51

-60-
KR-51 6. Semaphores

6. SEMAPHORES

6.1 Description

6.2 Semaphore representation

6.3 Implementation

6.4 Notes and suggestions

6.5 Semaphores and task groups (external version)

6.6 Semaphores and task synchronisation

6.7 Resources used

-61-
6. Semaphores KR-51

6.1 Description
The semaphore is an easy sharable resource management tool :
• When task T1 uses resource R1, it reserves it by asserting the semaphore associated with
R1 via a call to a kernel service function.
• If another task T2 requests the same resource (R1), access to it is refused, until the
semaphore associated with it is released by T1.
• Task T2 moves into the WAITING state and only enters the READY state, when T1
releases the semaphore that protects R1 (via a kr_free function call).

Semaphores can be applied to the following sharable resources :


• memory areas (variables).
• internal peripherals : CAN, UART,...
• MAILBOXES.
• tasks (initiating slave tasks)
• functions (for example maths library),....

Signal/semaphore difference
A signal is associated with a task. A semaphore is associated with a resource and is independent
of any task.

Types of semaphores
There are 2 types of semaphores :
• Semaphores with time-outs apply to versions of the kernel which use external RAM
4 semaphore flags in internal memory are allocated by the kernel to help manage the timer.
They are called :
SEMA_BIT0 SEMA_BIT1 SEMA_BIT2 SEMA_BIT3
• Normal semaphores without time-out facilities

-62-
KR-51 6. Semaphores

6.2 Semaphore representation

6.2.1 Semaphores with time-outs (external versions only)


The associated services allow combination of the wait for semaphore with the TIMER (time-out)
:
char kr_tst_tout (char time-out, char sem_num)
void kr_free_tout (char sem_num)

The delay must be thought of as a "relative delay", like in the kernel service kr_del_rel.

The kernel automatically ALLOCATES 4 bits in the bit segment, starting from the PUBLIC label
BIT_SEMA0.

The 4 semaphores which can be timer controlled are referred by their « number », from 0 to 3:

0 for BIT_SEMA0
1 for BIT_SEMA0+1
2 for BIT_SEMA0+2
3 for BIT_SEMA0+3

Example: kr_tst_tout (10,1)


/* delay = 10 ticks (of the group) */
/* semaphore number 1 */

6.2.2 Normal semaphores

6.2.2.1 Implementation
Although 128 bits are available in bit addressable space, some are used by KR-51. From a
practical point of view, over 100 bits are available, which is more than sufficient for most
applications using the 8051 microcontroller.

Remark :
The 4 bits, SEMA_BITi (i=0...3), are automatically allocated by the kernel. If you don’t need
these bits as timer controlled semaphores, you can use them for any other purpose including
« standard semaphores ». In this case, you must impose the allocation of the SEMA_BIT0
segment and subsequently refer to the address of these bits. Refer to the example SX in the
Appendix for further details.

6.2.2.2 Semaphore services for standard semaphores


The only semaphore services available are semaphore set and release. Semaphores must be
directly initialised.

Semaphores should be used by tasks only and not by interrupt services. which cannot be moved
to the WAITING state.

kr_tst : Reservation (Test and Set)


void kr_tst (char sema)

In this function, the bit state of the semaphore with the sema address is examined :
• if the semaphore is free (bit at 0), it sets the semaphore, enters the "busy" state and gives
control to the calling task that continues its execution.

-63-
6. Semaphores KR-51

• if the semaphore is set (bit at 1), the calling task enters the WAITING state and waits for
release of the semaphore.

In the DEBUG versions, the bit address passed as an argument is checked and should not exceed
127.

Error codes :
KR_ERR1 : 17h - if the semaphore reference (i.e. bit address) is greater than 7FH
KR_ERR2 : semaphore reference n°

-64-
KR-51 6. Semaphores

6.3 Implementation
The semaphore handler is built into KRYS and KRXS versions of KR51. However, the KR_TST
and KR_FREE functions expect the semaphore address to be specified as a parameter, whereas a
high-level language compiler such a ‘C’ does not usually assign absolute addresses.

To solve this difficulty, you can do any of the following :


• place semaphores at fixed addresses by declaring them in an assembly program. You only
need define constants corresponding to these addresses :
;Assembly program used for the allocation of the semaphores
BIT at 10H
SEMA0 : DB 1
SEMA1 : DB 1

/* ‘C’ program referring to the above semaphores*/


#define SEMA0 0x10
#define SEMA1 0x11
• reserve one byte in BDATA to be split into 8 semaphores. The semaphore address can
hence be found from the byte address, but the computation will be performed at run-time,
which is inefficient, and this option is not recommended. Let us rewrite the previous
example :
/* ‘C’ program allocating semaphores*/
char bdata sema8_1;

#define SEMA0 ((((char)&sema8_1)-0x20)*8)


#define SEMA1 ((((char)&sema8_1)-0x20)*8+1)
• use the suggested macro in the SX application in the Appendix.

6.4 Notes and suggestions


For correct operation, a semaphore should be reserved only via system calls. Any direct
semaphore reservation will result in incorrect operation of the scheduler.

Moreover, to ensure that semaphore release occurs within the shortest time, do not terminate a
task that has set a semaphore. If you do it, the semaphore will be set forever and no task can
access the protected resource.

Semaphores should be initialised (to zero) at the start of the application.

6.5 Semaphores and task groups (external versions)


Reminder : in the KRX version, 4 task groups are available and each group is associated with a
clock.

Each task group is assigned a pooler, which pools each task in the group and moves the "waiting
for a semaphore release" tasks to the READY state, when the corresponding semaphores are
released.

The interleaved pooler functionality permits higher kernel performance. For example, if a task in
group 3 must be initiated every 3 hours and it is associated with a sub-clock of 1 hour it will be
pooled only every hour.

This behaviour can pose some difficulties in specific cases : if an infrequent task of a higher
order group is waiting for a semaphore release, its move to the READY queue may be delayed
by lower order groups' tasks that are waiting for the same semaphore release.
The example below provides a solution to solve this difficulty :

-65-
6. Semaphores KR-51

Example 1 :
void ftestvers0 () task _tstvers0_ priority 0 group 3 {
...
kr_tst (sema0)
/*risk of important delay if tasks from group 0 or 1 share this
ressource*/
... /* use of the resource */
kr_free (sema0)
}

Example 2 (adaptation of the previous example)


/* task channel*/
void fchannel() task _channel_ priority 0 group 0 /*group 0*/
{
/*test if task _tstvers1_ is in the WAITING state (here,
waiting for a signal).*/
while (kr_getstatus (_tstvers1_)!=WAITING)
{
kr_del_abs (30);
}

/*at this stage tstvers1 is waiting for a signal*/

kr_test (sema0) /* SEMAPHORE_X set*/


kr_sendsig (_tstvers1_) /* sends signal to ftask_ex*/
} /* end of task channel*/

void ftaskvers1 ()task _tstvers1_ priority 0 group 3


/*adaptation of the task ftaskvers0*/
{
...
kr_create (_channel_)
kr_waitsig /*wait for the signal sent by the task channel*/
... /*use of the resource*/
kr_free (sema0)
/*release of the semaphore set in the task _channel_)*/
}

6.6 Semaphores and task synchronisation


It is not possible to synchronise a task from a time of origin and to call semaphore facilities. To
solve this problem you must spawn another task, which will receive a signal from the ‘parent
task’.

6.7 Resources used


Contrary to the utility services such as MAILBOXES, the semaphore management is performed
internally, which means that for KRXS, KRHS and KRYS versions, the semaphore code will
always be loaded with the kernel’s core. Other semaphore services such as (kr_tst, kr_tst_tout...)
are loaded only if there are used.

Semaphores do not require any RAM resource except for the semaphore bits. The semaphore
functionality requires approximately 300 additional bytes of code.

-66-
KR-51 7. Mailboxes

7. MAILBOXES

7.1 Description

7.2 Available services

7.3 Notes and suggestions

7.4 Resources used

-67-
7. Mailboxes KR-51

7.1 Description
Mailboxes are message storage modules used to pass messages between tasks. In KR-51, the
"messages" are limited to the simple expressions, as they are entered in the form of characters.

Mailboxes are mainly used for parameter passing. Contrary to function calls, a task call does not
allow a ‘message’ as a parameter. However, messages may be placed in a mailbox, before the
task call and later the task may read it.

Mailboxes are also used for data flow management : if, for example, a task must send a character
stream on the serial port, this data is transmitted via a mailbox that will act as a buffer (See the
SX example in the Appendix).

KR-51 can manage up to 8 mailboxes : the first mailbox (B0X0) has a capacity of 128 bytes and
is well suited for data flow transmissions. The other 7 mailboxes have a reduced capacity of 16
bytes, which is enough for parameter passing (or reduced data flow transmission).

Messages in the mailboxes are handled as First-in-First-out (FIFO) buffers. The first character
written will be the first character read.

The mailbox state can be determined by calling the MAIL_SIZE function, which returns the
number of characters contained in the box. The EMPTY and FULL values can be retrieved
directly from two PUBLIC addressable bit bytes named MAIL_FULL and MAIL_EMPTY.

The mailbox capabilities apply to all versions kernel.

7.2 Available services


The error returns indicated below are provided in the DEBUG versions only.
MAIL_RESET(0)

This function should be called (and terminated), before any first mailbox function call. It
initialises all mailboxes, and sets FULL bits to 0 and EMPTY bits to 1. There is no error return.

MAIL_SEND(char box, char message_character)

Sends message_character to the box.

Error return : 81h, 8Dh, 8Eh

This function requires the passing of 2 parameters, R4 for the box number and, R5 for message
character. This convention is compatible with passing conventions used by the RC-51 compiler
from RAISONANCE and the PL/M-51 compiler by INTEL.

-68-
KR-51 7. Mailboxes

Warning : The MAIL_RESET function must be performed during start-up and before
any call to MAIL related functions.

MAIL_READ (char box)

Reads a character contained in the mailbox.

Error return : 81h, 8Dh, 8Fh

MAIL_SIZE (char box)

Returns the number of characters contained in the mailbox. Indicates the box size, if the FULL
bit is set. If not, it indicates the number of bytes still to be read, modulo the box size.

Error return : 81h, 8Dh.

MAIL_FLUSH (char box)

Clears any characters in the mailbox. Puts the FULL bit associated with the box to 0 and the
EMPTY bit to 1.

Error return : 81h, 8Dh.

And for the DEBUG version :

MAIL_TEST (char box)

Tests the mail box. The test consists in verifying consistency of internal pointers and
MAIL_FULL and MAIL_EMPTY bits associated with box. If abnormalities are detected, the
KR_TRAP trap function is called.

MAIL_TEST is automatically called at the beginning of the following services : MAIL_READ,


MAIL_SEND, MAIL_SIZE and MAIL_FLUSH. If an abnormality is detected, the service is
aborted and the KR_TRAP function is initiated.

ERROR CODES :

KR_ERR1 KR_ERR2 Meaning


81h Mailbox ID Unknown mailbox
8Dh Mailbox ID Incoherent mailbox (inconsistent internal pointer).
8Eh Mailbox ID Write on full mailbox
8Fh Mailbox ID Read from empty mailbox

-69-
7. Mailboxes KR-51

7.3 Notes and suggestions


MAILBOXES allow interleaved tasks of different priority to access the same MAILBOX as a
sender and an addressee. ‘Simultaneous’ access to different MAILBOXES does not pose any
problem but, only one message can be sent or read in the same MAILBOX at one time. Multi-
message capability is not supported, because it corresponds to a bad programming style and
interrupts would be disabled for a long duration.

If the same MAILBOX can be addressed by more than one task a semaphore should be used to
control access to this shared resource For example in KRX the serial port is used by
MAILBOXES and protected by semaphores.

It is recommended to check that the MAILBOX is not full (or empty) before performing a send
(or read) operation. An error is identified by the return of the FFh with carry equal to 1. The
errors result from a read request on an empty box and a write request to a full box. The other
errors, ‘mailbox is not initialised’ and ‘invalid parameter’, are handled in the DEBUG version
only, and generate undefined results in the STANDARD version.

7.4 Resources used


Mailbox functions are independent from the kernel. The resources used by the mailboxes will
hence be reserved in the application, only if a task involves the mailbox service facility.

In XDATA area: A page of 256 bytes is used where the first 16 bytes indicate the state of the 8
MAILBOXES and the 240 following bytes correspond to the mailboxes' contents.

In DATA area: 2 addressable bit bytes (BDATA) contain the FULL and EMPTY Semaphores.
These bytes are consecutive. The first is MAIL_FULL, the second MAIL_EMPTY. The least
significant bits correspond to BOX0.

In CODE area : Approximately 300 bytes are used

-70-
KR-51 8. The memory allocator

8. THE MEMORY ALLOCATOR (KRX)

8.1 Description

8.2 Available services

-71-
8. The memory allocator KR-51

8.1 Description
Memory space allocation is essential for data systems with dynamically loaded applications.

It is less important for a microcontroller, which generally works on a static code and for which
the memory requirements are determined in advance.

The memory allocation capability applies only to external RAM (XDATA) as dynamic
management of internal RAM is inappropriate because of its small size. Consequently, the
memory allocation capability are available only in external versions (KRX and KRH).

8.2 Available services


Two basic functions are available :
• xdata char *mem_alloc (unsigned n)
• void memfree (xdata char *ptr)

8.2.1 MEM_ALLOC
xdata char *mem_alloc(unsigned n)
Allocates n bytes.

Parameter passing (compatible with ‘C’ and assembly language).


• Entry parameter (n) : R6:R7 (High part in R6)
• Return value (pointer in XDATA) : R6:R7

Remarks :
• MEM_ALLOC returns a NULL pointer, if the remaining space is insufficient for a new
allocation.
• For each block of n bytes reserved, n+2 bytes are in fact used in the XDATA segment. The
area used starts at KR_XTOP address and KR_XLEN indicates the segment length.
KR_XTOP and KR_XLEN must be declared in the set-up file (see SX application in the
Appendix).
• The first part of the KR_XTOP segment is used for dynamic stack and external stack
management. The following form should be observed :

XLEN >= SIGMA_STACK + SIGMA_XSTACK +2

where SIGMA_STACK represents the number of bytes necessary for stack management
and SIGMA_XSTACK represents the number of bytes necessary for external stack storage
(see section "Implementation/Task declaration").

The size actually available for allocator is in fact only XLEN - SIGMA_STACK -
SIGMA_XSTACK - 2.

-72-
KR-51 8. The memory allocator

8.2.2 MEM_FREE

void memfree (xdata char *ptr)

• Entry parameter (pointer in XDATA) : R6:R7 (High Part in R6).


• Return parameter : none

This function releases the block, which starts at the address given by the parameter. This function
also binds the released area to the free blocks located "upward" and "downward" in an attempt to
avoid fragmentation of the XDATA space.

8.2.3 PRECAUTIONAY MEASURES


Both memory allocator services should not be called simultaneously by two tasks (or interrupts)
of different priorities. Typically, a semaphore should be used to control access to this resource.

-73-
8. The memory allocator KR-51

-74-
KR-51 9. The calendar

9. THE CALENDAR

9.1 Description

9.2 Available services

9.3 Implementation

-75-
9. The calendar KR-51

9.1 Description
The perpetual calendar capability provides exact date handling with month length and
exceptional events such as leap-years management built-in.

The "dates" can be manipulated in two forms :

1. A compressed format : the time is expressed as a 32-bit unsigned number representing the
number of seconds since ‘January 1, 1992 at 00:00 hours’. Theoretically, this format permits
a maximum duration of approximately 136 years but it has been limited to 45 years to
simplify internal operations, which still ensures exact dating until 2037.

2. A split format : a structure in which the "year", "month",.."seconds" elements are split.

Two functions are supported in this module : a compressed-to-split format conversion and a split-
to-compressed conversion. Practically, these two primitives are sufficient to perform any
operation on dates or on times.

The "Implementation" section and the examples supplied illustrate some functions derived from
these primitive functions.

Some simple low-level timer functions are provided but there is none concerned with absolute
time management

The perpetual calendar is available in both internal and external versions of the Kernel.

-76-
KR-51 9. The calendar

9.2 Available services


The structure associated with the split format is called STIME. It is defined in the ‘C’ language
in the following form :
struct stime
{
char dayofweek; /* 0 (sunday)..6(saturday) */
char year; /* cf conventions hereafter */
char month; /* 1..12 */
char day; /* 1..31 */
char hour; /* 0..23 */
char minute; /* 0..59 */
char second; /* 0..59 */
};

For the year, the following convention is applied :


• 92 <= n <= 99 means year 19xx
• n <92 means year 20xx

Conversion functions are :

SPLIT=>COMPRESSED format : (structure=>long)

long unsigned time_2long (struct stime *st1);

The structure address is given as a parameter that is a generic pointer in 3 bytes :


• Register R3 contains the identification of the physical space according to the following
convention : CODE (1), DATA (3), XDATA (2), PDATA(4).
• R2:R1 registers contain the pointed address
• (High part in R2, Low part in R1).

The value returned is a 32-bit word placed in registers R7:R4 (MSB in R7, LSB in R4).

COMPRESSED -> SPLIT FORMAT (long -> structure)

void time_2struct (long unsigned L1, struct stime *st1);

The compressed value L1 is converted into the structure pointed to by st1.

Parameter passing :
• L1 is the first parameter : a 32-bit word in registers R7:R4 (MSB in R7, LSB in R4).
• *st1 is the second parameter (=generic pointer) : R1R2R3 (as above)
These passing conventions are transparent, if the tasks are written in the ‘C’ language. For calls
written in assembly language, the details of passing conventions are needed

A generic pointer (here a pointer to a stime structure) is represented by 3 bytes :

GENERIC POINTER =

Address Low (R1) Address High Memory SPACE (R3)


(R2)

-77-
9. The calendar KR-51

where SPACE =

0 "NULL" POINTER
1 CODE
2 XDATA
3 DATA
4 PDATA

PDATA space (4) is special. It is not a space qualifier. In fact, it is an XDATA space addressed
in the "page" mode using the "movx @Ri,A" or "movx A,@Ri" instruction. The high byte is then
placed on Port P2.

-78-
KR-51 9. The calendar

Example : call of TIME_2LONG function from a task written in


assembly language */

Aim : conversion of the number 131378758L (number of seconds) in


split format.

xdata at 10h
struct_time : db 7 ;split format
;first byte = dayofweek

mov R7,#46h ;13137858L= 0x07D4AE46


mov R6,#0AEh
mov R5,#0D4h
mov R4,#07h
mov R1,#low(struct_time) ;LSB address
mov R2,#high(struct_time) ;MSB address
mov R3,#2 ;xdata "SPACE" reference
lcall TIME_2STRUCT ;call to the convertion function
;converted value is :
;Wed 29 02 1996 14h 05 min 58s

-79-
9. The calendar KR-51

9.3 Implementation
The perpetual calendar requires the current time, which must given in the compressed format and
incremented by a task (or a function) that is called every second.

Example :
long unsigned curtime;
void taskx inc_time()
{
curtime++;
kr_del_abs(1); /* if tick rate equals 1 second */
}

The use of conversion functions with curtime permits easy definition of current date and time set
and get functions :

struct stime stcur;


struct stime *gettime()
{
time_2struct(curtime,&stcur);
return &stcur;
}
void setdate(unsigned day, unsigned month, unsigned year)
{
time_2struct(curtime,&stcur);
stcur.day = day;
strcur.month = month;
stcur.year = year;
curtime=time_2long(&stcur);
}
void settime(unsigned hour, unsigned minut, unsigned second)
{
time_2struct(curtime,&stcur);
stcur.hour = hour;
strcur.minute = minute;
stcur.second = second;
curtime=Time_2struct(&stcur);
}

Finally, (as it is a standard arithmetic on 32-bit words), the compressed format can immediately
be used for operations on dates and time duration in the form :
duration = date 2 - date1
date2 = date1 + interval
or comparisons such as (date2 > date1).

-80-
KR-51 10. The internal version KRY

10. THE INTERNAL VERSION : KRY

10.1 Description

10.2 Resources used

10.3 Example

10.4 Performances

-81-
10. The internal version KRY KR-51

10.1 Description
KRY versions are characterised by :
• non use of external RAM space (XDATA), except for utility services such as
MAILBOXES.
• management of up to 7 tasks.
• only two groups are available.
• external stack is not managed.
The time-out functions (KR_TST_TOUT) are not available.

10.2 Resources used


KRY versions uses only the microcontroller’s internal space.

The fixed kernel resources (excluding the utility services such as MAILBOXES) are :
• 1 byte of BDATA to indicate the state of the current task.
• 5 bytes of DATA to contain the status of the clock timer and the SP register contents
performed at task initiation.
• 3 additional bytes of DATA for the DEBUG version (KR_ERR1, KR_ERR2 and the trace
of the stack pointer maximum value).
• 4 additional bits (starting at address SEMA_BIT0) for the semaphore versions
For each task, the resources vary depending on the number of tasks and are :
• 2 bytes of DATA to be declared by the user according to the total number of tasks.
The dynamic resources (stack) are limited by the number of stack-able tasks and hence by the
number of priority levels. At task initiation, the following information is stacked :
• the return address (stacked during the TIMER0 interrupt service).
• the compiler-used resources: ACC, PSW (hence the register bank selection bits of the ‘old’
active register bank), B, DPL, DPH.
• the lower task descriptor byte.
• the RECEIVER address where execution will continue upon completion of the task. When
a task is ‘launched’, a pseudo “return address” is stacked.
Which is to say, a total of 10 bytes per priority level used. Consequently if two priority levels are
used, 20 additional stack bytes should be provided in addition to the bytes required by user
functions.

Code size (excluding the utility services to be loaded only if required) is :


• less than 500 bytes for KRY.OBJ
• less than 700 bytes for KRYS.OBJ (with the Semaphore capability).

Finally, the kernel uses timer 0 and the associated interrupt service.

82
KR-51 10. The internal version KRY

10.3 Example
This example consists of a simple clock with an LCD display that permanently indicates the time
and date. One set of tasks updates the display while a second set allows the time to be altered
using two push-buttons.

Diagram 1 : SI CLOCK

This application consists of one file only (SI_MAIN.C). Note that static task management with
static entry points is acceptable in this application but may cause a technical problem, if using the
KRY versions. See Section "Task declaration/The initiator" for details.

10.4 Performances
If the performance analyser of PCE-51 real-time emulator is applied to the TIMER 0 interrupt
handler in the example above, the following information is be obtained :

Minimum duration: 105 CPU clock cycles


Maximum duration : 216 CPU clock cycles
Mean time : 110 CPU clock cycles
Average CPU utilisation : 10%

See section "The external version/Example" to compare the performance between the internal
and external versions.

-83-
10. The internal version KRY KR-51

84
KR-51 11. The external versions KRX / KRH

11. THE EXTERNAL VERSIONS: KRX / KRH

11.1 Description

11.2 Resources used

11.3 Example

11.4 Performances

-85-
11. The external versions KRX / KRH KR-51

11.1 Description
The external versions are mainly characterised by :
• a reduced use of DATA internal space.
• up to 29 for the KRX version and 125 tasks for the KRH version.
• availability of 3 CLOCK dividers and four clock frequency groups.

11.2 Resources used


The fixed kernel resources are :
• 1 byte of BDATA : to indicate the state of the current task.
• 5 bytes of DATA : to contain the status of the clock timer and the SP register performed
at task initiation).
• 1 additional byte of DATA for the DEBUG version (and 2 of XDATA).
• 4 extra bits for the semaphore versions (starting at address SEMA_BIT0)
The dynamic resources (stack) are limited by the number of stack-able tasks and hence by the
number of priority levels - up to 4.

At task initiation, the following information is stacked :


• the return address (stacked during the TIMER 0 interrupt service).
• the compiler-used resources to be stored : ACC, PSW (and hence the bank selection bits of
the ‘old’ active register bank), B, DPL, DPH.
• the lower task descriptor byte.
• the address of the kernel’s internal function which generates task termination with lower
state retrieval.
Which is to say, a total of 10 bytes per priority level used. Consequently if the four priority levels
are used, 40 additional stack bytes should be provided in addition to the bytes required by user
functions.

XDATA space depends on the number of tasks : a minimum of 256 bytes for the KRX and
1 kbytes for the KRH versions are required.

In addition you must also take into account the bytes needed for certain services as well the
number bytes needed to save the stacks (internal and external) for each task.

Note that the XDATA space required by KRX is defined by the PAGE attribute, which means
that it will be placed by the linker at the beginning of a page of 256 bytes (i.e. address :
0XX00h). It starts at symbol MEM_TABLE.

Code size is :
• approximately 1500 bytes for KRX.OBJ
• approximately 1850 bytes for KRXS.OBJ
• approximately 2000 bytes for D_KRXS.OBJ (with the Semaphore capability).

Finally, the kernel uses timer 0 and the associated interrupt service.

86
KR-51 11. The external versions KRX / KRH

11.3 Example
The example for the KRX version uses most of KR-51’s resources. It consists of a 3-channel
recorder for a three-phase electrical supply that can store up to 5 days of measurements with an
average measurement rate of one per minute.

27C256 RAM 128k*8


74HC573
P0
TXD RXD

80C552

P2

AN0
AN1
AN2

Diagram 2 : SX 3-channel recorder

The listing appears in the Appendix.

1. INITIALIZATION : (SX_INIT.C file)


Description of the application (comments), task declaration and initialisation : SFR, task
initiation,...
2. CONFIGURATION: (SX_DCL.A51 file )
Declares the constants required by KR-51, configures the direct pooler functionality (some of
the settings outlined in this file are automatically carried out if you work with
RAISONANCE’s ‘C’ Compiler)
3. UTILITIES : (SX_UTIL.C file)
Front panel LED blinking management (system status are indicated by various blinking
modes), and real time clock increment feature.
4. DIALOG VIA MENUS : (SX_MENU.C file)
Tree-like menus permit system configuration, measurement inquiry and command initiation.
The communication is performed via the serial port.
5. SERIAL PORT MANAGEMENT : (SX_SERIE.A51 file).
The serial port management is interrupt-based. The interface with the MENU facility is
performed via two MAILBOXES (one for the Receive operation, the other for the Send
operation)
6. MEASUREMENTS : (SX_MESU.C file)
Measurements are performed at regular intervals and then stored in XDATA RAM. The
execution of a measurement is protected by Semaphores because it is shared with the
interactive search functionality.

87
11. The external versions KRX / KRH KR-51

11.4 Performances
In the previous example, if the performance analyser of the PCE-51 real time emulator is applied
to TIMER 0 interrupt handler, the following information is be obtained :

Minimum duration : 25 CPU clock cycles


Maximum duration : 242 CPU clock cycles
Mean time : 92 CPU clock cycles
Average CPU utilisation: 6.7%
In the SX example, the time base is 1250 CPU clock cycles. If a time base of 1000 CPU clock
cycles were applied, an average utilisation of 8.4% would be obtained. In the KRY example, (see
section "The internal version/Example"), the performance analysis gives a higher result (10%)
for an identical time base.

The results may appear inconsistent, considering the respective complexity of both applications :
in the KRX example, the kernel performs many more operations (Semaphore management,
mailbox management...) than in the KRY example.

The kernel’s higher performance in the KRX (SX recorder) example is due to the splitting of
tasks into GROUPS. In fact, in the SX application, only one task at level 0 is handled (although
the application can support up to 5 tasks). Tasks of lower groups are not resource intensive and
even less if belonging to a "high order" group. If the GROUP capability, where each group is
associated with a different clock, were not available, the kernel’s performance would have been
significantly reduced.

88
KR-51 12. Appendices

12. APPENDICES

12.1 TELEMEAS application (recorder)

89
12. Appendices KR-51

12.1 TELEMEAS application (recorder)

List of the files :


SX_INIT.C : Initialization
SX_MENU.C : Man/Machine dialog
SX_MESU.C : Measurement recording
SX_SERIE.A51 : Management by UART interrupt
SX_UTIL.C : Blinking and clock tasks

SX.H : Declaration file to be included in ‘C’ files


SX.H51 : Declaration file to be included in Assembly files

All these files are located in the TELEMEAS directory of the installation.

90
KR-51 12. Appendices

/************************************************************************\
3-CHANNEL RECORDER
------------------
File : SX_INIT (main program and initialization)
Date : 12/92
Author : FL/Raisonance
Aim : KRX example
==========================================================================

Hardware :

Microcontroller : 80C552 or 80C535 (the A/D converter if used).


Clock freqency : 12 MHz.

Adress spaces :
- Code in EPROM (32 kb beginning from addresse 0).
- 8 kb of external RAM (from address 0. Working area).
- 32 kb of external RAM (from address 8000H, to store the measures).

Analog inputs :
The channels are connected to AN0, AN1 and AN2 microcontroller inputs.

A front panel LED indicates the recorder state.

The serial port (P3.0, P3.1) is connected to a display teminal and operates
in 8 bit mode (without parity), at 1200 bauds.

List of tasks :

* TSK_BLINK : (file sx_util.c)


Function : operates a front panel LED which indicates the recorder SATE:
- blinks when measuremsnts are in progress
- high intensity when a communication is in progress
The adjustment of the intensity is obtained by trimming.
priority : 3
Groupe : 0
* TSK_measure : (file sx_mesu.c)
Function : measures and stores (an average value/ minute) 3 analog inputs.
priority : 3
Groupe : 0
* TSK_SECOND : (file sx_util.c)
Function : incrementation of the clock every second
priority : 2
Group : 2
* TSK_MENU : (file sx_menu.c)
function : management of a menu driven operator interface (transmitted by
the serial port).
Also used to run the commands.
priority : 0
Group : 1
* TSK_EXPORT : (file sx_mesu.c)
function : export the measures via the serial port
priority : 3
Group : 1

The following interrupts are used :


- TIMER0 (par KR-51), bank 3 priority 0
- EX1, by KR-51 (pooler), banque 3 priority 0
- serial port, bank 1 priority 1.

The 4 register banks are therefore used :


- bank 0 by TSK_MENU,

91
12. Appendices KR-51

- bank 1 by serial port inerrupt,


- bank 2 par TSK_SECOND,
- bank 3 par KR-51, TSK_EXPORT, TSK_BLINK and TSK_measure.

The reservation of the banks is carried out in the setup file SX_DCL.A51.
Tasks are all compiled with the option NOAREGS (program code become
independent of the register bank).

The applciation is made up of the following files :


. SX_INIT.C : current file
. SX_MESU.C : task fmeasure and associated functions,
. SX_MENU.C : menu driven operantor interface,
. SX_UTIL.C : other functions : blinking and clock.
. SX_SERIE.A51: serial port management
Also contains declarations which could not been made in
C51 (semaphore bits)

These files must be linked with the KRXS.LIB objet library.

This rate allows 64 series of 3 measurements to be effectuated per minute.

\***********************************************************************/
#pragma NOAREGS

#include <reg51.h> /* Declarations of SFR registers */


#include <stdio.h>
#include <krdcl.h> /* Prototypes of the kernel services */
#include "SX.H" /* Declarations of functions proper to the application
*/

/* functions contained in this file */


static void init_sfr ( void );
void main ( void ) ;
/* ---------------------------------------------------*\
* * * Tasks definition * * *
\* ---------------------------------------------------*/
void fblink ();
void fmesure ();
void fsecond ();
void fmenu ();
void fexport ();

/* the declaration hereabove would be necessary only if you don't use the
RIDE Windows environment.
Ohterwise, these settings may be carried out from the kernel dialog box
Definition of the tick rate. Fondamental tick rate = 12.5 ms
Group 1 ---> 1/10 s
Group 2 ---> 1s
Group 3 ---> 10s
*/

/* ---------------------------------------------------*\
* * * Function MAIN * * *
\* ---------------------------------------------------*/
void main (void)
{
/* Initialization of KR-51 */
kr_init(); /* Initialization of the kernel */
mail_reset(); /* Initialization of mailboxes */

/* Initialization of the semaphores */


_SEMA_MEASUREMENT = 0; /* reset semaphore. Direct acccess to the bit */

92
KR-51 12. Appendices

_SEMA_TIME = 0;
TRM_ON = 0; /* 1 if a transmission is in progress */

/* Initialization of the sfr */


init_sfr ();

/* Creation of the permanent tasks */


kr_create(_blink_) ;
kr_create(_second_) ;

while (1) ;
}

void init_sfr ( void )


/* sfr initialization */
{
/* setup of the POOLER */
IT1 = 1; /* External interrupt 1 is trigger detect mode */
EX1 = 1; /* Interrupt enabled */

/* Initialization of the serial port */


TMOD |= 0x20 ; /* Attention a ne pas deprogrammer le timer 0 */
/* Timer 1 en mode 1 */
TR1 = 1;
TH1 = 0xE6; /* 1200 bauds for 12.000 MHz */
SCON = 0x50; /* UART in mode 1 */
REN = 1; /* Reception enabled */
ES = 1; /* Serial port interrupt enabled */
}

#if 1
void KR_TRAP(void) /* KR_TRAP is used by the DEBUG version */
{
EA = 0;
while (1);
}
#endif

93
12. Appendices KR-51

/********************************************************************\
3-CHANNEL RECORDER
------------------
File: SX_MENU (menu driven operator interface)
Date : 12/92
Auteur : FL/Raisonance
Objet : KRX example
====================================================================
\********************************************************************/
#pragma NOAREGS

#include <reg51.h> /* Declarations of SFR registers */


#include <stdio.h>
#include <krdcl.h> /* Prototypes of the kernel services */
#include "sx.h" /* Declarations of functions proper to the
application */

/* ----------------------------------------------------------------*/
/* Declaration of the structure menu */
#define MAX_PROP 5 /* Maximum number of commands in a menu */
struct menu
{
char *title; /* menu title */
char *selection [MAX_PROP]; /* commands to be displayed */
void (* fct [MAX_PROP])(); /* function to run */
struct menu *mpere; /* father menu */
}
*menu_act; /* current menu pointer */

/* --------------------------------------------------------------*/
/* Declaration of the private functions */
void display_menu (struct menu *m0);
void new_menu (struct menu *m0); /* menu initialiazation */
void display_date(); /* current date */
void display_time (); /* current time */
void clrscr (); /* clear display terminal */
void error (char *message); /* user error */
char *get_str(); /* read string <- terminal */

/* --------------------------------------------------------------*/
/* Declaration of external functions */
extern void display_measurement ( int );
extern void stop_measurement ( void );
extern void initiate_measurement ( void );
extern void clear_measurement ( void );

/* --------------------------------------------------------------*/
/* declaration of PUBLIC functions */
void fmenu ( void ); /* TSK_MENU code */

/* --------------------------------------------------------------*/
/* Declaration of private variables */
static struct stime inst;
static unsigned char last_command;

/* --------------------------------------------------------------*/
/* declaration of external variables */
extern unsigned long seconds;

94
KR-51 12. Appendices

/* --------------------------------------------------------------*/
/* Declaration of menus
MAIN MENU
|
|_____MENU INITIALIZATION
| |_____MENU time update
| | |_____ Change time
| | |_____ Change date
| |
| |_____CLEAR measures
|
|_____MENU CONSULTING
|
|_____MENU COMMAND
|_____ initiate measurements
|_____ stop measurements
*/
#define _NULL (0L)

/* *** MAIN MENU *** */


void fct0_init(), fct0_consult(), fct0_command();
struct menu main_menu =
{
"MAIN MENU",
{"Initialization","Consulting","Command",""},
{fct0_init,fct0_consult,fct0_command},
NULL
};

/* *** MENU INITIALIZATION *** */


void fct1_time(), fct1_clear();
struct menu menu_initialization =
{
"MENU INITIALIZATION",
{"Time update","Clear measures",""},
{fct1_time,fct1_clear},
NULL
};

/* *** MENU COMMAND *** */


void fct2_initiate(), fct2_stop(), fct2_export();
struct menu menu_command =
{
"MENU measurement",
{"Initiate measurement","Stop measurements","Exportation",""},
{fct2_initiate, fct2_stop,fct2_export},
NULL
};

/* *** MENU TIME *** */


void fct3_time(), fct3_date();
struct menu menu_time =
{
/* this menu permits updating of both time and date */
"MENU TIME UPDATE",
{"Change time","Change date",""},
{fct3_time, fct3_date},
NULL
};

/* Task fmenu : menu management (= task nø20) */

95
12. Appendices KR-51

void fmenu() task _menu_ priority 0 group 2 istack 45 xstack 60


{
/* This function interactively displays the menus and run the chosen
command. A command is initiated by typing in its reference (0 to 5).
You go back to the father menu (menu_act->mfather) by typing 'Quit' (0).
It is necessary to allocate the 45 bytes for the internal RAM and 60 for
the xdata memory because of the imbricated calls
fmenu --> DisplayMenu --> printf ---> putchar
Note that printf uses 50 bytes of external stack and about 25 of internal
stack before calling putchar */

char c;

clrscr();
printf("\nExample for KRX");
printf("\n(c) RAISONANCE 1992");
kr_del_abs (50); /* in order to read the message */
menu_act = &main_menu;

while (1)
{
/* Menu display */
display_menu (menu_act);

/* wait for command character */


do c = getchar();
while ((c<'0')||(c>last_command));

/* a character has been received, the corresponding command will be run */


c -= '0';
if (!c)
{
/* 0 : quit */
menu_act = menu_act->mpere;
if (menu_act == NULL)
{
/* quit main menu */
clrscr();
printf("\nE3V End of communication");
display_time();
return;
}
}
else (*menu_act->fct[--c])();
/* initiate the corresponding function */
}
}

/* --------------------------------------------------------------*/
/* Private functions */
void display_menu (struct menu *m0)
{
int i; /* Complete display of a menu */

clrscr(); /* Clear screen */


// printf("\n 3-Channel recorder - RAISONANCE 1992");
// printf("\n\n * * * %s * * *",m0->title);

/* The first command (0) is systematically 'quit' or 'previous menu'*/


printf ("\n\n0. %s",m0==&main_menu?"Quit":"Previous menu");

/* Display of the menu commands. A void string indicates the last command*/
for (i=0;i<MAX_PROP;i++)

96
KR-51 12. Appendices

if (!*m0->selection[i]) break;
else printf("\n%d. %s", i+1, m0->selection[i]);
last_command = '0'+i+1;

printf("\n\nType in the command number ...");


}

void new_menu (struct menu *m0)


{
/* Initiation of a sub-menu */
m0->mpere = menu_act;
menu_act = m0;
return;
}

void display_time ()
{
kr_tst(SEMA_TIME); /* check if convertion function is already used
*/
time_2struct (seconds, &inst); /* convertion raw format -> split format */
kr_free(SEMA_TIME);

/* Display current time stored in the variable inst */


printf("%02.2u:%02.2u:%02.2u",
(int)inst.hour,
(int)inst.minute,
(int)inst.second);
}

void display_date ()
{
kr_tst(SEMA_TIME);
time_2struct (seconds, &inst); /* convertion raw format -> split format
*/
kr_free(SEMA_TIME);

/* Display of the current date stored in the variable inst */


printf("%2.2u/%02.2u/%4.4u",
(int)inst.day,
(int)inst.month,
(int) ((((unsigned)inst.year)>=92) ? (1900+inst.year) :
(2000+inst.year) ));
}

/* --------------------------------------------------------------*/
/* function called by the menus */

void fct0_init()
{
/* initiate the le menu initialization */
new_menu ( &menu_initialization );
}

char *daystr [7] = {


"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday"};

97
12. Appendices KR-51

void fct0_consult ()
{
int i;

/* to initialise dayofweek upon RESET */


kr_tst(SEMA_TIME);
time_2struct (seconds, &inst);
kr_free(SEMA_TIME);

/* display time and date */


while (MAIL_EMPTY&2) /* wait for character */
{
clrscr();
printf("\n * * * CONSULTING * * * \n");
printf("\n %s ",daystr[inst.dayofweek]);
display_date ();
printf(" at ");
display_time ();
printf("\n");
for (i=0; i < 3 ; i++)
display_measurement (i);
printf("\n\nStrike any key...");
kr_del_abs(50);
}
/* discard character */
getchar();
}

void fct0_command()
{
/* initiate the command menu */
new_menu ( &menu_command );
}

void fct1_time()
{
/* initiate the menu time */
new_menu ( &menu_time );
}

void fct1_clear()
{
if (kr_getstatus(_measurement_)!= UNVALIDATED)
error("\n Stop measurements first");
else clear_measurement();
}

void fct2_initiate()
{
char c;

/* initiate measurements */
if (kr_getstatus(_measurement_)!= UNVALIDATED)
{
error("Stop measurements first");
return;
}
printf("\nInitialization of the measures ? (Y/N) ");
c = getchar();

98
KR-51 12. Appendices

if ((c=='Y') || (c=='y'))
{
clear_measurement();
printf ("\n clear measurements");
}
initiate_measurement();
}

void fct2_stop()
{
if (kr_getstatus(_measurement_)==UNVALIDATED)
error("measurements already stopped");
else stop_measurement();
}

void fct2_export()
{
/* initiate the exportation task */
if (kr_getstatus(_measurement_)!=UNVALIDATED)
{
error("stop measurements before exportating");
return;
}
printf("\n\nExportation in progress ...");
kr_create(_export_);
kr_waitsig(); /* the signal will be sent by task_export */
}

void fct3_time()
{
/* time updating */
unsigned hr=12,mn=30,sc=0,i;

clrscr();
printf("\n current time : ");
display_time ();
printf("\n new time (hh:mm:ss) >> ");
i = sscanf(get_str(),"%d:%d:%d",&hr,&mn,&sc);
if (i!=3)
{
error("Bad format");
return;
}
else
{
if (hr<24) inst.hour = hr;
if (mn<60) inst.minute = mn;
if (sc<60) inst.second = sc;
}

/* Now record the new value */


kr_tst(SEMA_TIME);
seconds = time_2long (&inst);
kr_free(SEMA_TIME);
}

#define BEL 07
void fct3_date()
{
unsigned jj,mm,aa,i;

99
12. Appendices KR-51

clrscr();
printf("\n Current date : ");
display_date ();
printf("\n New date (jj/mm/aa) > ");
i = sscanf(get_str(),"%d/%d/%d",&jj,&mm,&aa);
if (i!=3)
{
error("Bad format");
return;
}
else
{
if (jj<=31) inst.day = jj;
if (mm<13) inst.month = mm;
if (aa<=99) inst.year = aa;
else if (aa>=2000) inst.year = aa-2000;
else if (aa>=1992) inst.year = aa-1900;
}

/* Now record the new value */


kr_tst(SEMA_TIME);
seconds = time_2long (&inst);
kr_free(SEMA_TIME);
}

void clrscr () /* clear screen */


{
putchar (0x0c);
}

char *get_str()
{
static char buf [25];
int i, c;

for (i = 0;i<24;i++)
{
#ifdef MINITEL
if ((c = getchar())==0x13)
if ((c = getchar())==0x41)
break; /* touche Envoi du minitel */
#else
if ((c = getchar())=='\r') break;
#endif
#define BS 0x08
if (c==BS)
{
if (i) i-=2;
}
else buf[i] = c;
}
buf [i] = 0;
return buf;

}
void error (char *message)
{
printf("\n\nerror : %s%c",message,BEL);
printf("\nStrike any key");
getchar();
}

100
KR-51 12. Appendices

/************************************************************************\
3-CHANNEL RECORDER
------------------
File : SX_MESU (including TSK_MESU task )
Date : 12/92
Author : FL/Raisonance
Aim : KRX example
==========================================================================

This file contains the code of task TSK_MESU (fmeasurement) as well as other
functions called by TSK_MENU.

Principle :
Each pack of measures (256 bytes) holds a series of values corresponding to
one hour of measurements (i.e. 60*3 values).
Every second, a new mesurement is carried out (on each of the 3 channels)
and then used to calculate an "average value" on the current minute. All these
values (measures and averages) are expressed on 10 bits.
Every minute, the 3 above average values are "concatened" to form a 32-bits
object (00+3*10). The 2 most significant bits are just put to zero.
Every hour, the current pack of measures is closed and the next one is
opened.
About 128 packs can therefore be stored in the 32K external memeory segment
dedicated for this purpose.

A pack of measures contains 60*4 = 240 bytes. The extra 16 bytes are used to
store other information :
- date + hour of the first recording (for the pack),
- number of measurements (some packs may be uncomplete),
- maximum value in the pack
- security code
Note : due to 3 channels, a meaurment is carried out every 1rd of second.

\********************************************************************/
#pragma NOAREGS
#define M80C552 /* this application requires an A/D converter */

#if defined(M80C552)
#include <reg552.h> /* SFR declaration for 80C552 */
#elif defined(M80C515)
#include <reg515.h> /* SFR declaration for 80C515 */
#else
#include <reg51.h> /* SFR declaration for 8051 */
#endif

#include <stdio.h>
#include <krdcl.h> /* prototype of KR-51 services */
#include "sx.h" /* declarations proper to the application
SX */

#define BOX_TRM_FULL (MAIL_FULL&1)


#define BOX_TRM_EMPTY (MAIL_EMPTY&1)

#ifdef EOF
# undef EOF
#endif
#define EOF 0xD /* convention used to indicate the end of a file */

/* -------------------------------------------------- */
/* Declaration of a pack (=1 hour of measurements) */
typedef struct /* size = 256 bytes */
{
char state3; /* 0 : not used,
0xA5 : measurements in progress,

101
12. Appendices KR-51

0x5A : full */
char number; /* number of measurements (0..59)
done */
unsigned long measurement [60] ; /* Average result each minute
*/
struct stime instant ;/* Beginning of the series of measurements
*/
unsigned maxi [3]; /* maximum values in the hour (one value/channel) */
char jam; /* Available. checksum upon exportation
*/
} pack_measurement ;

extern unsigned long seconds;


#define MAX_PACK 10 /* maximum number of packs */
at 0x8000 xdata pack_measurement pack [MAX_PACK] ;
/* 32 K reserved for data storage*/

pack_measurement xdata *pack_act; /* pack in progress */


static int dp_stop; /* flag used by task_measurement */

/* ---------------------------------------------------*/
/* private functions */
static unsigned measurement (unsigned channel);
/* Return a 10-bit analog measurement */

code unsigned char shifting [3] = {0,10,20};

/* ---------------------------------------------------*/
/* Corps de la tƒche TSK_MESU */
void fmeasurement () task _measurement_ priority 3 group 1
/* Measurements are carried out on the 3 channels 64 times per minute */
{
int i, j, full_measurement = 0;
static unsigned long average [3], global_value;

dp_stop = 0;
do
{
for (j = 0 ; j < 64 ; j ++ ) /* 64 measurements per minute */
{
/* Prise measurement channel 1 */
for (i=0;i<3;i++)
{
kr_tst(SEMA_MEASUREMENT);
average [i] += measurement (i);
kr_free(SEMA_MEASUREMENT);
if (j==63)
{
average [i] >>= 5; /* division per 64 to calculate
the average value */
if (pack_act->maxi[i] < average[i])
pack_act->maxi[i] = average[i]; /* New maximum value */
average [i] >>= shifting [i]; /* 30-bit storage */
global_value += average [i] ;
average [i] = 0 ; /* (re) initialization */
}
kr_del_abs (25); /* 64 * 25 * 3 * 12.5 ms = 1 minute */
if (dp_stop) break;
}
if (dp_stop) break;
}

102
KR-51 12. Appendices

if (!dp_stop)
/* After one minute, the result is stored */
pack_act -> measurement [pack_act -> number++] = global_value ;

/* (re) initialization of the values for the next series */


global_value = 0;

/* if one hour has elapsed, the current pack is close */


if (dp_stop || (pack_act -> number == 60))
{
char xdata *p;
char c;

/* calculation of the check-sum */


p = (xdata char *) pack_act;
pack_act->jam = 0;
for (i=0;i<256;i++)
c += *p++;
pack_act->jam = -c;
pack_act->state3 = 0x5A;

pack_act ++; /* changing pack */


if (pack_act == NULL) /* test if there is storage space left */
{
full_measurement = 1;
break;
}
else if (!dp_stop)
{
/* Initialization of a new pack */
pack_act->state3 = 0xA5; /* in progress */
pack_act->number = 0;
kr_tst(SEMA_TIME);
time_2struct (seconds, &(pack_act->instant) );
kr_free(SEMA_TIME);
pack_act->maxi [0] =
pack_act->maxi [1] =
pack_act->maxi [2] = 0;
}
}
if (dp_stop) return; /* end of task */
} while (!full_measurement) ;
}

/* ---------------------------------------------------*/
/* Task TSK_EXPORT (export the measurements on the serial port) */
void fexport () task _export_ priority 2 group 2
/* This function is initiated by the task MENU. Protocol is as follows :
Each pack (one hour of measurements) are sent one after another. The byte
jam holds the check-sum */
{
int i, j;
char xdata *p;

/* Wait until emission of the buffer is completed */


do kr_del_abs(10);
while (!BOX_TRM_EMPTY);

kr_del_abs(100); /* 10 seconds of delay */

/* no more parity */
PARITY = 0;

103
12. Appendices KR-51

for (i = 0 ; i < MAX_PACK ; i ++)


if (pack [ i ] . state3 == 0x5A )
{
p = &pack[i].state3;
for (j = 0 ; j<256 ; j++)
{
putchar(*p++);
if (BOX_TRM_FULL)
/* the transmission buffer is emptied*/
kr_del_abs(10); /* One second */
}
}
else break;
putchar (EOF); /* End of file */
kr_del_abs(50); /* 5 seconds */
PARITY = 1; /* Parity set */
kr_sendsig(_menu_); /* turn control over to TSK_MENU */
}

/* ---------------------------------------------------*/
/* Erase measurements */
void clear_measurement ()
{
int i;

for (i = 0 ; i < MAX_PACK ; i ++)


pack [ i ] . state3 = 0;
}

/* ---------------------------------------------------*/
void stop_measurement()
{
dp_stop = 1;
}

/* ---------------------------------------------------*/
/* (re) Initiation of measurements */
void initiate_measurement()
{
int i;

/* Measurements are restarted from the first pack whose state was NIL */
for (i=0; i<MAX_PACK; i++)
if (!pack [ i ] . state3) break;

/* Abort if the memory is full */


if (i==MAX_PACK)
{
printf("\nMemory full");
return;
}

/* Initialization of current variables and new pack */


pack_act = &pack [ i ];
pack_act->state3 = 0xA5; /* in progress */
pack_act->number = 0;
kr_tst(SEMA_TIME);
time_2struct (seconds, &(pack_act->instant) );
kr_free(SEMA_TIME);
pack_act->maxi [0] = pack_act->maxi [1] = pack_act->maxi [2] = 0;

/* creation of the task measurement */

104
KR-51 12. Appendices

kr_create(_measurement_);
}

/* ---------------------------------------------------*/
void display_measurement (int n)
/* Display of the measurement on channel n.
Measurements are carried out on 10 bits, and the reference analog voltage
are 0V (0), and 5V (0x3ff). Analog values are then "manually" converted
in float, to avoid referring to the floating point arithmetic library */
{
unsigned long result;

kr_tst(SEMA_MEASUREMENT);
/* Acces to the function measurement is regulated by a semaphore as both
TSK_MESU (for storage purpose) and TSK_MENU (for display purpose) can
concurrently refer to it */
result = measurement(n);
kr_free(SEMA_MEASUREMENT);
printf("\n channel %d : %d.%02.2d (%X)",
n,
(unsigned) ((result*5)/0x3ff),
(unsigned) (((result*500)/0x3ff)%100),
(unsigned) result);
}

/* ---------------------------------------------------*/
/* Measurement on channel n */
unsigned measurement (unsigned n) /* n = channel number */
{
unsigned mes;

#if defined(M80C552)
/* Cf documentation PHILIPS sur l'ADC du 552 (IC20 page 414) */
ADCON = 0x08 + n; /* conversion commences */
for (n=0;n<5;n++);
while (! (0x10 | ADCON) );
mes = (ADCH<<2) + ((ADCON&0xc0)>>6);
ADCON &= ~0x10; /* clear ADCI */
return mes;

#elif defined(M80C515)
unsigned base;

/* Cf SIEMENS 515/535 User's Manual */


ADCON |= n; /* Selection of the channel */
DAPR = 0; /* Triggers measurement on 5V */
while (!BSY) ;
base = ADDAT;
/* A sub-window is selected : 1,25 V = 64 units) */
if (base<32) base = 0x40;
else if (base>192) base = 0x0c; /* highest basis */
else {
base +=32;
base &=0xf0;
base |= ( (base>>4) - 4);
}
/* Initiation of the measurement on the "narrow" window */
DAPR = base;
base = (base & 0x0f) * 64;
while (!BSY) ;
return base+ADDAT;
#endif
}

105
12. Appendices KR-51

/************************************************************************\
3-CHANNEL RECORDER
------------------
File : SX_UTIL (includes TSK_BLINK and TSK_SECOND tasks)
Date : 12/92
Author : FL/Raisonance
Aim : KRX example
==========================================================================
The task TSK_SECOND jsut increments a current time. This task is activated
every second.

The task TSK_BLINK (LED blinking) allows 2 information to be displayed :


- are there measures in progress ?
- is there a communication in progress ?
\************************************************************************/
#pragma NOAREGS
#include <reg51.h> /* Declaration of sfr registers */
#include <krdcl.h> /* Prototype of KR-51 services */
#include "sx.h" /* Declarations proper to SX project */

/* ---------------------------------------------------*/
/* Declaration of the variables used by the tasks */
xdata at 0xF000 char led ;

unsigned long seconds;


/* Number of seconds starting from January 1, 1992 at 0 o'clock */

/* ---------------------------------------------------*/
/* PUBLIC functions */
void fblink ();
void fsecond ();

/* ---------------------------------------------------*/
/* Incrementation of seconds */
void fsecond () task _second_ priority 3 group 3
{
while (1)
{
seconds++;
kr_del_abs(1); /* put to sleep for one second */
}
}

/* ---------------------------------------------------*/
/* Blinking task */
#define L_ON 0xFE /* LED on */
#define L_OFF 0xFF /* LED off */
void fblink () task _blink_ priority 2 group 0
{
/* this task is infinite and provides information on the
recoreder state :
- blinking LED == measurement in progress.
- LED in high intensity = communication in progress. */
int n;
while (1)
{
if (kr_getstatus(_measurement_)!=UNVALIDATED)
{
led = L_OFF;
for (n=0;n<10;n++)
kr_del_abs (80) ;
n = 800; /* One second ON */
}

106
KR-51 12. Appendices

else n = 1600; /* whole period ON */


while ( n > 0 ) /* P‚riode ON : trimming */
{
led = L_ON ;
kr_del_abs (1);
if (kr_getstatus(_menu_)==UNVALIDATED)
led = L_OFF ;
/* in low intensity, the LED is ON 1/4 of time.
Trimming rate is 5 cycles, i.e. 62,5 ms */
kr_del_abs (9);
n -= 10;
}
}
}

107
12. Appendices KR-51

12.2 Revision History

DATE SECTION DESCRIPTION


2005/09 4.3.2 Explanation for KR_XLEN

108
KR-51 14. Appendices

13. INDEX
B N
Banks ................................................................... 20 N1 ........................................................................ 21
C P
Calendar............................................................... 76 Parameter passing ................................................ 49
Calendar............................................................... 80 Perpetual calendar................................................ 76
Clock ................................................................... 26 Perpetual calendar................................................ 80
Pooler................................................................... 26
D
Pooling
DEBUG direct pooling................................................... 28
debug versions................................................. 45
R
DIVIDE_1........................................................... 39
DIVIDE_i ............................................................ 21 READY................................................................ 59
task's state ........................................................ 19
G
Receiver ......................................................... 26, 28
Group Register banks...................................................... 20
group of tasks .................................................. 27 RUNNING........................................................... 59
task's state ........................................................ 19
I
S
IE 32
Include Scheduler ............................................................. 26
declaration files ............................................... 36 Semaphore
Initialization......................................................... 44 declaration ....................................................... 62
Initiator ................................................................ 26 Services
Installation ........................................................... 36 system services ................................................ 48
Interrupts SIGNAL......................................................... 22, 23
parallel interrupts ............................................ 29 stack
task/interrupts interface ................................... 31 keyword for task declaration ........................... 38
IP 32 Stack
external stack saving........................................ 42
K
stackx
kr_delete .............................................................. 28 keyword for task declaration ........................... 38
KR_DELETE ....................................................... 51 STIME ................................................................. 77
KR_DELSIG ........................................................ 57 SUSPENDED ...................................................... 59
KR_GETxxx........................................................ 59 task's state ........................................................ 19
KR_WAITSIG ...................................................... 57
T
KR_XLEN........................................................... 39
KR_XLEN.i.KR_XLEN...................................... 72 task
KRI version ......................................................... 82 task's state ........................................................ 19
Task
L
definition ......................................................... 18
Linking ................................................................ 37 task lifetime ..................................................... 32
Local variables..................................................... 41 TASK_CLi........................................................... 27
time_2long ........................................................... 77
M
time_2struct ......................................................... 77
MAIL_FLUSH ..................................................... 69 TIMEOUT ........................................................... 22
MAIL_READ ....................................................... 69
U
MAIL_RESET ...................................................... 68
MAIL_SEND........................................................ 68 UNKNOWN
MAIL_SIZE.......................................................... 69 task's state ........................................................ 19
MAIL_TEST......................................................... 69 UNKNOWN ........................................................ 59
Mailboxes ............................................................ 68 UNVALIDATED ................................................ 59
MEM_ALLOC .................................................... 72 task's state ........................................................ 19
MEMFREE.................................................... 72, 73
Memory allocator ................................................ 72

109
14. Appendices KR-51

V W
Version WAITING............................................................ 59
external versions ............................................. 86 task's state ........................................................ 19
KRI version ..................................................... 81
X
Versions............................................................... 14
xstack ................................................................... 42

110

Potrebbero piacerti anche