jklincn


Stm32F103 + NuttX(一):开发环境配置与系统安装


之前文章《Stm32F103 + Stm32CubeMX(一):VSCode 开发环境配置》配置了 stm32 裸机开发的一系列环境,这篇文章试着运行 RTOS,这里选择 NuttX 而不是 FreeRTOS 这种主要是由于作者的学习路线(以后上班接触的是 NuttX 所以就跑这个了),并且 Stm32F103 + FreeRTOS 的教程网上应该非常多,也就不重复写了。

注意这里不坚持纯 Windows 做开发了,因为作者试了几天觉得还是会带来不少不必要的麻烦,因此把整体的开发、调试环境切换到了 WSL,以下内容会从零开始配置 WSL 的开发环境,因此如果前面的文章没看过,无需去看,按照本篇文章配置环境即可。

硬件型号:正点原子精英开发板(STM32F103ZET6)

开发平台:Windows 11 专业版 24H2(26100.7462)+ WSL2(2.6.3)

NuttX 版本:12.11.0(Release Date:2025-10-05)

Windows 配置

安装 WSL

这部分可以直接参考 安装 WSL | Microsoft Learn,网上的教程也很多,因此这里不详细写了。

请自行安装 Debian 发行版(目前应该是 Debian13),并更换 APT 软件源,最好再配置好网络代理

安装 VSCode

我们会使用 VSCode 的 Remote 来连接 WSL 进行类远程开发,因此请先自行安装 VSCode 并学习如何使用 Remote 插件来打开 WSL

安装 MobaXterm

后续会通过串口访问 nsh,因此需要一个串口连接工具,这里推荐 MobaXterm,可以自行安装。

官网下载页面:https://mobaxterm.mobatek.net/download-home-edition.html,两个版本都可以。

安装 usbipd-win

usbipd-win 可以将 USB 设备连接到 WSL2

github 下载页面:https://github.com/dorssel/usbipd-win/releases,下载 msi 文件安装即可。

WSL 配置

安装依赖项

sudo apt install \
bison flex gettext texinfo libncurses5-dev libncursesw5-dev xxd \
git gperf automake libtool pkg-config build-essential gperf genromfs \
libgmp-dev libmpc-dev libmpfr-dev libisl-dev binutils-dev libelf-dev \
libexpat1-dev gcc-multilib g++-multilib picocom u-boot-tools util-linux \
wget gcc-arm-none-eabi binutils-arm-none-eabi cmake ninja-build kconfig-frontends \
python-is-python3 usbutils python3-pip gdb-multiarch binutils-multiarch clangd

pip install kconfiglib --break-system-packages

~/.local/bin 加入到环境变量中

echo 'export PATH=$HOME/.local/bin:$PATH' >> ~/.bashrc

安装 OpenOCD

wget https://github.com/xpack-dev-tools/openocd-xpack/releases/download/v0.12.0-7/xpack-openocd-0.12.0-7-linux-x64.tar.gz
tar xf xpack-openocd-0.12.0-7-linux-x64.tar.gz

解压后将 xpack-openocd-0.12.0-7/bin 加入到环境变量中**(注意换成你的实际路径)**

echo 'export PATH=$HOME/xpack-openocd-0.12.0-7/bin:$PATH' >> ~/.bashrc

这是最重要的一个过程,决定了是否能顺利在 WSL 上进行烧录和调试。

  1. 将 ST-Link 调试器连接到电脑
  2. 将开发板连接 ST-Link 调试器
  3. 开发板接入电源上电

在 Windows 中的管理员 PowerShell 中运行

查看当前的 USB 设备
usbipd list

可以看到 STLink 设备的 BUSID 是 4-7

4-7    0483:3748  STM32 STLink          Not shared

暂不清楚是否是因为之前在 Windows 上安装过 STLink 的驱动因此会显示名称。如果没有明确显示 STLink,可以通过插拔的方式来确认哪一个设备是 STLink

共享 USB 设备
usbipd bind --busid 4-7

共享后可以通过 usbipd list 再次查看,会发现 STLink 的状态变成了 Shared

附加 USB 设备
usbipd attach --wsl debian --busid 4-7

注意每次 STLink 设备插拔后,都要重新进行附加

关于更多说明可以看 连接 USB 设备 | Microsoft Learn

在 WSL 中的终端运行

查看当前的 USB 设备
lsusb

输出结果中应包含类似内容,看到产品型号 0483:3748

Bus 001 Device 002: ID 0483:3748 STMicroelectronics ST-LINK/V2
配置 udev 规则

这里主要是解决权限问题,让普通用户也可以访问到该 USB 设备。

先查看当前权限,文件路径 001/002 按照上面的 Bus 001 Device 002 进行相应修改

ls -l /dev/bus/usb/001/002
crw-rw-r-- 1 root root 189, 1 Dec 28 11:59 /dev/bus/usb/001/002

可以看到只有 root 用户或 root 组可以进行读写。

新建 udev 规则,注意将这里的 04833748 换成你实际的数字。

sudo tee /etc/udev/rules.d/49-stlink.rules >/dev/null <<'EOF'
SUBSYSTEM=="usb", ATTR{idVendor}=="0483", ATTR{idProduct}=="3748", GROUP="plugdev", MODE="0660"
EOF

重载并触发

sudo udevadm control --reload-rules
sudo udevadm trigger

重新查看权限,可以看到已经改变过来了,当前用户是处在 plugdev 组下的,因此具备了读写权限。

ls -l /dev/bus/usb/001/002
crw-rw---- 1 root plugdev 189, 1 Dec 28 12:07 /dev/bus/usb/001/002
测试连接
openocd -f interface/stlink.cfg -c "transport select swd" \
  -f target/stm32f1x.cfg -c "adapter speed 480"

其中 SWD 采样频率的有效值为 950/480/240/100,如果发现连接失败的情况(比如输出 Info : clock speed 480 kHz 后就退出了)可以适当降低采样频率。

如果一切正常,应该会输出类似内容:

xPack Open On-Chip Debugger 0.12.0+dev-02228-ge5888bda3-dirty (2025-10-04-22:42)
Licensed under GNU GPL v2
For bug reports, read
        http://openocd.org/doc/doxygen/bugs.html
adapter speed: 480 kHz
Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections
Info : STLINK V2J35S7 (API v2) VID:PID 0483:3748
Info : Target voltage: 3.220513
Info : clock speed 480 kHz
Info : SWD DPIDR 0x1ba01477
Info : [stm32f1x.cpu] Cortex-M3 r1p1 processor detected
Info : [stm32f1x.cpu] target has 6 breakpoints, 4 watchpoints
Info : [stm32f1x.cpu] Examination succeed
Info : [stm32f1x.cpu] starting gdb server on 3333
Info : Listening on port 3333 for gdb connections

说明 STLink 和开发板都已经正常连接上了,此时可以 Ctrl+C 退出。

安装系统

下载源码

mkdir nuttxspace
cd nuttxspace
git clone https://github.com/apache/nuttx.git nuttx
git clone https://github.com/apache/nuttx-apps apps

进行板级配置

可以先查看当前支持的配置,也可以直接在 nuttx/boards 目录下查找

cd nuttx
./tools/configure.sh -L | less

这里选用 stm3210e-eval 这个板级配置,它的 MCU 是 STM32F103ZET6,和我的硬件匹配。应用配置选择普通的 nsh,可以在终端中如下配置

cmake -B build -DBOARD_CONFIG=stm3210e-eval:nsh -GNinja

编译源码

cmake --build build

最终结果如下,得到 build/nuttx 文件

[1143/1145] Linking C executable nuttx
Memory region         Used Size  Region Size  %age Used
           flash:       92816 B       512 KB     17.70%
            sram:        7140 B        64 KB     10.89%
[1145/1145] Generating System.map

烧录文件

openocd -f interface/stlink.cfg \
  -c "transport select swd" \
  -f target/stm32f1x.cfg -c "adapter speed 480" \
  -c "init" \
  -c "program build/nuttx verify reset" \
  -c "shutdown"

烧录命令解释

  • -c "init":建立 SWD 连接/识别 CPU 等一系列初始化操作
  • -c "program build/nuttx verify reset" :把 ELF 文件写入 Flash,写完后再读取做一次校验。最后复位 MCU,开始运行。
  • -c "shutdown:关闭 OpenOCD 本身,释放 ST-Link,关闭 gdb 端口。

烧录输出

xPack Open On-Chip Debugger 0.12.0+dev-02228-ge5888bda3-dirty (2025-10-04-22:42)
Licensed under GNU GPL v2
For bug reports, read
        http://openocd.org/doc/doxygen/bugs.html
adapter speed: 480 kHz
Info : STLINK V2J35S7 (API v2) VID:PID 0483:3748
Info : Target voltage: 3.223173
Info : clock speed 480 kHz
Info : SWD DPIDR 0x1ba01477
Info : [stm32f1x.cpu] Cortex-M3 r1p1 processor detected
Info : [stm32f1x.cpu] target has 6 breakpoints, 4 watchpoints
Info : [stm32f1x.cpu] Examination succeed
Info : [stm32f1x.cpu] starting gdb server on 3333
Info : Listening on port 3333 for gdb connections
[stm32f1x.cpu] halted due to debug-request, current mode: Thread 
xPSR: 0x01000000 pc: 0x08000130 msp: 0x2000127c
** Programming Started **
Info : device id = 0x10036414
Info : flash size = 512 KiB
Warn : Adding extra erase range, 0x08016a90 .. 0x08016fff
** Programming Finished **
** Verify Started **
** Verified OK **
** Resetting Target **
shutdown command invoked

测试 nsh

使用 USB 线将板子和电脑连接,应该会自动安装驱动,设备管理器的端口中可以看到 USB-SERIAL CH340。

在 Windows 上使用 MobaXterm 进行串口连接:Session 中选择 Serial,Serial port 选择 USB-SERIAL CH340

连接后输入回车就可以看到

nsh> 

这就说明系统已经启动成功了,可以随便测试一下常用命令

VSCode 工程建立

成功运行 NuttX 后,我们会想着怎么更便利地在 VSCode 做开发。首先要在 WSL 中安装几个 VSCode 插件:

  • Cortex-Debug
  • clangd(在 C 语言插件这块本人偏向于 clangd,选择微软自家的 C/C++ 也没什么问题)

这里建议关闭所有的 VSCode 窗口,重新打开一次 VSCode,主要是为了刷新前面设置的环境变量。

然后在项目根目录创建 .vscode 文件夹,分别创建三个配置文件

tasks.json

配置两个任务,分别为编译和烧录,然后使用将两个任务打包在一起,并设置为默认的 build,这样就可以通过 ctrl+shift+B 来快速运行。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
{
  "version": "2.0.0",
  "tasks": [
    {
      "label": "NuttX: Build",
      "type": "shell",
      "command": "cmake",
      "args": [
        "--build",
        "build"
      ],
      "options": {
        "cwd": "${workspaceFolder}/nuttx"
      },
      "problemMatcher": []
    },
    {
      "label": "NuttX: Flash",
      "type": "shell",
      "command": "openocd",
      "args": [
        "-f",
        "interface/stlink.cfg",
        "-c",
        "transport select swd",
        "-f",
        "target/stm32f1x.cfg",
        "-c",
        "adapter speed 100",    // 可以自行调整频率
        "-c",
        "init",
        "-c",
        "program build/nuttx verify reset",
        "-c",
        "shutdown"
      ],
      "options": {
        "cwd": "${workspaceFolder}/nuttx"
      },
      "problemMatcher": []
    },
    {
      "label": "NuttX: Build + Flash",
      "dependsOrder": "sequence",
      "dependsOn": [
        "NuttX: Build",
        "NuttX: Flash"
      ],
      "problemMatcher": [],
      "group": {
          "kind": "build",
          "isDefault": true
      }
    }
  ]
}

launch.json

使用 cortex-debug 插件,创建一个启动配置,这会自动运行 openocd 并使用 gdb 连接。

启动调试的快捷键是 F5

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "NuttX: Debug",
      "type": "cortex-debug",
      "request": "launch",
      "servertype": "openocd",

      "cwd": "${workspaceFolder}",
      "executable": "${workspaceFolder}/nuttx/build/nuttx",
      "gdbPath": "gdb-multiarch",
      "armToolchainPath": "/usr/bin",

      "configFiles": [
        "interface/stlink.cfg",
        "target/stm32f1x.cfg"
      ],
      "openOCDLaunchCommands": [
        "transport select swd",
        "adapter speed 100"          // 可以自行调整频率
      ],

      "preLaunchCommands": [
        "monitor reset halt"
      ],

      "runToEntryPoint": "nx_start"  // 在 nx_start 处设置一个断点
    }
  ]
}

settings.json

主要是手动设置一下 clangd 插件的可执行文件路径,否则会一直提示下载 Windows 版本的。不知道是 Bug 还是我没配置好,反正每次在远程开发中使用 clangd 都要手动指定一下。

1
2
3
{
    "clangd.path": "/usr/bin/clangd"
}

GDB 调试

上面配置完之后,编译与烧录是没问题的,但调试仍读不到符号,即不能在 VSCode 中进行源码调试,这需要打开 NuttX 的调试配置,默认不启用。

打开配置菜单

cmake --build build -t menuconfig

启用配置

  • Build Setup -> Debug Options -> Generate Debug Symbols

分别按 q 退出和 y 保存

删除原有编译产物

cmake --build build --target clean

然后可以试试 ctrl+shift+B 进行编译和烧录。

完成后使用 F5 开始调试,发现成功在 nx_start() 处停止。

如果在调试中有问题,可以看看下文的《终极大坑》一节。

关于更多调试选项,可以自行看配置菜单。

终极大坑(无法正确复位)

问题描述

直接现象:

  • 使用 GDB 调试时复位后 CPU PC 卡在 0x1ffff020 而不是 0x08000130
  • 使用 MobaXterm 进行串口调试时,按复位物理按键无法继续输出,必须重新上电才能通信

间接原因:当开发板的 USB 串口和电脑连接时,板子复位会使用系统存储器启动。

根本原因:这块板子专门设计了一键下载电路,会通过串口的 DTR 和 RTS 信号,来自动配置 BOOT0 和 RST 信号,因此串口连接时会导致一些问题(这里作者也不太懂,只能说坑在这)。

解决方法

控制串口的 DTR 和 RTS 信号,在 VSCode 中安装 Serial Monitor 扩展,取消 DTR 和 RTS 的勾选,然后打开串口。有了这个插件以后 MobaXterm 其实就用不到了,之后都可以用这个插件来进行串口通信。

注意,这里是在 Windows 中的 VSCode 而不是 WSL 中,如果在 WSL 中,这里显示的串口是 /dev/ttyS0 等,因此串口调试时每次需要打开两个 VSCode 界面。

参考文档


本站不记录浏览量,但如果您觉得本内容有帮助,请点个小红心,让我知道您的喜欢。