µITRON Configuration FAQ

Q: How are µITRON objects created?

For each type of uITRON object (tasks, semaphores, flags, mboxes, mpf, mpl) these two quantities are controlled by configuration:

This is assuming that for the relevant object type, create and delete operations are enabled; enabled is the default. For example, the option CYGPKG_UITRON_MBOXES_CREATE_DELETE controls whether the functions cre_mbx() and del_mbx() exist in the API. If not, then the maximum number of mboxes is the same as the initial number of mboxes, and so on for all µITRON object types.

Mboxes have no initialization, so there are only a few, simple configuration options:

If you change CYGNUM_UITRON_MBOXES_INITIALLY, for example to 0, no mboxes are created automatically for you during startup. Any attempt to use an mbox without creating it will return E_NOEXS because the mbox does not exist. You can create an mbox, say cre_mbx(3,...) and then use it, say snd_msg(3,&foo), and all will be well.

Q: How are µITRON objects initialized?

Some object types have optional initialization. Semaphores are an example. You could have CYGNUM_UITRON_SEMAS=10 and CYGNUM_UITRON_SEMAS_INITIALLY=5 which means you can use semaphores 1-5 straight off, but you must create semaphores 6-10 before you can use them. If you decide not to initialize semaphores, semaphores 1-5 will have an initial count of zero. If you decide to initialize them, you must supply a dummy initializer for semaphores 6-10 also. For example, in terms of the configuration output in pkgconf/uitron.h:

   #define CYGDAT_UITRON_SEMA_INITIALIZERS \
        CYG_UIT_SEMA(  1 ),     \
        CYG_UIT_SEMA(  0 ),     \
        CYG_UIT_SEMA(  0 ),     \
        CYG_UIT_SEMA( 99 ),     \
        CYG_UIT_SEMA(  1 ),     \
        CYG_UIT_SEMA_NOEXS,     \
        CYG_UIT_SEMA_NOEXS,     \
        CYG_UIT_SEMA_NOEXS,     \
        CYG_UIT_SEMA_NOEXS,     \
        CYG_UIT_SEMA_NOEXS

Semaphore 1 will have initial count 1, semaphores 2 and 3 will be zero, number 4 will be 99 initially, 5 will be one and numbers 6 though 10 do not exist initially.

Aside: this is how the definition of the symbol would appear in the configuration header file pkgconf/uitron.h — unfortunately editing such a long, multi-line definition is somewhat cumbersome in the GUI config tool in current releases. The macros CYG_UIT_SEMA() — to create a semaphore initializer — and CYG_UIT_SEMA_NOEXS — to invoke a dummy initializer — are provided in in the environment to help with this. Similar macros are provided for other object types. The resulting #define symbol is used in the context of a C++ array initializer, such as:

Cyg_Counting_Semaphore2 cyg_uitron_SEMAS[ CYGNUM_UITRON_SEMAS ] = {
	CYGDAT_UITRON_SEMA_INITIALIZERS
};
which is eventually macro-processed to give
Cyg_Counting_Semaphore2 cyg_uitron_SEMAS[ 10 ] = {
	Cyg_Counting_Semaphore2( ( 1 ) ), 
	Cyg_Counting_Semaphore2( ( 0 ) ), 
	Cyg_Counting_Semaphore2( ( 0 ) ), 
	Cyg_Counting_Semaphore2( ( 99 ) ), 
	Cyg_Counting_Semaphore2( ( 1 ) ), 
	Cyg_Counting_Semaphore2(0), 
	Cyg_Counting_Semaphore2(0), 
	Cyg_Counting_Semaphore2(0), 
	Cyg_Counting_Semaphore2(0), 
	Cyg_Counting_Semaphore2(0), 
};
so you can see how it is necessary to include the dummy entries in that definition, otherwise the resulting code will not compile correctly.

If you choose CYGNUM_UITRON_SEMAS_INITIALLY=0 it is meaningless to initialize them, for they must be created and so initialized then, before use.

Q: What about µITRON tasks?

Some object types require initialization. Tasks are an example of this. You must provide a task with a priority, a function to enter when the task starts, a name (for debugging purposes), and some memory to use for the stack. For example (again in terms of the resulting definitions in pkgconf/uitron.h):

#define CYGNUM_UITRON_TASKS 4           // valid task ids are 1,2,3,4
#define CYGNUM_UITRON_TASKS_INITIALLY 4 // they all exist at start

#define CYGDAT_UITRON_TASK_EXTERNS          	\
extern "C" void startup( unsigned int );    	\
extern "C" void worktask( unsigned int );   	\
extern "C" void lowtask( unsigned int );        \
static char stack1[ CYGNUM_UITRON_STACK_SIZE ], \
            stack2[ CYGNUM_UITRON_STACK_SIZE ], \
            stack3[ CYGNUM_UITRON_STACK_SIZE ], \
            stack4[ CYGNUM_UITRON_STACK_SIZE ];

#define CYGDAT_UITRON_TASK_INITIALIZERS \
 CYG_UIT_TASK("main task", 8, startup,  &stack1, sizeof( stack1 )), \
 CYG_UIT_TASK("worker 2" , 9, worktask, &stack2, sizeof( stack2 )), \
 CYG_UIT_TASK("worker 3" , 9, worktask, &stack3, sizeof( stack3 )), \
 CYG_UIT_TASK("low task" ,20, lowtask,  &stack4, sizeof( stack4 )), \

So this example has all four tasks statically configured to exist, ready to run, from the start of time. The “main task” runs a routine called startup() at priority 8. Two “worker” tasks run both a priority 9, and a “low priority” task runs at priority 20 to do useful non-urgent background work.

Task ID | Exists at | Function | Priority | Stack   | Stack
 number |  startup  |  entry   |          | address | size
--------+-----------+----------+----------+---------+----------
   1    |    Yes    |  startup |    8     | &stack1 | CYGNUM...
   2    |    Yes    | worktask |    9 	  | &stack2 | CYGNUM...
   3    |    Yes    | worktask |    9 	  | &stack3 | CYGNUM...
   4    |    Yes    |  lowtask |   20 	  | &stack4 | CYGNUM...
--------+-----------+----------+----------+---------+----------

Q: How can I create µITRON tasks in the program?

You must provide free slots in the task table in which to create new tasks, by configuring the number of tasks existing initially to be smaller than the total. For a task ID which does not initially exist, it will be told what routine to call, and what priority it is, when the task is created. But you must still set aside memory for the task to use for its stack, and give it a name during initialization. For example:

#define CYGNUM_UITRON_TASKS 4           // valid task ids are 1-4
#define CYGNUM_UITRON_TASKS_INITIALLY 1 // only task #1 exists

#define CYGDAT_UITRON_TASK_EXTERNS \
extern "C" void startup( unsigned int ); \
static char stack1[ CYGNUM_UITRON_STACK_SIZE ], \
            stack2[ CYGNUM_UITRON_STACK_SIZE ], \
            stack3[ CYGNUM_UITRON_STACK_SIZE ], \
            stack4[ CYGNUM_UITRON_STACK_SIZE ];

#define CYGDAT_UITRON_TASK_INITIALIZERS \
   CYG_UIT_TASK( "main", 8, startup, &stack1, sizeof( stack1 ) ), \
   CYG_UIT_TASK_NOEXS( "slave",      &stack2, sizeof( stack2 ) ), \
   CYG_UIT_TASK_NOEXS( "slave2",     &stack3, sizeof( stack3 ) ), \
   CYG_UIT_TASK_NOEXS( "slave3",     &stack4, sizeof( stack4 ) ), \

So tasks numbered 2,3 and 4 have been given their stacks during startup, though they do not yet exist in terms of cre_tsk() and del_tsk() so you can create tasks 2–4 at runtime.

Task ID | Exists at | Function | Priority | Stack   | Stack
 number |  startup  |  entry   |          | address | size
--------+-----------+----------+----------+---------+----------
   1    |    Yes    |  startup |    8     | &stack1 | CYGNUM...
   2    |    No     |   N/A    |   N/A    | &stack2 | CYGNUM...
   3    |    No     |   N/A    |   N/A    | &stack3 | CYGNUM...
   4    |    No     |   N/A    |   N/A    | &stack4 | CYGNUM...
--------+-----------+----------+----------+---------+----------

(you must have at least one task at startup in order that the system can actually run; this is not so for other uITRON object types)

Q: Can I have different stack sizes for µITRON tasks?

Simply set aside different amounts of memory for each task to use for its stack. Going back to a typical default setting for the µITRON tasks, the definitions in pkgconf/uitron.h might look like this:

#define CYGDAT_UITRON_TASK_EXTERNS \
extern "C" void task1( unsigned int ); \
extern "C" void task2( unsigned int ); \
extern "C" void task3( unsigned int ); \
extern "C" void task4( unsigned int ); \
static char stack1[ CYGNUM_UITRON_STACK_SIZE ], \
            stack2[ CYGNUM_UITRON_STACK_SIZE ], \
            stack3[ CYGNUM_UITRON_STACK_SIZE ], \
            stack4[ CYGNUM_UITRON_STACK_SIZE ];
  
#define CYGDAT_UITRON_TASK_INITIALIZERS \
  CYG_UIT_TASK( "t1", 1, task1, &stack1, CYGNUM_UITRON_STACK_SIZE ), \
  CYG_UIT_TASK( "t2", 2, task2, &stack2, CYGNUM_UITRON_STACK_SIZE ), \
  CYG_UIT_TASK( "t3", 3, task3, &stack3, CYGNUM_UITRON_STACK_SIZE ), \
  CYG_UIT_TASK( "t4", 4, task4, &stack4, CYGNUM_UITRON_STACK_SIZE )

Note that CYGNUM_UITRON_STACK_SIZE is used to control the size of the stack objects themselves, and to tell the system what size stack is being provided.

Suppose instead stack sizes of 2000, 1000, 800 and 800 were required: this could be achieved by using the GUI config tool to edit these options, or editting the .ecc file to get these results in pkgconf/uitron.h:

#define CYGDAT_UITRON_TASK_EXTERNS \
extern "C" void task1( unsigned int ); \
extern "C" void task2( unsigned int ); \
extern "C" void task3( unsigned int ); \
extern "C" void task4( unsigned int ); \
static char stack1[ 2000 ], \
            stack2[ 1000 ], \
            stack3[  800 ], \
            stack4[  800 ];
 
#define CYGDAT_UITRON_TASK_INITIALIZERS \
      CYG_UIT_TASK( "t1", 1, task1, &stack1, sizeof( stack1 ) ), \
      CYG_UIT_TASK( "t2", 2, task2, &stack2, sizeof( stack2 ) ), \
      CYG_UIT_TASK( "t3", 3, task3, &stack3, sizeof( stack3 ) ), \
      CYG_UIT_TASK( "t4", 4, task4, &stack4, sizeof( stack4 ) )

Note that the sizeof() operator has been used to tell the system what size stacks are provided, rather than quoting a number (which is difficult for maintenance) or the symbol CYGNUM_UITRON_STACK_SIZE (which is wrong).

We recommend using (if available in your release) the stacksize symbols provided in the architectural HAL for your target, called CYGNUM_HAL_STACK_SIZE_TYPICAL and CYGNUM_HAL_STACK_SIZE_MINIMUM. So a better (more portable) version of the above might be:

#define CYGDAT_UITRON_TASK_EXTERNS \
extern "C" void task1( unsigned int ); \
extern "C" void task2( unsigned int ); \
extern "C" void task3( unsigned int ); \
extern "C" void task4( unsigned int ); \
static char stack1[ CYGNUM_HAL_STACK_SIZE_TYPICAL + 1200 ], \
            stack2[ CYGNUM_HAL_STACK_SIZE_TYPICAL +  200 ], \
            stack3[ CYGNUM_HAL_STACK_SIZE_TYPICAL        ], \
            stack4[ CYGNUM_HAL_STACK_SIZE_TYPICAL        ];

#define CYGDAT_UITRON_TASK_INITIALIZERS \
      CYG_UIT_TASK( "t1", 1, task1, &stack1, sizeof( stack1 ) ), \
      CYG_UIT_TASK( "t2", 2, task2, &stack2, sizeof( stack2 ) ), \
      CYG_UIT_TASK( "t3", 3, task3, &stack3, sizeof( stack3 ) ), \
      CYG_UIT_TASK( "t4", 4, task4, &stack4, sizeof( stack4 ) )