Multitasking on Arduino

Multitasking on Arduino © Apache-2.0

RT-Thread, a powerful multitasking tool optimized for Arduino. You are able to issue shell (FinSH) commands to control your hardware now!

  • 9 respects

Components and supplies

Ard due
Arduino Due
ARM Cortex-M3
Arduino MKR Zero
ARM Cortex-M0+

Apps and online services

About this project


As most of the Arduino players, I started from Arduino Uno. And soon I collected a lot of shields. To drive those shields I used various libraries, which ate up all the memory space.

So I moved to Arduino Mega and had a lot of fun, until I started working on a little bit more complex projects, like playing with display and sound.

Recently, I upgrade my weapon again to Arduino Due which has completely different architecture (ARM Cortex-M) with my previous boards (AVR). A 32-bit core with "huge" memory space and much higher clock speed, without doubt, is a powerful weapon. However, to fully utilize the power, using a simple "loop" function may not be enough. That's the issue Arduino RT-Thread library project want to address.


RT-Thread is a free and open source (Apache License 2.0) RTOS. Some unique features, like tiny shell (named FinSH), dynamic loading module and lots of device drivers, make it very interesting. Even though the most important feature is it has a very active community.

Let's Start

The library is hosted on Github and can be installed through "Library Manager".

Currently, there are two examples available which are also listing in "CODE" section. (More examples will be available later.)

The first example "Blink" shows how to create and start a thread named "Blink". The task of "Blink" thread is to blink the builtin LED with 1 second interval.

The second example "FinSH" shows how to add user defined variable and command to the tiny shell. There are two user variables led_id, led_state and one user command led() implemented.


FinSH, the tiny shell accepts C-style input (e.g. hello()), supports auto-completion (e.g. type lis[Tab]) and history (after issued several commands try type and ).

It provides the following predefined commands.

  • hello(): print "Hello RT-Thread!"
  • version(): print version information
  • list(): print available command list
  • list_mem(): print memory information
  • list_thread(): print thread information
  • list_sem(): print semaphore information
  • list_mutex(): print mutex information
  • list_event(): print event information
  • list_mb(): print mailbox information
  • list_mq(): print message queue information
  • list_memp(): print memory pool information
  • list_timer(): print timer information

You may add your own command by two steps.

  • Firstly, define a function of cause. The return value can be "void" or any type. The recommendation is to return a value with "char", "byte", "short", "unsigned short", "int" or "unsigned int" type, because of these types can be interpreted well by FinSH. There is no limitation on parameters. (However, there do have limit of FinSH command length, which is 80 characters by default.) So any number and any type are fine.
  • Secondly insert a line with ADD_SHELL_CMD(command_name, command description, function_name, return_type, parameter list) macro into "shell_cmd.h".

Following is a example of adding user command.

  • Define the function led().
unsigned int led(unsigned int id, byte state) {
    // use "rt_kprintf()" to print a message
    rt_kprintf("led%d=%d\n", id, state);
    if (id != 0) {
        return 1;
    if (state) {
        digitalWrite(LED_BUILTIN, HIGH);
    } else {
        digitalWrite(LED_BUILTIN, LOW);
    return 0;
  • Add a line to "shell_cmd.h".
ADD_SHELL_CMD(led, Turn on/off builtin LED, led, unsigned int, unsigned int id, rt_int32_t val)

In the example above the command name and the function name are the same. However, they can be different. Then the command name becomes the alias of the function name. When issue command to FinSH, the command name should be used.

You may also add your own variable by the similar steps.

  • Firstly, define a variable. The available types are "char", "byte", "char*", "short", "unsigned short", "short*", "int", "unsigned int", "int*" and "void*".
  • Secondly, add a line with ADD_SHELL_VAR(variable_alias, variable description, variable_name, variable_type) macro into "shell_var.h". The corresponding variable types here are "finsh_type_char", "finsh_type_uchar", "finsh_type_charp", "finsh_type_short", "finsh_type_ushort", "finsh_type_shortp", "finsh_type_int", "finsh_type_uint", "finsh_type_intp" and "finsh_type_voidp".

Following is a example of adding user variables.

  • Define the variables.
 unsigned int led_id = 0;
 byte led_state = 1;
  • Add two lines to "shell_var.h".
ADD_SHELL_VAR(id, LED ID, led_id, finsh_type_uint)
ADD_SHELL_VAR(state, LED state, led_state, finsh_type_uchar)

After uploaded the example sketch "FinSH", open the "Serial Monitor" and you will see the tiny shell.

\ | /
- RT -     Thread Operating System
/ | \     4.0.1 build Mar  8 2019
2006 - 2019 Copyright by rt-thread team
finsh >

Try some predefined commands.

finsh >hello()
Hello RT-Thread!
       0, 0x00000000
finsh >list()
--Function List:
hello            -- say hello world
version          -- show RT-Thread version information
list             -- list available commands
list_mem         -- list memory usage information
list_thread      -- list thread
list_sem         -- list semaphore in system
list_mutex       -- list mutex in system
list_event       -- list event in system
list_mb          -- list mail box in system
list_mq          -- list message queue in system
list_memp        -- list memory pool in system
list_timer       -- list timer in system
led              -- Turn on/off builtin LED
--Variable List:
dummy            -- dummy variable for finsh
id               -- LED ID
state            -- LED state
       0, 0x00000000

You may notice that after executed each command, the tiny shell prints a line with two values, "0, 0x00000000". These two values are actually the return value of the underlying function, in decimal and hexadecimal formats. "hello()" and "list()" return "void". Trying to issue "led(1, 0)", you will get a different value (which is an error code).

Now try the user defined command and variables. Having fun!

finsh >id
       0, 0x00000000
finsh >state
       1, 0x00000001
finsh >led(id, state)
       0, 0x00000000
finsh >state=0
       536870912, 0x20000000
finsh >led(id, state)
       0, 0x00000000
finsh >led(1, 1)
       1, 0x00000001
finsh >led(0, 1)
       0, 0x00000000

Next Steps

I have not done the examples of showing how to use kernel utilities like semaphore, mutex, mailbox, memory pool and etc., although all these features are currently ready in the library. I will update the library and this article later. In the meantime, you may check the examples from the original RT-Thread project.

I also plan to bring back some optional components (which I removed when porting) and develop some complex examples to show the potential of RT-Thread.

Thanks for reading!

  • RT-Thread Primer (coming soon)


  • Mar 15, 2019: The library is already available in "Library Manager".
  • May 6, 2019: From v0.5.1 onward, please use ADD_FINSH_CMD instead of ADD_SHELL_CMD.


The RT-Thread version of "Blink" example.
Demo of user defined FinSH command and variable


Similar projects you might like

Multitasking FreeRTOS for Arduino

Project showcase by Du Phạm

  • 4 respects

A Better SD Library with RT-Thread

by onelife

  • 7 respects

Multitasking And Real-Time Arduino System

by Melvin Mancini

  • 25 respects

Arduino GUI Library

by onelife

  • 1 comment
  • 16 respects

SerialDebug: Improving Debug to Arduino

Project tutorial by JoaoLopesF

  • 33 respects

Arduino App with RT-Thread

Project tutorial by onelife

  • 6 respects
Add projectSign up / Login