Now you can run Micro-Kernel Operating System on Raspberry Pi!

RT-Thread Smart Open Source Micro-Kernel Operating System was released last September by RT-Thread Open Source Team. RT-Thread Smart(Aka RT-Smart) is aimed primarily at mid-to-high-end processors with MMU(Memory Management Unit), providing a more competitive operating system-based software platform to benefit the industries in Security( such as IPC Camera), Gateway, Industrial Control, On-board Device, Consumer Electronics and so on.

We’re making the introduction of RT-Thread Smart into several articles intend to give a detailed explanation of RT-Thread Smart from a different perspective, so follow us to make sure you’re in the loop to be updated about new knowledge. Today, let’s get started with RT-Thread Smart Application Programming on Raspberry Pi.

Why Choose Raspberry Pi to Port?

Raspberry Pi is the first hardware platform officially supported by RT-Smart, many reasons for choosing the Raspberry Pi to best fit MicroKernel System. First of all, well-known fact that Raspberry Pi is the most popular ARM Cortex-A hardware dev board, extensively used in innovative applications, playing a significant role in college education and many other industries. Second, since the release of the Raspberry Pi 4B, the kernel has also become more standardized (Raspberry Pi 4B carrying the standard GIC interrupt controller, wired Ethernet port (vs Raspberry Pi3 needs USB switch to wired Ethernet), from which porting rt-smart to other A-Series processors will also be a good reference.

Comparison with Raspberry PI 3 B:

Write an application

It’s easy to run RT-Smart on Raspberry Pi. First of all, download the RT-Smart code, it carries Raspberry Pi 4B corresponding porting code and some user-space applications.

There are several ways to write a program on RT-Smart: the traditional RT-Thread scons build method, the Linux-like approach, this article will lead you with Makefile and CMake approach. Get you to a❀ Fancy Hello World program.

Built with scons

Because RT-Thread is natively built with scons, so we’re going to write an application built with scons, it will call RT-Thread’s APIs to create a thread and output “hello world!”

examples/scons/main.c File Checklist

1#include <rtthread.h>
2
3void thread_entry(void* parameter)
4{
5 rt_kprintf("hello world\n");
6}
7
8int main(int argc, char** argv)
9{
10 rt_thread_t tid;
11 tid = rt_thread_create("hello", thread_entry, RT_NULL,
12 1024, 20, 20);
13 if (tid)
14 {
15 rt_thread_startup(tid);
16 }
17 rt_thread_mdelay(100);
18
19 return 0;
20}

The corresponding compilation script consists of two, one is a Scanscript and the other is a SContruct.

SConstruct File Checklist:

1import os
2import sys
3
4# UROOT_DIR points to the userapps folder in rt-smart sdk
5UROOT_DIR = os.path.join('..', '..')
6
7# Add the directory of the building.py to the system search path
8sys.path = sys.path + [os.path.join(UROOT_DIR, '..', 'tools')]
9from building import *
10
11# Compile an application
12BuildApplication('scons', 'SConscript', usr_root = UROOT_DIR)

The SConscript file checklist, which is similar to the original RT-Thread component SConscript file:

1from building import *
2
3cwd = GetCurrentDir()
4src = Glob('*.c') + Glob('*.cpp')
5CPPPATH = [cwd]
6
7CPPDEFINES = ['HAVE_CCONFIG_H']
8group = DefineGroup('scons', src, depend = [''], CPPPATH = CPPPATH, CPPDEFINES = CPPDEFINES)
9
10Return('group')

According to the RT-Thread traditional building method, the scons will be executed directly and generating the corresponding executable scons.elf file. **

1~/workspace/rtthread-smart/userapps/examples/scons$ scons 
2scons: Reading SConscript files ...
3scons: done reading SConscript files.
4scons: Building targets ...
5scons: building associated VariantDir targets: build/scons
6CC build/scons/main.o
7LINK scons.elf
8scons: done building targets.

Built with Makefile

We also give an example of C++ version by using the Makefile method.

main.cpp File Checklist:

1#include <vector>
2#include <iostream>
3
4extern "C" {
5
6int main(int argc, char** argv)
7{
8 int index = 0;
9 std::vector<int> a;
10 for (index = 0; index < 5; index ++)
11 {
12 a.push_back(index);
13 }
14
15 for (std::vector<int>::iterator it=a.begin(); it != a.end(); it++)
16 std::cout << "hello world, index = " << *it << std::endl;
17 return 0;
18}
19
20}

Makefile can be written in such a way:

1# Set up a cross tool chain
2CROSS_COMPILE= arm-linux-musleabi-
3CC= $(CROSS_COMPILE)gcc
4CXX= $(CROSS_COMPILE)g++
5
6# Get the current directory
7PWD := $(shell pwd)
8
9# UROOT_DIR points to the userapps folder in rt-smart sdk
10UROOT_DIR := $(PWD)/../..
11RT_DIR=$(UROOT_DIR)/sdk/rt-thread
12INC_DIR=$(UROOT_DIR)/sdk/include
13LIB_DIR=${UROOT_DIR}/sdk/lib
14
15# Compilation and link parameters
16CFLAGS= -march=armv7-a -marm -msoft-float -D__RTTHREAD__ -Wall -O0 -g -gdwarf-2 -n --static
17CFLAGS+= -I. -I$(RT_DIR)/include -I$(RT_DIR)/components/dfs -I$(RT_DIR)/components/drivers -I$(RT_DIR)/components/finsh -I$(RT_DIR)/components/net -I${INC_DIR}
18
19LDFLAGS= -march=armv7-a -marm -msoft-float -T ${UROOT_DIR}/linker_scripts/arm/cortex-a/link.lds
20LDFLAGS+= -L$(RT_DIR)/lib -L$(LIB_DIR) -Wl,--whole-archive -lrtthread -Wl,--no-whole-archive -n --static -Wl,--start-group -lrtthread -Wl,--end-group
21
22default:
23 $(CXX) $(CFLAGS) -c main.cpp -o main.o
24 $(CXX) $(LDFLAGS) main.o -o main.elf
25
26clean:
27 @rm *.o *.elf
28
29.PHONY: default clean

Generate an executable makefile.elf file by executing a make in the directory. **

Built with CMake

We’ll write the pthread multithreaded version of hello world in the form of pthreads: output “hello world” in a POSIX thread.

POSIX thread version of the main .c code list

1#include <stdio.h>
2#include <pthread.h>
3
4void *pthread_entry(void* parameter)
5{
6 printf("hello world\n");
7 return NULL;
8}
9
10int main(int argc, char** argv)
11{
12 int ret;
13 void *value;
14 pthread_t pth;
15
16 /* Create a pthread thread to execute hello output*/
17 ret = pthread_create(&pth, NULL, pthread_entry, NULL);
18 printf("ret = %d\n", ret);
19
20 /* Waitting to end */
21 pthread_join(pth, &value);
22
23 return 0;
24}

The corresponding CMakeLists .txt file checklist

1cmake_minimum_required(VERSION 3.5)
2
3project(cmake)
4
5## system configuration
6enable_language(C ASM)
7
8set(CMAKE_SYSTEM_NAME Generic)
9set(CMAKE_SYSTEM_PROCESSOR arm)
10
11if(NOT DEFINED ENV{RTT_EXEC_PATH})
12 message(FATAL_ERROR "not defined environment variable: RTT_EXEC_PATH")
13 message(FATAL_ERROR "Please execute the command: $ source smart_env.sh")
14endif()
15
16set(CONFIG_PREFIX "$ENV{RTT_EXEC_PATH}/arm-linux-musleabi-")
17# UROOT_DIR points to the userapps folder in rt-smart sdk
18set(UROOT_DIR "${PROJECT_SOURCE_DIR}/../..")
19
20set(CMAKE_C_COMPILER "${CONFIG_PREFIX}gcc")
21set(CMAKE_CXX_COMPILER "${CONFIG_PREFIX}g++")
22set(CMAKE_ASM_COMPILER "${CONFIG_PREFIX}gcc")
23set(CMAKE_OBJCOPY "${CONFIG_PREFIX}objcopy")
24set(CMAKE_C_AR "${CONFIG_PREFIX}ar")
25set(CMAKE_SIZE "${CONFIG_PREFIX}size")
26
27set(SDK_DIR "${UROOT_DIR}/sdk")
28set(LINK_SCRIPTS_DIR "${UROOT_DIR}/linker_scripts/arm/cortex-a")
29
30set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=armv7-a -marm -msoft-float -Werror -Wall -O0 -g -gdwarf-2 -n --static")
31set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -march=armv7-a -marm -msoft-float -x assembler-with-cpp -O0 -g")
32set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=armv7-a -marm -msoft-float -Werror -Wall -Woverloaded-virtual -fno-exceptions -fno-rtti -O0 -g -gdwarf-2 -n --static")
33
34set(SDK_INC
35 "${UROOT_DIR}/include"
36 "${UROOT_DIR}/rt-thread/include"
37 "${UROOT_DIR}/rt-thread/components/dfs"
38 "${UROOT_DIR}/rt-thread/components/drivers"
39 "${UROOT_DIR}/rt-thread/components/finsh"
40 "${UROOT_DIR}/rt-thread/components/net"
41)
42
43# Set the location of the link script
44set(CMAKE_EXE_LINKER_FLAGS "-T ${LINK_SCRIPTS_DIR}/link.lds -static")
45
46## user configuration
47set(APPS_INC
48 "${PROJECT_SOURCE_DIR}"
49 "${SDK_INC}"
50)
51
52set(APPS_SRC
53 "${PROJECT_SOURCE_DIR}/main.c"
54)
55
56set(CMAKE_EXECUTABLE_SUFFIX ".elf")
57
58add_executable(${PROJECT_NAME} ${SDK_SRC} ${APPS_SRC})
59target_include_directories(${PROJECT_NAME} PRIVATE ${APPS_INC})

Create a build folder in this directory

1~/workspace/rtthread-smart/userapps/examples/cmake/build$ cmake ..
2-- The C compiler identification is GNU 7.5.0
3-- The CXX compiler identification is GNU 7.5.0
4-- Check for working C compiler: /usr/bin/cc
5-- Check for working C compiler: /usr/bin/cc -- works
6-- Detecting C compiler ABI info
7-- Detecting C compiler ABI info - done
8-- Detecting C compile features
9-- Detecting C compile features - done
10-- Check for working CXX compiler: /usr/bin/c++
11-- Check for working CXX compiler: /usr/bin/c++ -- works
12-- Detecting CXX compiler ABI info
13-- Detecting CXX compiler ABI info - done
14-- Detecting CXX compile features
15-- Detecting CXX compile features - done
16-- The ASM compiler identification is GNU
17-- Found assembler: /usr/bin/cc
18-- Configuring done
19-- Generating done
20-- Build files have been written to: ~/workspace/rtthread-smart/userapps/examples/cmake/build

Generate the Makefile file and compile it via make.

1~/workspace/rtthread-smart/userapps/examples/cmake/build$ make
2[ 50%] Building C object CMakeFiles/cmake.dir/main.c.o
3[100%] Linking C executable cmake.elf
4[100%] Built target cmake

Run the Application

Place the above three compiled applications on the Raspberry Pi’s SD card. We can use the card reader to copy the application to the SD card on the PC. Then plug it back into the Raspberry Pi and power it back on. Show Time:

1 \ | /
2- RT - Thread Smart Operating System
3 / | \ 5.0.0 build May 4 2021
4 2006 - 2020 Copyright by rt-thread team
5lwIP-2.1.2 initialized!
6[I/sal.skt] Socket Abstraction Layer initialize success.
7file system initialization done!
8msh /> cd bin
9msh /bin> scons.elf
10msh /bin> hello world!

The program is executed and can output hello world!

From the above three examples, we can find out some new trending in RT-Smart:

  1. In the user-space is running the RT-Thread traditional API: RT-Thread multi-thread, all the schedule that based with Priority Preemption can be used;
  2. Support the C++ to write the application, as well as stdc++ library;
  3. Support the pthreads in the form of POSIX thread mode to execute, which will be mapped and executed in RT-Thread multithread.

Get Example Codes

https://gitee.com/rtthread/rt-smart-notes/tree/master/examples

Get RT-Smart Source Code

https://github.com/RT-Thread/rt-thread/tree/rt-smart

What’s Next?

  • wget & curl Porting
  • busybox Porting
  • sdl Graphic Application
  • dropbear & ssh server Application

Any questions while using RT-Smart, feel free to share on RT-Thread Club!

An Open-Source Community-Powered Real-Time Operating System (RTOS) Project! We develop, we DIY, we create, we share, we explore this new IoT World together!