stk

SuperTinyKernel (STK)

Minimalistic C++ thread scheduling kernel for Embedded systems.

About

STK tends to me as minimal as possible to be able to provide a multi-threading capability for your Embedded system without any attempt to abstract operations with peripherals. It does not pretent to be a fully-fledged Real-Time OS (RTOS) but instead it adds multi-threading into a bare-metal project with a very little effort.

STK is developed in C++ and follows an Object-Oriented Design principles while at the same time does not pollute namespace with exceeding declarations, nor using fancy new C++ features. It tries to be very friendly to C developers ;)

Features

STK supports soft real-time (default) and hard-real time (HRT) modes of operation. It supports infinite looping (KERNEL_STATIC), finite (KERNEL_DYNAMIC) and periodic (HRT mode - KERNEL_HRT) tasks.

STK intercepts main process program flow if it is in a KERNEL_STATIC mode but it can also return into the main process when all tasks exited in case of KERNEL_DYNAMIC mode.

HRT mode allows to run periodic tasks which can be finite or infinite depending on whether KERNEL_STATIC or KERNEL_DYNAMIC mode is used in addition to the KERNEL_HRT. HRT tasks are checked for a deadline miss by STK automatically therefore it guarantees a fully deterministic behavior of the application.

STK’s run-time performance is comparable to other well known C-based thread schedulers but its code base is much smaller (slimmer) and therefore easier to test, maintain and advance.

Summary:

Hardware support

STK supports single-core MCUs yet, multi-core support is in to-do.

MCU

Requires

Development Mode

STK facilitates a productive development workflow through its special Development Mode on x86 Windows. In this mode STK’s thread scheduling is emulated on the Windows operating system. You can compile and run your embedded application code on a standard x86 platform, effectively simulating the concurrent execution of threads. This enables early-stage development, debugging, and unit testing in a convenient Windows environment (requiring the simulation or mocking of target-specific peripherals) before the final deployment and hardware-level testing on the target embedded system.

Example

Here is an example to toggle Red, Green, Blue LEDs of the NXP FRM-K66F or STM STM32F4DISCOVERY development boards hosting ARM Cortex-M4F CPU where each thread is handling its own LED, e.g. there are 3 threads in total which are switching LEDs with 1 second periodicity.

#include <stk_config.h>
#include <stk.h>
#include "example.h"

static volatile uint8_t g_TaskSwitch = 0;

template <stk::EAccessMode _AccessMode>
class MyTask : public stk::Task<256, _AccessMode>
{
    uint8_t m_taskId;

public:
    MyTask(uint8_t taskId) : m_taskId(taskId) {}
    stk::RunFuncType GetFunc() { return &Run; }
    void *GetFuncUserData() { return this; }

private:
    static void Run(void *user_data)
    {
        ((MyTask *)user_data)->RunInner();
    }

    void RunInner()
    {
        uint8_t task_id = m_taskId;

        float count = 0;
        uint64_t count_skip = 0;

        while (true)
        {
            if (g_TaskSwitch != task_id)
            {
                ++count_skip;
                continue;
            }

            ++count;

            switch (task_id)
            {
            case 0:
                LED_SET_STATE(LED_RED, true);
                LED_SET_STATE(LED_GREEN, false);
                LED_SET_STATE(LED_BLUE, false);
                break;
            case 1:
                LED_SET_STATE(LED_RED, false);
                LED_SET_STATE(LED_GREEN, true);
                LED_SET_STATE(LED_BLUE, false);
                break;
            case 2:
                LED_SET_STATE(LED_RED, false);
                LED_SET_STATE(LED_GREEN, false);
                LED_SET_STATE(LED_BLUE, true);
                break;
            }

            g_KernelService->Sleep(delay_ms);

            g_TaskSwitch = (task_id + 1) % 3;
        }
    }
};

static void InitLeds()
{
    LED_INIT(LED_RED, false);
    LED_INIT(LED_GREEN, false);
    LED_INIT(LED_BLUE, false);
}

void RunExample()
{
    using namespace stk;

    InitLeds();

    static Kernel<KERNEL_STATIC, 3, SwitchStrategyRoundRobin, PlatformDefault> kernel;
    static MyTask<ACCESS_PRIVILEGED> task1(0), task2(1), task3(2);

    kernel.Initialize();

    kernel.AddTask(&task1);
    kernel.AddTask(&task2);
    kernel.AddTask(&task3);

    kernel.Start(PERIODICITY_DEFAULT);

    assert(false);
    while (true);
}

Test boards

Build

It is fairly easy to build and run examples without even having embedded hardware on your hands. You will need these tools to run examples on your PC:

ARM platform:

In case of NXP MCU you will only need MCUXpresso IDE which is comes with bundled GCC compler.

RISC-V platform:

If you are working with only ARM platform then you only need ARM-related tools.

Generic eclipse examples are located in the build/example/project/eclipse folder and sorted by platform:

Additionally, examples for NXP MCUXpresso IDE are provided in build/example/project/nxp-mcuxpresso folder. These examples are compatible with NXP Kinetis® K66, Kinetis® K26 and NXP i.MX RT1050 MCUs and can be executed directly on corresponding evaluation boards.

Test coverage

Platform independent (generic) code is 100% covered by tests. Platform dependent code is covered by tests executed on QEMU virtual machines of corresponding CPU architectures.

Porting

You are welcome to port STK to a new platform and suggest a patch. The platform dependent files are located in: stk/src/arch and stk/include/arch folders of STK GitHub repository.

License

STK is licensed under MIT license therefore you can use it freely in your personal, commercial, closed- or open- source projects.

Service

Additional services for your project:

For all these questions please contact us.