Task Management

The core of Nano-RK is a Real-Time scheduler that supports preemptive scheduling, task synchronization and deadlock prevention. This guarantees that even under worst case conditions tasks will meet deadlines. We now discuss the details of the scheduler’s ability to enforce timeliness guarantees as well as predicable lifetime.

Nano-RK saves energy by ensuring that tasks never poll for a resource. Instead, tasks block on certain events (such as being woken up at a certain point of time or on the arrival of a network packet) and can be unblocked when the events occur. If there are no tasks eligible to run, the system can be powered down.

Nano-RK uses priority-based preemptive scheduling and while we provide explicit support for periodic tasks, we also support aperiodic and sporadic tasks in our framework. The highest priority task that is eligible to run in the system is always scheduled by the operating system. A periodic task can suspend itself before its CPU reserve has expired and wait until its next scheduled period. This adds slack to the system that can be used by soft real-time tasks.

Task synchronization is important in any system with multiple tasks that access a shared resource. In order to bound the blocking time encountered by a higher priority task, we implement priority ceiling protocol (PCP) emulation (Highest Locker Priority). This prevents the phenomenon of priority inversion wherein a shared resource needed by the high-priority process is currently being used by a lower-priority process. In Nano-RK, each mutex is associated with a priority ceiling value. When a mutex is acquired, the priority of the task is elevated to the priority ceiling of the mutex. Once the mutex is released, the priority of the task reverts to its original level. PCP allows offline schedulability analysis to bound the priority inversion problem.

#include <nrk.h>
#include <include.h>
#include <ulib.h>
#include <stdio.h>

int main ()
{
   nrk_setup_ports();
   nrk_setup_uart(UART_BAUDRATE_115K2); 
   printf( "Starting up...\r\n" );
   nrk_init();
   nrk_time_set(0,0);
   nrk_create_taskset();  // User defined function application task config
   nrk_start();
   return 0;
}

Typical startup code required to setup and begin Nano-RK.

nrk_setup_ports

void nrk_setup_ports( void )
Parameters: none.
Return Values: none

This function configures the cpu specific ports based on the current platform. For instance, it may configure UART0 or UART1 as the primary serial output based on which hardware you have selected in the makefile.

nrk_init

void nrk_init( void )
Parameters: none.
Return Values: none

This should be called before nrk_start() and before any user tasks are defined. This function configures the kernel stack, resources, the idle task and default TCB parameters.

nrk_start

void nrk_start( void )
Parameters: none.
Return Values: none

Call this function once user tasks have been defined to start Nano-RK. This function schedules the first high priority task and begins execution of the OS. This function will never return and any state currently associated with the kernel stack thus far will be lost.

nrk_activate_task

nrk_status_t nrk_activate_task( nrk_task_type * )
Parameters: nrk_task_type * task pointer
Return Values: nrk_status_t NRK_OK upon success and NRK_ERROR on failure

This function makes a user defined task runnable upon calling nrk_start. It operates on the nrk_task_type structure defined below.

typedef struct task_type {
   void *Ptos;             // Top of stack pointer
   void *Pbos;             // Bottom of stack pointer
   void (*task)();         // Function pointer to task entry point
   uint8_t prio;           // Task priority, higher value has greater priority
   uint8_t Type;           // Type of task
   uint8_t SchType;        // Type of scheduling
   nrk_time_t period;      // Period of Task
   nrk_time_t cpu_reserve; // CPU Reserve of task
   nrk_time_t offset;      // Starting offset phase
} nrk_task_type;

Task parameters set by a user to define a task. Related links: nrk_time_t

NRK_STK Stack1[NRK_APP_STACKSIZE];
nrk_task_type TaskOne;

void Task1(void);
...
void nrk_create_taskset()
{
   nrk_task_set_entry_function( &TaskOne, Task1);
   nrk_task_set_stk( &TaskOne, Stack1, NRK_APP_STACK_SIZE);
   TaskOne.prio = 2;
   TaskOne.FirstActivation = TRUE;
   TaskOne.Type = BASIC_TASK;
   TaskOne.SchType = PREEMPTIVE;
   TaskOne.period.secs = 0;
   TaskOne.period.nano_secs = 200*NANOS_PER_MS;
   TaskOne.cpu_reserve.secs = 0;
   TaskOne.cpu_reserve.nano_secs = 50*NANOS_PER_MS;
   TaskOne.offset.secs = 0;
   TaskOne.offset.nano_secs= 0;
   nrk_activate_task (&TaskOne);
}

Example of how a user would create a task that executes every 200ms with a 50ms reserve. Notice the task entry point and the task’s stack are passed as functions to the task structure.

nrk_terminate_task

nrk_status_t nrk_terminate_task()
Parameters: none
Return Values: nrk_status_t NRK_OK upon success and NRK_ERROR on failure

This can be called by a task to terminate itself. After being called, the task will no longer be scheduled.

nrk_get_pid

uint8_t nrk_get_pid()
Parameters: none
Return Values: uint8_t containing the current task PID

This functions returns the task ID to the currently running task. The task is given a unique ID before it is executed once nrk_start() is called. Returns the current task PID.

nrk_wait_until_next_period

uint8_t nrk_wait_until_next_period()
Parameters: none
Return Values: NRK_ERROR or NRK_OK

This function suspends a task until the start of its next period. When the task is suspended, other tasks can execute. If the system has no more tasks to execute, it will automatically enter a power-down state to save energy. Returns 1 upon success and 0 upon failure.

nrk_halt

uint8_t nrk_halt()
Parameters: none
Return Values: none

This functions halts the OS forever. If NRK_WATCHDOG_TIMER is enabled and there is no HALT_ON_ERROR defined in nrk_cfg.h, then nrk_halt() will reboot the node by allowing the watchdog timer to expire.

| Contents | Static Configuration |