夜眸2.烧录登录与HelloWorld上板指南

原创2026-10-26 09:45:13浏览3
3
Star

烧录 · 登录 · SDK 目录 · Hello World 上板全流程

[!abstract] 一句话 FastBurn 把 out/<chip>/image/spi_image/ 里的 6 个文件按分区表写进板载 SPI NOR; 串口 115200 8N1 上电即可自动 root 登录;日常改程序不烧固件,用 SDK 工具链交叉编译后 scp 传上去 chmod +x 直接跑(scp 版本 < 9.0 不加 -O,≥ 9.0 必须加)。 只有要改内核/根文件系统/裁剪系统时才重新 make fs_image 并烧录。

[!info] 本文对应环境

  • SDK:/home/dachou/NightEyes/sdk

  • cfg.mk:xm7206v11a(GK7206V11A,128 MB DDR,linux-5.10.y,arm-gcc12.2.0-linux-uclibceabi)

  • 板型:GK7206V11A Demo Board,板载 16 MB SPI NOR

  • 若切到 xm7206v12a,把文中所有 xm7206v11a 换成 xm7206v12a 即可,目录结构完全一致

  • 官方对应章节:快速入门 03 镜像烧录 / 04 系统登录 / 06 文件传输 / 07 SDK 目录结构 / 08 部署第一个应用程序


〇、全景图

auto—bashshellpowershellccppcsharpverilogvhdlrustpythonpython-replcmakemakefilenginxarduinogojavajavascripttypescriptjsonkotlincssscsssqllessmarkdownphpplaintextrubyvimyamldockerfileini

flowchart LR
    A["写代码<br/>source/app/helloworld/"] --> B["make 交叉编译<br/>arm uclibc 可执行文件"]
    B --> C{"要不要固化?"}
    C -->|"日常调试<br/>不烧机"| D["scp 上传<br/>/root 或 /usr/bin"]
    D --> E["chmod +x && ./helloworld"]
    C -->|"发布/改系统"| F["make install<br/>装进 out/.../rootfs"]
    F --> G["make fs_image<br/>重新打 jffs2"]
    G --> H["FastBurn 烧录<br/>USB / 串口"]
    H --> I["上电: U-Boot → kernel → rootfs"]
    I --> E

四条主线:烧录(搬固件)→ 登录(进系统)→ 读懂 SDK(知道东西在哪)→ 上板跑程序(scp 或打包)。前三步干一次,第四步天天用。


一、烧录:把固件写进板子

1.1 先确认镜像存在

auto—bashshellpowershellccppcsharpverilogvhdlrustpythonpython-replcmakemakefilenginxarduinogojavajavascripttypescriptjsonkotlincssscsssqllessmarkdownphpplaintextrubyvimyamldockerfileini

cd /home/dachou/NightEyes/sdk
ls -l out/xm7206v11a/image/spi_image/

实测内容(这是 SPI NOR 那一套,本板就用这个):

文件

大小

身份

烧到哪

uboot.bin

212 KB

二级引导

fastboot,偏移 0

bootargs.bin

64 KB

U-Boot 环境变量块

bootargs,偏移 512K

kernel

3.3 MB

uImage(装载地址 0x40208000)

kernel,偏移 1M

rootfs.64k.jffs2

6.3 MB

可读写根文件系统

rootfs,偏移 5M

rootfs.squashfs

4.3 MB

只读备用方案(当前未使用)

同上,二选一

spi_partitions.xml

913 B

分区表,烧写工具必读

不烧

没有这些文件就先编译:./run.sh all -j(全量,时间长)或 ./run.sh rootfs -j(只重建根文件系统 + 打包)。

1.2 工具在哪

auto—bashshellpowershellccppcsharpverilogvhdlrustpythonpython-replcmakemakefilenginxarduinogojavajavascripttypescriptjsonkotlincssscsssqllessmarkdownphpplaintextrubyvimyamldockerfileini

sdk/tools/windows/burning_tools/
├── FastBurn-1.0.16.zip          # 烧录工具(USB 烧录 / 量产)
├── 量产工具-1.0.16.zip           # 量产版
└── ftdi-driver/FTDI-CDM-Driver.exe   # FT232 串口小板 / USB 驱动

工具是 Windows GUI 程序,Linux 这边只负责产出镜像。把 zip 拷到 Windows 解压,双击 FastBurn-1.0.16.exe。

1.3 三种烧录通道,选一种

通道

进烧录模式的手势

适用场景

速度

纯串口

点"烧写"后按一下 RESET

没有 USB 口、只有串口线

慢(几分钟)

串口 + USB

点"烧写"后按 RESET;或在 U-Boot 执行 usb device

最常见

快

纯 USB

按住 Boot 不松 → 点 RESET → 松开 RESET

量产、无串口

最快

纯串口要先装 FT232 驱动:ftdi-driver/FTDI-CDM-Driver.exe,设备管理器里确认 USB Serial Port (COMx)。 USB 通道要在设备管理器看到带黄色叹号的设备后按工具提示装驱动,叹号消失再按复位键重启板子。

1.4 标准烧写流程(7 步)

  1. 把 out/xm7206v11a/image/spi_image/ 整个目录拷到 Windows。 —— 分区表 XML 里写的是相对路径(ImagePath="uboot.bin"),镜像必须和 XML 同目录,否则工具找不到文件。

  2. 打开 FastBurn,先选芯片类型,再选通讯接口(串口 / 串口+USB / USB)。

  3. 选分区表:.../spi_image/spi_partitions.xml,工具会自动识别分区(名字、起始地址、大小)。

  4. 烧写方式选 USBBurn(或对应通道),设备选"自动识别";多板并行才需要绑定端口。

  5. 点"开始烧写"。

  6. 按 1.3 的手势让板子进入烧录模式 —— 工具自动开始写入,进度条走完提示成功。

  7. 板子复位或重新上电,从新固件启动。

[!warning] 分区表不用改,除非你动了系统 默认分区表 = fastboot / bootargs / ddr_param / kernel / rootfs / factory_test,合计 16 MB,和 SPI NOR 容量、bootargs 里的 mtdparts= 严格一一对应。 只有这几种情况才需要改:镜像超过分区大小(典型是 kernel/rootfs 变大后报 image size too large)、换 Flash 容量、增删分区、改 OTA 方案(A/B 分区)、改启动方式。 改 XML 后必须同步 configs/<board>/prebuilts/spi_bootargs.txt 里的 mtdparts,否则内核报 VFS: Cannot open root device。

[!tip] 根文件系统余量 rootfs 分区 11200K ≈ 10.9 MB,当前 jffs2 只有 6.3 MB,剩约 4.6 MB。往 rootfs 里塞大程序前先 ls -lh 看一眼镜像大小。

1.5 烧录成功的判据

接串口(115200 8N1)上电,依次应看到:

auto—bashshellpowershellccppcsharpverilogvhdlrustpythonpython-replcmakemakefilenginxarduinogojavajavascripttypescriptjsonkotlincssscsssqllessmarkdownphpplaintextrubyvimyamldockerfileini

U-Boot 2021.04 (...)
Model: GK7206V11A Demo Board
DRAM:  128 MiB
Loading Environment from SPI Flash... OK
Starting kernel ...
[    0.000000] Booting Linux on physical CPU 0x0
[    0.000000] Linux version 5.10.130 ...
Freeing unused kernel memory: 1024K
Run /sbin/init as init process

Welcome to GK7206
Auto login as root ...
  • 串口完全没输出:uboot 没烧进去(分区错/没进烧录模式),或串口 TX/RX 接反、GND 没接、波特率不对。

  • U-Boot 有、kernel 没有:kernel 分区写坏或超出 4 MB。

  • kernel 起来但 Cannot open root device:rootfs 没烧成,或 mtdparts 与分区表不一致。


二、登录板子

2.1 串口登录(最可靠,永远可用)

项

值

终端软件

MobaXterm / minicom / picocom / PuTTY 均可

串口小板

FT232(SDK 配套)

驱动

sdk/tools/windows/burning_tools/ftdi-driver/FTDI-CDM-Driver.exe

波特率

115200

数据位/校验/停止位

8 / None / 1(8N1)

流控

None(硬件流控必须关,否则收不到输出)

用户名密码

不需要,/etc/inittab 里 getty ... -l /etc/autologin.sh 直接 login -f root

接线(三根线足够,不要接 VCC):

串口小板

开发板

TX

RX

RX

TX

GND

GND

Linux 主机上直接用命令行也行:

auto—bashshellpowershellccppcsharpverilogvhdlrustpythonpython-replcmakemakefilenginxarduinogojavajavascripttypescriptjsonkotlincssscsssqllessmarkdownphpplaintextrubyvimyamldockerfileini

ls /dev/ttyUSB*                 # 插上 FT232 后出现
sudo picocom -b 115200 /dev/ttyUSB0      # 退出: Ctrl-A Ctrl-X
# 或
sudo minicom -D /dev/ttyUSB0 -b 115200

进去后提示符是 #(root),说明已经在板子的 shell 里了。

2.2 进 U-Boot 命令行(改启动参数/救砖用)

上电后 持续按回车,打断 Hit any key to stop autoboot: 0,出现 => 即进入 U-Boot。

auto—bashshellpowershellccppcsharpverilogvhdlrustpythonpython-replcmakemakefilenginxarduinogojavajavascripttypescriptjsonkotlincssscsssqllessmarkdownphpplaintextrubyvimyamldockerfileini

=> usb device          # 让板子进 USB 设备模式(配合 USB 烧录)
=> boot                # 继续正常启动 Linux

2.3 SSH 登录(日常调试用它)

第 1 步:拿到板子 IP。 板子没有固定默认 IP,S40network 里走 DHCP,并把首次 MAC 存到 /etc/.mac_addr 保证每次拿到同一个地址。

三种拿法:

auto—bashshellpowershellccppcsharpverilogvhdlrustpythonpython-replcmakemakefilenginxarduinogojavajavascripttypescriptjsonkotlincssscsssqllessmarkdownphpplaintextrubyvimyamldockerfileini

# 方法 A(最快):串口里直接看
ip addr show eth0
# 或看启动日志里的 [NET]: 行

# 方法 B:PC 上扫描本网段
nmap -sn 192.168.1.0/24        # Windows 用户按官方教程用 Zenmap → Ping scan

# 方法 C:路由器后台看 DHCP 客户端列表

[!tip] 为什么找回同一个 IP 这么重要 板子设备树里 MAC 是全 0,内核每次启动随机生成,路由器会当成新设备发新 IP。S40network 把首个 MAC 落到 rootfs,只要别重烧 rootfs,IP 就稳定。

第 2 步:连。

auto—bashshellpowershellccppcsharpverilogvhdlrustpythonpython-replcmakemakefilenginxarduinogojavajavascripttypescriptjsonkotlincssscsssqllessmarkdownphpplaintextrubyvimyamldockerfileini

ssh root@192.168.1.100
# 密码:123456      ← 已验证:/etc/passwd 中 hash 为 $1$xmedia$ZhrAZn.KQNruBVd058poT0,即 md5crypt("123456")

首次连接会问 Are you sure you want to continue connecting,输入 yes 记指纹。

服务端是 dropbear(/usr/sbin/dropbear -R -B -p 22),由 /etc/init.d/S50dropbear 拉起。板端没有 ssh 客户端(只有 dropbear 和 scp),所以方向只能是 PC → 板。

[!note] 串口免密、SSH 要密码 串口是本地物理访问,autologin.sh 直接给 root shell;SSH 走网络必须验密码。 忘了密码:串口里 passwd 重设;或者改 source/rootfs 里的 passwd 再重打镜像。


三、SDK 目录详解

3.1 顶层实况

auto—bashshellpowershellccppcsharpverilogvhdlrustpythonpython-replcmakemakefilenginxarduinogojavajavascripttypescriptjsonkotlincssscsssqllessmarkdownphpplaintextrubyvimyamldockerfileini

sdk/
├── Makefile -> ./build/root.mk   # 顶层 Makefile(软链),make 实际走 build/root.mk
├── run.sh                        # 一键构建入口(对 make 的封装)
├── cfg.mk                        # 当前生效配置(menuconfig 生成,类似内核 .config)
├── build/                        # 构建系统本体(*.mk 规则)
├── configs/                      # 板级/芯片配置(xm7206v11a、xm7206v12a ...)
├── version_config/               # menuconfig 的菜单定义
├── source/                       # 核心源码(bootloader/kernel/gmp/rootfs/app)
├── sample/                       # SDK 官方示例(vio/venc/audio/npu/vo/fb/tde/ive/uvc_app...)
├── app_sample/                   # 应用层示例(face_recognize、rock_paper_scissors、rpi_detector)
├── open_source/                  # 三方组件(busybox/dropbear/mtd-utils/zlib/gdb...)
├── mcu/                          # MCU / RISC-V 子系统(低功耗、AOV)
├── env_tools/                    # gperf / automake 源码,供 develop_env.sh 编译
├── tools/                        # 工具:linux/ 工具链·PQ·AQ·kconfig,windows/ 烧录·画质工具
├── shimetad_GK7206/              # 厂商预置包目录(当前 SDK 包内为空)
├── tar_rootfs.sh                 # 手动打包 rootfs.tgz
└── out/                          # 编译产物(首次编译后才生成)

3.2 各目录职责速查

目录/文件

干什么

什么时候碰它

run.sh

构建入口:./run.sh all/kernel/uboot/rootfs/app/clean

每次编译

cfg.mk

芯片型号、工具链、内核版本、flash 类型

换板/换芯片(一般用 menuconfig 改)

build/base.mk

定义 CC、SDK_USR_CFLAGS、SDK_LD_CFLAGS、XMEDIA_ROOTFS_DIR

写应用 Makefile 时 include 它

build/root.mk

顶层目标(build 依赖链:prepare→uboot→linux→gmp→rootfs→bootargs→fs_image→sample)

想知道 make 做了什么

build/rootfs_image.mk

rootfs 打包规则(jffs2/squashfs/yaffs/ubifs/ext4)

改文件系统格式

configs/<chip>/

prebuilts/(分区表 XML、spi_bootargs.txt)、reg/、*_cfg.mk

改分区/bootargs

source/bootloader/

U-Boot 2020.01 + 产品定制 + secureboot

改引导

source/kernel/linux-5.10.y/

内核源码(当前用 5.10.y)

改驱动/开内核配置

source/gmp/

媒体平台核心:drv/→.ko、usr/→.so、include/→头文件、ko/→预编译

调 MPP/编码/NPU

source/rootfs/

根文件系统源:scripts/(etc/init.d/rcS、opt/ko/load)、busybox、dropbear 配置

改启动脚本、加开机自启

source/app/

应用源码,实测 16 个:factory_test、helloworld、oled_display、sd_rw_demo、spi_display…

写业务程序

sample/

官方示例:vio/venc/vo/audio/npu/tde/ive/vgs/region/uvc_app/ainr/quickstart…

抄用法、验证硬件

app_sample/

应用层示例:face_recognize、rock_paper_scissors、rpi_detector

看完整应用怎么组织

open_source/

busybox、dropbear、mtd-utils、zlib、gdb…

系统组件裁剪/升级

tools/linux/toolchains/

交叉工具链 arm-gcc12.2.0-linux-uclibceabi

编译一切用户态程序

out/<chip>/

产物:rootfs/、lib/、ko/、linux-5.10.y/、boot_builddir/、image/

取库、取头文件、取固件

3.3 out/<chip>/ 产物地图

auto—bashshellpowershellccppcsharpverilogvhdlrustpythonpython-replcmakemakefilenginxarduinogojavajavascripttypescriptjsonkotlincssscsssqllessmarkdownphpplaintextrubyvimyamldockerfileini

out/xm7206v11a/
├── boot_builddir/      # U-Boot 编译中间目录
├── linux-5.10.y/       # 内核编译目录(.config、uImage、驱动 .o)
├── rootfs/             # 根文件系统 staging 目录 —— 就是板子上的 "/"
├── lib/                # SDK 动态库(libmpi.so 等)
├── ko/                 # 内核模块 xm_*.ko(打包进 rootfs/opt/ko)
├── include/            # SDK 头文件
├── obj/                # 中间 .o
└── image/
    ├── spi_image/      # ← 本板烧这个(SPI NOR)
    ├── nand_image/     # NAND 固件
    └── emmc_image/     # eMMC 固件

关键理解:out/<chip>/rootfs/ 不是"某份拷贝",它就是板子根目录的镜像源。你 install 进去的东西,make fs_image 之后才会出现在 jffs2 里。

3.4 我要改 X,去哪找

需求

位置

加自己的程序

source/app/<name>/,Makefile include $(SDK_DIR)/build/base.mk

改开机自启

source/rootfs/scripts/etc/init.d/ 加 S99xxx(按文件名排序执行)

改串口波特率/自动登录

source/rootfs/scripts/etc/inittab

改分区/flash 布局

configs/<chip>/prebuilts/spi_partitions.xml + spi_bootargs.txt

开内核选项

source/kernel/linux-5.10.y/ 的 defconfig → ./run.sh kernel

用媒体/NPU 接口

source/gmp/include/ + out/<chip>/lib/*.so

找官方示例

sample/<模块>/


四、Hello World:编译出来

4.1 目录与源码

工作区里已有的 source/app/helloworld/ 就是按官方 08 章建的:

auto—bashshellpowershellccppcsharpverilogvhdlrustpythonpython-replcmakemakefilenginxarduinogojavajavascripttypescriptjsonkotlincssscsssqllessmarkdownphpplaintextrubyvimyamldockerfileini

sdk/source/app/helloworld/
├── helloworld.c
├── Makefile
├── helloworld        # 交叉编译产物(ARM 可执行文件)
└── helloworld.o

helloworld.c:

auto—bashshellpowershellccppcsharpverilogvhdlrustpythonpython-replcmakemakefilenginxarduinogojavajavascripttypescriptjsonkotlincssscsssqllessmarkdownphpplaintextrubyvimyamldockerfileini

#include <stdio.h>

int main(void)
{
    printf("hello world from firmware!\n");
    return 0;
}

从零建的话:

auto—bashshellpowershellccppcsharpverilogvhdlrustpythonpython-replcmakemakefilenginxarduinogojavajavascripttypescriptjsonkotlincssscsssqllessmarkdownphpplaintextrubyvimyamldockerfileini

cd /home/dachou/NightEyes/sdk
mkdir -p source/app/helloworld && cd source/app/helloworld
# 写 helloworld.c 和下面的 Makefile

4.2 Makefile 逐段说明

auto—bashshellpowershellccppcsharpverilogvhdlrustpythonpython-replcmakemakefilenginxarduinogojavajavascripttypescriptjsonkotlincssscsssqllessmarkdownphpplaintextrubyvimyamldockerfileini

SDK_DIR := $(shell cd $(shell pwd)/../../.. && /bin/pwd)   # 往上三级回到 SDK 根
include $(SDK_DIR)/build/base.mk                            # 拿到 CC 和编译参数

TARGET := helloworld
SRCS   := helloworld.c
OBJS   := $(SRCS:.c=.o)

all: $(TARGET)

$(TARGET): $(OBJS)
	$(CC) $(SDK_LD_CFLAGS) -o $@ $^

%.o: %.c
	$(CC) $(SDK_USR_CFLAGS) -c -o $@ $<

install: all
	@mkdir -p $(XMEDIA_ROOTFS_DIR)/usr/bin
	@cp -f $(TARGET) $(XMEDIA_ROOTFS_DIR)/usr/bin/$(TARGET)
	@chmod 755 $(XMEDIA_ROOTFS_DIR)/usr/bin/$(TARGET)

clean:
	rm -f $(TARGET) $(OBJS)

base.mk 实际给的东西(sdk/build/base.mk):

auto—bashshellpowershellccppcsharpverilogvhdlrustpythonpython-replcmakemakefilenginxarduinogojavajavascripttypescriptjsonkotlincssscsssqllessmarkdownphpplaintextrubyvimyamldockerfileini

CC := $(TOOLCHAIN)-gcc        # = arm-gcc12.2.0-linux-uclibceabi-gcc
SDK_USR_CFLAGS := -mcpu=cortex-a7 -mfloat-abi=hard -mfpu=neon-vfpv4 -Wall -fPIC -Os ...
SDK_LD_CFLAGS  := -mcpu=cortex-a7 -mfloat-abi=hard ... -Wl,-z,relro,-z,now,-s -ldl
XMEDIA_ROOTFS_DIR := $(XMEDIA_INSTALL_DIR)/rootfs

[!important] 不要用主机 gcc 板子是 ARM Cortex-A7 + uClibc(interpreter /lib/ld-uClibc.so.0)。主机 gcc 编出来是 x86 ELF,传到板上会报 Exec format error 或 not found(缺动态链接器)。 始终 make -C source/app/...,让它走 SDK 工具链。

4.3 编译

auto—bashshellpowershellccppcsharpverilogvhdlrustpythonpython-replcmakemakefilenginxarduinogojavajavascripttypescriptjsonkotlincssscsssqllessmarkdownphpplaintextrubyvimyamldockerfileini

cd /home/dachou/NightEyes/sdk
make -C source/app/helloworld clean
make -C source/app/helloworld

验证产物:

auto—bashshellpowershellccppcsharpverilogvhdlrustpythonpython-replcmakemakefilenginxarduinogojavajavascripttypescriptjsonkotlincssscsssqllessmarkdownphpplaintextrubyvimyamldockerfileini

file source/app/helloworld/helloworld
# ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV),
# dynamically linked, interpreter /lib/ld-uClibc.so.0, stripped

看到 ARM + ld-uClibc.so.0 就对了。


五、scp 到板子上跑(日常主路径,不用烧机)

[!important] 在哪执行 scp:容器里、宿主机,都行 传输只依赖两件事:能路由到板子的 SSH 端口 + scp 版本决定加不加 -O。位置本身不限制。 两个环境实测都能传,区别只在参数和路径:

编译容器

宿主机 WSL2

scp 版本

OpenSSH_7.6p1(Ubuntu 18.04)

OpenSSH_10.2p1

参数

不带 -O(加了报 unknown option -- O)

必须带 -O(不加会卡住)

源码路径

/opt/sdk/...(挂载点)

~/NightEyes/sdk/...

known_hosts

容器内 /root/.ssh,--rm 退出即丢,下次重新问 yes

持久

已经进了容器就别退出,直接在里面传最省事;路径别写成宿主机的那种。

5.1 前置检查

检查项

命令

期望

板子开机、在网

ping <板子IP>

有回包

22 端口通(容器内没有 ping/nc 时用这条)

timeout 3 bash -c '</dev/tcp/<板子IP>/22'

立刻返回 = 通;卡满 3 秒 = 不通

SSH 服务在

nc -zv <板子IP> 22 或直接 ssh

open / 出密码提示

知道 IP

串口 ip addr show eth0

192.168.x.x

账号

root / 123456

容器走 bridge(172.17) → WSL2(192.168.76.x) → Windows NAT → LAN(192.168.31.x),多层 NAT 通常能出,但先测这一行最省时间。

5.2 命令模板(-O 按版本决定,不是万能)

先确认客户端版本,加不加 -O 完全由它决定:

auto—bashshellpowershellccppcsharpverilogvhdlrustpythonpython-replcmakemakefilenginxarduinogojavajavascripttypescriptjsonkotlincssscsssqllessmarkdownphpplaintextrubyvimyamldockerfileini

ssh -V        # 输出类似 OpenSSH_10.2p1 Ubuntu-...

客户端版本

典型系统

默认协议

-O

< 9.0

Ubuntu 18.04(7.6p1)、20.04(8.2p1)、22.04(8.9p1)、Debian 11

老 SCP 协议

不支持,加了直接 unknown option -- O

>= 9.0

Ubuntu 24.04(9.6p1)、Debian 12、Windows 自带

SFTP

必须加,否则卡住或 subsystem request failed

容器内(pico-g1-build-env:18.04 = 7.6p1)——不带 -O:

auto—bashshellpowershellccppcsharpverilogvhdlrustpythonpython-replcmakemakefilenginxarduinogojavajavascripttypescriptjsonkotlincssscsssqllessmarkdownphpplaintextrubyvimyamldockerfileini

cd /opt/sdk/source/app/factory_test

# 上传文件(实测 3.5 MB,约 994 KB/s)
scp factory_server root@192.168.31.55:/usr/bin/

# 上传整个目录:老版本是 -r,不是 -Or
scp -r web root@192.168.31.55:/usr/share/

# 从板子下载
scp root@192.168.31.55:/root/dmesg.txt ./

宿主机 WSL2(OpenSSH_10.2p1)——必须带 -O:

auto—bashshellpowershellccppcsharpverilogvhdlrustpythonpython-replcmakemakefilenginxarduinogojavajavascripttypescriptjsonkotlincssscsssqllessmarkdownphpplaintextrubyvimyamldockerfileini

cd ~/NightEyes/sdk/source/app/factory_test

scp -O factory_server root@192.168.31.55:/usr/bin/
scp -Or web root@192.168.31.55:/usr/share/
scp -O root@192.168.31.55:/root/dmesg.txt ./

[!note] 容器内不带 -O 有没有坑 协议层面没有:7.6p1 默认就发老 SCP 协议,和加 -O 的报文完全一致,板端 dropbear 收到的请求一模一样。速率也不受影响(实测约 1 MB/s,瓶颈是板子侧)。 真正的约束只有一条:这个结论绑死在 7.6p1 上。哪天把基础镜像换成 Ubuntu 22.04(8.9p1)还能用;换成 24.04(9.6p1)就必须反过来加 -O。 所以别记"容器里不用加",记 ssh -V 决定。容器内 ssh -V 是 7.6p1,宿主机是 10.2p1,两边参数相反。

[!warning] 为什么和 -O 死磕:板端是 dropbear 板端 scp 来自 dropbear,只实现老 SCP 协议,没有 SFTP 子系统。 OpenSSH 9.0 起客户端默认改走 SFTP,才有了 -O 这个"退回老协议"的开关——它本身就是 9.0 才新增的参数,8.x 及更早的 scp 解析不了。 一句话:ssh -V ≥ 9.0 才写 -O,否则写上去就是语法错误。

5.3 完整实操

auto—bashshellpowershellccppcsharpverilogvhdlrustpythonpython-replcmakemakefilenginxarduinogojavajavascripttypescriptjsonkotlincssscsssqllessmarkdownphpplaintextrubyvimyamldockerfileini

# ① 编译(在哪编都一样,产物落在挂载卷里是同一份文件)
cd ~/NightEyes/sdk                        # 容器内换成 /opt/sdk
make -C source/app/helloworld clean && make -C source/app/helloworld

# ② 挑一条执行,别两条都跑
# 容器内(7.6p1,不带 -O)
scp source/app/helloworld/helloworld root@192.168.1.100:/root/
# 宿主机(10.2p1,必须 -O)
scp -O source/app/helloworld/helloworld root@192.168.1.100:/root/

# 首次连接问指纹输 yes;密码 123456

auto—bashshellpowershellccppcsharpverilogvhdlrustpythonpython-replcmakemakefilenginxarduinogojavajavascripttypescriptjsonkotlincssscsssqllessmarkdownphpplaintextrubyvimyamldockerfileini

# ③ SSH 上板运行
ssh root@192.168.1.100

auto—bashshellpowershellccppcsharpverilogvhdlrustpythonpython-replcmakemakefilenginxarduinogojavajavascripttypescriptjsonkotlincssscsssqllessmarkdownphpplaintextrubyvimyamldockerfileini

# 板子 shell 内
cd /root
chmod +x helloworld        # 从 Windows 拷过来的文件常丢可执行位
./helloworld

输出:

auto—bashshellpowershellccppcsharpverilogvhdlrustpythonpython-replcmakemakefilenginxarduinogojavajavascripttypescriptjsonkotlincssscsssqllessmarkdownphpplaintextrubyvimyamldockerfileini

hello world from firmware!

5.4 放到 /usr/bin(更像"装好的程序")

auto—bashshellpowershellccppcsharpverilogvhdlrustpythonpython-replcmakemakefilenginxarduinogojavajavascripttypescriptjsonkotlincssscsssqllessmarkdownphpplaintextrubyvimyamldockerfileini

# 容器内 7.6p1
scp source/app/helloworld/helloworld root@192.168.1.100:/usr/bin/
# 宿主机 10.2p1
scp -O source/app/helloworld/helloworld root@192.168.1.100:/usr/bin/

ssh root@192.168.1.100 'chmod 755 /usr/bin/helloworld && helloworld'

之后任何目录下直接输 helloworld 就能跑,重启后仍然在(jffs2 是可写根)。

5.5 把板上日志拉回 PC

auto—bashshellpowershellccppcsharpverilogvhdlrustpythonpython-replcmakemakefilenginxarduinogojavajavascripttypescriptjsonkotlincssscsssqllessmarkdownphpplaintextrubyvimyamldockerfileini

ssh root@192.168.1.100 'dmesg > /root/dmesg.txt'
scp root@192.168.1.100:/root/dmesg.txt ./        # 容器内 7.6p1
scp -O root@192.168.1.100:/root/dmesg.txt ./     # 宿主机 10.2p1

MobaXterm 用户可直接在左侧 SFTP 面板拖拽(本质也是 SCP)。

5.6 报错对照表

现象

原因

处理

Exec format error

用了主机 gcc 编的 x86 程序

用 make -C source/app/... 重新交叉编译

not found(文件明明存在)

缺 /lib/ld-uClibc.so.0(静态/glibc 编译)

用 SDK 工具链,别加 -static 也别混用 glibc 工具链

Permission denied

没有可执行位

chmod 755 helloworld

scp 卡住 / subsystem request failed

客户端 ≥ 9.0,默认走了 SFTP

加 -O

unknown option -- O

客户端 < 9.0(容器内 7.6p1),scp 根本没这个参数

去掉 -O,老协议本来就是默认

Connection timed out

容器多层 NAT 没通;或板子没拿到 IP

先测 /dev/tcp,再串口 ip addr 对网段

cd: too many arguments

敲成 cd cd ...

重新输入

cd: No such file or directory

在容器里用了宿主机路径

容器内用 /opt/sdk/...,宿主机用 ~/NightEyes/sdk/...

Connection refused

dropbear 没起

串口进板执行 /etc/init.d/S50dropbear restart 或 dropbear -R -B -p 22

No space left on device

rootfs 写满(余量约 4.6 MB)

删旧文件,或改用 SD 卡/U 盘存数据

Host key verification failed

IP 被别的设备复用

ssh-keygen -R <IP> 后重连

Connection timed out

不同网段 / 板子没拿到 IP

串口 ip addr,确认和 PC 同网段


六、另一条路:装进 rootfs 一起烧(发布用)

不想每次手动 scp、或者要交付"开机就有"的程序,就走固件路线:

auto—bashshellpowershellccppcsharpverilogvhdlrustpythonpython-replcmakemakefilenginxarduinogojavajavascripttypescriptjsonkotlincssscsssqllessmarkdownphpplaintextrubyvimyamldockerfileini

cd /home/dachou/NightEyes/sdk

# ① 装进 rootfs staging
make -C source/app/helloworld install
# Installed helloworld to .../out/xm7206v11a/rootfs/usr/bin/helloworld

ls -l out/xm7206v11a/rootfs/usr/bin/helloworld   # 确认在

# ② 重新打镜像
make fs_image

# ③ 按第一章烧 out/xm7206v11a/image/spi_image/

上板后 /usr/bin/helloworld 随固件就在。

要做开机自启,在 source/rootfs/scripts/etc/init.d/ 加一个 S99helloworld:

auto—bashshellpowershellccppcsharpverilogvhdlrustpythonpython-replcmakemakefilenginxarduinogojavajavascripttypescriptjsonkotlincssscsssqllessmarkdownphpplaintextrubyvimyamldockerfileini

#!/bin/sh
case "$1" in
  start) /usr/bin/helloworld & ;;
  stop)  killall helloworld 2>/dev/null ;;
esac

auto—bashshellpowershellccppcsharpverilogvhdlrustpythonpython-replcmakemakefilenginxarduinogojavajavascripttypescriptjsonkotlincssscsssqllessmarkdownphpplaintextrubyvimyamldockerfileini

chmod +x source/rootfs/scripts/etc/init.d/S99helloworld
make rootfs && make fs_image     # 重新打包并烧录

七、一页速查

auto—bashshellpowershellccppcsharpverilogvhdlrustpythonpython-replcmakemakefilenginxarduinogojavajavascripttypescriptjsonkotlincssscsssqllessmarkdownphpplaintextrubyvimyamldockerfileini

# ---- 编译 ----
cd /home/dachou/NightEyes/sdk
./run.sh all -j                      # 全量(会先 clean,很久)
./run.sh rootfs -j                   # 只重建 rootfs + 打包
make -C source/app/helloworld        # 只编你的 app
make -C source/app/helloworld install   # 装进 out/<chip>/rootfs/usr/bin
make fs_image                        # 出 image/

# ---- 烧录 ----
# Windows: FastBurn-1.0.16.exe + out/<chip>/image/spi_image/(整目录)
# 手势: 按住 Boot → 点 Reset → 松 Reset(纯 USB)
#       或点"烧写"后按一下 Reset(串口/串口+USB)

# ---- 登录 ----
picocom -b 115200 /dev/ttyUSB0       # 串口,8N1,无流控,自动 root
ssh root@<板子IP>                     # 密码 123456(dropbear :22)

# ---- 上板跑(-O 看 ssh -V:容器 7.6p1 不加,宿主机 10.2p1 必须加)----
scp    source/app/helloworld/helloworld root@<IP>:/root/    # 容器内
scp -O source/app/helloworld/helloworld root@<IP>:/root/    # 宿主机
ssh root@<IP> 'chmod +x /root/helloworld && /root/helloworld'

[!success] 三条铁律

  1. 程序一定要用 SDK 工具链编(ARM + uClibc),否则板上跑不起来。

  2. spi_image 整目录一起拷,分区表和镜像不能分家。

  3. 日常调试只 scp,不烧机;只有改内核/rootfs/分区时才烧固件。