我们从现在开始会逐步连载RT-Thread Smart(简称rt-smart,甚至有时会称为smart os)的介绍文章,旨在让大家认识,接触到smart os的方方面面。
这个是本系列的第一篇文章,一些介绍及树莓派上rt-smart的应用编程入门(更多的从应用程序角度入手)。后续还包括在rt-smart上的不同应用程序介绍:
wget & curl移植
busybox移植
sdl图形类应用
dropbear及ssh server应用
为什么选择树莓派
树莓派是第一个smart对外提供公开支持的硬件平台?选择树莓派有诸多方面的原因:第一,它可以算是普及度最广的一款ARM Cortex-A硬件开发板,被广泛地应用在一些创新应用,高校教育等方面。第二,自树莓派4B发布以来,芯片核心部分也越来越标准化(相比较之前的树莓派2、3等,携带了标准的GIC中断控制器,有线以太网网口(vs 树莓派3的USB转有线以太网)),从这个再把rt-smart移植扩展到其他A系列处理器也会是很好的参考,例如后续ART-Pi版本ART-Pi smart开发板(ARM Cortex-A7核心,更合适的量产版本)。
树莓派4B包括了4核的ARM Cortex-A72,1.5GHz的BCM2711芯片,可以执行ARM AArch64位指令,也可以执行ARM AArch32位指令,具备标准化的通用控制器GIC。和树莓派3B+的硬件规格对比情况:
编写应用程序
要在树莓派上运行smart也很简单,直接下载smart的发布版,里面有树莓派4B上对应的移植代码,及一些用户态应用程序。
在smart上写程序,可以有以下几种方式:传统的RT-Thread scons构建方式;类Linux的方式,这里给出了基于Makefile的方式,及基于CMake的方式。下面通过一个 ❀ 花式的Hello World程序来进行介绍。
采用scons构建的应用程序
因为RT-Thread原生是采用scons来进行构建的,所以这里也用scons来构建一个应用程序,它会调用RT-Thread的一些API来创建一个线程,并输出"hello world!"。
examples/scons/main.c文件清单
-
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}
对应的编译脚本,包含两个,一份是SConscript脚本,另外一份是SContruct脚本
SConstruct文件清单:
-
1import os
-
2import sys
-
3
-
4# UROOT_DIR指向rt-smart sdk中的userapps文件夹
-
5UROOT_DIR = os.path.join(
'..',
'..')
-
6
-
7# 把building.py的目录添加到系统搜索路径中
-
8sys.path = sys.path + [os.path.join(UROOT_DIR,
'..',
'tools')]
-
9from building
import *
-
10
-
11# 编译一个应用程序
-
12BuildApplication(
'scons',
'SConscript', usr_root = UROOT_DIR)
SConscript文件清单,和原本的RT-Thread 组件SConscript文件类似:
-
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')
按照RT-Thread传统的构建方式,直接执行scons,会生成相应的scons.elf可执行文件。
-
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.
采用Makefile构建的应用程序
除了scons构建方式以外,我们也可以使用Makefile方式,以一个C++版本的方式来给出这份例子。
main.cpp文件清单:
-
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的编写可以按照这样的方式编写:
-
1# 设置交叉工具链
-
2CROSS_COMPILE= arm-linux-musleabi-
-
3CC= $(CROSS_COMPILE)gcc
-
4CXX= $(CROSS_COMPILE)g++
-
5
-
6# 获得当前目录
-
7PWD := $(shell pwd)
-
8
-
9# UROOT_DIR指向rt-smart sdk中的userapps文件夹
-
10UROOT_DIR := $(PWD)/../..
-
11RT_DIR=$(UROOT_DIR)/sdk/rt-thread
-
12INC_DIR=$(UROOT_DIR)/sdk/include
-
13LIB_DIR=${UROOT_DIR}/sdk/lib
-
14
-
15# 编译及链接时参数
-
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
-
22
default:
-
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
在目录下执行make即可生成makefile.elf可执行文件。
采用CMake构建的应用程序
针对CMake的版本,我们以pthreads的方式来编写这个pthread多线程版本的hello world:在一个POSIX thread线程中输出”hello world”。
POSIX thread版本的main.c代码清单
-
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
/* 创建pthread线程来执行后续的hello输出 */
-
17 ret = pthread_create(&pth, NULL, pthread_entry, NULL);
-
18 printf(
"ret = %d\n", ret);
-
19
-
20
/* 等待结束 */
-
21 pthread_join(pth, &value);
-
22
-
23
return
0;
-
24}
对应的CMakeLists.txt文件清单
-
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指向rt-smart sdk中的userapps文件夹
-
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# 设置链接脚本位置
-
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})
可以在这个目录下创建一个build文件夹,然后通过cmake
-
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
来生成Makefile文件,然后通过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
运行应用程序
在使用的时候,需要把上面编译好的三个应用程序放置到树莓派用的SD卡上。我们可以使用读卡器在PC上把应用程序复制到SD卡上。然后再插回到树莓派板子上,重新上电。这个时候我们可以在串口上看到RT-Thread Smart的启动界面:
-
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!
执行程序,可以输出hello world!
通过上面三个例子,我们看到了在smart上目前支持的数种技术:
1、在用户态以RT-Thread传统API方式运行:RT-Thread的多线程,基于优先级全抢占的调度都可以被使用,具备平滑的延续性;
2、可以支持C++编写应用程序,同时也可以使用stdc++库;
3、可以支持pthreads,以POSIX thread线程的模式执行,它们会被映射到RT-Thread的多线程上执行。
上面的一些代码都放在了gitee的rt-smart notes仓库中:
https://gitee.com/rtthread/rt-smart-notes/tree/master/examples
下集预告:
下集我们将通过经典的Linux方式的configure & make模式来移植wget & cURL程序到rt-smart上,从而可以看到rt-smart对POSIX的兼容能力,敬请期待。
学习活动
跟随本系列文章一起打卡学习RT-Thread Smart吧,学习期间在RT-Thread论坛分享学习心得或者提问答疑均可获得积分奖励,截止最后一篇连载文章完结的一周内,可兑换相应奖品!立即进群参与活动~
进群交流学习
RT-Thread线下技术培训:MQTT网关
本次培训RT-Thread将以ART-Pi为硬件平台+RT-Thread物联网操作系统提供MQTT网关原型,希望帮助工程师快速熟悉基于RT-Thread的项目开发流程,熟悉MQTT网关开发中所涉及到的技术要点如Modbus、MQTT、连网、文件系统、FTP、Bootloader、OTA、裁剪优化,提升产品开发速度。
我们将到访的城市有:上海、深圳、南京、广州、郑州、北京、武汉、天津、成都、西安
长按识别上方二维码报名
你可以添加微信17775982065为好友,注明:公司+姓名,拉进 RT-Thread 官方微信交流群!
???????????? 点击阅读原文报名培训
转载:https://blog.csdn.net/rtthreadiotos/article/details/116725950