ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

02-驱动设计的硬件基础

02-驱动设计的硬件基础 2.1 处理器2.1.1 通用处理器驱动工程师需要从处理器手册中提取的信息不是它有多少核而是地址空间布局外设寄存器的物理基地址、大小、是否可缓存。总线宽度与字节序32/64 位访问、大小端、是否支持非对齐访问。中断模型中断控制器类型x86 的 APIC、ARM 的 GIC、中断号空间、是否支持 MSI。缓存与一致性DMA 是否与 CPU 缓存一致决定要不要用dma_sync_*。启动流程复位向量、Boot ROM、谁负责加载内核。主流处理器家族家族典型场景驱动相关特点x86/x86_64PC、服务器、QEMU 默认平台独立的 I/O 端口空间inb/outb MMIOPCI/PCIe 枚举APIC 中断ARM/ARM64嵌入式、手机、开发板几乎只有 MMIO设备树描述硬件GIC IRQ domainRISC-V新兴嵌入式设备树PLIC/APLIC 中断控制器MIPS/PowerPC网络设备、历史平台各自的总线模型如 PowerPC 的 device tree 起源在 QEMU 中观察处理器# 宿主侧看虚拟 CPU 型号 qemu-system-x86_64 -cpu help | head -30 qemu-system-aarch64 -machine virt -cpu help | head -30 # guest 侧 cat /proc/cpuinfo lscpu cat /proc/interrupts # 每个 CPU 的中断计数观察中断亲和性 cat /proc/iomem # 物理地址空间布局等价于内存映射图2.1.2 数字信号处理器DSPDSP 与通用处理器的差异单周期乘加MAC、哈佛结构、循环寻址、定点运算、专用加速器。在 Linux 里 DSP 通常以三种形态出现独立核通过 remoteproc/rpmsg 与 Linux 通信drivers/remoteproc/、drivers/rpmsg/。同一 SoC 内的协处理器通过 mailbox 中断 共享内存通信drivers/mailbox/。作为外设的加速器通过 MMIO 寄存器投递任务例如加解密引擎drivers/crypto/。驱动视角的要点共享内存的 cache 一致性、mailbox 中断的时序、固件加载与版本协商。这些在 QEMU 里都能用 remoteproc/rpmsg 的虚拟实现CONFIG_RPMSG_VIRTIO、CONFIG_RPMSG_CHAR做实验。2.2 存储器原书按易失/非易失、可随机访问/块访问展开。现代驱动工程师需要掌握的分类与对应内核接口存储器类型特点内核接口 / 驱动子系统QEMU 实验SRAM片上、小容量、快ioremapreadl/writel或sram子系统自定义 QEMU 设备或ram后端SDRAM/DDR主存内存管理子系统、memblock、NUMA-m 2G即虚拟 DDRNOR Flash可执行、按扇区擦写MTD/CFI、physmap-drive ifpflashNAND Flash大容量、有坏块MTD/NAND 框架、UBI通过mtdram/nandsim模拟eMMC/SD块设备 命令协议MMC 子系统 块层-device sd-card、-drive ifsdEEPROM小容量、字节寻址at24I²C、spi-norSPIi2c-stubat24第 15 章持久内存字节寻址的非易失内存ndctl/dax/pmem-device virtio-pmem内存映射的关键概念必须掌握物理地址 ≠ 虚拟地址。驱动拿到的物理地址必须ioremap()才能访问返回的是void __iomem *只能用readl()/writel()系列访问不能直接解引用。MMIO 与 RAM 的区别MMIO 访问可能有副作用读清中断标志、写触发动作编译器/CPU 可能重排必须用readl()/writel()以及必要时readl_relaxed()wmb()。保留内存设备树reserved-memory节点、memblock_reserve()用于把某段 DDR 从内核分配器中排除供固件或 DMA 使用。# guest 中观察物理地址空间相当于看芯片手册的 memory map cat /proc/iomem | head -40 cat /proc/meminfo ls /sys/devices/system/memory/ dmesg | grep -i Memory:\|memblock2.3 接口与总线2.3.1 串口UART硬件要点TXD/RXD 交叉连接、波特率、数据位/停止位/校验位、流控RTS/CTS。TTL 电平与 RS-232 电平不同接错可能损坏器件。内核视角8250 系列drivers/tty/serial/8250/控制台在arch/x86/kernel/early_printk.c与kernel/printk/配合。驱动接口struct uart_port、uart_register_driver()、struct uart_ops。用户空间/dev/ttyS0、termiosstty、setserial。QEMU 实验# 把串口输出到宿主终端-nographic 自动完成或输出到文件/管道 qemu-system-x86_64 ... -nographic qemu-system-x86_64 ... -serial mon:stdio qemu-system-x86_64 ... -serial file:/tmp/serial.log # guest 中 stty -F /dev/ttyS0 115200 cat /proc/tty/driver/serial2.3.2 I²C硬件要点两根线SDA数据、SCL时钟必须外接上拉电阻这是新手最容易漏掉的硬件知识。开漏输出支持多主多从每个从设备有 7 位或 10 位地址。时序START → 地址读写位 → ACK → 数据字节 ACK → … → STOP。速率Standard 100 kHz、Fast 400 kHz、Fast 1 MHz、High-speed 3.4 MHz。常见坑地址7 位 vs 8 位写法混乱内核用 7 位地址、时钟拉伸clock stretching、总线死锁SDA 被拉低。内核视角核心层drivers/i2c/i2c-core-base.c适配器驱动drivers/i2c/busses/设备驱动客户端如drivers/misc/eeprom/at24.c。QEMU / 软件实验# 内核自带 i2c-stub不需要任何硬件模拟 SMBus 从设备 modprobe i2c-stub chip_addr0x50 ls /sys/bus/i2c/devices/ # 出现 i2c-0 适配器 i2cdetect -l i2cdetect -y 0 i2cset -y 0 0x50 0x00 0x41 # 往模拟 EEPROM 写数据 i2cget -y 0 0x50 0x00 dmesg | tail # i2c-stub 会打印每条命令详见第 15 章。2.3.3 SPI硬件要点四线SCLK、MOSI、MISO、CS片选低有效可扩展多 CS。全双工、主从模式模式 0/1/2/3 由 CPOL时钟极性和 CPHA时钟相位决定——这是 SPI 驱动最常见的调试点。速率可达几十 MHz因此对走线、阻抗、时序余量敏感。内核视角核心层drivers/spi/spi.c控制器驱动drivers/spi/设备驱动如drivers/spi/spidev.c用户空间与各类传感器驱动。QEMU / 软件实验# 1) 内核自带回环测试把 MOSI 与 MISO 短接的模型 modprobe spi_loopback_test dmesg | tail -30 # 2) 用户空间访问若控制器与 spidev 可用 ls /dev/spidev* spi-config -d /dev/spidev0.0 # spi-tools 包详见第 17 章。2.3.4 USB硬件要点主机侧EHCIUSB 2.0、xHCIUSB 3.x、OHCI/UHCIUSB 1.1。设备侧UDCUSB Device Controller Gadget 框架。拓扑主机 → 根 Hub → Hub → 设备设备内部有配置/接口/端点Endpoint三级结构。传输类型控制、批量、中断、等时。电气D/D- 差分对、VBUS 供电、Type-C 的 CC 线协商。内核视角drivers/usb/core/核心、drivers/usb/host/HCD、drivers/usb/gadget/Gadget、drivers/usb/class/设备类驱动。QEMU 实验# 主机侧加一个 xHCI 控制器和一个 USB 存储设备 qemu-system-x86_64 ... \ -device qemu-xhci,idxhci \ -drive idusbdisk,file/tmp/usb.img,ifnone,formatraw \ -device usb-storage,driveusbdisk,busxhci.0 # guest 中 lsusb ls /sys/bus/usb/devices/ dmesg | grep -i usbGadget 侧用dummy_hcdCONFIG_USB_DUMMY_HCD configfs 即可在没有真实 UDC 的情况下练习第 16 章。2.3.5 以太网接口硬件要点MAC控制器 PHY物理层通过 MII/RMII/RGMII 连接管理接口是 MDIO。PHY 内部有寄存器标准寄存器 0/1 提供 ID 与状态驱动需要读 PHY 状态判断链路。现代 SoC 常用MAC 内建、PHY 外置结构用设备树描述 PHY 地址与连接方式。内核视角net_device/netdev_ops、PHY 抽象层drivers/net/phy/、phylib与phylink。QEMU 实验-device virtio-net-pci或-netdev user -device e1000。ip link show ethtool eth0 cat /proc/net/dev dmesg | grep -i -E eth|virtio_net|e10002.3.6 PCI 和 PCI-E硬件要点配置空间前 64 字节标准头 能力链表包含 Vendor ID / Device ID / Class Code / BAR。BARBase Address Register决定设备寄存器映射到哪段物理地址驱动必须先pci_enable_device()再pci_request_regions()再pci_iomap()。中断传统 INTx、MSI、MSI-X现代设备首选 MSI-X支持多向量。PCIe 是点对点串行链路有链路训练、ASPM 电源管理、ATS/IOMMU 等特性。内核视角drivers/pci/设备驱动用struct pci_driver、pci_device_id定义在include/linux/device-id/pci.h。QEMU 实验qemu-system-x86_64 ... -device e1000 # 经典 PCI 网卡 lspci -nn -vv # guest 中查看配置空间 lspci -xxx # 原始配置空间十六进制2.3.7 SD 和 SDIO硬件要点SD 卡用于存储SDIO 用于外设Wi-Fi、蓝牙、GPS共用物理接口。命令/响应协议CMD0/CMD8/CMD17/CMD24…、总线宽度1/4/8 bit、高速模式、电压切换1.8V/3.3V。热插拔检测通过 CDCard Detect引脚或轮询。内核视角drivers/mmc/core/host块设备侧接入 blk-mqSDIO 设备驱动用struct sdio_driver、sdio_device_id。QEMU 实验qemu-system-x86_64 ... \ -drive idsd0,file/tmp/sd.img,ifnone,formatraw \ -device sd-card,drivesd02.4 CPLD 和 FPGA原书要点CPLD/FPGA 常被用来实现粘合逻辑或自定义外设驱动工程师面对的是厂商自己定义的寄存器接口没有标准协议必须读它的寄存器手册。7.2.5 语境下的三点更新FPGA 上的自定义 IP 越来越多地通过AXI/AHB 总线挂到 SoC 上用设备树描述compatible指向厂商字符串。FPGA 固件通过FPGA Manager 框架drivers/fpga/动态加载/sys/class/fpga_manager/name/firmware写入比特流。寄存器访问必须走ioremapreadl/writel并在需要时用readl_poll_timeout()做轮询等待。没有 FPGA 时如何练用软件模拟寄存器。两种方式QEMU 自定义设备模型在 QEMU 的hw/misc/里加一个小设备学习成本中等但最接近真实。内核模块模拟寄存器块自己写一个 platform 驱动用devm_kzalloc出来的内存当寄存器暴露 debugfs 或 sysfs 接口让上层驱动读它。这能完整练习寄存器语义 → 驱动逻辑的映射。2.5 原理图分析原书要点原理图告诉你哪个引脚连到哪个引脚。读原理图的顺序找到目标芯片的电源域哪些引脚供电电压多少。找到时钟输入晶振/外部时钟源频率。找到复位引脚高有效还是低有效。找到总线连接I²C 的 SDA/SCL 接到哪个控制器、上拉电阻多大SPI 的 CS 接到哪个片选。找到中断/GPIO 引脚连到哪个中断控制器有没有外部上拉。找到地址/片选译码CS 决定设备地址时地址怎么算。没有开发板时的替代方法把设备树当作软件原理图把 QEMU 源码当作虚拟原理图。# 1) 看真实平台的原理图设备树源码 ls arch/arm64/boot/dts/qcom/ | head sed -n 1,80p arch/arm64/boot/dts/arm/fvp-base-revc.dts # 2) 看 QEMU 的虚拟原理图设备模型如何连接 # 若获取了 QEMU 源码 ls hw/ ls hw/i2c/ hw/spi/ hw/gpio/ hw/usb/ # 3) 看内核的设备树绑定文档等价于接线规范 ls Documentation/devicetree/bindings/i2c/ cat Documentation/devicetree/bindings/i2c/i2c.txt 2/dev/null | head -40结论设备树里每一个reg、interrupts、clocks、gpios、pinctrl-0属性都对应原理图上的一根或一组连线。会读设备树就掌握了读软件原理图的能力。2.6 硬件时序分析2.6.1 时序分析的概念建立时间setup数据必须在时钟有效沿之前稳定的最短时间。保持时间hold数据必须在时钟有效沿之后保持的最短时间。传播延迟信号从 A 到 B 的时间。时钟频率与余量频率越高允许的延迟越小余量为负 偶发错误最难查的一类 bug。驱动工程师需要关注的时序有三类总线协议时序I²C 的 START/STOP、SPI 的 CPOL/CPHA、UART 的位宽——由控制器硬件完成但配置错误会导致通信失败。芯片控制时序复位脉冲宽度、上电到可访问的等待时间、命令间的延迟——由驱动用udelay/msleep或readl_poll_timeout()保证。中断/事件时序状态位何时置起、何时清除、清除与读的顺序——必须按数据手册的 read-clear / write-clear 语义写。2.6.2 典型的硬件时序I²C 写时序写一个字节到寄存器START | 从机地址(7bit)W | ACK | 寄存器地址(8bit) | ACK | 数据(8bit) | ACK | STOPSPI 模式选择模式CPOLCPHA采样沿000第一个沿上升101第二个沿下降210第一个沿下降311第二个沿上升设备树的spi-cpol/spi-cpha属性或驱动里的SPI_MODE_*宏就是配置这个。UART 一帧起始位(0) | D0 D1 D2 D3 D4 D5 D6 D7 | 校验位(可选) | 停止位(1)没有示波器时如何看时序# 1) 内核 I²C/SPI 的 tracepoint ls /sys/kernel/tracing/events/i2c/ cat /sys/kernel/tracing/events/i2c/i2c_write/enable # 2) 打开动态调试看控制器驱动打印的时序参数 echo module i2c_i801 p /sys/kernel/debug/dynamic_debug/control # 3) QEMU 的 trace 事件宿主侧 qemu-system-x86_64 ... -trace help | grep -i i2c qemu-system-x86_64 ... -trace i2c* -D /tmp/qemu-i2c.log # 4) 用逻辑分析仪模拟软件把 SPI/I²C 时序画出来 # sigrok/PulseView 支持导入 QEMU 或内核 ftrace 导出的数据2.7 芯片数据手册阅读方法标准阅读顺序这个方法论在任何时代都不过时Features/Overview先知道芯片能做什么、支持哪些总线、封装与引脚。Pin Description / Pinout确认电源、地、时钟、复位、总线、中断引脚。Block Diagram理解内部模块划分寄存器块、FIFO、DMA、中断。Electrical Characteristics电压范围、时序极限这些决定驱动里的延时与配置。Register Map地址偏移、位域定义、复位默认值、访问类型RO/RW/W1C。Functional Description每种工作模式的流程初始化顺序、命令序列。Errata勘误表这是原书强调、但新手最容易忽略的一节——很多驱动里莫名其妙的 workaround都来自这里。没有真实芯片手册时用以下材料替代需要的信息替代材料设备如何被描述Documentation/devicetree/bindings/子系统/厂商,设备.yaml寄存器语义内核中已有的同类驱动drivers/初始化序列驱动的probe()与*_init()函数时序要求驱动中的udelay/msleep/readl_poll_timeout勘误与 workaround驱动里的/* Erratum ... */注释与*_quirk变量虚拟设备的手册QEMU 的hw/设备模型源码 include/hw/寄存器定义练习方法挑一个内核里简单的 I²C 传感器驱动如drivers/iio/temperature/或drivers/hwmon/从probe()读起把它翻译成伪代码的寄存器操作序列。你会在 20 分钟内理解手册 → 驱动的映射关系。2.8 仪器仪表使用2.8.1 万用表用途测供电电压是否正常、地是否连通、复位引脚电平、总线空闲电平I²C 空闲时应为高如果为低说明总线被拉住或缺少上拉。没有硬件时的等价检查# regulator 电压是否正确 cat /sys/class/regulator/regulator.*/microvolts 2/dev/null # GPIO 电平通过 gpio-sim 或真实控制器 gpioset gpiochip0 31 gpioget gpiochip0 3 # I²C 从设备是否存在等价于总线上有没有器件响应 i2cdetect -y 02.8.2 示波器用途看时钟频率与占空比、看总线波形、看复位脉冲宽度、看信号完整性过冲/振铃。替代手段频率与时序参数内核时钟框架/sys/kernel/debug/clk/clk_summary能告诉你实际配置频率。波形ftrace的function_graph、irqsoff/preemptofftracer 能画出时间轴QEMU 的-trace与-icount能给出确定性时序。用trace-cmdkernelshark可以得到类似示波器的可视化时间轴。# 看各时钟实际频率等价于用示波器量时钟 cat /sys/kernel/debug/clk/clk_summary # 看中断时序 cat /sys/kernel/debug/tracing/trace2.8.3 逻辑分析仪用途抓多路数字信号解析 I²C/SPI/UART 协议定位谁在第几个字节出错。替代手段这是没有开发板时最有效的一招内核 tracepoint 当逻辑分析仪i2c、spi、gpio、irq、timer等子系统都有 tracepoint可以直接看到第几次传输、方向、长度、返回值。i2c-stub当日志型逻辑分析仪它会把每条 SMBus 命令打印到内核日志。spidevspi-loopback-test把 MOSI 与 MISO 短接验证控制器与驱动的完整路径。QEMU trace-trace i2c*、-trace usb*输出设备模型级别的事件。sigrok/PulseView支持多种数据源导入可以把 trace 数据转成波形图。# 打开 I²C tracepoint抓一次传输 echo 1 /sys/kernel/tracing/events/i2c/enable i2cget -y 0 0x50 0x00 cat /sys/kernel/tracing/trace | tail -202.9 总结处理器、存储器、总线是驱动必须理解的硬件三要素现代 SoC 把它们通过设备树/ACPI 暴露给内核。总线知识I²C/SPI/USB/PCIe/SDIO是后续章节的基础重点是协议时序 内核抽象 常见坑。原理图与数据手册的阅读方法是通用技能没有硬件时用设备树 内核绑定文档 现有驱动 QEMU 源码替代。仪器仪表的作用是观察信号与时间没有仪器时用tracepoint、ftrace、dynamic debug、QEMU trace、i2c-stub 日志获得同类信息。记住一条经验驱动里 80% 的疑难问题最后都能归结为时序不对或资源没准备好。
返回列表