Start Back Next End
  
ZBasic Language Reference
66
ZBasic Microcontrollers
    Call SetInterval(5.0)
    Do
        WaitForInterval()
        <stuff-to-do-periodically>
    Loop
End Sub
In this partial example, a task is set up to perform some important activity periodically.  If this were part of
a system to control the chlorine level in a pool, MyTask might read a transducer that indicates chlorine
level and, if it’s below a certain level, cause a known amount of chlorine solution to be injected into the
circulation stream.
One important aspect of creating and using tasks is the allocation of a task stack.  The task stack has two
components: a task control block and the portion used as an execution stack.  The task control block is a
fixed size (see Section 3.30 for details) and resides either at the beginning (for VM mode devices) or at
end (for native mode devices) of the task stack.  The remainder of the task stack is dedicated to the
execution stack for the task.  The execution stack is used for local variables in the task routine,
parameters passed to other subroutines and functions that might be invoked as well as local variables
used in those routines, and space required for expression evaluation.
If a task stack is allocated that is much larger than is actually necessary, User RAM is wasted since no
other task can use the excess space.  On the other hand, if a task stack is smaller than required, data
items preceding or following the task stack in memory will be overwritten.  This will generally cause your
application to misbehave and may result in the processor resetting.
This begs the question, of course, of what is the optimum task stack size.  Unfortunately, this is not as
easy to answer as it might seem.  The difficulty in answering this question lies in the fact that stack use is
dynamic and may depend on external factors such as a signal applied by an external device or a user
pressing a key.  Not only that, the stack use may depend on the order or the timing of such external
events.  Further, recursive invocation of routines adds to the dynamic nature of stack use and is
impossible to account for (in most cases) using any kind of static analysis.
The ZBasic compiler automatically estimates the minimum task stack size for each task in your
application.  Information about the estimate, including the stack use of individual routines, is displayed in
the .map file (assuming that one is generated as is the default).  If the size of the stack that you have
allocated is smaller than the estimated size plus a safety margin, the compiler will generate a warning
indicating the deficiency and indicating the minimum allocation required.  By default, the safety margin is
10 bytes but you may specify a larger or smaller safety margin (including zero) using
Register.StackMargin.
To assist you in finely tuning the task stack size a special System Library function is provided that
determines, at run time, how much unused space exists in the task stack.  By exercising your application
and periodically checking the amount of unused task stack space exists, you may be able to determine
empirically a more suitable minimum task stack size.  See the description of System.TaskHeadRoom() 
3.5.1 Advanced Multi-tasking Options
For advanced users, a task’s main routine may also be defined with parameters.  This may be useful to
provide information for the task to perform its function rather than doing so using global variables. 
Parameters for the task are specified in a comma-separated list enclosed in parentheses just as they are
for a subroutine invocation.  The number and types of the parameters specified must match those of the
task being invoked.
For special circumstances, it is possible to specify the task’s stack by giving its address as an integral
value.  Generally, it will also be advisable to specify the size of the stack since the compiler will be unable
to deduce the size.  Unless the task stack size is specified or can be deduced, no stack overrun checking
can be performed.  For native mode ZBasic devices the task size must be explicitly specified or it must be
determinable by the compiler at compile time, otherwise, the compiler will issue an error message.
Previous page Top Next page