杰瑞科技汇

嵌入式linux系统开发教程

嵌入式Linux系统开发终极指南

这份教程将整个开发过程分解为几个核心阶段,每个阶段都有明确的目标、学习资源和实践项目。

嵌入式linux系统开发教程-图1
(图片来源网络,侵删)

基础知识储备

在开始接触硬件和复杂的系统之前,你需要打下坚实的基础。

计算机基础

  • 操作系统原理: 理解进程、线程、内存管理、文件系统、I/O等基本概念。
  • 计算机网络: 掌握TCP/IP协议栈、HTTP、Socket编程等。
  • 数据结构与算法: 嵌入式开发中,高效的代码至关重要。

C语言编程

  • 核心语法: 指针、结构体、联合体、内存布局(栈、堆、静态/全局区)是重中之重。
  • Makefile: 学习如何编写Makefile来管理项目编译,这是嵌入式开发的必备技能。
  • GCC/GDB: 熟悉GCC编译器的常用选项,以及使用GDB进行程序调试。

Linux基础

嵌入式linux系统开发教程-图2
(图片来源网络,侵删)
  • Shell命令: 熟练使用 ls, cd, cp, mv, rm, grep, find, ssh, scp 等常用命令。
  • 文本编辑器: 至少熟练掌握一个,如 VimEmacs
  • 软件安装: 了解使用 apt (Debian/Ubuntu) 或 yum (CentOS) 管理软件包。
  • 用户与权限: 理解 sudo, chown, chmod 等命令。

推荐资源:

  • 书籍: 《C Primer Plus》、《C陷阱与缺陷》、《鸟哥的Linux私房菜》。
  • 在线: 菜鸟教程、Runoob、Coursera/edX上的相关课程。

嵌入式Linux开发环境搭建

这是从纯软件到软硬件结合的第一步,也是最关键的一步。

交叉编译工具链

  • 概念: 嵌入式设备的CPU架构(如ARM, MIPS)通常与你的开发主机(x86)不同,交叉编译工具链允许你在x86主机上编译出能在ARM上运行的程序。
  • 实践:
    • 获取工具链: 从芯片厂商(如NXP, TI, Allwinner)或第三方(如Linaro)获取预编译好的工具链。
    • 配置环境: 将工具链的 bin 目录添加到系统的 PATH 环境变量中。
    • 验证: 使用 arm-linux-gnueabihf-gcc --version 命令检查是否成功。

开发主机与目标板的连接

嵌入式linux系统开发教程-图3
(图片来源网络,侵删)
  • 网络连接: 最常用方式,通过以太网或Wi-Fi将开发主机和目标板连接到同一局域网。
  • 串口连接: 用于获取目标板的启动信息、系统日志和交互式Shell,你需要一个USB转TTL模块(如CH340/FT232)和串口终端软件(如 minicom, picocom, SecureCRT)。

文件传输

  • NFS (Network File System): 将开发主机的一个目录共享给目标板,目标板可以直接挂载并运行该目录下的程序,无需每次都烧写到板子上,极大加快开发调试速度。
  • TFTP (Trivial File Transfer Protocol): 通常用于通过U-Boot将内核、设备树和根文件系统镜像传输到目标板的内存中。

实践项目:

  • 搭建好你的开发环境,确保能通过串口登录到目标板,并且能通过NFS挂载主机目录。

引导加载程序 - U-Boot

U-Boot是系统启动的第一段代码,负责初始化硬件、加载操作系统内核并启动它。

U-Boot核心概念

  • 启动流程: 上电 -> 执行第一阶段代码(通常在内部ROM/SRAM)-> 加载第二阶段代码到RAM -> 执行初始化 -> 加载内核。
  • 常用命令:
    • help: 查看所有可用命令。
    • printenv / setenv: 查看和设置环境变量。
    • ping: 测试网络连接。
    • tftpboot: 通过TFTP下载文件到内存。
    • bootcmd: 自动启动命令,通常是 tftpboot + bootm 的组合。
    • bootm: 加载并启动内核镜像。

移植与配置

  • 获取源码: 从 U-Boot官网 下载。
  • 配置: 进入源码目录,使用 make <board_name>_config 命令配置,对于树莓派4,可能是 make rpi_4_defconfig
  • 编译: make CROSS_COMPILE=arm-linux-gnueabihf- 进行编译。
  • 烧写: 将生成的 u-boot.bin 或类似文件烧写到目标板的存储介质中。

实践项目:

  • 熟悉U-Boot的常用命令,手动通过TFTP下载一个Linux内核镜像和设备树文件,并尝试启动它。

Linux内核

内核是操作系统的核心,管理着所有硬件资源。

内核核心概念

  • 进程管理: 调度、创建、销毁进程。
  • 内存管理: 虚拟内存、物理内存管理。
  • 设备驱动: 让内核能够与硬件(如串口、网卡、I2C设备)通信。
  • 系统调用: 用户程序请求内核服务的接口。

内核配置与编译

  • 获取源码: 从 The Linux Kernel Archives 下载。
  • 配置: 使用 make menuconfig 进入图形化配置界面,选择你的目标板架构、CPU型号、需要的驱动(如串口、网卡、文件系统)等。
  • 编译: make CROSS_COMPILE=arm-linux-gnueabihf- -j$(nproc) 进行编译。-j$(nproc) 使用所有CPU核心进行并行编译,速度更快。
  • 输出: 编译完成后,在 arch/arm/boot/ 目录下会生成 zImage (ARM内核镜像) 和 dts 目录(设备树源文件编译后的产物)。

设备树

  • 作用: 描述硬件的拓扑结构,如CPU有多少个核、外设(串口、I2C、SPI)的地址和中断号等,它让内核可以“无感知”地运行在不同但相似的硬件上。
  • 实践: 学习设备树语法,修改目标板对应的设备树文件(.dts),然后重新编译内核。

实践项目:

  • 下载一个主线内核,针对你的开发板进行配置和编译,生成内核镜像和设备树文件。

根文件系统

根文件系统是内核启动后挂载的第一个文件系统,它包含了运行系统所需的基本程序、库和配置文件。

根文件系统类型

  • RAM Disk: 早期方式,整个文件系统加载到RAM中。
  • Initramfs: 更现代的RAM Disk,由CPIO格式打包,内核可以自动解压。
  • Flash File System: 直接存储在Flash或eMMC上,如 jffs2, ubifs
  • Network File System: 从网络挂载,如NFS。

构建根文件系统

  • Busybox: 一个集成了大量常用Linux命令(如 sh, ls, cp, ifconfig)的工具集,它是构建最小化根文件系统的核心。
  • 构建流程:
    1. 编译安装Busybox: 配置、编译Busybox,并选择需要包含的命令,make install 将文件安装到一个目录(如 rootfs)。
    2. 创建必要目录: 在 rootfs 中创建 dev, proc, sys, etc 等标准目录。
    3. 创建设备节点: 使用 mdevudev 自动创建,或手动创建。
    4. 创建启动脚本: 在 etc/inittabetc/init.d/rcS 中编写启动脚本,挂载文件系统、启动必要服务等。
    5. 打包: 将 rootfs 目录打包成 cpio 文件,再压缩成 gzip 格式,得到 initramfs 镜像。

实践项目:

  • 使用Busybox手动构建一个最简单的根文件系统,包含基本的Shell、网络工具和启动脚本。

应用层开发

当系统跑起来后,大部分工作都是在应用层完成的。

应用程序开发

  • 标准C/C++应用: 在开发主机上编写代码,使用交叉编译工具链编译,然后通过NFS或SCP放到目标板上运行。
  • 多线程/多进程: 使用 pthread 库进行多线程编程。
  • 网络编程: 使用 Socket API开发网络客户端和服务端程序。

系统编程

  • 文件I/O: open, read, write, close, lseek
  • 进程控制: fork, exec, wait, exit
  • 信号处理: signal, sigaction
  • 进程间通信: 管道、消息队列、共享内存、信号量。

开发调试工具

  • GDB (远程调试): 在开发主机上运行 gdb,在目标板上运行 gdbserver,可以实现对目标板上程序的源码级断点调试。
  • strace: 跟踪程序发出的系统调用。
  • ltrace: 跟踪程序调用的库函数。
  • dmesg: 查看内核打印的日志。

实践项目:

  • 开发一个简单的Web服务器,在目标板上运行,并能通过浏览器访问。
  • 编写一个程序,通过I2C或GPIO与板上的一个传感器(如温湿度传感器)进行通信。

高级主题与最佳实践

当你掌握了以上所有内容后,可以探索更高级的领域。

  1. Yocto Project: 学习使用Yocto Project来构建一个定制化、可重复、工业级的Linux发行版,它比手动构建根文件系统复杂得多,但提供了更强的灵活性和可维护性。
  2. 设备驱动开发: 深入学习内核,编写自己的字符设备驱动、平台驱动或I2C/SPI设备驱动。
  3. Buildroot: 一个比Yocto更简单的构建系统,用于生成完整的、定制的Linux系统,对于快速原型开发非常有用。
  4. 实时性: 了解Linux的实时性补丁,学习如何将Linux改造成一个实时操作系统。
  5. 安全: 学习嵌入式系统安全,如文件系统加密、安全启动、安全Shell等。

学习路径总结

阶段 关键技能/工具 实践项目
基础 C语言, Linux基础, 计算机网络 GCC, GDB, Shell 编写一个简单的C程序并调试
环境 交叉编译, 主机-板子连接 交叉工具链, TFTP, NFS, Minicom 搭建开发环境,通过串口登录板子
U-Boot 启动流程, 常用命令, 移植 U-Boot命令, make menuconfig 手动通过U-Boot启动内核
内核 内核配置, 编译, 设备树 make menuconfig, make, DTS 编译一个支持自己板子的内核
根文件系统 Busybox, Initramfs构建 Busybox, CPIO 手动构建一个最小根文件系统
应用开发 应用程序, 系统编程, 调试 Socket, strace, GDB远程调试 开发一个Web服务器或传感器应用
高级 Yocto, 驱动开发, Buildroot Yocto, Buildroot, 内核模块 使用Yocto/Buildroot构建一个完整系统

推荐硬件平台

  • 初学者: 树莓派BeagleBone Black,社区支持强大,资料丰富,自带Linux系统,可以快速上手。
  • 进阶/商业项目: i.MX系列 (NXP), AM/DM系列 (TI/Allwinner),这些是工业界主流的SoC,学习它们对找工作非常有帮助。

嵌入式Linux开发是一个庞大但非常有魅力的领域,这条路需要大量的动手实践和耐心,不要害怕失败,解决问题本身就是学习过程的一部分,祝你学习顺利!

分享:
扫描分享到社交APP
上一篇
下一篇