1. NuttX简介与开发环境搭建:NuttX是什么?为什么选择NuttX?搭建基于QEMU的模拟开发环境。

1.1 NuttX到底是什么?

先说说NuttX是什么。简单来讲,它是一个实时操作系统(RTOS),专门为嵌入式设备设计的。你想想看,我们平时用的Linux,功能很强大,但体积也大,启动也慢。而NuttX呢?它很小,很轻,但该有的功能一个不少。

我个人习惯把NuttX叫做「嵌入式界的瑞士军刀」。为什么这么说?因为它支持POSIX标准接口。这意味着什么?意味着你在Linux上写的很多代码,稍微改改就能在NuttX上跑。我在项目中遇到过好几次,客户要求从Linux迁移到RTOS,如果选NuttX,迁移成本就低很多。

NuttX的创始人叫Gregory Nutt,他一个人写了十几年,后来被Apache基金会收编了。嗯,这里要注意,NuttX现在是Apache 2.0协议,商用完全没问题。

核心特点:

  • 完全支持POSIX接口(pthread、文件系统、网络栈)
  • 模块化设计,按需裁剪
  • 支持80+架构(ARM、RISC-V、x86、MIPS等)
  • 实时性:硬实时,可抢占内核
  • 内存占用极小:最小配置只需几十KB

1.2 为什么选择NuttX?

说实话,RTOS市场选择很多。FreeRTOS、RT-Thread、Zephyr,各有各的优势。那为什么我推荐NuttX?

第一,POSIX兼容性。 这是NuttX最大的杀手锏。你想想看,如果你用FreeRTOS,你得学它那一套API,换平台就得重写。但NuttX不一样,它用标准的open/read/write,用标准的pthread_create。说白了,你学一次,到处用。

第二,生态丰富。 NuttX自带文件系统(FAT、NFS、PROCFS)、网络协议栈(TCP/IP、IPv6、TLS)、USB协议栈、图形框架(LVGL、NX)。我在项目中做过一个物联网网关,需要同时跑MQTT、HTTP Server和文件系统,NuttX开箱即用,省了我至少两周的开发时间。

第三,调试方便。 NuttX支持GDB调试,支持QEMU模拟。你可以在没有硬件的情况下,先把软件逻辑调通。这一点,做嵌入式开发的都懂——硬件调试有多痛苦。

对比项 NuttX FreeRTOS Zephyr
POSIX支持 完整 有限 部分
架构支持 80+ 40+ 50+
最小RAM ~32KB ~2KB ~8KB
商业友好 Apache 2.0 MIT Apache 2.0

1.3 搭建基于QEMU的模拟开发环境

好,理论说完了,咱们动手。我建议你直接用QEMU模拟,这样不用买开发板,也能跑起来NuttX。

1.3.1 环境准备

你需要准备这些东西:

  • Linux系统(Ubuntu 20.04/22.04 最好,我用的是22.04)
  • Git(用来拉代码)
  • GCC交叉编译工具链
  • QEMU模拟器

我曾经踩过一个坑:Ubuntu 18.04上的QEMU版本太老,跑NuttX会出奇怪的问题。所以建议你用新一点的系统。

1.3.2 安装依赖

打开终端,执行以下命令:

# 更新包列表
sudo apt update

# 安装必要工具
sudo apt install -y git gcc-arm-none-eabi binutils-arm-none-eabi \
    gdb-multiarch qemu-system-arm qemu-utils

# 验证安装
arm-none-eabi-gcc --version
qemu-system-arm --version

嗯,这里要注意,如果你用的是64位系统,可能还需要安装32位库:

sudo apt install -y libc6-i386 lib32stdc++6

1.3.3 获取NuttX源码

我个人习惯把源码放在 ~/workspace 目录下:

mkdir -p ~/workspace
cd ~/workspace

# 克隆NuttX主仓库
git clone https://github.com/apache/nuttx.git

# 克隆应用仓库(里面有很多示例程序)
git clone https://github.com/apache/nuttx-apps.git apps

为什么要克隆两个仓库?NuttX的设计是内核和应用程序分开的。内核在 nuttx 目录,应用在 apps 目录。你想想看,这样方便裁剪——你只需要编译你需要的应用。

1.3.4 配置并编译

我们以 sim 配置为例,这个配置可以在QEMU上直接跑:

cd ~/workspace/nuttx

# 选择模拟器配置
./tools/configure.sh sim:nsh

# 编译
make -j$(nproc)

第一次编译会下载一些依赖,耐心等几分钟。编译成功后,你会看到 nuttx 这个可执行文件。

小技巧: 如果你编译报错,多半是缺少某个库。看看错误信息,用apt安装对应的 -dev 包就行。我遇到过 libncurses-dev 没装,报了一堆奇怪的错误。

1.3.5 运行NuttX

编译成功后,直接运行:

./nuttx

你会看到NuttX的启动信息,最后出现一个 nsh> 提示符。这就是NuttX的命令行界面(NSH)。

试试几个命令:

nsh> help
nsh> ls /
nsh> free
nsh> ps

看到没?这些命令和Linux很像吧?这就是POSIX兼容性的好处。

避坑指南: 我曾经在Windows上用WSL跑QEMU,结果图形界面死活出不来。后来发现是WSL不支持图形加速。解决方案有两个:要么用WSL2,要么直接在Linux物理机上跑。我建议你直接用Ubuntu物理机或者虚拟机。

1.4 知识体系总览

下面这张图,是我自己画的NuttX知识体系结构。你看一眼,心里就有数了:

NuttX 知识体系结构 应用层 (User Applications) NSH Shell | 用户程序 | 网络应用 | 文件系统操作 系统调用接口 (System Call Interface) NuttX 内核 (Kernel) 任务调度 (Scheduler) 内存管理 (MM) 文件系统 (FS) 网络协议栈 (Net) 设备驱动 (Drivers) IPC/同步机制 硬件抽象层 (HAL) / 架构支持

这张图展示了NuttX的分层结构。从上到下依次是:应用层、系统调用接口、内核层、硬件抽象层。我们这门课,重点就是中间那个「系统调用接口」——说白了,就是用户程序怎么和内核打交道。

1.5 验证环境是否搭建成功

最后,我们写一个小程序验证一下。在NSH里,你可以直接运行内置的 hello 程序:

nsh> hello
Hello, World!!

看到输出,说明你的环境搭建成功了。恭喜你,你已经迈出了NuttX开发的第一步。

个人建议: 刚开始别急着看源码,先在NSH里多玩玩。试试 ls /dev 看看有哪些设备,试试 cat /proc/uptime 看看系统运行时间。玩熟了,你自然就知道NuttX能干什么了。

好,这一章就到这里。环境搭好了,下一章我们开始写第一个用户态程序,真正体验一下系统调用的威力。


专注资料整理