Skip to content
Antonio Giacomelli edited this page Jun 12, 2025 · 378 revisions

A typical RK0 Application

Configure the kernel

In kconfig.h there are several important parameters. You need to set the number of tasks your system will be running and the highest priority number. This is essential.

/***[• USER-DEFINED TASKS (NUMBER) ********************************************/

#define RK_CONF_N_USRTASKS      	            (3)

/***[• MINIMAL EFFECTIVE PRIORITY (HIGHEST PRIORITY NUMBER)  ******************/

#define RK_CONF_MIN_PRIO	           	    (3)

There are other important settings, look through the file, they are explained.

The application

It all begins in app/src/main.c. A typical main.c will include application.h and other headers related to your hardware platform. For instance, on a Nucleo Board you would have something like:

Note that you can have your application whenever you want; it depends on your building system. The provided Makefile assumes an application folder named app/. The core/ and arch/ folders are not intended to be changed.

#include "main.h" /* hardware platform related */
#include <stm32f1xx.h> /* hardware platform related */
#include <application.h> /* the application header - can be as minimal as just including `<kapi.h>` */

UART_HandleTypeDef huart2; /* BSP type for UART */


/* 
  This is a helper setting mandatory interrupts. Systick is set @ 1ms period. 
- SVCall priority should be higher than SysTick and PendSV. 
- PendSV is preferable lower than SysTick, could be equal - but never higher 
*/

#define RK_CORE_INIT() \
do { \
    SysTick_Config( SystemCoreClock/1000); \
    NVIC_SetPriority(PendSV_IRQn, 7); \
    NVIC_SetPriority(SVCall_IRQn, 5); \
    NVIC_SetPriority(SysTick_IRQn, 6); \
} while(0)


int main(void)
{

 /* setup the hardware platform, this is using the HAL provided by the platform */
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_USART2_UART_Init();
  NVIC_EnableIRQ(SysTick_IRQn);
  NVIC_EnableIRQ(PendSV_IRQn);
  NVIC_EnableIRQ(SVCall_IRQn);
  RK_CORE_INIT();

/* start the kernel */
  kInit();

  while(1)
  {   /* not to be here - possible causes are stack overflow or bad task configuration */
        asm volatile("BKPT #0");
        asm volatile ("cpsid i" : : : "memory");
  }
}

Now, on application.c:

#include <application.h>

/* Helper macro to declare task handles, entry points, stack and stack size */
/* Each task might have a different stack size */

#define STACKSIZE 128

K_DECLARE_TASK(task1Handle, Task1, stack1, STACKSIZE)
K_DECLARE_TASK(task2Handle, Task2, stack2, STACKSIZE)
K_DECLARE_TASK(task3Handle, Task3, stack3, STACKSIZE)

/* Other kernel objects */

RK_SEMA       binSema;


/* This function is mandatory: you create the tasks whose data were declared by the macro on the top of the file, */
/* and initialise other kernel objects */

VOID kApplicationInit(VOID)
{
    /* parms: task handle address, task entry function, arguments, task name, stack address, stack size, 
       priority, preemptible/non-preemptible */	
    kassert(!kCreateTask(&task1Handle, Task1, RK_NO_ARGS, "Task1", stack1, STACKSIZE, 1, RK_PREEMPT));
    kassert(!kCreateTask(&task2Handle, Task2, RK_NO_ARGS, "Task2", stack2, STACKSIZE, 2, RK_PREEMPT));
    kassert(!kCreateTask(&task3Handle, Task3, RK_NO_ARGS, "Task3", stack3, STACKSIZE, 3, RK_PREEMPT));

   /* initialise a binary semaphore as full */
    kassert(!kSemaBinInit(&binSema, 1));
}

/* Define Tasks */

VOID Task1(VOID *args)
{
   RK_UNUSEARGS
   while(1)
   {
     /* highest prio task code */
   }
}

VOID Task2(VOID *args)
{
   RK_UNUSEARGS
   while(1)
   {
     /*middle prio task code */   
   }
}

VOID Task3(VOID *args)
{
   RK_UNUSEARGS
   while(1)
   {
 
     /*lowest prio task code */   
   }
}

Clone this wiki locally