pico]OS  1.0.4
Functions
pico]OS Porting Information
Introduction

Functions

POSFROMEXT UVAR_t POSCALL p_pos_findbit (const UVAR_t bitfield)
POSFROMEXT UVAR_t POSCALL p_pos_findbit (const UVAR_t bitfield, UVAR_t rrOffset)
POSFROMEXT void POSCALL p_pos_initArch (void)
POSFROMEXT void POSCALL p_pos_initTask (POSTASK_t task, void *stackstart, POSTASKFUNC_t funcptr, void *funcarg)
POSFROMEXT VAR_t POSCALL p_pos_initTask (POSTASK_t task, UINT_t stacksize, POSTASKFUNC_t funcptr, void *funcarg)
POSFROMEXT void POSCALL p_pos_freeStack (POSTASK_t task)
POSFROMEXT void POSCALL p_pos_lock (void)
POSFROMEXT void POSCALL p_pos_unlock (void)
POSFROMEXT VAR_t POSCALL p_pos_initTask (POSTASK_t task, POSTASKFUNC_t funcptr, void *funcarg)
POSFROMEXT void POSCALL p_pos_startFirstContext (void)
POSFROMEXT void POSCALL p_pos_softContextSwitch (void)
POSFROMEXT void POSCALL p_pos_intContextSwitch (void)
POSFROMEXT void POSCALL p_pos_intContextSwitchPending (void)
POSEXTERN void POSCALL c_pos_intEnter (void)
POSEXTERN void POSCALL c_pos_intExit (void)
POSEXTERN void POSCALL c_pos_intExitQuick (void)
POSEXTERN void POSCALL c_pos_timerInterrupt (void)

Detailed Description

General Information

Choose the best type of stack management

The operating system can be easily ported to other architectures, it can be ported to very small 8 bit architectures with low memory and to 32 bit architectures with lots of memory. To keep the porting as simple as possible, there are only a couple of functions that must be adapted to the architecute. Before you start porting the operating system to your architecture, you must choose a stack management type. You have the choice between:

POSCFG_TASKSTACKTYPE = 0
The stack memory is provided by the user. This is the best choice for very small architectures with low memory.

POSCFG_TASKSTACKTYPE = 1
The stack memory is dynamically allocated by the architecture dependent code of the operating system. The size of the stack frame is variable and can be choosen by the user who creates the task. This is the best choice for big architectures with lots of memory.

POSCFG_TASKSTACKTYPE = 2
The stack memory is dynamically allocated by the architecture dependent code of the operating system. The size of the stack frame is fixed and can not be changed by the user. This may be an alternative to type 0, it is a little bit more user friendly.

Here is a list of the functions that are architecture specific and must be ported:
p_pos_initTask, p_pos_startFirstContext, p_pos_softContextSwitch, p_pos_intContextSwitch.

If you choose POSCFG_TASKSTACKTYPE = 2 or 3, you must also provide the function p_pos_freeStack.


Get more speed with optimized "findbit" function

If your application is critical in performance, you may also provide an assembler version of the function "findbit". There are two different function prototypes possible. The simple prototype for the standard scheduling scheme (POSCFG_ROUNDROBIN = 0) is

UVAR_t p_pos_findbit(const UVAR_t bitfield);

The prototype for a findbit function that supports round robin scheduling (POSCFG_ROUNDROBIN = 1) is

UVAR_t p_pos_findbit(const UVAR_t bitfield, UVAR_t rrOffset);

The function gets a bitfield as input, and returns the number of the right most set bit (that is the number of the first lsb that is set). If round robin is enabled, the function takes an offset as second parameter. The offset is the position where the function starts to search the first set bit. The function scans the bitfield always from right to left, starting with the bit denoted by the offset. The bitfield is seen as circle, when the rightmost bit is not set the function must continue scanning the leftmost bit (wrap around), so all bits of the field are scanned.
It is possible to implement the findbit mechanism as look up table. For this purpose you can define the macro FINDBIT. Please see the header file picoos.h (search for the word POSCFG_FBIT_USE_LUTABLE) and the source file fbit_gen.c for details.


Assembler Functions

Unfortunately, not the whole operating system can be written in C. The platform port must be written in assembly language. I tried to keep the assembly part of the RTOS as small as possible. But there are three assembly functions left, that are needed for doing the context switching:

The operating system requires also a timer interrupt that is used to cut the task execution time into slices. Hardware interrupts must comply with some conventions to be compatible to pico]OS. So the fourth thing you need to write in assember is a framework for hardware interrupts.

The diagram shows the assembler functions in logical structure. At the left side I have drawn a normal interrupt service routine for reference.



The context switching (multitasking) is done by simply swaping the stack frame when an interrupt service routine (eg. the timer interrupt) is left. But it must also be possible for a task to give of processing time without the need of an interrupt. This is done by the function p_pos_softContextSwitch at the right side in the diagram. Since this function is not called by a processor interrupt, it must build up an ISR compatible stack frame by itself. Note that the second part of this function is equal to the function p_pos_intContextSwitch, so the function must be terminated by an return-from-interrupt instruction, even if the function was called from a C-routine.

For completeness, the next diagram shows at its left side how the function p_pos_startFirstContext works. Again, this function looks like the lower part of the funtion p_pos_intContextSwitch in the diagram above. In the middle you can see how the timer interrupt routine must look like.



There is a special interrupt handling needed when interrupts are interruptable on your system. To prevent a deadlock situation (that is, an ISR would be called again and again until the stack flows over), a counting flag variable is exported by pico]OS: posInInterrupt_g. This variable contains the value zero if no interrupt is running yet. And only if no other interrupt is running, the ISR must save the stack pointer to the task environment structure where posCurrentTask_g points to. This behaviour is shown at the right side in the diagram above.

Note that interrupt service routines need some stack space to be able to do their work - in the discussed configuration every ISR would take some stack memory from the stack frame of the currently active task. But this may be a problem at platforms that are low on memory - it would be to expensive to increase every tasks stack frame by the count of bytes an ISR would need. In this case, you can set up a special stackframe that is only used by interrupt service routines. The diagram below shows the small changes to the ISRs discussed above. But attention - this method is only applicable on platforms where interrupts can not interrupt each other.




Function Documentation

POSEXTERN void POSCALL c_pos_intEnter ( void  )

Interrupt control function. This function must be called from an interrupt service routine to show the operating system that an ISR is currently running. This function must be called first before other operating system functions can be called from within the ISR.

See also:
c_pos_intExit, c_pos_timerInterrupt
POSEXTERN void POSCALL c_pos_intExit ( void  )

Interrupt control function. This function must be called from an interrupt service routine to show the operating system that the ISR is going to complete its work and no operating system functions will be called any more from within the ISR.

See also:
c_pos_intEnter, c_pos_timerInterrupt
POSEXTERN void POSCALL c_pos_intExitQuick ( void  )

Interrupt control function. Similar to c_pos_intExit, except that context switch is not performed. Instead, a call to p_pos_intContextSwitchQueue is performed if it is necessary to perform task scheduling. p_pos_intContextSwitchQueue should "queue" context switch to occur at later time.

This was needed for Arm Cortex-M cpus, which need to use PendSV exception for context switching.

See also:
c_pos_intExit, p_pos_intContextSwitchQueue
POSEXTERN void POSCALL c_pos_timerInterrupt ( void  )

Timer interrupt control function. This function must be called periodically from within a timer interrupt service routine. The whole system timing is derived from this timer interrupt.

A timer ISR could look like this:

PUSH ALL; // push all registers to stack@n
if (posInInterrupt_g == 0)
saveStackptrToCurrentTaskEnv();
PULL ALL; // pull all registers from stack@n
RETI; // return from interrupt@n
Note:
Any other ISR looks like this, only the function c_pos_timerInterrupt is replaced by an user function.
Dependent on the platform port, it can be necessary to evaluate the variable posRunning_g to ensure that the timer interrupt is not triggered when the OS is not yet running.
To avoid this race condintions, it is better to initialize the timer interrupt in the function p_pos_startFirstContext.
See also:
c_pos_intEnter, c_pos_intExit
POSFROMEXT UVAR_t POSCALL p_pos_findbit ( const UVAR_t  bitfield)

Bit finding function. This function is called by the operating system to find the first set bit in a bitfield. See the file fbit_gen.c for an example.

Parameters:
bitfieldThis is the bitfield that shall be scanned.
Returns:
the number of the first set bit (scanning begins with the lsb).
Note:
POSCFG_ROUNDROBIN must be defined to 0 to have this format of the function compiled in.
POSFROMEXT UVAR_t POSCALL p_pos_findbit ( const UVAR_t  bitfield,
UVAR_t  rrOffset 
)

Bit finding function. This function is called by the operating system to find the first set bit in a bitfield. See the file fbit_gen.c for an example.

Parameters:
bitfieldThis is the bitfield that shall be scanned.
rrOffsetOffset into the bitfield. Scanning begins here.
Returns:
the number of the first set bit (scanning begins with the lsb).
Note:
POSCFG_ROUNDROBIN must be defined to 1 to have this format of the function compiled in.
POSFROMEXT void POSCALL p_pos_freeStack ( POSTASK_t  task)

Stack free function. This function is called by the operating system to free a stack frame that was set up by the function p_pos_initTask. See the available port source files for an example on how to write this function.

Parameters:
taskpointer to the task environment structure.
Note:
POSCFG_TASKSTACKTYPE must be defined to 1 or 2 to have this format of the function compiled in.
This function is not part of the pico]OS. It must be provided by the user, since it is architecture specific.
The processor interrupts are disabled when this function is called; but the processor may still write some bytes to the stack frame after this function was called and before the interrupts are enabled again.
See also:
p_pos_initTask

Stack free function. This function is called by the operating system to free a stack frame that was set up by the function p_pos_initTask. See the available port source files for an example on how to write this function.

Parameters:
taskpointer to the task environment structure.
Note:
POSCFG_TASKSTACKTYPE must be defined to 1 or 2 to have this format of the function compiled in.
This function is not part of the pico]OS. It must be provided by the user, since it is architecture specific.
The processor interrupts are disabled when this function is called.
See also:
p_pos_initTask
POSFROMEXT void POSCALL p_pos_initArch ( void  )

Architecture port initialization. This function is called from the posInit function to initialize the architecture specific part of the operating system.

Note:
POSCFG_CALLINITARCH must be defined to 1 when posInit shall call this function.
This function is not part of the pico]OS. It must be provided by the user, since it is architecture specific.
A timer interrupt should be initialized in the funcion p_pos_startFirstContext.
POSFROMEXT void POSCALL p_pos_initTask ( POSTASK_t  task,
void *  stackstart,
POSTASKFUNC_t  funcptr,
void *  funcarg 
)

Task initialization function. This function is called by the operating system to initialize the stack frame of a new task. See the available port source files for an example on how to write this function.

Parameters:
taskpointer to the task environment structure.
stackstartpointer to the start of the stack memory.
funcptrpointer to the first function that shall be executed by the new task.
funcargargument that should be passed to the first function.
Note:
POSCFG_TASKSTACKTYPE must be defined to 0 to have this format of the function compiled in.
This function is not part of the pico]OS. It must be provided by the user, since it is architecture specific.
The processor interrupts are disabled when this function is called.
POSFROMEXT VAR_t POSCALL p_pos_initTask ( POSTASK_t  task,
UINT_t  stacksize,
POSTASKFUNC_t  funcptr,
void *  funcarg 
)

Task initialization function. This function is called by the operating system to initialize the stack frame of a new task. See the available port source files for an example on how to write this function.

Parameters:
taskpointer to the task environment structure.
stacksizesize of the stack memory for the new task. The stack memory may be allocated dynamically from within this function.
funcptrpointer to the first function that shall be executed by the new task.
funcargargument that should be passed to the first function.
Returns:
zero on success. A negative value should be returned to denote an error (e.g. out of stack memory).
Note:
POSCFG_TASKSTACKTYPE must be defined to 1 to have this format of the function compiled in.
This function is not part of the pico]OS. It must be provided by the user, since it is architecture specific.
The processor interrupts are disabled when this function is called.
See also:
p_pos_freeStack
POSFROMEXT VAR_t POSCALL p_pos_initTask ( POSTASK_t  task,
POSTASKFUNC_t  funcptr,
void *  funcarg 
)

Task initialization function. This function is called by the operating system to initialize the stack frame of a new task. This function is responsible to allocate the stack memory and to store the pointer of the stack frame into the task environment. See the available port source files for an example on how to write this function.

Parameters:
taskpointer to the task environment structure.
funcptrpointer to the first function that shall be executed by the new task.
funcargargument that should be passed to the first function.
Returns:
zero on success. A negative value should be returned to denote an error (e.g. out of stack memory).
Note:
POSCFG_TASKSTACKTYPE must be defined to 2 to have this format of the function compiled in.
This function is not part of the pico]OS. It must be provided by the user, since it is architecture specific.
The processor interrupts are disabled when this function is called.
See also:
p_pos_freeStack
POSFROMEXT void POSCALL p_pos_intContextSwitch ( void  )

Context switch function. This function is called by the operating system to initiate a context switch from interrupt level. This function has then to switch the context variable and restore the new context from stack memory. See the available port source files for an example on how to write this function.

Note:
This function is not part of the pico]OS. It must be provided by the user, since it is architecture specific. The processor interrupts are disabled when this function is called.
See also:
p_pos_softContextSwitch, p_pos_startFirstContext
POSFROMEXT void POSCALL p_pos_intContextSwitchPending ( void  )

Context switch function. Called by c_pos_intExitQuick if task scheduling is needed. This function should queue context switch somehow, for example in Arm Cortex-M CPU:s a PendSV exception can be set pending.

Note:
This function is not part of the pico]OS. It must be provided by the user, since it is architecture specific. The processor interrupts are disabled when this function is called.
See also:
p_pos_softContextSwitch, c_pos_intExitQuick
POSFROMEXT void POSCALL p_pos_lock ( void  )

Port lock. In some really special cases it may be required that Pico]OS must acquire a mutex before it can call the functions p_pos_initTask and p_pos_freeStack. If you need such a mutex for your port, please define POSCFG_PORTMUTEX to 1. Then implement the both functions p_pos_lock and p_pos_unlock in your arch_c.c file.

See also:
p_pos_unlock, POSCFG_PORTMUTEX
POSFROMEXT void POSCALL p_pos_softContextSwitch ( void  )

Context switch function. This function is called by the operating system to initiate a software context switch. This function has then to save all volatile processor registers to stack memory, switch the context variable and restore the new context from stack memory. See the available port source files for an example on how to write this function.

Note:
This function is not part of the pico]OS. It must be provided by the user, since it is architecture specific.
The processor interrupts are disabled when this function is called.
See also:
p_pos_intContextSwitch, p_pos_startFirstContext
POSFROMEXT void POSCALL p_pos_startFirstContext ( void  )

Context switch function. This function is called by the operating system to start the multitasking. The function has to restore the first context from stack memory. See the available port source files for an example on how to write this function.

Note:
This function is not part of the pico]OS. It must be provided by the user, since it is architecture specific.
The processor interrupts are disabled when this function is called.
See also:
p_pos_softContextSwitch, p_pos_intContextSwitch
POSFROMEXT void POSCALL p_pos_unlock ( void  )

Port unlock. Counterpart of function p_pos_lock.