Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
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.
CONTENTS
1. OVERVIEW 7
2. TASK DESCRIPTION 17
3. THE SCHEDULER 25
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
6. SEMAPHORES 61
7. MAILBOXES 67
-4-
KR-51 Contents
9. THE CALENDAR 75
12. APPENDICES 89
-5-
Contents KR-51
-6-
KR-51 1. Overview
1. OVERVIEW
1.1 Introduction
-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.
4. IMPLEMENTATION : Indicates how to use KR-51 and associate it with tasks written in a
high level language or assembly language.
6. SEMAPHORES : Describes how the flag capability ensures resource sharing between
tasks.
-8-
KR-51 1. Overview
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
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
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.
-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
-13-
1. Overview KR-51
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).
* 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.
Note:
During development, the DEBUG versions are recommended, but they may later be replaced
if performance is too low.
-14-
KR-51 1. Overview
-15-
1. Overview KR-51
-16-
KR-51 2. Task Description
2. TASK DESCRIPTION
-17-
2. Task Description KR-51
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
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
-20-
KR-51 2. Task Description
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.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
The KR_WAITSIG function causes a task to enter the ‘Wait for signal’ state.
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
-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 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
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.
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.
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 :
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.
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.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.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.
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.
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
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
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
• 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
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
-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.
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 */
...
-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
Example :
void fmenu() task _menu_ group 1 priority 3 istack 3 xstack 4
...
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
...
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
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’.
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
-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.
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
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).
-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.
pragma auto
float f1=12; /*static variable*/
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();
}
-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
Primary start-up
Kernel set-up
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.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
-46-
KR-51 5. List of services
5. List of Services
-47-
5. List of services KR-51
-48-
KR-51 5. List of services
-49-
5. List of services KR-51
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
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
Function: Moves a task to the idle state for a given time duration
Remarks: Moves the current task into the WAITING state for the
number of clocks specified by the ‘time’ parameter.
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.
In the time diagram below, it is assumed that to end the task, KR_DEL_ABS (10) function is
systematically used.
TASK SCHEDULING
LEGEND
-52-
KR-51 5. List of services
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.
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.
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)
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
Task 1counter
New value of
task1 counter
0 (mod 256)
0 (mod 256)
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 :
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
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".
-56-
KR-51 5. List of services
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.
Function: Moves a task to the Wait for a signal state (WAITING), but
the wait is limited by a time-out.
Return value: 0 if the time-out has elapsed before a signal was received
!=0 otherwise
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
Return value: 0 if the time-out has elapsed before a signal was received
!=0 otherwise
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.
-58-
KR-51 5. List of services
kr_getstatus:
char kr_getstatus (unsigned char task_id)
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)
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 ( )
kr_getprioritycur:
char kr_getprioritycur ( )
-59-
5. List of services KR-51
-60-
KR-51 6. Semaphores
6. SEMAPHORES
6.1 Description
6.3 Implementation
-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).
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
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
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.
Semaphores should be used by tasks only and not by interrupt services. which cannot be moved
to the WAITING state.
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.
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.
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)
}
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
-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.
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.
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.
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.
Clears any characters in the mailbox. Puts the FULL bit associated with the box to 0 and the
EMPTY bit to 1.
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.
ERROR CODES :
-69-
7. Mailboxes KR-51
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.
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.
-70-
KR-51 8. The memory allocator
8.1 Description
-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.1 MEM_ALLOC
xdata char *mem_alloc(unsigned n)
Allocates n bytes.
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 :
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
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.
-73-
8. The memory allocator KR-51
-74-
KR-51 9. The calendar
9. THE CALENDAR
9.1 Description
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.
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
The value returned is a 32-bit word placed in registers R7:R4 (MSB in R7, LSB in R4).
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
GENERIC POINTER =
-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
xdata at 10h
struct_time : db 7 ;split format
;first byte = dayofweek
-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 :
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.1 Description
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.
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.
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 :
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.1 Description
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.
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.
80C552
P2
AN0
AN1
AN2
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 :
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
89
12. Appendices KR-51
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 :
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.
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 :
91
12. Appendices KR-51
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).
\***********************************************************************/
#pragma NOAREGS
/* 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 */
92
KR-51 12. Appendices
_SEMA_TIME = 0;
TRM_ON = 0; /* 1 if a transmission is in progress */
while (1) ;
}
#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
/* ----------------------------------------------------------------*/
/* 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)
95
12. Appendices KR-51
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);
/* --------------------------------------------------------------*/
/* Private functions */
void display_menu (struct menu *m0)
{
int i; /* Complete display of a 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;
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);
void display_date ()
{
kr_tst(SEMA_TIME);
time_2struct (seconds, &inst); /* convertion raw format -> split format
*/
kr_free(SEMA_TIME);
/* --------------------------------------------------------------*/
/* function called by the menus */
void fct0_init()
{
/* initiate the le menu initialization */
new_menu ( &menu_initialization );
}
97
12. Appendices KR-51
void fct0_consult ()
{
int i;
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;
}
#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;
}
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 */
#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 ;
/* ---------------------------------------------------*/
/* private functions */
static unsigned measurement (unsigned channel);
/* Return a 10-bit analog measurement */
/* ---------------------------------------------------*/
/* 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 ;
/* ---------------------------------------------------*/
/* 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;
/* no more parity */
PARITY = 0;
103
12. Appendices KR-51
/* ---------------------------------------------------*/
/* Erase measurements */
void clear_measurement ()
{
int i;
/* ---------------------------------------------------*/
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;
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;
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.
/* ---------------------------------------------------*/
/* Declaration of the variables used by the tasks */
xdata at 0xF000 char led ;
/* ---------------------------------------------------*/
/* 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
107
12. Appendices KR-51
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