第八章:驱动程序开发与文件系统¶
——“让硬件会说话、让数据不掉链”的完整指南
本章采用“硬件→驱动模型→代码模板→文件系统→量产脚本”五步走,所有示例均基于 Linux 内核 5.x / RTOS 双场景,可直接拷贝到项目中编译运行。
──────────────────
1 驱动程序:硬件与 OS 的“翻译层”¶
1.1 三种数据交互模型¶
| 模型 | 原理 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| 轮询 (Polling) | CPU 死循环读寄存器 | 实现简单 | 100 % CPU 占用 | 启动阶段/调试 |
| 中断驱动 | 设备就绪触发 ISR | CPU 0 % 等待 | 上下文切换开销 | 字符设备、GPIO |
| DMA | 外设 ↔ 内存 搬运 | CPU 解放 | 配置复杂、Cache 一致 | 音视频、SDIO |
1.2 Linux 内核驱动三大件¶
• 字符设备 (cdev) — 串口、ADC、PWM
• 块设备 (block_device) — eMMC、SD、NAND
• 网络设备 (net_device) — Wi-Fi、Ethernet
1.3 最小字符设备模板(Linux)¶
#include <linux/module.h>
#include <linux/fs.h>
#define DEV_NAME "myled"
static int major;
static ssize_t myled_write(struct file *f, const char __user *buf,
size_t len, loff_t *off)
{
u8 val;
if (copy_from_user(&val, buf, 1))
return -EFAULT;
iowrite32(val ? 1:0, GPIO_BASE + GPIO_DR);
return 1;
}
static const struct file_operations fops = {.write = myled_write};
static int __init myled_init(void)
{
major = register_chrdev(0, DEV_NAME, &fops);
return 0;
}
module_init(myled_init);
MODULE_LICENSE("GPL");
obj-m += myled.o
all:
make -C $(KDIR) M=$(PWD) modules
1.4 RTOS(FreeRTOS)最小驱动¶
void vADCTask(void *pv)
{
for (;;) {
uint16_t val = ADC1->DR;
xQueueSend(adcQueue, &val, 0);
vTaskDelay(pdMS_TO_TICKS(100));
}
}
1.5 并发/同步原语¶
Linux:
- spinlock_t — 中断上下文
- mutex — 进程上下文
- completion — 等待硬件完成
FreeRTOS:
- SemaphoreHandle_t (二值/计数)
- xQueue
──────────────────
2 文件系统:让数据“住得安心”¶
2.1 嵌入式对文件系统的 3 大刚需¶
| 需求 | 技术实现 | 关键参数 |
|---|---|---|
| 掉电保护 | 日志 (Journaling)、Copy-on-Write | 掉电 0 秒数据丢失 |
| 磨损均衡 | 动态/静态均衡、垃圾回收 | 写放大 < 2 |
| 小容量 | 元数据开销 < 5 % | 4 KB 页对齐 |
2.2 常见文件系统横向对比¶
| 类型 | 介质 | 掉电保护 | 磨损均衡 | 最大容量 | 元数据 | 典型挂载 |
|---|---|---|---|---|---|---|
| FAT32 | SD/eMMC | 无 | 无 | 2 TB | 4 KB | 车载娱乐 |
| exFAT | SDXC | 无 | 无 | 128 PB | 4 KB | 摄像机 |
| JFFS2 | NOR Flash | 日志 | 动态 | 128 MB | 节点级 | 路由器 |
| YAFFS2 | NAND SLC | 日志 | 动态 | 2 GB | 页级 | 早期手机 |
| UBIFS | Raw NAND | 日志 + UBI | UBI 均衡 | 1 TB | 子页 | 工业网关 |
| SPIFFS | SPI NOR | 日志 | 静态 | 16 MB | 2 KB | 传感器节点 |
| LittleFS | NOR/NAND | COW + 日志 | 动态 | 2 GB | 32 B | MCU/MPU |
2.3 使用示例¶
• Linux 挂载 UBIFS
# 1. 创建 UBI 卷
ubiattach /dev/ubi_ctrl -m 2
ubimkvol /dev/ubi0 -N rootfs -s 100MiB
# 2. 格式化 & 挂载
mkfs.ubifs -r rootfs/ -m 2048 -e 126976 -c 800 -o rootfs.ubifs
mount -t ubifs ubi0:rootfs /mnt
• RTOS(LittleFS)
lfs_t lfs;
const struct lfs_config cfg = {
.read = flash_read,
.prog = flash_prog,
.erase = flash_erase,
.sync = flash_sync,
.block_size = 4096,
.block_count = 2048,
};
lfs_mount(&lfs, &cfg);
2.4 掉电保护实现细节¶
- LittleFS:采用 COW + 日志双保险
– 任何页在写入前会复制到新位置
– 元数据块尾部追加日志,掉电后重放 - UBIFS:依赖 UBI layer
– UBI 记录擦除计数,实现动态磨损均衡
– 掉电后扫描卷表 (volume table) 恢复
──────────────────
3 量产脚本示例¶
#!/bin/bash
# flash.sh – 一键烧录
IMG=rootfs.squashfs
DEV=/dev/mtd2
flash_erase $DEV 0 0
nandwrite -p $DEV $IMG
──────────────────
4 一页速查表¶
| 场景 | 推荐 FS | 挂载命令 | 注意 |
|---|---|---|---|
| SD 卡 | exFAT | mount -t exfat /dev/mmcblk0p1 /mnt |
需 CONFIG_EXFAT_FS |
| SPI NOR | LittleFS | lfs_mount |
用 4 KB 对齐 |
| Raw NAND | UBIFS | mount -t ubifs ubi0:rootfs /mnt |
先 ubiattach |
| 日志记录 | JFFS2 | mount -t jffs2 /dev/mtdblock0 /mnt |
预留 5 % 空间 |
这张表90 % 的“文件系统选哪个”问题可在 30 秒内解决。
How does DMA improve data transfer efficiency?¶
DMA improves efficiency by off-loading the actual data movement from the CPU to a dedicated peripheral engine.
Key gains:
- CPU cycles freed – The processor only sets up the transfer (source, destination, length) and can run other tasks or enter sleep while DMA runs.
- Higher throughput – DMA engines often sit directly on the AHB/AXI bus and can saturate memory bandwidth; e.g., STM32H7’s DMA moves 16 MB/s vs ≈ 2 MB/s with a tight CPU loop.
- Lower latency – No context-switch overhead or interrupt jitter for every word; interrupts arrive only on completion or error.
- Burst & FIFO optimizations – DMA uses burst transfers and FIFO buffering, reducing bus arbitration and wait states.
- Scalable parallelism – Multiple DMA streams can run simultaneously, overlapping peripheral-to-memory, memory-to-memory, and even memory-to-peripheral transfers.
In short, DMA replaces “CPU bit-banging” with hardware-accelerated, autonomous data pipelines, cutting both time and energy per byte.