Tina Linux嵌入式系统开发实战:从SDK结构到应用部署全解析
1. 项目概述从零开始理解 Tina Linux 系统开发如果你正在为一个嵌入式设备寻找一个稳定、开源且高度可定制的操作系统那么 Tina Linux 很可能已经进入了你的视野。它不是一个凭空出现的全新系统而是基于 OpenWrt 和 Linux 内核深度定制而来专门服务于智能硬件、物联网终端等资源受限的嵌入式场景。简单来说你可以把它理解为一个“嵌入式领域的 Ubuntu”但它更轻量、启动更快并且天生为连接和交互设计。我接触 Tina Linux 已经有好几年了从最初在某个智能摄像头项目上用它来驱动视频编码和网络传输到后来在智能家居中控、工业网关等多个产品上深度定制。这个过程里我最大的体会是Tina Linux 的强大之处在于其完整的构建系统但它的学习曲线也恰恰隐藏在这里。很多开发者尤其是从应用层转过来的朋友第一次面对它的 SDK 目录结构时都会感到无从下手——交叉编译工具链在哪内核配置怎么改根文件系统如何打包应用程序又该放在哪个目录这份指南的目的就是帮你捋清这些头绪。它不是一份简单的命令罗列文档而是结合我踩过的无数个坑为你梳理出一套从环境搭建到系统烧录、从内核定制到应用开发的完整实战路径。无论你是刚接手 Tina Linux 项目的新手还是希望更深入理解其构建机制的老兵我相信这里面的经验都能让你少走弯路。我们将从最核心的 SDK 结构开始一步步拆解直到你能够独立完成一个功能完整的系统镜像。2. 核心基石深度解析 Tina Linux SDK 目录结构拿到 Tina Linux 的 SDK 包第一件事不是急着编译而是静下心来花十分钟搞清楚它的目录结构。这就像看一张地图知道了东南西北后面的路才好走。一个典型的 Tina Linux SDK 顶层目录看起来是这样的tina-sdk/ ├── build/ # 构建系统的核心目录 ├── config/ # 顶层配置和方案选择 ├── device/ # 设备树和板级支持包 (BSP) ├── kernel/ # Linux 内核源码 ├── bootloader/ # U-Boot 引导程序 ├── out/ # 编译输出目录 ├── package/ # 软件包定义和源码 ├── prebuilt/ # 预编译的工具链和组件 ├── scripts/ # 构建用的脚本工具 ├── staging_dir/ # 主机和目标平台的临时安装目录 ├── target/ # 目标系统的根文件系统模板和配置 └── tools/ # 各种主机工具这个结构继承了 OpenWrt 的基因但针对全志等国产芯片平台做了大量优化。我们挑几个最关键的目录深入聊聊。2.1device/目录你的硬件身份证这是与你的具体硬件板卡关联最紧密的地方。device/config/chips/下存放着不同芯片如全志 V853、R328的通用配置而device/config/boards/下则是具体开发板或产品板的配置。当你执行lunch命令选择方案时本质上就是让构建系统去加载对应板子的配置文件。这里有一个非常重要的文件target/allwinner/xxx/defconfig路径可能因平台而异。它定义了该方案最终系统镜像中包含哪些软件包。比如你是否需要 Wi-Fi 驱动、蓝牙支持、某种视频解码库等都是在这里通过CONFIG_PACKAGE_xxxy这样的选项来开关。一个常见的坑是明明在make menuconfig里勾选了某个包但编译出来的系统里却没有。这很可能是因为你只修改了临时配置却没有更新这个板级的defconfig文件。正确的做法是在make menuconfig中配置完成后使用make savedefconfig将配置保存到正确的板级目录下。2.2package/目录软件生态的基石这是整个系统软件生态的核心。Tina Linux 采用“包管理”的思想几乎所有用户空间的软件从基础的busybox、libc到复杂的ffmpeg、openssh都以“包”的形式存在于此。每个包通常是一个独立的目录里面至少包含两个关键文件Makefile定义了包的下载地址、编译方式、安装规则等。这是包的核心。patches/目录存放针对上游源码的补丁文件。这是 Tina Linux 能适配各种硬件和解决特定问题的关键。例如如果你想为你的设备添加一个自定义的守护进程最佳实践不是在target/下直接放二进制文件而是遵循规则在package/下创建一个新的包目录。这样做的好处是你的软件能无缝融入 Tina 的构建系统享受自动下载、交叉编译、依赖解析和版本管理。实操心得当你需要移植一个第三方开源库时不要急于修改target/下的文件。先去package/目录下看看是否有现成的包定义。如果没有找一个功能相近的包的Makefile作为模板来修改这会让你事半功倍并且符合项目的长期维护规范。2.3kernel/与bootloader/系统启动的双引擎kernel/目录下就是标准的 Linux 内核源码Tina 会在此基础打上芯片厂商提供的特定补丁。内核的配置通常由device/目录下的板级配置所决定。修改内核配置除了使用标准的make kernel_menuconfig更要关注device/目录下对应的内核配置片段.config文件。bootloader/里通常是 U-Boot。对于嵌入式设备U-Boot 的配置尤为重要它负责初始化最基础的硬件如 DDR、时钟、加载内核镜像、传递启动参数bootargs。一个非常关键的参数是bootargs中的console它指定了内核启动后的调试串口。如果这个设错了你的系统启动后可能一片寂静没有任何打印输出给调试带来极大困难。务必在硬件原理图上确认好调试串口的 UART 编号如ttyS0,ttyS1。2.4out/目录成果的集散地这是编译完成后所有产出的存放位置。对于某个具体方案例如v853-perf1其输出路径通常是out/v853-perf1/。在这里你可以找到images/最终可以烧录到存储设备如 SD 卡、eMMC、SPI NAND的系统镜像文件如tina_v853-perf1_uart0.img。staging_dir/的镜像这里存放着目标平台的工具链、库文件头文件等是开发应用程序时配置交叉编译环境的重要参考。编译过程中生成的临时文件、日志等。理解这个结构能帮助你在编译出错时快速定位日志在需要提取中间文件时知道去哪找。3. 开发环境搭建与首次编译实战理论说得再多不如动手一试。搭建 Tina Linux 的开发环境本质上是在准备一个能够执行其复杂构建脚本的 Linux 主机环境。3.1 主机环境准备避坑指南官方推荐使用 Ubuntu 18.04/20.04 LTS。我强烈建议使用物理机安装 Ubuntu或者使用配置了文件共享和剪贴板共享的VMware/VirtualBox 虚拟机。不推荐使用 WSL/WSL2因为在构建过程中涉及大量的符号链接和文件系统操作WSL 与 Windows 文件系统之间的交互有时会引发难以排查的权限和性能问题。安装必备的软件包是第一步以下命令适用于 Ubuntu 20.04sudo apt-get update sudo apt-get install -y build-essential subversion git-core libncurses5-dev zlib1g-dev gawk flex quilt libssl-dev xsltproc libxml-parser-perl mercurial bzr ecj cvs unzip lib32z1 lib32z1-dev lib32stdc6 libstdc6 libc6:i386 libstdc6:i386 lib32ncurses6 lib32z1 python3 python3-distutils python3-pip wget curl这里有几个容易忽略的点lib32stdc6等 32 位库即使你的主机是 64 位系统交叉编译工具链的某些部分可能仍然是 32 位的缺少这些库会导致工具链无法运行。Python 版本Tina 的构建脚本主要使用 Python 3。确保python命令指向的是 Python 3。可以通过sudo update-alternatives --config python来管理。磁盘空间一个完整的 SDK加上编译过程中的中间文件至少需要30GB以上的空闲空间。SSD 硬盘能显著提升编译速度。3.2 获取源码与配置方案假设你已经从官方渠道获得了 SDK 压缩包解压后进入目录。第一步是加载构建环境变量source build/envsetup.sh接着你会看到类似这样的输出列出了所有可用的方案lunch命令Youre building on Linux Lunch menu... pick a combo: 1. v853-perf1 2. r328s2-perf1 3. ...选择与你硬件对应的方案编号例如1。这个操作会设置一系列环境变量如TARGET_BOARD、TARGET_PLATFORM等告诉构建系统你要为哪个平台编译。3.3 首次编译理解过程而非等待执行编译最直接的命令是make -j$(nproc)-j$(nproc)表示使用与你的 CPU 核心数相同的线程进行并行编译以最大化利用硬件资源。首次编译会经历以下几个主要阶段理解它们有助于调试下载DL构建系统会根据package/和toolchain/下的Makefile从互联网下载所需的源码包、工具链到dl/目录。这是最容易出错的一步。网络超时、服务器关闭、证书问题都可能导致下载失败。如果失败可以尝试手动下载对应的tar.gz或git仓库放到dl/目录下。注意保持文件名一致。工具链编译编译针对目标架构如arm-openwrt-linux-gnueabi的交叉编译工具链。这一步通常比较耗时但成功后工具链会安装在staging_dir/下。编译目标软件包按照依赖关系依次编译在配置中选中的软件包。每个包的编译日志可以在out/board/compile_dir/target/或.../host/下对应的包目录里找到。安装与打包将编译好的二进制文件、库、配置文件等安装到临时根文件系统目录最后打包成各种格式的镜像sys_partition.fex描述分区然后生成.img。注意事项编译过程中如果报错不要只看最后一行。向上滚动日志找到第一个出现 “error:” 或 “ERROR:” 的地方。常见的错误包括依赖缺失如某个.h文件找不到、权限问题、源码补丁patch应用失败。对于补丁失败可以尝试进入该包的编译目录手动执行quilt push -a查看具体哪个补丁出了问题有时需要根据代码的微小差异手动调整补丁文件。首次编译成功在out/board/images/下看到.img文件只是万里长征第一步。接下来才是定制的开始。4. 系统定制进阶内核、根文件系统与驱动4.1 内核配置与裁剪系统镜像体积和启动速度很大程度上取决于内核的配置。使用make kernel_menuconfig进入内核的图形化配置界面。裁剪的核心原则按需加载。对于功能固定的嵌入式设备不需要的驱动和功能坚决去掉。文件系统你的设备只使用ext4和squashfs那就关掉btrfs,xfs,jffs2等。网络协议设备不需要 IPv6关掉。不需要复杂的网络过滤Netfilter关掉。调试支持量产时可以考虑关闭KGDB、内核调试符号CONFIG_DEBUG_INFO来减小体积但开发阶段建议保留CONFIG_PRINTK和CONFIG_EARLY_PRINTK以便调试。驱动移除所有你硬件上不存在的设备驱动如不用的 USB 控制器、声卡、显卡驱动等。修改后务必记得执行make kernel_savedefconfig将配置保存到device/config/chips/chip/configs/board/linux/kernel_version/下的对应文件中否则下次lunch后你的修改会丢失。4.2 根文件系统定制BusyBox 与软件包管理Tina Linux 的根文件系统主要由两部分构成BusyBox和Opkg 软件包。BusyBox 定制BusyBox 提供了一个精简的 Unix 工具集ls,cp,mount等。通过make menuconfig进入Base system - busybox可以进行配置。通常我们会保留必要的调试工具如ps,top,strace但去掉一些不常用的命令。注意过度裁剪可能导致某些脚本运行异常建议在确定不需要后再移除。软件包管理通过make menuconfig在各级菜单下选择你需要的软件包。例如Network - SSH选择openssh-server和openssh-client以支持 SSH 登录。Utilities - disc选择fdisk和e2fsprogs用于磁盘管理。Sound - alsa-utils如果需要音频功能。添加自定义软件包如前所述最好在package/下创建。一个极简的包Makefile模板如下include $(TOPDIR)/rules.mk PKG_NAME:my-daemon PKG_VERSION:1.0 PKG_RELEASE:1 include $(INCLUDE_DIR)/package.mk define Package/my-daemon SECTION:utils CATEGORY:Utilities TITLE:My Custom Daemon DEPENDS:libpthread endef define Package/my-daemon/description This is a custom daemon for my device. endef define Build/Prepare mkdir -p $(PKG_BUILD_DIR) $(CP) ./src/* $(PKG_BUILD_DIR)/ endef define Build/Compile $(MAKE) -C $(PKG_BUILD_DIR) \ CC$(TARGET_CC) \ CFLAGS$(TARGET_CFLAGS) \ LDFLAGS$(TARGET_LDFLAGS) endef define Package/my-daemon/install $(INSTALL_DIR) $(1)/usr/bin $(INSTALL_BIN) $(PKG_BUILD_DIR)/my-daemon $(1)/usr/bin/ $(INSTALL_DIR) $(1)/etc/init.d $(INSTALL_BIN) ./files/my-daemon.init $(1)/etc/init.d/my-daemon endef $(eval $(call BuildPackage,my-daemon))将你的源码放在package/my-daemon/src/下启动脚本放在package/my-daemon/files/下Tina 的构建系统就会自动处理交叉编译、打包和安装。4.3 外设驱动集成以 GPIO 和 I2C 为例对于 Tina Linux大多数常见芯片的驱动如 GPIO、I2C、SPI、UART已经在内核中集成并通过设备树Device Tree进行配置和管理。设备树.dts 文件是一种描述硬件拓扑和资源的数据结构。它位于kernel/linux-version/arch/arm/boot/dts/对于 ARM 平台或对应架构的目录下。你需要找到与你板子对应的.dts文件如sun8i-v853-perf1.dts。启用 GPIO通常 GPIO 控制器节点已经定义好。你需要在设备树中为你使用的具体 GPIO 引脚定义其功能。例如将一个 GPIO 定义为输出并连接一个 LEDpio { my_led_pin: my_led_pin { pins PB2; // 具体引脚名需查阅芯片手册 function gpio_out; drive-strength 10; }; }; my_led { compatible gpio-leds; pinctrl-names default; pinctrl-0 my_led_pin; status okay; led1 { label my_led; gpios pio 1 2 GPIO_ACTIVE_HIGH; // 参数含义GPIO控制器组(B)序号(2)高电平有效 default-state off; }; };修改后内核在启动时会根据此描述创建/sys/class/leds/my_led/目录你可以通过echo 1 brightness来控制 LED。启用 I2C 并添加设备首先确保内核配置中启用了对应的 I2C 控制器驱动如CONFIG_I2C_SUNXI。然后在设备树中启用该控制器并挂载设备i2c0 { // 启用 i2c0 控制器 status okay; clock-frequency 100000; // 设置速率 100kHz my_sensor: sensor1a { // 在地址 0x1a 挂载一个设备 compatible vendor,sensor-model; // 用于匹配内核驱动 reg 0x1a; // 其他设备特定属性如中断引脚 interrupt-parent pio; interrupts 1 3 IRQ_TYPE_EDGE_FALLING; // PB3 下降沿中断 }; };内核启动时会为i2c0创建设备节点/dev/i2c-0并根据compatible属性加载对应的驱动如果已编译进内核或作为模块。你的应用程序可以通过标准的 Linux I2C 接口如ioctl或i2c-dev或驱动提供的 sysfs 接口来访问这个传感器。关键点修改设备树后需要重新编译内核make kernel或至少重新编译设备树make dtbs。设备树二进制文件.dtb会被打包进最终的镜像中。5. 应用程序开发与调试实战系统定制好了最终是要跑自己的应用程序。在 Tina Linux 环境下开发应用核心是交叉编译。5.1 交叉编译环境配置Tina 编译完成后完整的工具链已经就绪路径通常在out/board/staging_dir/toolchain-arch/bin/。你可以通过以下方式设置环境变量export STAGING_DIR/path/to/tina-sdk/out/v853-perf1/staging_dir export PATH$STAGING_DIR/toolchain-arm_cortex-a7neon_gcc-8.4.0_musl_eabi/bin:$PATH export TARGET_CCarm-openwrt-linux-gcc export TARGET_CXXarm-openwrt-linux-g export TARGET_STRIParm-openwrt-linux-strip更简单的方法是直接使用 Tina SDK 提供的环境脚本source staging_dir/target-arch/environment-setup。配置好后执行arm-openwrt-linux-gcc --version验证。5.2 编写、编译与部署一个简单应用假设我们有一个简单的helloworld.c#include stdio.h int main() { printf(Hello, Tina Linux!\n); return 0; }使用交叉编译器编译并压缩体积arm-openwrt-linux-gcc -o helloworld helloworld.c -static # 静态链接避免库依赖问题 arm-openwrt-linux-strip helloworld # 去除调试符号减小体积部署到设备有多种方式通过网络如果设备已启动并连接网络可以使用scp上传。scp helloworld root192.168.1.100:/tmp/ ssh root192.168.1.100 /tmp/helloworld打包进镜像这是产品化的方式。如前所述创建一个 Tina 软件包将编译好的helloworld放入install阶段的目标目录。重新编译系统后它就会出现在根文件系统的指定位置如/usr/bin。通过 SD 卡或 U 盘对于开发板这是最直接的方式。将文件复制到存储设备的 FAT 分区在设备上挂载后执行。5.3 系统级调试技巧嵌入式开发调试能力至关重要。串口调试最根本确保bootargs中的console参数正确波特率匹配通常是115200。使用minicom,picocom或screen连接串口。内核启动信息、系统日志dmesg、应用打印printf都从这里输出。日志系统Tina 默认使用logd和logread。你的应用可以使用syslog库将日志发送到系统日志守护进程然后通过logread查看。这对于后台守护进程非常有用。核心转储Core Dump当程序崩溃时生成 core 文件便于分析。需要在系统配置中开启内核CONFIG_COREDUMPy文件系统通过make menuconfig在Base system - busybox中启用coreutils - enable debugger (core dump) support。同时设置 core 文件路径和模式echo /tmp/core.%e.%p /proc/sys/kernel/core_pattern ulimit -c unlimited程序崩溃后会在/tmp/下生成 core 文件将其拷贝到主机用交叉编译工具链中的gdb进行分析arm-openwrt-linux-gdb ./helloworld ./core.helloworld.1234。GDB 远程调试对于复杂问题这是终极武器。在目标板上运行gdbservergdbserver :2345 ./my_app在主机上使用交叉编译的gdb连接arm-openwrt-linux-gdb ./my_app (gdb) target remote 192.168.1.100:2345 (gdb) continue6. 系统烧录、启动与量产化考量6.1 镜像烧录工具与流程Tina Linux 生成的.img文件通常是一个完整的、包含分区表的磁盘镜像。烧录方式取决于设备的启动介质和烧录模式。SD 卡用于开发板直接使用dd命令。务必确认设备路径误操作会清空主机硬盘。sudo dd if./tina_v853-perf1_uart0.img of/dev/sdX bs1M statusprogress syncSPI NAND / eMMC通过 USB OTG 烧录这是全志芯片常用的FEL 模式。设备上电时特定引脚拉低进入 FEL 模式通过 USB 连接电脑。使用全志官方的sunxi-fel工具或 Tina SDK 中的sunxi-pack工具进行烧录。通常有一个打包脚本如pack.sh它会调用相关工具将各个分区镜像boot.img,rootfs.img等打包并烧录。量产工具对于工厂量产会使用更专业的工具如全志的 LiveSuit 或 PhoenixSuit它们支持通过 USB 进行稳定、批量的烧录。6.2 启动流程分析与优化了解启动流程有助于定位启动失败的问题ROM Code芯片内部固件初始化最基本硬件并从预定介质如 SPI Flash 的 0 地址加载 Bootloader。U-Boot初始化 DRAM、时钟等加载环境变量根据bootcmd从存储设备如 eMMC 的某个分区加载内核镜像uImage和设备树.dtb并传递bootargs给内核最后跳转到内核入口。Linux Kernel解压自身初始化 CPU、内存管理、设备树解析、驱动探测最后挂载根文件系统。用户空间内核启动第一个用户进程/sbin/init通常是 BusyBox 的 init进而执行/etc/inittab或/etc/init.d/中的脚本启动系统服务。启动优化方向U-Boot关闭不必要的命令和功能使用CONFIG_SKIP_LOWLEVEL_INIT如果时钟/DDR 已在 ROM Code 初始化。内核如前所述极致裁剪。使用CONFIG_CC_OPTIMIZE_FOR_SIZE。将非启动必须的驱动编译为模块。根文件系统使用只读的squashfs作为根文件系统主体搭配可读写的overlayfs如jffs2或ubifs分区。使用mdev或eudev的静态设备列表减少启动时间。Init 进程精简/etc/inittab和/etc/init.d/中的启动脚本并行启动非依赖的服务。6.3 量产化前的关键检查清单在将系统交付工厂量产前请逐一核对以下事项检查项目的与操作常见问题串口调试信息关闭或减少内核启动printk级别bootargs添加quiet移除调试符号。保留consolettyS0,115200以备售后调试。根文件系统只读确保根文件系统/挂载为只读或使用overlayfs将写操作重定向到独立分区。避免系统运行时关键文件被意外修改导致无法启动。默认网络配置清除测试用的静态 IP、Wi-Fi 密码等。配置为合理的出厂默认值如 DHCP。防止设备联网冲突或泄露信息。用户与密码修改默认 root 密码或禁用 root 远程登录。创建低权限用户用于维护。安全基线要求。自启动服务确保只有必要的守护进程如业务主程序、网络管理自启动。关闭telnetd、ftpd等测试服务。减少资源占用和安全风险。日志管理配置logrotate或限制日志文件大小避免日志写满存储。防止因存储空间耗尽导致系统异常。看门狗Watchdog启用硬件看门狗驱动并配置用户空间守护进程如watchdogd。确保设备在异常死机后能自动重启。OTA 升级支持设计好分区布局如 A/B 分区并集成可靠的升级脚本和校验机制。为后续固件远程升级预留通道。压力与老化测试对设备进行长时间高负载运行、反复重启、异常断电测试。提前发现硬件或软件在极端条件下的稳定性问题。7. 常见问题排查与经验实录即使流程再熟悉实际开发中依然会遇到各种“坑”。这里记录几个我印象最深的问题和解决方法。问题一编译时提示 “No rule to make target ‘…”现象执行make时报错找不到某个目标尤其是刚lunch一个新方案后。排查这通常是因为该方案对应的某些源码包或补丁缺失。首先检查dl/目录下对应的包是否存在且完整。其次检查package/下该包的Makefile中定义的下载 URL 是否有效。最后查看out/board/logs/下该包的编译日志看是否有更早的错误。解决手动下载缺失的包到dl/目录。对于补丁问题可以尝试暂时清空该包目录下的patches/文件夹或者根据错误信息手动修改补丁文件。问题二系统启动后网络不通有线现象内核启动正常但ifconfig看不到以太网接口或接口没有获取到 IP 地址。排查dmesg | grep eth或dmesg | grep dwmac根据网卡驱动查看内核是否成功识别到网卡硬件以及驱动加载情况。检查设备树中以太网控制器节点是否被启用status “okay”;PHY 的复位引脚、MDIO 总线配置是否正确。检查bootargs中是否传入了错误的 MAC 地址或其它网络参数。检查根文件系统中是否有/etc/init.d/network脚本以及/etc/config/network配置文件是否正确。解决根据排查结果修正设备树或配置文件。一个常见陷阱是 PHY 的复位引脚reset-gpios配置错误或极性不对导致 PHY 芯片未被正确初始化。问题三应用程序运行时出现 “Segmentation fault”现象交叉编译的程序在设备上运行立即或随机段错误。排查库依赖使用readelf -d ./your_app | grep NEEDED查看程序动态链接的库。在设备上使用ldd ./your_app检查这些库是否存在路径是否正确。静态链接-static可以彻底避免此问题。硬件差异你的开发主机是 x86_64设备是 ARM。确保没有执行任何与架构相关的未定义行为如对未对齐内存的访问。在编译时添加-Wall -Wextra显示所有警告。调试如前所述开启 core dump使用 gdb 分析。如果问题难以复现可以考虑在代码中添加详细的日志或使用strace跟踪系统调用。解决对于动态链接确保设备根文件系统上有完整的、版本匹配的动态链接库。将主机staging_dir/target-arch/lib/下的库拷贝到设备的/lib/下是一个方法但更好的方法是确保该库已通过 Tina 的包管理系统正确编译并包含在镜像中。问题四文件系统变为只读Read-only Filesystem现象系统运行一段时间后无法创建或删除文件提示只读文件系统。排查这通常是底层存储设备NAND Flash出现坏块或文件系统错误触发了内核的错误保护机制。dmesg查看是否有关于 MTD、UBI、JFFS2 或 FAT 分区的 I/O 错误日志。对于 Flash 设备检查是否启用了正确的 ECC 校验配置。检查存储设备是否因异常断电导致文件系统结构损坏。解决对于开发阶段可以重新烧录镜像。对于量产设备需要在产品设计中加入健壮的文件系统检查与修复机制如fsck在启动时运行并考虑使用更耐用的文件系统如f2fs对于 eMMC或带有损耗均衡的 UBI/UBIFS 对于 NAND Flash。开发 Tina Linux 系统的过程是一个不断与硬件细节、软件依赖和系统资源博弈的过程。它没有桌面 Linux 那样充裕的资源每一个字节的内存和每一毫秒的启动时间都可能需要去争取。但正是这种限制让成功启动并稳定运行自己定制的系统时带来的成就感也格外强烈。这份指南覆盖了从入门到进阶的主要路径但真正的精通还需要你在具体的项目中去解决那些独一无二的问题。记住善用串口日志、理解设备树、吃透构建系统是解决大多数问题的钥匙。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2629527.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!