Kaynağa Gözat

lint: prettier 格式化嵌入式驱动知识库(LF 行尾)

- npx prettier --write --end-of-line lf \**/*.md\
- 统一表格对齐、列表标记与空行,规范 markdown 排版
OpenCode 1 gün önce
ebeveyn
işleme
80a66dcfc2
37 değiştirilmiş dosya ile 628 ekleme ve 662 silme
  1. 16 18
      X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/01-ARM架构与裸机编程/01-Cortex-A7架构详解.md
  2. 21 22
      X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/01-ARM架构与裸机编程/02-ARM汇编基础.md
  3. 66 68
      X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/01-ARM架构与裸机编程/03-时钟与电源管理.md
  4. 27 29
      X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/01-ARM架构与裸机编程/04-GPIO与中断系统.md
  5. 36 40
      X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/01-ARM架构与裸机编程/05-定时器与看门狗.md
  6. 0 1
      X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/01-ARM架构与裸机编程/07-BSP工程管理与封装.md
  7. 54 58
      X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/01-ARM架构与裸机编程/08-裸机实验总结.md
  8. 1 3
      X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/01-ARM架构与裸机编程/面试-ARM架构与裸机.md
  9. 0 3
      X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/02-嵌入式Linux内核基础/01-内核编译与配置.md
  10. 8 8
      X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/02-嵌入式Linux内核基础/02-内核模块编程.md
  11. 2 2
      X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/02-嵌入式Linux内核基础/04-进程调度与中断管理.md
  12. 1 1
      X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/02-嵌入式Linux内核基础/05-内存管理.md
  13. 4 4
      X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/02-嵌入式Linux内核基础/面试-Linux内核基础.md
  14. 22 23
      X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/03-Linux驱动开发核心/01-字符设备驱动基础.md
  15. 31 32
      X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/03-Linux驱动开发核心/02-设备树语法与实战.md
  16. 4 4
      X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/03-Linux驱动开发核心/03-pinctrl与gpio子系统.md
  17. 101 88
      X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/03-Linux驱动开发核心/04-并发同步与原子操作.md
  18. 16 17
      X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/03-Linux驱动开发核心/05-中断下半部处理.md
  19. 0 1
      X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/03-Linux驱动开发核心/06-阻塞IO与poll机制.md
  20. 21 22
      X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/03-Linux驱动开发核心/面试-Linux驱动开发.md
  21. 8 8
      X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/04-Linux总线与接口驱动/01-I2C驱动开发.md
  22. 0 1
      X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/04-Linux总线与接口驱动/02-SPI驱动开发.md
  23. 56 57
      X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/04-Linux总线与接口驱动/03-USB驱动开发.md
  24. 13 13
      X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/04-Linux总线与接口驱动/04-CAN驱动开发.md
  25. 0 1
      X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/04-Linux总线与接口驱动/05-RS232与485通信.md
  26. 6 8
      X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/05-Linux外设驱动实战/01-LED与蜂鸣器驱动.md
  27. 7 8
      X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/05-Linux外设驱动实战/02-按键驱动.md
  28. 0 1
      X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/05-Linux外设驱动实战/04-触摸屏驱动.md
  29. 0 1
      X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/05-Linux外设驱动实战/05-音频驱动.md
  30. 4 4
      X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/05-Linux外设驱动实战/06-RTC与PWM驱动.md
  31. 7 10
      X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/05-Linux外设驱动实战/07-ADC与IIO驱动.md
  32. 25 27
      X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/05-Linux外设驱动实战/08-块设备驱动.md
  33. 11 16
      X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/05-Linux外设驱动实战/面试-外设驱动实战.md
  34. 16 18
      X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/06-系统移植与启动/01-U-Boot命令与使用.md
  35. 20 21
      X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/06-系统移植与启动/02-U-Boot启动流程.md
  36. 11 11
      X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/06-系统移植与启动/03-Linux内核裁剪与编译.md
  37. 13 13
      X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/06-系统移植与启动/04-根文件系统构建.md

+ 16 - 18
X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/01-ARM架构与裸机编程/01-Cortex-A7架构详解.md

@@ -16,13 +16,13 @@ pdf_ref: "【正点原子】I.MX6U嵌入式Linux驱动开发指南V2.0.1 - 第
 
 ### 1.1 ARM架构演进
 
-| 架构版本 | 代表核心         | 应用领域   | 关键特性           |
-| -------- | ---------------- | ---------- | ------------------ |
-| ARMv7-A  | Cortex-A7/A9/A15 | 应用处理器 | MMU、VFP、NEON     |
-| ARMv7-R  | Cortex-R4/R5/R7  | 实时处理器 | MPU、低延迟        |
-| ARMv7-M  | Cortex-M3/M4/M7  | 微控制器   | NVIC、Thumb-2      |
+| 架构版本 | 代表核心         | 应用领域   | 关键特性            |
+| -------- | ---------------- | ---------- | ------------------- |
+| ARMv7-A  | Cortex-A7/A9/A15 | 应用处理器 | MMU、VFP、NEON      |
+| ARMv7-R  | Cortex-R4/R5/R7  | 实时处理器 | MPU、低延迟         |
+| ARMv7-M  | Cortex-M3/M4/M7  | 微控制器   | NVIC、Thumb-2       |
 | ARMv8-A  | Cortex-A53/A72   | 64位应用   | AArch64、big.LITTLE |
-| ARMv9-A  | Cortex-A510/A710 | 最新一代   | SVE2、CCA          |
+| ARMv9-A  | Cortex-A510/A710 | 最新一代   | SVE2、CCA           |
 
 ### 1.2 Cortex-A7架构定位
 
@@ -119,16 +119,16 @@ Cortex-A7 MPCore多核配置的关键组件:
 
 ARM架构提供了16个32位通用寄存器(R0~R15)供软件使用:
 
-| 寄存器 | 别名 | 分类         | 说明                                  |
-| ------ | ---- | ------------ | ------------------------------------- |
-| R0~R7  | -    | 未备份寄存器 | 所有模式共享同一组物理寄存器          |
-| R8~R12 | -    | 备份寄存器   | FIQ模式下有独立物理寄存器             |
-| R13    | SP   | 栈指针       | 每种模式有自己的SP(共8个物理寄存器) |
-| R14    | LR   | 链接寄存器   | 保存子程序返回地址(共7个物理寄存器) |
-| R15    | PC   | 程序计数器   | 保存当前执行指令地址+8字节            |
-| CPSR   | -    | 当前程序状态 | 所有模式共享一个物理寄存器            |
-| SPSR   | -    | 备份程序状态 | 异常模式下保存CPSR的备份              |
-| ELR_hyp | -   | 异常链接寄存器 | Hyp 模式独有,保存虚拟化异常返回地址  |
+| 寄存器  | 别名 | 分类           | 说明                                  |
+| ------- | ---- | -------------- | ------------------------------------- |
+| R0~R7   | -    | 未备份寄存器   | 所有模式共享同一组物理寄存器          |
+| R8~R12  | -    | 备份寄存器     | FIQ模式下有独立物理寄存器             |
+| R13     | SP   | 栈指针         | 每种模式有自己的SP(共8个物理寄存器) |
+| R14     | LR   | 链接寄存器     | 保存子程序返回地址(共7个物理寄存器) |
+| R15     | PC   | 程序计数器     | 保存当前执行指令地址+8字节            |
+| CPSR    | -    | 当前程序状态   | 所有模式共享一个物理寄存器            |
+| SPSR    | -    | 备份程序状态   | 异常模式下保存CPSR的备份              |
+| ELR_hyp | -    | 异常链接寄存器 | Hyp 模式独有,保存虚拟化异常返回地址  |
 
 **寄存器总量小结**(原书第六章 6.3 节):
 
@@ -179,7 +179,6 @@ ELR_hyp      -       -       -        -        -        -        -        -
 
 **R8~R12**:在FIQ模式下有独立的物理寄存器(R8_fiq~R12_fiq),其他模式共享R8~R12。FIQ是快速中断模式,中断处理程序可以使用R8~R12而无需执行保存/恢复指令,从而加速中断执行。
 
-
 **R13(SP,栈指针)**:共8个物理寄存器,User/Sys共享一个,其余7种模式各对应一个。应用程序初始化时需设置各模式的SP指向专用栈地址。
 
 **R14(LR,链接寄存器)**:共7个物理寄存器,User/Sys/Hyp共享一个,其余6种模式各一个。LR的两个主要用途:
@@ -306,7 +305,6 @@ Cortex-A7使用32位地址线,总寻址空间为4GB(0x00000000~0xFFFFFFFF)
 
 > 说明:I.MX6U-ALPHA 开发板 DDR 起始地址均为 **0x8000_0000**,512MB 型号终止于 **0x9FFF_FFFF**,256MB 型号终止于 **0x8FFF_FFFF**;裸机程序统一链接到 **0x8780_0000**(与 U-Boot 保持一致)。
 
-
 **LPAE(Large Physical Address Extension)**:支持40位存储地址,最高可访问1TB内存。
 
 ### 3.2 L1 Cache

+ 21 - 22
X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/01-ARM架构与裸机编程/02-ARM汇编基础.md

@@ -60,11 +60,11 @@ ARM 32位指令格式:
 
 原书第 7.2.1 节重点讲解的三个数据传输指令:
 
-| 指令        | 目的 | 源   | 描述                                       |
-| ----------- | ---- | ---- | ------------------------------------------ |
-| `MOV R0,R1` | R0   | R1   | 将 R1 里面的数据复制到 R0 中                |
-| `MRS R0,CPSR` | R0 | CPSR | 将特殊寄存器 CPSR 里面的数据复制到 R0 中    |
-| `MSR CPSR,R1` | CPSR | R1 | 将 R1 里面的数据复制到特殊寄存器 CPSR 里中  |
+| 指令          | 目的 | 源   | 描述                                       |
+| ------------- | ---- | ---- | ------------------------------------------ |
+| `MOV R0,R1`   | R0   | R1   | 将 R1 里面的数据复制到 R0 中               |
+| `MRS R0,CPSR` | R0   | CPSR | 将特殊寄存器 CPSR 里面的数据复制到 R0 中   |
+| `MSR CPSR,R1` | CPSR | R1   | 将 R1 里面的数据复制到特殊寄存器 CPSR 里中 |
 
 ```asm
 MOV R0, R1           @ R0 = R1
@@ -195,12 +195,12 @@ LDMFD SP!, {R0~R3, R12}   @ 再恢复 R0~R3,R12
 
 > ⚠️ **来源说明**:本小节不属于原书第七章内容,为扩展知识;原书只讲解了 STM/LDM 与 STMFD/LDMFD。
 
-| 后缀 | 模式   | 用途                |
-| ---- | ------ | ------------------- |
-| IA   | 后递增 | 连续内存读取        |
-| IB   | 前递增 | 连续内存写入        |
-| DA   | 后递减 | 逆序内存读取        |
-| DB   | 前递减 | 堆栈压入            |
+| 后缀 | 模式   | 用途         |
+| ---- | ------ | ------------ |
+| IA   | 后递增 | 连续内存读取 |
+| IB   | 前递增 | 连续内存写入 |
+| DA   | 后递减 | 逆序内存读取 |
+| DB   | 前递减 | 堆栈压入     |
 
 > 堆栈类型后缀(FD/FA/ED/EA)用于描述堆栈模型,其中 **FD(满递减)为 ARM 默认**,对应 `STMFD`/`LDMFD`;不要把 FD 与 IA/IB/DA/DB 混为同类后缀。x86 使用的是空递减(ED)模型。
 
@@ -223,7 +223,7 @@ BLX function        @ 结合BX和BL:跳转到Rm指定地址、保存返回地
 | `B <label>`  | 跳转到 label;若跳转范围超过 ±2KB,可用 `B.W <label>` 使用 32 位版本 |
 | `BX <Rm>`    | 间接跳转,跳转到 Rm 中保存的地址处,并且切换指令集                   |
 | `BL <label>` | 跳转到标号地址,并将返回地址保存在 LR 中                             |
-| `BLX <Rm>`   | 结合 BX 和 BL 的特点,跳转到 Rm 指定地址、保存返回地址、切换指令集    |
+| `BLX <Rm>`   | 结合 BX 和 BL 的特点,跳转到 Rm 指定地址、保存返回地址、切换指令集   |
 
 **原书示例**:汇编初始化 C 运行环境后跳转到 main(B 指令,不返回):
 
@@ -284,15 +284,15 @@ MOVNE R1, #1        @ R0!=10时执行
 
 原书第 7.1 节列出的常用伪操作:
 
-| 伪操作   | 说明                                                     |
-| -------- | -------------------------------------------------------- |
-| `.byte`  | 定义单字节数据,如 `.byte 0x12`                          |
-| `.short` | 定义双字节数据,如 `.short 0x1234`                       |
-| `.long`  | 定义 4 字节数据,如 `.long 0x12345678`                   |
-| `.equ`   | 赋值语句,格式 `.equ 变量名, 表达式`,如 `.equ num, 0x12` |
-| `.align` | 数据字节对齐,如 `.align 4` 表示 4 字节对齐              |
-| `.end`   | 表示源文件结束                                           |
-| `.global`| 定义一个全局符号,格式 `.global symbol`,如 `.global _start` |
+| 伪操作    | 说明                                                         |
+| --------- | ------------------------------------------------------------ |
+| `.byte`   | 定义单字节数据,如 `.byte 0x12`                              |
+| `.short`  | 定义双字节数据,如 `.short 0x1234`                           |
+| `.long`   | 定义 4 字节数据,如 `.long 0x12345678`                       |
+| `.equ`    | 赋值语句,格式 `.equ 变量名, 表达式`,如 `.equ num, 0x12`    |
+| `.align`  | 数据字节对齐,如 `.align 4` 表示 4 字节对齐                  |
+| `.end`    | 表示源文件结束                                               |
+| `.global` | 定义一个全局符号,格式 `.global symbol`,如 `.global _start` |
 
 ```asm
 .byte 0x12           @ 定义8位数据
@@ -499,7 +499,6 @@ loop:
     B loop                 @ 死循环,保持LED亮
 ```
 
-
 ### 7.2 代码逐行解释
 
 | 行号 | 指令                  | 说明                         |

+ 66 - 68
X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/01-ARM架构与裸机编程/03-时钟与电源管理.md

@@ -46,15 +46,15 @@ graph TD
     PLL3 --> PFD3_3["PLL3_PFD3 (455 MHz)"]
 ```
 
-| PLL  | 名称       | 倍频方式        | 输出频率     | 主要用途                       |
-| ---- | ---------- | --------------- | ------------ | ------------------------------ |
-| PLL1 | ARM_PLL    | 可编程 (54~108) | 最高 1.3 GHz | ARM 内核主频                   |
-| PLL2 | System_PLL | 固定 ×22        | 528 MHz      | 系统总线、DDR、NAND/NOR        |
-| PLL3 | USB1_PLL   | 固定 ×20        | 480 MHz      | USB1 PHY + 4 路 PFD            |
-| PLL4 | AUDIO_PLL  | 可编程          | 650~1300 MHz | 音频外设 (ESAI 等),最终输出可选 1/2/4 分频 |
+| PLL  | 名称       | 倍频方式        | 输出频率     | 主要用途                                        |
+| ---- | ---------- | --------------- | ------------ | ----------------------------------------------- |
+| PLL1 | ARM_PLL    | 可编程 (54~108) | 最高 1.3 GHz | ARM 内核主频                                    |
+| PLL2 | System_PLL | 固定 ×22        | 528 MHz      | 系统总线、DDR、NAND/NOR                         |
+| PLL3 | USB1_PLL   | 固定 ×20        | 480 MHz      | USB1 PHY + 4 路 PFD                             |
+| PLL4 | AUDIO_PLL  | 可编程          | 650~1300 MHz | 音频外设 (ESAI 等),最终输出可选 1/2/4 分频     |
 | PLL5 | VIDEO_PLL  | 可编程          | 650~1300 MHz | 显示外设 (LCD 等),最终输出可选 1/2/4/8/16 分频 |
-| PLL6 | ENET_PLL   | 固定 ×(20+5/6)  | 500 MHz      | 以太网时钟 (25/50/100/125 MHz) |
-| PLL7 | USB2_PLL   | 固定 ×20        | 480 MHz      | USB2 PHY                       |
+| PLL6 | ENET_PLL   | 固定 ×(20+5/6)  | 500 MHz      | 以太网时钟 (25/50/100/125 MHz)                  |
+| PLL7 | USB2_PLL   | 固定 ×20        | 480 MHz      | USB2 PHY                                        |
 
 > 原书第 16.1.2 节列举的 7 路 PLL 顺序为:① ARM_PLL(PLL1) ② 528_PLL(PLL2) ③ USB1_PLL(PLL3) ④ USB2_PLL(**PLL7**,序号为 4 但实际是 PLL7) ⑤ ENET_PLL(PLL6) ⑥ VIDEO_PLL(PLL5) ⑦ AUDIO_PLL(PLL4)。
 
@@ -146,24 +146,24 @@ I.MX6ULL 使用 PODF (Prescale Output Divider) 进行分频。原书第 16.1.4/1
 
 I.MX6ULL 通过 7 组 CCGR 寄存器 (`CCM->CCGR0` ~ `CCM->CCGR6`) 控制外设时钟的使能与关闭。每个外设时钟占 **2 个连续位**(CGn),可设置为 4 种状态:
 
-| CCGR 位设置 | 含义                                                         |
-| ----------- | ------------------------------------------------------------ |
-| 00          | 所有模式下都关闭外设时钟                                     |
-| 01          | 只在运行(Run)模式下打开,等待(Wait)和停止(Stop)模式下均关闭  |
-| 10          | 未使用(保留)                                               |
-| 11          | 除停止模式以外,其他所有模式下时钟都打开                     |
+| CCGR 位设置 | 含义                                                        |
+| ----------- | ----------------------------------------------------------- |
+| 00          | 所有模式下都关闭外设时钟                                    |
+| 01          | 只在运行(Run)模式下打开,等待(Wait)和停止(Stop)模式下均关闭 |
+| 10          | 未使用(保留)                                              |
+| 11          | 除停止模式以外,其他所有模式下时钟都打开                    |
 
 CCGR 寄存器地址(CCM 基地址 0x020C4000):
 
-| 寄存器   | 地址       | 说明                                             |
-| -------- | ---------- | ------------------------------------------------ |
-| CCM_CCGR0 | 0x020C4068 | 如 bit[31:30] 控制 GPIO2 时钟                    |
-| CCM_CCGR1 | 0x020C406C | 如 bit[27:26] 控制 GPIO1 时钟                    |
-| CCM_CCGR2 | 0x020C4070 |                                                  |
-| CCM_CCGR3 | 0x020C4074 |                                                  |
-| CCM_CCGR4 | 0x020C4078 |                                                  |
-| CCM_CCGR5 | 0x020C407C | UART 等相关                                      |
-| CCM_CCGR6 | 0x020C4080 |                                                  |
+| 寄存器    | 地址       | 说明                          |
+| --------- | ---------- | ----------------------------- |
+| CCM_CCGR0 | 0x020C4068 | 如 bit[31:30] 控制 GPIO2 时钟 |
+| CCM_CCGR1 | 0x020C406C | 如 bit[27:26] 控制 GPIO1 时钟 |
+| CCM_CCGR2 | 0x020C4070 |                               |
+| CCM_CCGR3 | 0x020C4074 |                               |
+| CCM_CCGR4 | 0x020C4078 |                               |
+| CCM_CCGR5 | 0x020C407C | UART 等相关                   |
+| CCM_CCGR6 | 0x020C4080 |                               |
 
 > 位域规律:CGn 占据 bit[2n+1 : 2n]。例如 CCGR0 的 bit[31:30]=GPIO2,CCGR1 的 bit[27:26]=GPIO1。
 
@@ -216,19 +216,19 @@ void clk_enable(void)
 
 #### CCM_CBCDR — 总线时钟分频寄存器
 
-| 位域    | 名称             | 功能                                                     |
-| ------- | ---------------- | -------------------------------------------------------- |
-| [29:27] | PERIPH_CLK2_PODF | periph_clk2 时钟分频:0~7 对应 1~8 分频                  |
-| [26]    | PERIPH2_CLK_SEL  | periph2_clk 源:0=PLL2, 1=periph2_clk2_clk(触发 MMDC 握手) |
-| [25]    | PERIPH_CLK_SEL   | periph_clk 源:0=pre_periph_clk, 1=periph_clk2_clock(触发 MMDC 握手) |
-| [21:19] | MMDC_CH0_PODF    | mmdc_ch0 时钟分频:0~7 对应 1~8 分频                     |
-| [18:16] | AXI_PODF         | AXI 分频:0~7 对应 1~8                                   |
-| [12:10] | AHB_PODF         | AHB 分频:0~7 对应 1~8(触发 MMDC 握手)                 |
-| [9:8]   | IPG_PODF         | IPG 分频:0~3 对应 1~4                                   |
-| [7]     | AXI_ALT_CLK_SEL  | axi_alt 时钟选择:0=PLL2_PFD2, 1=PLL3_PFD1               |
-| [6]     | AXI_CLK_SEL      | axi 时钟源选择:0=periph_clk, 1=axi_alt                  |
-| [5:3]   | FABRIC_MMDC_PODF | fabric/mmdc 时钟分频:0~7 对应 1~8(即 mmdc_podf)       |
-| [2:0]   | PERIPH2_CLK2_PODF| periph2_clk2 时钟分频:0~7 对应 1~8                      |
+| 位域    | 名称              | 功能                                                                   |
+| ------- | ----------------- | ---------------------------------------------------------------------- |
+| [29:27] | PERIPH_CLK2_PODF  | periph_clk2 时钟分频:0~7 对应 1~8 分频                                |
+| [26]    | PERIPH2_CLK_SEL   | periph2_clk 源:0=PLL2, 1=periph2_clk2_clk(触发 MMDC 握手)           |
+| [25]    | PERIPH_CLK_SEL    | periph_clk 源:0=pre_periph_clk, 1=periph_clk2_clock(触发 MMDC 握手) |
+| [21:19] | MMDC_CH0_PODF     | mmdc_ch0 时钟分频:0~7 对应 1~8 分频                                   |
+| [18:16] | AXI_PODF          | AXI 分频:0~7 对应 1~8                                                 |
+| [12:10] | AHB_PODF          | AHB 分频:0~7 对应 1~8(触发 MMDC 握手)                               |
+| [9:8]   | IPG_PODF          | IPG 分频:0~3 对应 1~4                                                 |
+| [7]     | AXI_ALT_CLK_SEL   | axi_alt 时钟选择:0=PLL2_PFD2, 1=PLL3_PFD1                             |
+| [6]     | AXI_CLK_SEL       | axi 时钟源选择:0=periph_clk, 1=axi_alt                                |
+| [5:3]   | FABRIC_MMDC_PODF  | fabric/mmdc 时钟分频:0~7 对应 1~8(即 mmdc_podf)                     |
+| [2:0]   | PERIPH2_CLK2_PODF | periph2_clk2 时钟分频:0~7 对应 1~8                                    |
 
 #### CCM_CBCMR — 总线时钟模式寄存器
 
@@ -236,7 +236,7 @@ void clk_enable(void)
 | ------- | ------------------- | ---------------------------------------------------------------------- |
 | [25:23] | LCDIF1_PODF         | lcdif1 时钟分频:0~7 对应 1~8 分频                                     |
 | [22:21] | PRE_PERIPH2_CLK_SEL | pre_periph2 源:00=PLL2, 01=PLL2_PFD2, 10=PLL2_PFD0, 11=PLL4           |
-| [20]    | PERIPH2_CLK2_SEL    | periph2_clk2 源:0=pll3_sw_clk, 1=OSC                                 |
+| [20]    | PERIPH2_CLK2_SEL    | periph2_clk2 源:0=pll3_sw_clk, 1=OSC                                  |
 | [19:18] | PRE_PERIPH_CLK_SEL  | pre_periph_clk 源:00=PLL2, 01=PLL2_PFD2, 10=PLL2_PFD0, 11=PLL2_PFD2/2 |
 | [13:12] | PERIPH_CLK2_SEL     | periph_clk2 源:00=pll3_sw_clk, 01=osc_clk, 10=pll2_bypass_clk         |
 
@@ -253,14 +253,14 @@ void clk_enable(void)
 
 CCM_ANALOG(ANATOP)基地址 = **0x020C8000**:
 
-| 寄存器                  | 地址       | 说明                     |
-| ----------------------- | ---------- | ------------------------ |
-| CCM_ANALOG_PLL_ARMn     | 0x020C8000 | PLL1 (ARM PLL) 控制寄存器 |
-| CCM_ANALOG_PLL_528n     | 0x020C8030 | PLL2 (528_PLL)           |
-| CCM_ANALOG_PLL_USB1n    | 0x020C8010 | PLL3 (USB1_PLL)          |
-| CCM_ANALOG_PLL_USB2n    | 0x020C8020 | PLL7 (USB2_PLL)          |
-| CCM_ANALOG_PFD_480n     | 0x020C80F0 | PLL3 PFD 控制            |
-| CCM_ANALOG_PFD_528n     | 0x020C8100 | PLL2 PFD 控制            |
+| 寄存器               | 地址       | 说明                      |
+| -------------------- | ---------- | ------------------------- |
+| CCM_ANALOG_PLL_ARMn  | 0x020C8000 | PLL1 (ARM PLL) 控制寄存器 |
+| CCM_ANALOG_PLL_528n  | 0x020C8030 | PLL2 (528_PLL)            |
+| CCM_ANALOG_PLL_USB1n | 0x020C8010 | PLL3 (USB1_PLL)           |
+| CCM_ANALOG_PLL_USB2n | 0x020C8020 | PLL7 (USB2_PLL)           |
+| CCM_ANALOG_PFD_480n  | 0x020C80F0 | PLL3 PFD 控制             |
+| CCM_ANALOG_PFD_528n  | 0x020C8100 | PLL2 PFD 控制             |
 
 #### CCM_ANALOG_PLL_ARMn — PLL1 (ARM PLL) 控制寄存器
 
@@ -273,21 +273,20 @@ CCM_ANALOG(ANATOP)基地址 = **0x020C8000**:
 
 寄存器分为四组(PFD0~PFD3),每组 8 个 bit;FRAC 可设置范围 **12~35**:
 
-| 位域    | 名称         | 功能                                          |
-| ------- | ------------ | --------------------------------------------- |
-| [5:0]   | PFD0_FRAC    | PLL2_PFD0 分频因子:PLL2_PFD0 = 528×18/FRAC   |
-| [6]     | PFD0_STABLE  | 只读,读此位判断 PLL2_PFD0 是否稳定           |
-| [7]     | PFD0_CLKGATE | PFD0 输出使能:1=关闭, 0=使能                 |
-| [13:8]  | PFD1_FRAC    | PLL2_PFD1 分频因子                            |
-| [14]    | PFD1_STABLE  | PLL2_PFD1 稳定标志(只读)                    |
-| [15]    | PFD1_CLKGATE | PFD1 门控:1=关闭, 0=使能                     |
-| [21:16] | PFD2_FRAC    | PLL2_PFD2 分频因子                            |
-| [22]    | PFD2_STABLE  | PLL2_PFD2 稳定标志(只读)                    |
-| [23]    | PFD2_CLKGATE | PFD2 门控                                     |
-| [29:24] | PFD3_FRAC    | PLL2_PFD3 分频因子                            |
-| [30]    | PFD3_STABLE  | PLL2_PFD3 稳定标志(只读)                    |
-| [31]    | PFD3_CLKGATE | PFD3 门控                                     |
-
+| 位域    | 名称         | 功能                                        |
+| ------- | ------------ | ------------------------------------------- |
+| [5:0]   | PFD0_FRAC    | PLL2_PFD0 分频因子:PLL2_PFD0 = 528×18/FRAC |
+| [6]     | PFD0_STABLE  | 只读,读此位判断 PLL2_PFD0 是否稳定         |
+| [7]     | PFD0_CLKGATE | PFD0 输出使能:1=关闭, 0=使能               |
+| [13:8]  | PFD1_FRAC    | PLL2_PFD1 分频因子                          |
+| [14]    | PFD1_STABLE  | PLL2_PFD1 稳定标志(只读)                  |
+| [15]    | PFD1_CLKGATE | PFD1 门控:1=关闭, 0=使能                   |
+| [21:16] | PFD2_FRAC    | PLL2_PFD2 分频因子                          |
+| [22]    | PFD2_STABLE  | PLL2_PFD2 稳定标志(只读)                  |
+| [23]    | PFD2_CLKGATE | PFD2 门控                                   |
+| [29:24] | PFD3_FRAC    | PLL2_PFD3 分频因子                          |
+| [30]    | PFD3_STABLE  | PLL2_PFD3 稳定标志(只读)                  |
+| [31]    | PFD3_CLKGATE | PFD3 门控                                   |
 
 #### CCM_ANALOG_PFD_480n — PLL3 PFD 控制寄存器
 
@@ -509,14 +508,13 @@ I.MX6ULL 的电源管理由 CCM (Clock Controller Module) 和 PMU (Power Managem
 
 I.MX6ULL 支持多种运行模式:
 
-| 模式    | CPU 状态        | 功耗 | 唤醒源            | 典型应用     |
-| ------- | --------------- | ---- | ----------------- | ------------ |
-| RUN     | 全速运行        | 最高 | N/A               | 正常工作     |
-| WAIT    | 内核时钟停止    | 中   | 中断              | 等待事件     |
-| STOP    | PLL/时钟门控    | 低   | 中断/GPIO/RTC     | 深度休眠     |
-| DORMANT | 内核掉电保持    | 极低 | 中断/GPIO         | 超低功耗待机 |
-| SNVS    | 仅 SNVS 域运行  | 最低 | RTC/SNVS 唤醒引脚 | 电池备份/RTC |
-
+| 模式    | CPU 状态       | 功耗 | 唤醒源            | 典型应用     |
+| ------- | -------------- | ---- | ----------------- | ------------ |
+| RUN     | 全速运行       | 最高 | N/A               | 正常工作     |
+| WAIT    | 内核时钟停止   | 中   | 中断              | 等待事件     |
+| STOP    | PLL/时钟门控   | 低   | 中断/GPIO/RTC     | 深度休眠     |
+| DORMANT | 内核掉电保持   | 极低 | 中断/GPIO         | 超低功耗待机 |
+| SNVS    | 仅 SNVS 域运行 | 最低 | RTC/SNVS 唤醒引脚 | 电池备份/RTC |
 
 ### 5.3 DVFS (动态电压频率调节)
 

+ 27 - 29
X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/01-ARM架构与裸机编程/04-GPIO与中断系统.md

@@ -18,7 +18,6 @@ pdf_ref: "【正点原子】I.MX6U嵌入式Linux驱动开发指南V2.0.1 - 第
 
 GPIO(General Purpose Input/Output)是通用输入输出接口,是处理器与外部设备交互的基础通道。IMX6ULL芯片提供5组GPIO(GPIO1~GPIO5),但各组引脚数并不相同:GPIO1 有 32 个 IO,GPIO2 有 22 个,GPIO3 有 29 个,GPIO4 有 29 个,GPIO5 最少只有 12 个,**一共 124 个 GPIO**(原书第 8.1.3 节)。
 
-
 ```mermaid
 flowchart LR
     accTitle: GPIO功能架构
@@ -546,16 +545,16 @@ I.MX6U 是 Cortex-A7,只支持 32 个优先级,因此 **GICC_PMR = 0b1111100
 
 2. **设置抢占/子优先级位数** —— GICC_BPR,只有低 3 位有效:
 
-| Binary Point | 抢占优先级域 | 子优先级域 | 描述                     |
-| ------------ | ------------ | ---------- | ------------------------ |
-| 0            | [7:1]        | [0]        | 7 级抢占,1 级子         |
-| 1            | [7:2]        | [1:0]      | 6 级抢占,2 级子         |
-| 2            | [7:3]        | [2:0]      | 5 级抢占,3 级子         |
-| 3            | [7:4]        | [3:0]      | 4 级抢占,4 级子         |
-| 4            | [7:5]        | [4:0]      | 3 级抢占,5 级子         |
-| 5            | [7:6]        | [5:0]      | 2 级抢占,6 级子         |
-| 6            | [7:7]        | [6:0]      | 1 级抢占,7 级子         |
-| 7            | 无           | [7:0]      | 0 级抢占,8 级子         |
+| Binary Point | 抢占优先级域 | 子优先级域 | 描述             |
+| ------------ | ------------ | ---------- | ---------------- |
+| 0            | [7:1]        | [0]        | 7 级抢占,1 级子 |
+| 1            | [7:2]        | [1:0]      | 6 级抢占,2 级子 |
+| 2            | [7:3]        | [2:0]      | 5 级抢占,3 级子 |
+| 3            | [7:4]        | [3:0]      | 4 级抢占,4 级子 |
+| 4            | [7:5]        | [4:0]      | 3 级抢占,5 级子 |
+| 5            | [7:6]        | [5:0]      | 2 级抢占,6 级子 |
+| 6            | [7:7]        | [6:0]      | 1 级抢占,7 级子 |
+| 7            | 无           | [7:0]      | 0 级抢占,8 级子 |
 
 为简单起见,一般把所有位都配置为抢占优先级:I.MX6U 优先级位数为 5,故 Binary point 设为 **2**。
 
@@ -569,12 +568,12 @@ GICD_IPRIORITYR[40] = 5 << 3;   /* 设置 ID40 中断优先级为 5 */
 
 中断使能分两部分:**IRQ/FIQ 总开关**和 **ID0~ID1019 中断源使能**。
 
-| 指令      | 描述            |
-| --------- | --------------- |
-| `cpsid i` | 禁止 IRQ 中断   |
-| `cpsie i` | 使能 IRQ 中断   |
-| `cpsid f` | 禁止 FIQ 中断   |
-| `cpsie f` | 使能 FIQ 中断   |
+| 指令      | 描述          |
+| --------- | ------------- |
+| `cpsid i` | 禁止 IRQ 中断 |
+| `cpsie i` | 使能 IRQ 中断 |
+| `cpsid f` | 禁止 FIQ 中断 |
+| `cpsie f` | 使能 FIQ 中断 |
 
 中断源使能由 **GICD_ISENABLERn / GICD_ICENABLERn** 完成。Cortex-A7 内核只使用了 512 个中断 ID,一个 bit 控制一个中断 ID,故需要 512/32 = **16 个** GICD_ISENABLERn(同理 16 个 GICD_ICENABLERn)。其中 `GICD_ISENABLER0` 的 bit[15:0] 对应 ID15~0 的 SGI 中断,bit[31:16] 对应 ID31~16 的 PPI 中断;`GICD_ISENABLER1~15` 控制 SPI 中断。
 
@@ -705,21 +704,20 @@ void irq_disable(int irq)
 }
 ```
 
-
 **原书第 17.3.1 节 GIC 相关 API(core_ca7.h,共 10 个)**:
 
-| 函数                      | 描述                       |
-| ------------------------- | -------------------------- |
-| `GIC_Init`                | 初始化 GIC                 |
-| `GIC_EnableIRQ`           | 使能指定的外设中断         |
-| `GIC_DisableIRQ`          | 关闭指定的外设中断         |
-| `GIC_AcknowledgeIRQ`      | 返回中断号                 |
-| `GIC_DeactivateIRQ`       | 无效化指定中断             |
+| 函数                      | 描述                         |
+| ------------------------- | ---------------------------- |
+| `GIC_Init`                | 初始化 GIC                   |
+| `GIC_EnableIRQ`           | 使能指定的外设中断           |
+| `GIC_DisableIRQ`          | 关闭指定的外设中断           |
+| `GIC_AcknowledgeIRQ`      | 返回中断号                   |
+| `GIC_DeactivateIRQ`       | 无效化指定中断               |
 | `GIC_GetRunningPriority`  | 获取当前正在运行的中断优先级 |
-| `GIC_SetPriorityGrouping` | 设置抢占优先级位数         |
-| `GIC_GetPriorityGrouping` | 获取抢占优先级位数         |
-| `GIC_SetPriority`         | 设置指定中断的优先级       |
-| `GIC_GetPriority`         | 获取指定中断的优先级       |
+| `GIC_SetPriorityGrouping` | 设置抢占优先级位数           |
+| `GIC_GetPriorityGrouping` | 获取抢占优先级位数           |
+| `GIC_SetPriority`         | 设置指定中断的优先级         |
+| `GIC_GetPriority`         | 获取指定中断的优先级         |
 
 ---
 

+ 36 - 40
X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/01-ARM架构与裸机编程/05-定时器与看门狗.md

@@ -107,7 +107,6 @@ EPIT(Enhanced Periodic Interrupt Timer)增强的周期中断定时器,I.MX
 #define EPIT_CR_CLKSRC(x)   (((x) & 0x3) << 24)   /* 时钟源: 01=ipg_clk */
 ```
 
-
 #### EPITx_SR — 状态寄存器(偏移 0x004)
 
 | 位域 | 名称 | 功能                                                |
@@ -162,31 +161,31 @@ GPT(General Purpose Timer)通用定时器,比 EPIT 功能更丰富。教
 
 **五个可选时钟源(PDF 图 20.1.1.1):**
 
-| CLKSRC(bit8:6) | 时钟源                              |
-| -------------- | ----------------------------------- |
-| 0              | 关闭时钟源                          |
-| **1**          | **ipg_clk(=66MHz,本例程选择)**   |
-| 2              | ipg_clk_highfreq                    |
-| 3              | 外部时钟 GPT_CLK                    |
-| 4              | ipg_clk_32k                         |
-| 5              | ipg_clk_24M                         |
+| CLKSRC(bit8:6) | 时钟源                            |
+| -------------- | --------------------------------- |
+| 0              | 关闭时钟源                        |
+| **1**          | **ipg_clk(=66MHz,本例程选择)** |
+| 2              | ipg_clk_highfreq                  |
+| 3              | 外部时钟 GPT_CLK                  |
+| 4              | ipg_clk_32k                       |
+| 5              | ipg_clk_24M                       |
 
 **两种工作模式(FRR 位):**
 
-| 模式                  | FRR位 | 行为                                              |
-| --------------------- | ----- | ------------------------------------------------- |
-| **restart(重新启动)** | FRR=0 | 计数值等于比较值时计数器清零,仅比较通道 1 有效   |
-| **free-run(自由运行)** | FRR=1 | 比较事件不清零计数器,直到 0xFFFFFFFF 回滚到 0    |
+| 模式                     | FRR位 | 行为                                            |
+| ------------------------ | ----- | ----------------------------------------------- |
+| **restart(重新启动)**  | FRR=0 | 计数值等于比较值时计数器清零,仅比较通道 1 有效 |
+| **free-run(自由运行)** | FRR=1 | 比较事件不清零计数器,直到 0xFFFFFFFF 回滚到 0  |
 
 **GPTx_CR 重要位域(PDF 20.1.1):**
 
-| 位域   | 名称    | 功能                                             |
-| ------ | ------- | ------------------------------------------------ |
-| bit15  | SWR     | 复位 GPT 定时器,写 1 复位,完成后自动清零       |
-| bit9   | FRR     | 0=restart 模式,1=free-run 模式                  |
-| bit8:6 | CLKSRC  | 时钟源选择(见上表)                             |
-| bit1   | ENMOD   | 0=关闭时保留计数值,1=关闭时计数器清零           |
-| bit0   | EN      | GPT 使能:1=使能,0=关闭                         |
+| 位域   | 名称   | 功能                                       |
+| ------ | ------ | ------------------------------------------ |
+| bit15  | SWR    | 复位 GPT 定时器,写 1 复位,完成后自动清零 |
+| bit9   | FRR    | 0=restart 模式,1=free-run 模式            |
+| bit8:6 | CLKSRC | 时钟源选择(见上表)                       |
+| bit1   | ENMOD  | 0=关闭时保留计数值,1=关闭时计数器清零     |
+| bit0   | EN     | GPT 使能:1=使能,0=关闭                   |
 
 **GPTx_PR:** PRESCALER(bit11:0),0~4095 → 1~4096 分频。
 **GPTx_SR:** ROV(bit5) 回滚标志、IF2~IF1(bit4:3) 输入捕获标志、OF3~OF1(bit2:0) 输出比较标志。
@@ -231,18 +230,17 @@ void delay_init(void)
 }
 ```
 
-
 #### EPIT vs GPT 对比
 
-| 特性         | EPIT                          | GPT                        |
-| ------------ | ----------------------------- | -------------------------- |
-| 计数方向     | **向下**                      | 向上                       |
-| 核心功能     | 周期性中断                    | 高精度延时/PWM/捕获/比较   |
-| 输出比较通道 | 无(仅CMPR)                  | 3个(OCR1/OCR2/OCR3)      |
-| 输入捕获     | 无                            | 2个(ICR1/ICR2)           |
-| 工作模式     | set-and-forget / free-running | restart / free-run         |
+| 特性         | EPIT                          | GPT                           |
+| ------------ | ----------------------------- | ----------------------------- |
+| 计数方向     | **向下**                      | 向上                          |
+| 核心功能     | 周期性中断                    | 高精度延时/PWM/捕获/比较      |
+| 输出比较通道 | 无(仅CMPR)                  | 3个(OCR1/OCR2/OCR3)         |
+| 输入捕获     | 无                            | 2个(ICR1/ICR2)              |
+| 工作模式     | set-and-forget / free-running | restart / free-run            |
 | 典型用途     | 周期中断定时、定时器消抖      | 高精度延时、PWM输出、输入捕获 |
-| 配置复杂度   | **简单**                      | 较复杂                     |
+| 配置复杂度   | **简单**                      | 较复杂                        |
 
 > **选型建议:** 简单定时/周期中断用 EPIT,需要 PWM 或输入捕获用 GPT。
 
@@ -610,16 +608,15 @@ int main(void)
 
 #### WDOG_WCR — 看门狗控制寄存器(偏移 0x000)
 
-| 位域    | 名称  | 功能                                           |
-| ------- | ----- | ---------------------------------------------- |
-| bit0    | WDZST | 停止计数:1=在调试/低功耗模式停止计数          |
-| bit1    | WDBG  | 调试模式:1=调试模式停止计数                   |
-| bit2    | WDE   | **看门狗使能**:0=禁止,1=使能                 |
-| bit3    | WDT   | 定时器复位使能:1=超时产生复位                 |
-| bit4    | SRS   | 软件复位:写 0 产生复位                        |
-| bit5    | WDA   | 软件看门狗:写 1 暂停看门狗                    |
-| bit15:8 | WT    | **超时时间配置位**(16 个档位)                |
-
+| 位域    | 名称  | 功能                                  |
+| ------- | ----- | ------------------------------------- |
+| bit0    | WDZST | 停止计数:1=在调试/低功耗模式停止计数 |
+| bit1    | WDBG  | 调试模式:1=调试模式停止计数          |
+| bit2    | WDE   | **看门狗使能**:0=禁止,1=使能        |
+| bit3    | WDT   | 定时器复位使能:1=超时产生复位        |
+| bit4    | SRS   | 软件复位:写 0 产生复位               |
+| bit5    | WDA   | 软件看门狗:写 1 暂停看门狗           |
+| bit15:8 | WT    | **超时时间配置位**(16 个档位)       |
 
 #### WDOG_WSR — 服务寄存器(偏移 0x002)
 
@@ -672,7 +669,6 @@ void wdog_feed(void)
 }
 ```
 
-
 **看门狗配置要点:**
 
 | 操作     | 说明                                             |

+ 0 - 1
X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/01-ARM架构与裸机编程/07-BSP工程管理与封装.md

@@ -376,7 +376,6 @@ void led_switch(int led, int status);
 #endif
 ```
 
-
 #### 5.2.3 bsp_led.c
 
 ```c

+ 54 - 58
X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/01-ARM架构与裸机编程/08-裸机实验总结.md

@@ -68,13 +68,13 @@ pdf_ref:
 
 I.MX6ULL的GPIO系统由5组控制器组成:
 
-| GPIO组 | IO数量 | 基地址     | 说明                                              |
-| ------ | ------ | ---------- | ------------------------------------------------- |
-| GPIO1  | 32个   | 0x0209C000 | GPIO1_IO00~IO09 在 IOMUXC 中有独立 GPIO 命名      |
+| GPIO组 | IO数量 | 基地址     | 说明                                               |
+| ------ | ------ | ---------- | -------------------------------------------------- |
+| GPIO1  | 32个   | 0x0209C000 | GPIO1_IO00~IO09 在 IOMUXC 中有独立 GPIO 命名       |
 | GPIO2  | 22个   | 0x020A0000 | 其余 IO 需先经 IOMUXC 复用(MUX_MODE=ALT5)为 GPIO |
-| GPIO3  | 29个   | 0x020A4000 |                                                   |
-| GPIO4  | 29个   | 0x020A8000 |                                                   |
-| GPIO5  | 12个   | 0x020AC000 | 包含 SNVS 域 IO(如 SNVS_TAMPER1)                |
+| GPIO3  | 29个   | 0x020A4000 |                                                    |
+| GPIO4  | 29个   | 0x020A8000 |                                                    |
+| GPIO5  | 12个   | 0x020AC000 | 包含 SNVS 域 IO(如 SNVS_TAMPER1)                 |
 
 > 5 组 GPIO 共 124 个 IO(32+22+29+29+12)。每组都有 8 个寄存器:`DR`(数据)、`GDIR`(方向)、`PSR`(状态)、`ICR1`/`ICR2`(中断配置,每个 IO 2 位)、`IMR`(中断屏蔽)、`ISR`(中断状态,写 1 清零)、`EDGE_SEL`(边沿选择,置 1 为双边沿,覆盖 ICR)。ICR 触发方式:00 低电平、01 高电平、10 上升沿、11 下降沿。
 
@@ -465,19 +465,18 @@ void delayms(unsigned int msdelay)
 }
 ```
 
-
 ### 6.4 运行效果
 
 延时精度达到1μs级别,比循环延时准确得多。
 
 ### 6.5 延时精度对比
 
-| 延时方式   | 精度 | 原理                      | 适用场景                       |
-| ---------- | ---- | ------------------------- | ------------------------------ |
-| 循环延时   | ms级 | 编译器优化影响大          | 仅用于简单等待                 |
-| SysTick    | μs级 | Cortex-M专用              | STM32系列                      |
-| GPT定时器  | 1μs  | 硬件计数(读 GPTx_CNT)   | I.MX6U 高精度延时(本章选用)  |
-| EPIT定时器 | —    | 32位向下计数 + 比较中断   | 周期中断、定时器消抖,不做延时 |
+| 延时方式   | 精度 | 原理                    | 适用场景                       |
+| ---------- | ---- | ----------------------- | ------------------------------ |
+| 循环延时   | ms级 | 编译器优化影响大        | 仅用于简单等待                 |
+| SysTick    | μs级 | Cortex-M专用            | STM32系列                      |
+| GPT定时器  | 1μs  | 硬件计数(读 GPTx_CNT) | I.MX6U 高精度延时(本章选用)  |
+| EPIT定时器 | —    | 32位向下计数 + 比较中断 | 周期中断、定时器消抖,不做延时 |
 
 ---
 
@@ -516,7 +515,6 @@ I.MX6U Boot ROM会读取IVT中的DCD(Data Configuration Data)表,自动完成D
   2. `CCM_CBCDR.PERIPH2_CLK_SEL(bit26)=0` → periph2_clk 选 pll2_main_clk;
   3. `CCM_CBCDR.FABRIC_MMDC_PODF(bit5:3)=0` → 1 分频,得到 MMDC 时钟 ≈396MHz。
 
-
 **NXP 官方工具流程(教材第23章):**
 
 1. 用 `I.MX6UL_DDR3_Script_Aid_V0.02.xlsx` 填写 DDR3 参数(容量、位宽、行/列地址、tRCD/tRC/tRAS 等),生成 `.inc` 初始化脚本(全是“寄存器地址=寄存器值”);
@@ -527,14 +525,14 @@ I.MX6U Boot ROM会读取IVT中的DCD(Data Configuration Data)表,自动完成D
 
 **校准得到的 6 个寄存器(教材示例代码 23.5.3.1):**
 
-| 寄存器名 | 地址 |
-| -------- | ---- |
+| 寄存器名         | 地址       |
+| ---------------- | ---------- |
 | MMDC_MPWLDECTRL0 | 0x021B080C |
 | MMDC_MPWLDECTRL1 | 0x021B0810 |
-| MPDGCTRL0 PHY0 | 0x021B083C |
-| MPDGCTRL1 PHY0 | 0x021B0840 |
-| MPRDDLCTL PHY0 | 0x021B0848 |
-| MPWRDLCTL PHY0 | 0x021B0850 |
+| MPDGCTRL0 PHY0   | 0x021B083C |
+| MPDGCTRL1 PHY0   | 0x021B0840 |
+| MPRDDLCTL PHY0   | 0x021B0848 |
+| MPWRDLCTL PHY0   | 0x021B0850 |
 
 **DDR3 关键时间参数(NT5CC256M16EP-EK):** tRCD=tRP=CL=13.91ns(CL-tRCD-tRP = 13-13-13)、tRC=47.91ns、tRAS=34ns。
 
@@ -578,31 +576,31 @@ DDR3初始化成功后,程序可使用0x80000000~0xA0000000地址范围(512M
 
 eLCDIF 基地址 **`LCDIF = 0x021C8000`**,支持 MPU / VSYNC / DOTCLK 三种接口,驱动 RGB 屏使用 **DOTCLK** 接口。
 
-| 寄存器 | 作用 |
-| ------ | ---- |
-| `LCDIF_CTRL` | 控制:SFTRST(bit31) 软复位、MASTER(bit5) 主模式、RUN(bit0) 使能、DATA_FORMAT_16_BIT(bit3) 选 ARGB555/RGB565、bit11:10 总线宽度、bit9:8 数据宽度 |
-| `LCDIF_CTRL1` | BYTE_PACKING_FORMAT(bit19:16),ARGB8888 下设为 0x7 |
-| `LCDIF_TRANSFER_COUNT` | bit31:16 = 帧高 V_COUNT,bit15:0 = 帧宽 H_COUNT |
-| `LCDIF_VDCTRL0` | VSYNC/DOTCLK 控制:`VSYNC_PULSE_WIDTH(bit17:0)` 设置 VSPW,bit28 使能 ENABLE 输出等 |
-| `LCDIF_VDCTRL1` | VSYNC 总周期 = 屏高 + VSPW + VBP + VFP |
-| `LCDIF_VDCTRL2` | bit31:18 = HSPW;bit17:0 = HSYNC 总周期 = 屏宽 + HSPW + HBP + HFP |
-| `LCDIF_VDCTRL3` | bit27:16 = HBP+HSPW;bit15:0 = VBP+VSPW |
-| `LCDIF_VDCTRL4` | bit18 置 1(使用 VSYNC/HSYNC/DOTCLK);bit17:0 = 屏宽 |
-| `LCDIF_CUR_BUF` / `LCDIF_NEXT_BUF` | 当前/下一帧缓存地址 |
+| 寄存器                             | 作用                                                                                                                                            |
+| ---------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
+| `LCDIF_CTRL`                       | 控制:SFTRST(bit31) 软复位、MASTER(bit5) 主模式、RUN(bit0) 使能、DATA_FORMAT_16_BIT(bit3) 选 ARGB555/RGB565、bit11:10 总线宽度、bit9:8 数据宽度 |
+| `LCDIF_CTRL1`                      | BYTE_PACKING_FORMAT(bit19:16),ARGB8888 下设为 0x7                                                                                              |
+| `LCDIF_TRANSFER_COUNT`             | bit31:16 = 帧高 V_COUNT,bit15:0 = 帧宽 H_COUNT                                                                                                 |
+| `LCDIF_VDCTRL0`                    | VSYNC/DOTCLK 控制:`VSYNC_PULSE_WIDTH(bit17:0)` 设置 VSPW,bit28 使能 ENABLE 输出等                                                             |
+| `LCDIF_VDCTRL1`                    | VSYNC 总周期 = 屏高 + VSPW + VBP + VFP                                                                                                          |
+| `LCDIF_VDCTRL2`                    | bit31:18 = HSPW;bit17:0 = HSYNC 总周期 = 屏宽 + HSPW + HBP + HFP                                                                               |
+| `LCDIF_VDCTRL3`                    | bit27:16 = HBP+HSPW;bit15:0 = VBP+VSPW                                                                                                         |
+| `LCDIF_VDCTRL4`                    | bit18 置 1(使用 VSYNC/HSYNC/DOTCLK);bit17:0 = 屏宽                                                                                           |
+| `LCDIF_CUR_BUF` / `LCDIF_NEXT_BUF` | 当前/下一帧缓存地址                                                                                                                             |
 
 ### 8.4 ATK-7016(1024×600)时序参数(教材例程)
 
-| 参数 | 含义 | 值 |
-| ---- | ---- | -- |
-| width / height | 屏宽 / 屏高 | 1024 / 600 |
-| pixsize | 每像素字节数(ARGB8888) | 4 |
-| hspw | HSYNC 信号宽度 | 20 |
-| hbpd | 水平同步后肩 HBP | 140 |
-| hfpd | 水平同步前肩 HFP | 160 |
-| vspw | VSYNC 信号宽度 | 3 |
-| vbpd | 帧同步后肩 VBP | 20 |
-| vfpd | 帧同步前肩 VFP | 12 |
-| framebuffer | 显存首地址 | 0x89000000 |
+| 参数           | 含义                     | 值         |
+| -------------- | ------------------------ | ---------- |
+| width / height | 屏宽 / 屏高              | 1024 / 600 |
+| pixsize        | 每像素字节数(ARGB8888) | 4          |
+| hspw           | HSYNC 信号宽度           | 20         |
+| hbpd           | 水平同步后肩 HBP         | 140        |
+| hfpd           | 水平同步前肩 HFP         | 160        |
+| vspw           | VSYNC 信号宽度           | 3          |
+| vbpd           | 帧同步后肩 VBP           | 20         |
+| vfpd           | 帧同步前肩 VFP           | 12         |
+| framebuffer    | 显存首地址               | 0x89000000 |
 
 帧周期:`T = (VSPW+VBP+LINE+VFP) × (HSPW+HBP+HVALID+HFP)`。
 
@@ -736,7 +734,6 @@ unsigned int rtc_getseconds(void)
 
 **教材 bsp_rtc.c 共 9 个函数**:`rtc_init`、`rtc_enable`、`rtc_disable`、`rtc_isleapyear`、`rtc_coverdate_to_seconds`、`rtc_setdatetime`、`rtc_convertseconds_to_datetime`、`rtc_getseconds`、`rtc_getdatetime`。时间基准为 1970-01-01,年份范围 1970~2099。
 
-
 ### 9.4 寄存器注意事项
 
 NXP参考手册中SNVS_SRTCMR和SNVS_SRTCLR的描述有误:
@@ -776,13 +773,13 @@ LCD显示实时时间,秒数持续递增。
 
 I2C1 基地址 **`I2C1 = 0x021A0000`**。I.MX6U 使用**硬件 I2C 控制器**,关键寄存器:
 
-| 寄存器 | 关键位 | 说明 |
-| ------ | ------ | ---- |
-| `I2Cx_IADR` | ADR(bit7:1) | I2C 从设备地址 |
-| `I2Cx_IFDR` | IC(bit5:0) | 波特率分频(档位固定,IC=0x15 为 640 分频) |
-| `I2Cx_I2CR` | IEN(bit7)/IIEN(bit6)/MSTA(bit5)/MTX(bit4)/TXAK(bit3)/RSTA(bit2) | 使能/中断/主从/方向/应答/重复起始 |
-| `I2Cx_I2SR` | ICF(bit7)/IAAS(bit6)/IBB(bit5)/IAL(bit4)/SRW(bit2)/IIF(bit1)/RXAK(bit0) | 状态寄存器 |
-| `I2Cx_I2DR` | 低 8 位 | 收发数据 |
+| 寄存器      | 关键位                                                                  | 说明                                        |
+| ----------- | ----------------------------------------------------------------------- | ------------------------------------------- |
+| `I2Cx_IADR` | ADR(bit7:1)                                                             | I2C 从设备地址                              |
+| `I2Cx_IFDR` | IC(bit5:0)                                                              | 波特率分频(档位固定,IC=0x15 为 640 分频) |
+| `I2Cx_I2CR` | IEN(bit7)/IIEN(bit6)/MSTA(bit5)/MTX(bit4)/TXAK(bit3)/RSTA(bit2)         | 使能/中断/主从/方向/应答/重复起始           |
+| `I2Cx_I2SR` | ICF(bit7)/IAAS(bit6)/IBB(bit5)/IAL(bit4)/SRW(bit2)/IIF(bit1)/RXAK(bit0) | 状态寄存器                                  |
+| `I2Cx_I2DR` | 低 8 位                                                                 | 收发数据                                    |
 
 时钟源为 IPG_CLK_ROOT=66MHz;设 100KHz:IC=0x15(640 分频),66MHz/640=103.125KHz≈100KHz。
 
@@ -855,14 +852,13 @@ unsigned char i2c_master_start(I2C_Type *base, unsigned char address,
 
 ECSPI3 基地址 **`ECSPI3 = 0x02010000`**。I.MX6U 的 SPI 外设叫 ECSPI,收发各带 32×64 位 FIFO。
 
-| 寄存器 | 关键位 | 说明 |
-| ------ | ------ | ---- |
-| `ECSPIx_CONREG` | BURST_LENGTH(bit31:20)/CHANNEL_SELECT(bit19:18)/DRCTL(bit17:16)/PRE_DIVIDER(bit15:12)/POST_DIVIDER(bit11:8)/CHANNEL_MODE(bit7:4)/SMC(bit3)/XCH(bit2)/EN(bit0) | 控制寄存器 |
-| `ECSPIx_CONFIGREG` | HT_LENGTH(bit28:24)/SCLK_CTL(bit23:20)/DATA_CTL(bit19:16)/SS_POL(bit15:12)/SCLK_POL(bit7:4)/SCLK_PHA(bit3:0) | 通道极性/相位(各 4 位对应通道 3~0) |
-| `ECSPIx_PERIODREG` | CSD_CTL(bit21:16)/CSRC(bit15)/SAMPLE_PERIOD(bit14:0) | 采样周期/片选延时 |
-| `ECSPIx_STATREG` | TC(bit7)/RO(bit6)/RF(bit5)/RDR(bit4)/RR(bit3)/TF(bit2)/TDR(bit1)/TE(bit0) | 状态寄存器 |
-| `ECSPIx_TXDATA` / `ECSPIx_RXDATA` | 32 位 | 发送/接收数据 |
-
+| 寄存器                            | 关键位                                                                                                                                                        | 说明                                 |
+| --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------ |
+| `ECSPIx_CONREG`                   | BURST_LENGTH(bit31:20)/CHANNEL_SELECT(bit19:18)/DRCTL(bit17:16)/PRE_DIVIDER(bit15:12)/POST_DIVIDER(bit11:8)/CHANNEL_MODE(bit7:4)/SMC(bit3)/XCH(bit2)/EN(bit0) | 控制寄存器                           |
+| `ECSPIx_CONFIGREG`                | HT_LENGTH(bit28:24)/SCLK_CTL(bit23:20)/DATA_CTL(bit19:16)/SS_POL(bit15:12)/SCLK_POL(bit7:4)/SCLK_PHA(bit3:0)                                                  | 通道极性/相位(各 4 位对应通道 3~0) |
+| `ECSPIx_PERIODREG`                | CSD_CTL(bit21:16)/CSRC(bit15)/SAMPLE_PERIOD(bit14:0)                                                                                                          | 采样周期/片选延时                    |
+| `ECSPIx_STATREG`                  | TC(bit7)/RO(bit6)/RF(bit5)/RDR(bit4)/RR(bit3)/TF(bit2)/TDR(bit1)/TE(bit0)                                                                                     | 状态寄存器                           |
+| `ECSPIx_TXDATA` / `ECSPIx_RXDATA` | 32 位                                                                                                                                                         | 发送/接收数据                        |
 
 ### 11.4 关键代码(教材 bsp_spi.c)
 

+ 1 - 3
X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/01-ARM架构与裸机编程/面试-ARM架构与裸机.md

@@ -145,14 +145,13 @@ IMX6ULL(I.MX6U)的启动流程(教材第9章「I.MX6U启动方式详解」
 
 **追问**:
 
-- 追问1:裸机 `start.S` 里并没有初始化 DDR,为什么可以直接把 SP 设到 DDR 地址? 
+- 追问1:裸机 `start.S` 里并没有初始化 DDR,为什么可以直接把 SP 设到 DDR 地址?
   - 因为 Boot ROM 已经执行 **DCD** 完成了 DDR 初始化,用户代码运行时 DDR 已经可用(教材第9、10章)。这也解释了为什么 I.MX6U 不需要像 S3C2440 那样在汇编里手写 DDR 初始化。
 - 追问2:Boot ROM如何保证启动安全?
   - Boot ROM支持HAB(High Assurance Boot)安全启动,通过数字签名验证加载的镜像是否经过厂商授权,防止恶意代码在启动阶段执行。
 - 追问3:什么是启动介质?IMX6ULL支持哪些?如何选择?
   - 启动介质是存储启动代码的外部存储器,IMX6ULL支持 SD卡、eMMC、NAND Flash、QSPI NOR Flash 等。启动模式由 `BOOT_MODE[1:0]` 引脚/eFUSE 选择(00 从 FUSE、01 串行下载、10 内部 BOOT、11 保留),具体启动设备再由 `BOOT_CFG1/2/4` 配置引脚(或 eFUSE)决定。
 
-
 ---
 
 ### Q4: Cortex-A7与Cortex-M4在架构层面有哪些核心区别?
@@ -1116,7 +1115,6 @@ ldr r0, =0x00A02010      @ GICC_EOIR地址
 str r1, [r0]             @ 写入中断号确认
 ```
 
-
 GIC中断优先级:
 
 - 每个中断有独立的优先级(0-255,0最高)

+ 0 - 3
X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/02-嵌入式Linux内核基础/01-内核编译与配置.md

@@ -82,7 +82,6 @@ linux-4.1.15/
 └── vmlinux.o       # 编译生成的 vmlinux.o
 ```
 
-
 以 `arch/arm` 为例,其下还有 `boot`、`common`、`configs`、`mach-xxx` 等子目录,分别用于控制系统引导、系统调用、动态调频、主频设置等:
 
 - `arch/arm/configs/` — 各平台的默认配置文件 `xxx_defconfig`,其中 `imx_v7_defconfig` 即 I.MX6U-ALPHA 开发板的默认配置;
@@ -270,7 +269,6 @@ EXTRAVERSION =
 KERNELVERSION = $(VERSION)$(if $(PATCHLEVEL),.$(PATCHLEVEL)$(if $(SUBLEVEL),.$(SUBLEVEL)))$(EXTRAVERSION)
 ```
 
-
 ### 3.2 MAKEFLAGS设置
 
 ```makefile
@@ -1025,7 +1023,6 @@ saveenv
 run bootcmd
 ```
 
-
 ---
 
 ## 相关知识

+ 8 - 8
X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/02-嵌入式Linux内核基础/02-内核模块编程.md

@@ -462,14 +462,14 @@ scp mymodule.ko root@192.168.1.200:/home/root/
 
 ### 4.3 编译选项说明
 
-| 选项             | 作用                   |
-| ---------------- | ---------------------- |
-| `obj-m`          | 编译为可加载模块       |
-| `obj-y`          | 编译进内核(built-in) |
-| `-C $(KERNELDIR)` | 切换到内核源码目录执行 |
-| `M=$(CURRENT_PATH)` | 指定模块源码目录     |
-| `ARCH=arm`       | 指定目标架构           |
-| `CROSS_COMPILE=` | 指定交叉编译工具链前缀 |
+| 选项                | 作用                   |
+| ------------------- | ---------------------- |
+| `obj-m`             | 编译为可加载模块       |
+| `obj-y`             | 编译进内核(built-in) |
+| `-C $(KERNELDIR)`   | 切换到内核源码目录执行 |
+| `M=$(CURRENT_PATH)` | 指定模块源码目录       |
+| `ARCH=arm`          | 指定目标架构           |
+| `CROSS_COMPILE=`    | 指定交叉编译工具链前缀 |
 
 ### 4.4 编译常见问题
 

+ 2 - 2
X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/02-嵌入式Linux内核基础/04-进程调度与中断管理.md

@@ -146,8 +146,8 @@ vruntime 增量 = 实际运行时间 × (NICE_0_LOAD / 该进程权重)
 | nice 值 | 权重  | nice 值 | 权重 |
 | ------- | ----- | ------- | ---- |
 | -20     | 88761 | 0       | 1024 |
-| -10     |  9548 | 10      |  110 |
-| -5      |  3121 | 19      |   15 |
+| -10     | 9548  | 10      | 110  |
+| -5      | 3121  | 19      | 15   |
 
 #### 2.2.2 红黑树组织
 

+ 1 - 1
X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/02-嵌入式Linux内核基础/05-内存管理.md

@@ -448,7 +448,7 @@ static int my_probe(struct platform_device *pdev)
 | 访问方式 | 直接解引用                         | 直接解引用             | `readl`/`writel`       | 直接解引用             |
 | 缓存属性 | 普通可缓存                         | 普通可缓存             | `MT_DEVICE`,不缓存    | 不缓存(coherent)     |
 | 分配速度 | 快                                 | 慢                     | 中(改页表)           | 慢(可能需要迁移页面) |
-| 大小上限 | 4MB~8MB(`KMALLOC_MAX_SIZE`)    | 虚拟地址空间限制       | 任意                   | CMA 区大小限制         |
+| 大小上限 | 4MB~8MB(`KMALLOC_MAX_SIZE`)      | 虚拟地址空间限制       | 任意                   | CMA 区大小限制         |
 | 可睡眠   | `GFP_KERNEL` 可,`GFP_ATOMIC` 不可 | 可(不可在原子上下文) | 可                     | 可                     |
 | 释放     | `kfree`                            | `vfree`                | `iounmap`              | `dma_free_coherent`    |
 | 典型用途 | 结构体、小缓冲区                   | 大块内存、模块加载     | 外设寄存器             | DMA 描述符与缓冲区     |

+ 4 - 4
X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/02-嵌入式Linux内核基础/面试-Linux内核基础.md

@@ -938,10 +938,10 @@ nice值与权重映射表:
 | Nice值 | 权重  | 说明       |
 | ------ | ----- | ---------- |
 | -20    | 88761 | 最高优先级 |
-| -10    |  9548 |            |
-| 0      |  1024 | 基准       |
-| 10     |   110 |            |
-| 19     |    15 | 最低优先级 |
+| -10    | 9548  |            |
+| 0      | 1024  | 基准       |
+| 10     | 110   |            |
+| 19     | 15    | 最低优先级 |
 
 示例:
 

+ 22 - 23
X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/03-Linux驱动开发核心/01-字符设备驱动基础.md

@@ -258,22 +258,21 @@ struct file_operations {
 
 **各字段详细说明:**
 
-| 字段             | 函数原型                                                            | 说明                                             |
-| ---------------- | ------------------------------------------------------------------- | ------------------------------------------------ |
-| `owner`          | `struct module *`                                                   | 拥有该结构体的模块指针,一般设置为 `THIS_MODULE` |
-| `llseek`         | `loff_t (*)(struct file *, loff_t, int)`                            | 修改文件当前的读写位置                           |
-| `read`           | `ssize_t (*)(struct file *, char __user *, size_t, loff_t *)`       | 从设备读取数据到用户空间                         |
-| `write`          | `ssize_t (*)(struct file *, const char __user *, size_t, loff_t *)` | 从用户空间写入数据到设备                         |
-| `poll`           | `unsigned int (*)(struct file *, struct poll_table_struct *)`       | 轮询函数,查询设备是否可以非阻塞读写             |
-| `unlocked_ioctl` | `long (*)(struct file *, unsigned int, unsigned long)`              | 设备控制功能,对应用户空间的 `ioctl()`           |
+| 字段             | 函数原型                                                            | 说明                                                                                                                                     |
+| ---------------- | ------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
+| `owner`          | `struct module *`                                                   | 拥有该结构体的模块指针,一般设置为 `THIS_MODULE`                                                                                         |
+| `llseek`         | `loff_t (*)(struct file *, loff_t, int)`                            | 修改文件当前的读写位置                                                                                                                   |
+| `read`           | `ssize_t (*)(struct file *, char __user *, size_t, loff_t *)`       | 从设备读取数据到用户空间                                                                                                                 |
+| `write`          | `ssize_t (*)(struct file *, const char __user *, size_t, loff_t *)` | 从用户空间写入数据到设备                                                                                                                 |
+| `poll`           | `unsigned int (*)(struct file *, struct poll_table_struct *)`       | 轮询函数,查询设备是否可以非阻塞读写                                                                                                     |
+| `unlocked_ioctl` | `long (*)(struct file *, unsigned int, unsigned long)`              | 设备控制功能,对应用户空间的 `ioctl()`                                                                                                   |
 | `compat_ioctl`   | `long (*)(struct file *, unsigned int, unsigned long)`              | 与 `unlocked_ioctl` 功能相同,区别在于 64 位系统上运行 32 位应用程序时会调用此函数;32 位系统上运行 32 位程序调用的仍是 `unlocked_ioctl` |
-| `mmap`           | `int (*)(struct file *, struct vm_area_struct *)`                   | 将设备内存映射到进程空间(用户空间),帧缓冲类设备常用 |
-| `mremap`         | `int (*)(struct file *, struct vm_area_struct *)`                   | 扩展/收缩已有的内存映射                          |
-| `open`           | `int (*)(struct inode *, struct file *)`                            | 打开设备文件                                     |
-| `release`        | `int (*)(struct inode *, struct file *)`                            | 关闭/释放设备文件,对应 `close()`                |
-| `fsync`          | `int (*)(struct file *, loff_t, loff_t, int)`                       | 将缓冲区数据刷新到设备                           |
-| `fasync`         | `int (*)(int, struct file *, int)`                                  | 异步通知                                         |
-
+| `mmap`           | `int (*)(struct file *, struct vm_area_struct *)`                   | 将设备内存映射到进程空间(用户空间),帧缓冲类设备常用                                                                                   |
+| `mremap`         | `int (*)(struct file *, struct vm_area_struct *)`                   | 扩展/收缩已有的内存映射                                                                                                                  |
+| `open`           | `int (*)(struct inode *, struct file *)`                            | 打开设备文件                                                                                                                             |
+| `release`        | `int (*)(struct inode *, struct file *)`                            | 关闭/释放设备文件,对应 `close()`                                                                                                        |
+| `fsync`          | `int (*)(struct file *, loff_t, loff_t, int)`                       | 将缓冲区数据刷新到设备                                                                                                                   |
+| `fasync`         | `int (*)(int, struct file *, int)`                                  | 异步通知                                                                                                                                 |
 
 **字符设备驱动中常用的函数:**
 
@@ -508,11 +507,11 @@ MODULE_LICENSE("GPL");
 int register_chrdev_region(dev_t from, unsigned count, const char *name);
 ```
 
-| 参数    | 类型           | 说明                             |
-| ------- | -------------- | -------------------------------- |
+| 参数    | 类型           | 说明                               |
+| ------- | -------------- | ---------------------------------- |
 | `from`  | `dev_t`        | 要申请的起始设备号(给定的设备号) |
-| `count` | `unsigned`     | 要申请的设备号数量,一般为一个    |
-| `name`  | `const char *` | 设备名字                          |
+| `count` | `unsigned`     | 要申请的设备号数量,一般为一个     |
+| `name`  | `const char *` | 设备名字                           |
 
 **返回值:**
 
@@ -663,10 +662,10 @@ void device_destroy(struct class *class, dev_t devt);
 void class_destroy(struct class *cls);
 ```
 
-| 函数              | 参数                                 | 说明                                       |
-| ----------------- | ------------------------------------ | ------------------------------------------ |
-| `device_destroy`  | `class`:设备所处类;`devt`:设备号   | 删除用 `device_create` 创建的设备          |
-| `class_destroy`   | `cls`:要删除的类                     | 删除用 `class_create` 创建的类             |
+| 函数             | 参数                                | 说明                              |
+| ---------------- | ----------------------------------- | --------------------------------- |
+| `device_destroy` | `class`:设备所处类;`devt`:设备号 | 删除用 `device_create` 创建的设备 |
+| `class_destroy`  | `cls`:要删除的类                   | 删除用 `class_create` 创建的类    |
 
 #### 3.3.4 完整示例
 

+ 31 - 32
X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/03-Linux驱动开发核心/02-设备树语法与实战.md

@@ -22,12 +22,12 @@ pdf_ref:
 
 设备树相关概念:
 
-| 概念 | 文件后缀 | 说明                                |
-| ---- | -------- | ----------------------------------- |
-| DTS  | `.dts`   | 设备树源文件,文本格式,开发者编写  |
-| DTSI | `.dtsi`  | 设备树头文件,可被 DTS 包含         |
-| DTB  | `.dtb`   | 编译后的二进制文件,bootloader 加载 |
-| DTC  | —        | 设备树编译器,将 DTS 编译为 DTB     |
+| 概念 | 文件后缀 | 说明                                                   |
+| ---- | -------- | ------------------------------------------------------ |
+| DTS  | `.dts`   | 设备树源文件,文本格式,开发者编写                     |
+| DTSI | `.dtsi`  | 设备树头文件,可被 DTS 包含                            |
+| DTB  | `.dtb`   | 编译后的二进制文件,bootloader 加载                    |
+| DTC  | —        | 设备树编译器,将 DTS 编译为 DTB                        |
 | DTBO | `.dtbo`  | 设备树 Overlay,运行时动态叠加(扩展知识,原书未涉及) |
 
 ### 1.2 为什么需要设备树
@@ -282,7 +282,6 @@ aips3: aips-bus@02200000 {
 };
 ```
 
-
 #### `reg` — 寄存器地址范围
 
 `reg` 属性的格式为 `<address length>` 对,描述设备在父节点地址空间中的寄存器基地址和大小。
@@ -308,12 +307,12 @@ alphaled {
 
 #### `status` — 设备状态
 
-| 值           | 含义                 |
-| ------------ | -------------------- |
-| `"okay"`     | 表明设备是可操作的   |
+| 值           | 含义                                                                                           |
+| ------------ | ---------------------------------------------------------------------------------------------- |
+| `"okay"`     | 表明设备是可操作的                                                                             |
 | `"disabled"` | 表明设备当前不可操作,但未来可以变为可操作(如热插拔设备插入后);具体含义还要看设备的绑定文档 |
-| `"fail"`     | 表明设备不可操作,设备检测到了一系列错误,而且不大可能变得可操作 |
-| `"fail-sss"` | 含义和 `"fail"` 相同,后面的 sss 部分是检测到的错误内容 |
+| `"fail"`     | 表明设备不可操作,设备检测到了一系列错误,而且不大可能变得可操作                               |
+| `"fail-sss"` | 含义和 `"fail"` 相同,后面的 sss 部分是检测到的错误内容                                        |
 
 > ⚠️ 上表取自原书表 43.3.3.1。`"reserved"`(设备被占用、由其他软件组件管理)属设备树规范中的扩展取值,原书未列出。
 
@@ -654,12 +653,12 @@ int of_property_count_elems_of_size(const struct device_node *np,
                                      int elem_size);
 ```
 
-| 参数        | 类型                         | 说明                   |
-| ----------- | ---------------------------- | ---------------------- |
-| `np`        | `const struct device_node *` | 设备节点               |
+| 参数        | 类型                         | 说明                     |
+| ----------- | ---------------------------- | ------------------------ |
+| `np`        | `const struct device_node *` | 设备节点                 |
 | `propname`  | `const char *`               | 需要统计元素数量的属性名 |
-| `elem_size` | `int`                        | 元素长度               |
-| 返回值      | `int`                        | 得到的属性元素数量     |
+| `elem_size` | `int`                        | 元素长度                 |
+| 返回值      | `int`                        | 得到的属性元素数量       |
 
 #### 按下标读取 u32 数值
 
@@ -672,12 +671,12 @@ int of_property_read_u32_index(const struct device_node *np,
                                 u32 *out_value);
 ```
 
-| 参数        | 类型           | 说明                                                             |
-| ----------- | -------------- | ---------------------------------------------------------------- |
-| `np`        | 设备节点       | 设备节点                                                         |
-| `propname`  | `const char *` | 要读取的属性名字                                                 |
-| `index`     | `u32`          | 要读取的值标号                                                   |
-| `out_value` | `u32 *`        | 读取到的值                                                       |
+| 参数        | 类型           | 说明                                                                                       |
+| ----------- | -------------- | ------------------------------------------------------------------------------------------ |
+| `np`        | 设备节点       | 设备节点                                                                                   |
+| `propname`  | `const char *` | 要读取的属性名字                                                                           |
+| `index`     | `u32`          | 要读取的值标号                                                                             |
+| `out_value` | `u32 *`        | 读取到的值                                                                                 |
 | 返回值      | `int`          | 0 读取成功,负值读取失败(-EINVAL 属性不存在,-ENODATA 无数据,-EOVERFLOW 属性值列表太小) |
 
 #### 读取整数属性
@@ -813,10 +812,10 @@ int of_device_is_compatible(const struct device_node *device,
                              const char *compat);
 ```
 
-| 参数     | 类型                         | 说明               |
-| -------- | ---------------------------- | ------------------ |
-| `device` | `const struct device_node *` | 设备节点           |
-| `compat` | `const char *`               | 要查看的字符串     |
+| 参数     | 类型                         | 说明                       |
+| -------- | ---------------------------- | -------------------------- |
+| `device` | `const struct device_node *` | 设备节点                   |
+| `compat` | `const char *`               | 要查看的字符串             |
 | 返回值   | `int`                        | 0 表示不包含;正数表示包含 |
 
 #### of_get_named_gpio — 获取 GPIO 编号
@@ -829,12 +828,12 @@ int of_get_named_gpio(struct device_node *np,
                        int index);
 ```
 
-| 参数       | 类型                   | 说明                                                         |
-| ---------- | ---------------------- | ------------------------------------------------------------ |
-| `np`       | `struct device_node *` | 设备节点                                                     |
-| `propname` | `const char *`         | 包含要获取 GPIO 信息的属性名(如 `"led-gpio"`)              |
+| 参数       | 类型                   | 说明                                                          |
+| ---------- | ---------------------- | ------------------------------------------------------------- |
+| `np`       | `struct device_node *` | 设备节点                                                      |
+| `propname` | `const char *`         | 包含要获取 GPIO 信息的属性名(如 `"led-gpio"`)               |
 | `index`    | `int`                  | GPIO 索引;一个属性含多个 GPIO 时指定取哪一个,只有一个时为 0 |
-| 返回值     | `int`                  | 正值:获取到的 GPIO 编号;负值:失败                         |
+| 返回值     | `int`                  | 正值:获取到的 GPIO 编号;负值:失败                          |
 
 ```c
 /* 第四十五章 gpioled 驱动片段 */

+ 4 - 4
X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/03-Linux驱动开发核心/03-pinctrl与gpio子系统.md

@@ -407,10 +407,10 @@ int of_get_named_gpio(struct device_node *np,
 
 **与 GPIO 相关的 OF 函数(原书 45.2.5 逐项核对)**:
 
-| 函数                  | 原型                                                                 | 说明                                                              |
-| --------------------- | -------------------------------------------------------------------- | ----------------------------------------------------------------- |
-| `of_gpio_named_count` | `int of_gpio_named_count(struct device_node *np, const char *propname)` | 统计某个属性里定义了几个 GPIO;**空的 GPIO 也会被统计到**          |
-| `of_gpio_count`       | `int of_gpio_count(struct device_node *np)`                          | 统计 `gpios` 属性里的 GPIO 数量(只能统计 "gpios")               |
+| 函数                  | 原型                                                                             | 说明                                                           |
+| --------------------- | -------------------------------------------------------------------------------- | -------------------------------------------------------------- |
+| `of_gpio_named_count` | `int of_gpio_named_count(struct device_node *np, const char *propname)`          | 统计某个属性里定义了几个 GPIO;**空的 GPIO 也会被统计到**      |
+| `of_gpio_count`       | `int of_gpio_count(struct device_node *np)`                                      | 统计 `gpios` 属性里的 GPIO 数量(只能统计 "gpios")            |
 | `of_get_named_gpio`   | `int of_get_named_gpio(struct device_node *np, const char *propname, int index)` | 把 `<&gpio5 7 GPIO_ACTIVE_LOW>` 这类属性值转换为内核 GPIO 编号 |
 
 > 原书说明:`gpio_get_value` / `gpio_set_value` 在书中是宏定义,分别展开为 `int __gpio_get_value(unsigned gpio)` 与 `void __gpio_set_value(unsigned gpio, int value)`,使用时传的是 GPIO 编号。

+ 101 - 88
X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/03-Linux驱动开发核心/04-并发同步与原子操作.md

@@ -1,12 +1,26 @@
 ---
 title: 并发同步与原子操作
-tags: [Linux驱动, 并发, 锁, 原子操作, 嵌入式, 自旋锁, 信号量, 互斥体, 读写锁, 顺序锁, RCU]
+tags:
+  [
+    Linux驱动,
+    并发,
+    锁,
+    原子操作,
+    嵌入式,
+    自旋锁,
+    信号量,
+    互斥体,
+    读写锁,
+    顺序锁,
+    RCU,
+  ]
 created: 2026-09-16
 updated: 2026-09-17
 pdf_ref:
   - "【正点原子】I.MX6U嵌入式Linux驱动开发指南V2.0.1 - 第四十七章 Linux并发与竞争"
   - "【正点原子】I.MX6U嵌入式Linux驱动开发指南V2.0.1 - 第四十八章 Linux并发与竞争实验"
 ---
+
 # 并发同步与原子操作
 
 > 💡 **关联知识**: [[FreeRTOS学习笔记/07-中断管理与临界段]] | [[03-Linux驱动开发核心/05-中断下半部处理]] | [[03-Linux驱动开发核心/07-platform总线模型]]
@@ -42,8 +56,8 @@ sequenceDiagram
 
 ### 1.2 竞态条件产生场景
 
-| 场景                    | 说明                                                 | 危害程度   |
-| ----------------------- | ---------------------------------------------------- | ---------- |
+| 场景              | 说明                                                 | 危害程度   |
+| ----------------- | ---------------------------------------------------- | ---------- |
 | **中断与进程**    | 进程访问共享数据时被中断,中断处理函数也访问同一数据 | ⭐⭐⭐⭐   |
 | **多进程/多线程** | 多个进程或线程同时读写共享内存                       | ⭐⭐⭐     |
 | **多CPU(SMP)**  | 多核处理器上多个CPU核心同时执行访问同一数据          | ⭐⭐⭐⭐⭐ |
@@ -94,8 +108,8 @@ Linux是多任务操作系统,以下因素导致并发不可避免:
 
 Linux内核提供的同步机制从"轻"到"重"排列如下,选择哪一种是驱动开发中最基础的判断:
 
-| 机制               | 典型类型              | 是否可睡眠 | 中断上下文             | 适用场景                   |
-| ------------------ | --------------------- | ---------- | ---------------------- | -------------------------- |
+| 机制         | 典型类型            | 是否可睡眠 | 中断上下文             | 适用场景                   |
+| ------------ | ------------------- | ---------- | ---------------------- | -------------------------- |
 | **原子操作** | `atomic_t`          | 否         | 可用                   | 单个整数计数、状态标志     |
 | **自旋锁**   | `spinlock_t`        | 否         | 可用                   | 极短临界区、中断上下文     |
 | **读写锁**   | `rwlock_t`          | 否         | 可用                   | 读多写少、临界区短         |
@@ -124,8 +138,8 @@ typedef struct {
 
 ### 2.2 原子变量操作API
 
-| 函数                                            | 说明                   |
-| ----------------------------------------------- | ---------------------- |
+| 函数                                          | 说明                   |
+| --------------------------------------------- | ---------------------- |
 | `ATOMIC_INIT(int i)`                          | 定义原子变量时初始化值 |
 | `int atomic_read(atomic_t *v)`                | 读取原子变量的值       |
 | `void atomic_set(atomic_t *v, int i)`         | 设置原子变量的值       |
@@ -169,8 +183,8 @@ static int led_release(struct inode *inode, struct file *filp)
 
 ### 2.4 原子位操作API
 
-| 函数                                        | 说明                 |
-| ------------------------------------------- | -------------------- |
+| 函数                                      | 说明                 |
+| ----------------------------------------- | -------------------- |
 | `void set_bit(int nr, void *p)`           | 设置第nr位为1        |
 | `void clear_bit(int nr, void *p)`         | 清除第nr位           |
 | `void change_bit(int nr, void *p)`        | 反转第nr位           |
@@ -218,8 +232,8 @@ typedef struct spinlock {
 
 ### 3.3 自旋锁API
 
-| 函数                                      | 说明                  | 使用场景     |
-| ----------------------------------------- | --------------------- | ------------ |
+| 函数                                    | 说明                  | 使用场景     |
+| --------------------------------------- | --------------------- | ------------ |
 | `DEFINE_SPINLOCK(spinlock_t lock)`      | 静态定义并初始化      | 全局锁       |
 | `void spin_lock_init(spinlock_t *lock)` | 动态初始化            | 运行时初始化 |
 | `void spin_lock(spinlock_t *lock)`      | 获取锁(忙等待)      | 进程上下文   |
@@ -229,8 +243,8 @@ typedef struct spinlock {
 
 ### 3.4 中断安全的自旋锁API
 
-| 函数                                                                   | 说明                           |
-| ---------------------------------------------------------------------- | ------------------------------ |
+| 函数                                                                 | 说明                           |
+| -------------------------------------------------------------------- | ------------------------------ |
 | `void spin_lock_irq(spinlock_t *lock)`                               | 禁止本地中断并获取锁           |
 | `void spin_unlock_irq(spinlock_t *lock)`                             | 释放锁并开启本地中断           |
 | `void spin_lock_irqsave(spinlock_t *lock, unsigned long flags)`      | 保存中断状态、禁止中断、获取锁 |
@@ -342,13 +356,13 @@ static ssize_t led_write(struct file *filp, const char __user *buf,
 
 ### 4.4 自旋锁 vs 信号量对比表
 
-| 特性                 | 自旋锁             | 信号量              |
-| -------------------- | ------------------ | ------------------- |
+| 特性           | 自旋锁             | 信号量              |
+| -------------- | ------------------ | ------------------- |
 | **等待方式**   | 忙等待(自旋)     | 睡眠等待            |
 | **CPU占用**    | 占用CPU            | 不占用CPU           |
 | **可睡眠**     | ❌ 不可以          | ✅ 可以             |
 | **中断上下文** | ✅ 可以使用        | ❌ 不可以           |
-| **临界区长度** | 短(μs级)        | 长(ms级)          |
+| **临界区长度** | 短(μs级)         | 长(ms级)          |
 | **性能开销**   | 低(忙等)         | 高(上下文切换)    |
 | **适用场景**   | 中断处理、短临界区 | 长时间操作、I/O操作 |
 
@@ -419,14 +433,14 @@ static ssize_t led_write(struct file *filp, const char __user *buf,
 
 ### 5.4 互斥体 vs 自旋锁对比
 
-| 特性                 | 互斥体      | 自旋锁      |
-| -------------------- | ----------- | ----------- |
+| 特性           | 互斥体      | 自旋锁      |
+| -------------- | ----------- | ----------- |
 | **睡眠**       | ✅ 可以睡眠 | ❌ 不能睡眠 |
 | **持有时长**   | 可以较长    | 必须很短    |
 | **中断上下文** | ❌ 不能使用 | ✅ 可以使用 |
 | **优先级继承** | ✅ 支持     | ❌ 不支持   |
 | **递归锁**     | ❌ 不支持   | ❌ 不支持   |
-| **调试支持**   | ✅ 丰富     | ⚠️ 有限   |
+| **调试支持**   | ✅ 丰富     | ⚠️ 有限     |
 
 ---
 
@@ -504,8 +518,8 @@ DEFINE_RWLOCK(my_rwlock);
 
 **读锁 API**(共享)——原书表 47.3.3.1:
 
-| 函数                                                                 | 描述                                                   |
-| -------------------------------------------------------------------- | ------------------------------------------------------ |
+| 函数                                                               | 描述                                                   |
+| ------------------------------------------------------------------ | ------------------------------------------------------ |
 | `void read_lock(rwlock_t *lock)`                                   | 获取读锁                                               |
 | `void read_unlock(rwlock_t *lock)`                                 | 释放读锁                                               |
 | `void read_lock_irq(rwlock_t *lock)`                               | 禁止本地中断,并且获取读锁                             |
@@ -517,8 +531,8 @@ DEFINE_RWLOCK(my_rwlock);
 
 **写锁 API**(排他)——原书表 47.3.3.1:
 
-| 函数                                                                  | 描述                                                   |
-| --------------------------------------------------------------------- | ------------------------------------------------------ |
+| 函数                                                                | 描述                                                   |
+| ------------------------------------------------------------------- | ------------------------------------------------------ |
 | `void write_lock(rwlock_t *lock)`                                   | 获取写锁                                               |
 | `void write_unlock(rwlock_t *lock)`                                 | 释放写锁                                               |
 | `void write_lock_irq(rwlock_t *lock)`                               | 禁止本地中断,并且获取写锁                             |
@@ -598,16 +612,16 @@ MODULE_LICENSE("GPL");
 
 ### 6.5 读写锁 vs 自旋锁对比
 
-| 特性                 | 读写锁(rwlock_t)              | 自旋锁(spinlock_t) |
-| -------------------- | ------------------------------- | -------------------- |
-| **并发性**     | 读者可并发                      | 完全互斥             |
-| **实现开销**   | 稍大(维护读者计数)            | 更小                 |
-| **写者开销**   | 稍大                            | 小                   |
-| **中断上下文** | ✅ 可用                         | ✅ 可用              |
-| **可睡眠**     | ❌ 不可以                       | ❌ 不可以            |
-| **适用场景**   | 读多写少(读:写 > 10:1)        | 读写均衡或写为主     |
+| 特性           | 读写锁(rwlock_t)            | 自旋锁(spinlock_t) |
+| -------------- | ----------------------------- | -------------------- |
+| **并发性**     | 读者可并发                    | 完全互斥             |
+| **实现开销**   | 稍大(维护读者计数)          | 更小                 |
+| **写者开销**   | 稍大                          | 小                   |
+| **中断上下文** | ✅ 可用                       | ✅ 可用              |
+| **可睡眠**     | ❌ 不可以                     | ❌ 不可以            |
+| **适用场景**   | 读多写少(读:写 > 10:1)      | 读写均衡或写为主     |
 | **饥饿风险**   | ⚠️ 读者持续涌入时写者可能饥饿 | 无                   |
-| **优先级继承** | ❌ 不支持                       | ❌ 不支持            |
+| **优先级继承** | ❌ 不支持                     | ❌ 不支持            |
 
 ### 6.6 读写锁注意事项
 
@@ -689,11 +703,10 @@ seqlock_init(&my_seqlock);
 DEFINE_SEQLOCK(my_seqlock);
 ```
 
-
 **顺序锁写操作 API**(原书表 47.3.3.2):
 
-| 函数                                                                    | 描述                                                       |
-| ----------------------------------------------------------------------- | ---------------------------------------------------------- |
+| 函数                                                                  | 描述                                                       |
+| --------------------------------------------------------------------- | ---------------------------------------------------------- |
 | `void write_seqlock(seqlock_t *sl)`                                   | 获取写顺序锁                                               |
 | `void write_sequnlock(seqlock_t *sl)`                                 | 释放写顺序锁                                               |
 | `void write_seqlock_irq(seqlock_t *sl)`                               | 禁止本地中断,并且获取写顺序锁                             |
@@ -705,8 +718,8 @@ DEFINE_SEQLOCK(my_seqlock);
 
 **顺序锁读操作 API**(原书表 47.3.3.2):
 
-| 函数                                                            | 描述                                                                           |
-| --------------------------------------------------------------- | ------------------------------------------------------------------------------ |
+| 函数                                                          | 描述                                                                           |
+| ------------------------------------------------------------- | ------------------------------------------------------------------------------ |
 | `unsigned read_seqbegin(const seqlock_t *sl)`                 | 读单元访问共享资源的时候调用此函数,此函数会返回顺序锁的顺序号                 |
 | `unsigned read_seqretry(const seqlock_t *sl, unsigned start)` | 读结束以后调用此函数检查在读的过程中有没有对资源进行写操作,如果有的话就要重读 |
 
@@ -772,16 +785,16 @@ static ssize_t sensor_read(struct file *filp, char __user *buf,
 
 ### 7.4 顺序锁 vs 读写锁对比
 
-| 特性                     | 顺序锁(seqlock)                | 读写锁(rwlock)        |
-| ------------------------ | -------------------------------- | ----------------------- |
-| **读者加锁**       | ❌ 完全不加锁                    | ✅ 需要加读锁           |
-| **读者开销**       | 极低(2 次读序号)               | 中(原子操作)          |
-| **读者可能重试**   | ✅ 会被写者打断后重试            | ❌ 不会                 |
-| **写者饥饿**       | ❌ 不会(写者优先)              | ⚠️ 可能               |
+| 特性               | 顺序锁(seqlock)          | 读写锁(rwlock)        |
+| ------------------ | -------------------------- | ----------------------- |
+| **读者加锁**       | ❌ 完全不加锁              | ✅ 需要加读锁           |
+| **读者开销**       | 极低(2 次读序号)         | 中(原子操作)          |
+| **读者可能重试**   | ✅ 会被写者打断后重试      | ❌ 不会                 |
+| **写者饥饿**       | ❌ 不会(写者优先)        | ⚠️ 可能                 |
 | **可保护的数据**   | 仅限**不含指针**的简单数据 | 任意数据(含链表/指针) |
-| **保护指针的危险** | ⚠️ 读侧可能读到野指针          | ✅ 安全                 |
-| **典型场景**       | jiffies、时间戳、统计计数        | 配置表、缓存            |
-| **是否可睡眠**     | ❌ 写侧不可睡眠                  | ❌ 不可睡眠             |
+| **保护指针的危险** | ⚠️ 读侧可能读到野指针      | ✅ 安全                 |
+| **典型场景**       | jiffies、时间戳、统计计数  | 配置表、缓存            |
+| **是否可睡眠**     | ❌ 写侧不可睡眠            | ❌ 不可睡眠             |
 
 > ⚠️ **关键限制**:顺序锁的读侧**不能保护指针**。因为读者在无锁读取指针时,写者可能已经释放(free)了指针指向的内存,读者解引用就是**野指针访问**。所以顺序锁只能用于"纯值类型"的数据(整数、结构体内全是整数)。
 
@@ -859,11 +872,11 @@ kfree_rcu(ptr, rcu_head_field);    /* 延迟释放 */
 
 **RCU 链表 API**:
 
-| 函数                                           | 说明                                   |
-| ---------------------------------------------- | -------------------------------------- |
-| `list_add_rcu(new, head)`                    | RCU 版链表插入                         |
-| `list_del_rcu(entry)`                        | RCU 版链表删除(不释放内存,仅断链)   |
-| `list_replace_rcu(old, new)`                 | RCU 版节点替换                         |
+| 函数                                         | 说明                                 |
+| -------------------------------------------- | ------------------------------------ |
+| `list_add_rcu(new, head)`                    | RCU 版链表插入                       |
+| `list_del_rcu(entry)`                        | RCU 版链表删除(不释放内存,仅断链) |
+| `list_replace_rcu(old, new)`                 | RCU 版节点替换                       |
 | `list_for_each_entry_rcu(pos, head, member)` | RCU 版遍历(需在`rcu_read_lock` 内) |
 
 ### 8.3 RCU 使用示例
@@ -932,8 +945,8 @@ static void del_first_node(void)
 
 ### 8.4 RCU vs 读写锁 vs 顺序锁
 
-| 特性                       | RCU                                | 顺序锁          | 读写锁         |
-| -------------------------- | ---------------------------------- | --------------- | -------------- |
+| 特性                 | RCU                                | 顺序锁          | 读写锁         |
+| -------------------- | ---------------------------------- | --------------- | -------------- |
 | **读者开销**         | 极低(近乎零)                     | 极低(读序号)  | 中(原子操作) |
 | **读者会重试**       | ❌ 不会                            | ✅ 会           | ❌ 不会        |
 | **读者是否阻塞写者** | ❌ 完全不阻塞                      | ❌ 不阻塞       | ✅ 阻塞        |
@@ -998,16 +1011,16 @@ DECLARE_COMPLETION(my_completion);
 DECLARE_COMPLETION_ONSTACK(my_completion);   /* 栈上定义,用于局部等待 */
 ```
 
-| 函数                                                                                       | 说明                                     |
-| ------------------------------------------------------------------------------------------ | ---------------------------------------- |
-| `void init_completion(struct completion *x)`                                             | 初始化完成量(计数=0)                   |
-| `void reinit_completion(struct completion *x)`                                           | 重置完成量(允许重复使用)               |
-| `void wait_for_completion(struct completion *x)`                                         | 等待完成,**不可被信号打断**       |
+| 函数                                                                                     | 说明                                   |
+| ---------------------------------------------------------------------------------------- | -------------------------------------- |
+| `void init_completion(struct completion *x)`                                             | 初始化完成量(计数=0)                 |
+| `void reinit_completion(struct completion *x)`                                           | 重置完成量(允许重复使用)             |
+| `void wait_for_completion(struct completion *x)`                                         | 等待完成,**不可被信号打断**           |
 | `int wait_for_completion_interruptible(struct completion *x)`                            | 可被信号打断,被打断返回`-ERESTARTSYS` |
-| `int wait_for_completion_killable(struct completion *x)`                                 | 可被致命信号打断                         |
-| `unsigned long wait_for_completion_timeout(struct completion *x, unsigned long timeout)` | 带超时等待,超时返回 0                   |
-| `void complete(struct completion *x)`                                                    | 唤醒**一个**等待者(计数+1)       |
-| `void complete_all(struct completion *x)`                                                | 唤醒**所有**等待者                 |
+| `int wait_for_completion_killable(struct completion *x)`                                 | 可被致命信号打断                       |
+| `unsigned long wait_for_completion_timeout(struct completion *x, unsigned long timeout)` | 带超时等待,超时返回 0                 |
+| `void complete(struct completion *x)`                                                    | 唤醒**一个**等待者(计数+1)           |
+| `void complete_all(struct completion *x)`                                                | 唤醒**所有**等待者                     |
 
 ### 9.3 完成量使用示例
 
@@ -1057,16 +1070,16 @@ static int __init completion_demo_init(void)
 
 ### 9.4 完成量 vs 信号量对比
 
-| 特性                     | 完成量(completion)       | 信号量(semaphore)            |
-| ------------------------ | -------------------------- | ------------------------------ |
-| **语义**           | "等待事件完成"             | "资源计数 / 互斥"              |
+| 特性               | 完成量(completion)       | 信号量(semaphore)          |
+| ------------------ | -------------------------- | ---------------------------- |
+| **语义**           | "等待事件完成"             | "资源计数 / 互斥"            |
 | **初始值**         | 固定为 0                   | 可任意(`sema_init(&s, n)`) |
-| **主要用途**       | 一对一/一对多事件通知      | 资源池、互斥                   |
-| **能否重复使用**   | 需`reinit_completion()`  | 天然支持                       |
-| **是否可睡眠**     | ✅ 可以                    | ✅ 可以                        |
-| **中断上下文使用** | ✅ 只能`complete()`      | ✅ 只能`up()`                |
-| **代码可读性**     | 语义更明确                 | 需要看初值才知道意图           |
-| **典型场景**       | 等待硬件就绪、等待线程退出 | 限制并发数、简单互斥           |
+| **主要用途**       | 一对一/一对多事件通知      | 资源池、互斥                 |
+| **能否重复使用**   | 需`reinit_completion()`    | 天然支持                     |
+| **是否可睡眠**     | ✅ 可以                    | ✅ 可以                      |
+| **中断上下文使用** | ✅ 只能`complete()`        | ✅ 只能`up()`                |
+| **代码可读性**     | 语义更明确                 | 需要看初值才知道意图         |
+| **典型场景**       | 等待硬件就绪、等待线程退出 | 限制并发数、简单互斥         |
 
 > 💡 **选择建议**:如果只是想"等某件事做完",用**完成量**比信号量语义更清晰、更不容易出错;如果需要"限制最多 N 个并发"或"互斥",用信号量或互斥体。
 
@@ -1280,8 +1293,8 @@ MODULE_AUTHOR("zuozhongkai");
 
 ### 10.2 代码逐行解析
 
-| 行号                                   | 代码                   | 说明                 |
-| -------------------------------------- | ---------------------- | -------------------- |
+| 行号                                 | 代码                   | 说明                 |
+| ------------------------------------ | ---------------------- | -------------------- |
 | `atomic_t lock`                      | 设备结构体中的原子变量 | 用于实现设备互斥访问 |
 | `atomic_set(&gpioled.lock, 1)`       | 初始化原子变量为1      | 表示设备可用         |
 | `atomic_dec_and_test(&gpioled.lock)` | 原子减1并测试是否为0   | 如果为0表示获取成功  |
@@ -1473,20 +1486,20 @@ gantt
 
 ### 12.1 IMX6ULL vs STM32 vs RK3568并发机制差异
 
-| 特性                       | IMX6ULL            | STM32         | RK3568                    |
-| -------------------------- | ------------------ | ------------- | ------------------------- |
-| **CPU架构**          | Cortex-A7 单核     | Cortex-M4/M7  | Cortex-A55 四核           |
-| **并发模型**         | 单核+中断          | 单核+中断     | 多核SMP+中断              |
-| **自旋锁**           | ✅ 支持            | ❌ 不需要     | ✅ 核间同步               |
-| **原子操作**         | ✅ 支持            | ⚠️ 部分支持 | ✅ 支持                   |
-| **互斥体**           | ✅ 支持            | ❌ 不支持     | ✅ 支持                   |
-| **信号量**           | ✅ 支持            | ✅ 支持       | ✅ 支持                   |
-| **读写锁**           | ✅ 支持            | ❌ 不需要     | ✅ 支持                   |
-| **顺序锁**           | ✅ 支持            | ❌ 不需要     | ✅ 支持                   |
-| **RCU**              | ✅ 支持            | ❌ 不需要     | ✅ 支持(重点)           |
-| **中断优先级**       | 32级               | 16级          | 32级                      |
-| **典型锁选择**       | spinlock_irqsave   | 临界区        | mutex/spinlock            |
-| **其他类型锁的使用** | 内核为主,驱动少用 | 无对应机制    | RCU 广泛用于网络/文件系统 |
+| 特性                 | IMX6ULL            | STM32        | RK3568                    |
+| -------------------- | ------------------ | ------------ | ------------------------- |
+| **CPU架构**          | Cortex-A7 单核     | Cortex-M4/M7 | Cortex-A55 四核           |
+| **并发模型**         | 单核+中断          | 单核+中断    | 多核SMP+中断              |
+| **自旋锁**           | ✅ 支持            | ❌ 不需要    | ✅ 核间同步               |
+| **原子操作**         | ✅ 支持            | ⚠️ 部分支持  | ✅ 支持                   |
+| **互斥体**           | ✅ 支持            | ❌ 不支持    | ✅ 支持                   |
+| **信号量**           | ✅ 支持            | ✅ 支持      | ✅ 支持                   |
+| **读写锁**           | ✅ 支持            | ❌ 不需要    | ✅ 支持                   |
+| **顺序锁**           | ✅ 支持            | ❌ 不需要    | ✅ 支持                   |
+| **RCU**              | ✅ 支持            | ❌ 不需要    | ✅ 支持(重点)           |
+| **中断优先级**       | 32级               | 16级         | 32级                      |
+| **典型锁选择**       | spinlock_irqsave   | 临界区       | mutex/spinlock            |
+| **其他类型锁的使用** | 内核为主,驱动少用 | 无对应机制   | RCU 广泛用于网络/文件系统 |
 
 ### 12.2 多核 vs 单核的锁选择
 
@@ -1526,7 +1539,7 @@ flowchart TD
 | 等待方式   | 忙等待(占用CPU)  | 睡眠(释放CPU)  |
 | 可睡眠     | ❌ 不可以          | ✅ 可以          |
 | 中断上下文 | ✅ 可以使用        | ❌ 不可以        |
-| 临界区长度 | 短(μs级)        | 长(ms级)       |
+| 临界区长度 | 短(μs级)         | 长(ms级)       |
 | CPU占用    | 高(忙等)         | 低(上下文切换) |
 | 适用场景   | 中断处理、短临界区 | 长时间操作、I/O  |
 

+ 16 - 17
X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/03-Linux驱动开发核心/05-中断下半部处理.md

@@ -61,27 +61,27 @@ int request_irq(unsigned int irq,
                 void *dev);
 ```
 
-| 参数      | 含义                                                                                       |
-| --------- | ------------------------------------------------------------------------------------------ |
-| `irq`     | 要申请中断的中断号                                                                         |
-| `handler` | 中断处理函数,中断发生后就执行                                                             |
-| `flags`   | 中断标志,见下表                                                                           |
-| `name`    | 中断名字,设置后可在 `/proc/interrupts` 中看到                                             |
-| `dev`     | 区分共享中断;一般传设备结构体,会作为第二个参数传给中断处理函数                           |
+| 参数      | 含义                                                             |
+| --------- | ---------------------------------------------------------------- |
+| `irq`     | 要申请中断的中断号                                               |
+| `handler` | 中断处理函数,中断发生后就执行                                   |
+| `flags`   | 中断标志,见下表                                                 |
+| `name`    | 中断名字,设置后可在 `/proc/interrupts` 中看到                   |
+| `dev`     | 区分共享中断;一般传设备结构体,会作为第二个参数传给中断处理函数 |
 
 返回值:`0` 申请成功;其他负值失败;返回 `-EBUSY` 表示中断已被申请。
 
 **常用中断标志(原书表 51.1.1.1)**:
 
-| 标志                    | 描述                                                                 |
-| ----------------------- | -------------------------------------------------------------------- |
-| `IRQF_SHARED`           | 多个设备共享一根中断线,共享的所有中断都必须指定此标志;此时 `dev` 是唯一区分标志 |
-| `IRQF_ONESHOT`          | 单次中断,中断执行一次就结束                                          |
-| `IRQF_TRIGGER_NONE`     | 无触发                                                               |
-| `IRQF_TRIGGER_RISING`   | 上升沿触发                                                           |
-| `IRQF_TRIGGER_FALLING`  | 下降沿触发                                                           |
-| `IRQF_TRIGGER_HIGH`     | 高电平触发                                                           |
-| `IRQF_TRIGGER_LOW`      | 低电平触发                                                           |
+| 标志                   | 描述                                                                              |
+| ---------------------- | --------------------------------------------------------------------------------- |
+| `IRQF_SHARED`          | 多个设备共享一根中断线,共享的所有中断都必须指定此标志;此时 `dev` 是唯一区分标志 |
+| `IRQF_ONESHOT`         | 单次中断,中断执行一次就结束                                                      |
+| `IRQF_TRIGGER_NONE`    | 无触发                                                                            |
+| `IRQF_TRIGGER_RISING`  | 上升沿触发                                                                        |
+| `IRQF_TRIGGER_FALLING` | 下降沿触发                                                                        |
+| `IRQF_TRIGGER_HIGH`    | 高电平触发                                                                        |
+| `IRQF_TRIGGER_LOW`     | 低电平触发                                                                        |
 
 这些标志可以通过 `|` 组合。例如 I.MX6U-ALPHA 的 KEY0 使用 GPIO1_IO18,按下为低电平,可设为 `IRQF_TRIGGER_FALLING`。
 
@@ -549,7 +549,6 @@ static int __init xxxx_init(void)
 }
 ```
 
-
 ### 4.5 创建和销毁工作队列
 
 > ⚠️ **来源说明**:本节不属于《I.MX6U嵌入式Linux驱动开发指南》内容,为扩展知识。

+ 0 - 1
X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/03-Linux驱动开发核心/06-阻塞IO与poll机制.md

@@ -470,7 +470,6 @@ int flags = fcntl(fd, F_GETFL);
 fcntl(fd, F_SETFL, flags | FASYNC);
 ```
 
-
 **信号处理函数示例**:
 
 ```c

+ 21 - 22
X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/03-Linux驱动开发核心/面试-Linux驱动开发.md

@@ -1231,7 +1231,6 @@ bit 15:14: PUS          上下拉电阻值 (4档)
 bit 16:    HYS          迟滞比较器使能 (IO作输入时有用)
 ```
 
-
 多状态 pinctrl(低功耗场景):
 
 ```dts
@@ -1347,7 +1346,7 @@ static int led_probe(struct platform_device *pdev)
 
 1. `GPIO_ACTIVE_LOW` 表示"逻辑有效电平为低",即逻辑 1 对应物理低电平
 2. 使用 **gpiod 新 API** 时,内核会自动做电平反转,写 1 实际输出物理低电平
-3. 使用 _*旧 gpio_* API_* 时,`GPIO_ACTIVE_LOW` 不会被自动处理,通常仍需按实际物理电平调用
+3. 使用 _\*旧 gpio_* API_* 时,`GPIO_ACTIVE_LOW` 不会被自动处理,通常仍需按实际物理电平调用
 4. 这正是新 API 相比旧 API 更"语义化"的体现:驱动只关心"开/关",不关心硬件极性
 5. 点不亮的常见原因是:极性理解错误、pinctrl 没配、GPIO 没设输出
 
@@ -1573,18 +1572,18 @@ typedef struct {
 
 常用 API:
 
-| 函数                                    | 说明               |
-| --------------------------------------- | ------------------ |
-| `ATOMIC_INIT(int i)`                    | 静态定义并初始化   |
-| `atomic_read(v)`                        | 读值               |
-| `atomic_set(v, i)`                      | 设值               |
-| `atomic_inc(v)` / `atomic_dec(v)`       | 自增 / 自减        |
-| `atomic_add(i, v)` / `atomic_sub(i, v)` | 加 / 减            |
-| `atomic_dec_return(v)`                  | 自减并返回 v 的值  |
-| `atomic_inc_return(v)`                  | 自增并返回 v 的值  |
-| `atomic_dec_and_test(v)`                | 自减并测试是否为 0 |
-| `atomic_inc_and_test(v)`                | 自增并测试是否为 0 |
-| `atomic_sub_and_test(i, v)`             | 减并测试是否为 0   |
+| 函数                                    | 说明                  |
+| --------------------------------------- | --------------------- |
+| `ATOMIC_INIT(int i)`                    | 静态定义并初始化      |
+| `atomic_read(v)`                        | 读值                  |
+| `atomic_set(v, i)`                      | 设值                  |
+| `atomic_inc(v)` / `atomic_dec(v)`       | 自增 / 自减           |
+| `atomic_add(i, v)` / `atomic_sub(i, v)` | 加 / 减               |
+| `atomic_dec_return(v)`                  | 自减并返回 v 的值     |
+| `atomic_inc_return(v)`                  | 自增并返回 v 的值     |
+| `atomic_dec_and_test(v)`                | 自减并测试是否为 0    |
+| `atomic_inc_and_test(v)`                | 自增并测试是否为 0    |
+| `atomic_sub_and_test(i, v)`             | 减并测试是否为 0      |
 | `atomic_add_negative(i, v)`             | 加 i 后结果为负返回真 |
 
 对应 64 位版本为 `atomic64_t`(`typedef struct { long long counter; } atomic64_t;`),API 前缀换为 `atomic64_`、类型换为 `long long`。本书 Cortex-A7 为 32 位架构,只用 32 位原子操作。
@@ -2248,15 +2247,15 @@ free_irq(irqnum, &imx6uirq);
 
 flags 常用值:
 
-| flag                  | 含义                   |
-| --------------------- | ---------------------- |
-| IRQF_TRIGGER_NONE     | 无触发                 |
-| IRQF_TRIGGER_RISING   | 上升沿触发             |
-| IRQF_TRIGGER_FALLING  | 下降沿触发             |
-| IRQF_TRIGGER_HIGH/LOW | 高/低电平触发          |
-| IRQF_SHARED           | 共享中断线             |
+| flag                  | 含义                                         |
+| --------------------- | -------------------------------------------- |
+| IRQF_TRIGGER_NONE     | 无触发                                       |
+| IRQF_TRIGGER_RISING   | 上升沿触发                                   |
+| IRQF_TRIGGER_FALLING  | 下降沿触发                                   |
+| IRQF_TRIGGER_HIGH/LOW | 高/低电平触发                                |
+| IRQF_SHARED           | 共享中断线                                   |
 | IRQF_ONESHOT          | 单次中断(中断线上保持屏蔽,线程化中断常用) |
-| IRQF_NO_SUSPEND       | 休眠期间不关闭         |
+| IRQF_NO_SUSPEND       | 休眠期间不关闭                               |
 
 > **原书要点**:`request_irq` 可能会导致睡眠,因此不能在中断上下文或其他禁止睡眠的代码段中使用;`request_irq` 会激活(使能)中断,不需要我们手动去使能。返回 `-EBUSY` 表示中断已经被申请。
 

+ 8 - 8
X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/04-Linux总线与接口驱动/01-I2C驱动开发.md

@@ -429,14 +429,14 @@ cat /sys/bus/i2c/devices/0-001e/name
 
 ### 4.1 驱动注册/注销
 
-| 函数                                          | 说明                    |
-| --------------------------------------------- | ----------------------- |
-| `i2c_add_driver(driver)`                      | 注册I2C设备驱动(常用) |
-| `i2c_del_driver(driver)`                      | 注销I2C设备驱动         |
-| `i2c_register_driver(owner, driver)`          | 注册驱动(底层函数)    |
-| `i2c_add_adapter(adapter)`                    | 注册适配器(动态总线号)|
-| `i2c_add_numbered_adapter(adap)`              | 注册适配器(静态总线号)|
-| `i2c_del_adapter(adap)`                       | 注销适配器              |
+| 函数                                 | 说明                     |
+| ------------------------------------ | ------------------------ |
+| `i2c_add_driver(driver)`             | 注册I2C设备驱动(常用)  |
+| `i2c_del_driver(driver)`             | 注销I2C设备驱动          |
+| `i2c_register_driver(owner, driver)` | 注册驱动(底层函数)     |
+| `i2c_add_adapter(adapter)`           | 注册适配器(动态总线号) |
+| `i2c_add_numbered_adapter(adap)`     | 注册适配器(静态总线号) |
+| `i2c_del_adapter(adap)`              | 注销适配器               |
 
 **函数原型**(原书第 61.1.1/61.1.2 节):
 

+ 0 - 1
X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/04-Linux总线与接口驱动/02-SPI驱动开发.md

@@ -389,7 +389,6 @@ static int spi_receive(struct spi_device *spi, u8 *buf, int len)
 }
 ```
 
-
 ## 五、完整源码分析
 
 ### 5.1 ICM20608寄存器定义头文件

+ 56 - 57
X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/04-Linux总线与接口驱动/03-USB驱动开发.md

@@ -22,14 +22,14 @@ USB(Universal Serial Bus,通用串行总线)是一种主从式总线架构
 
 USB 版本演进(原书 67.1.1 节):
 
-| 版本      | 速率      | 说明                                             |
-| --------- | --------- | ------------------------------------------------ |
-| USB 1.0   | 1.5 Mbps  | 1996 年正式发布,低速                          |
-| USB 1.1   | 12 Mbps   | Full-Speed(FS) 全速                              |
-| USB 2.0   | 480 Mbps  | High-Speed(HS),半双工,兼容 USB1.0;另有 FS 12Mbps |
-| USB 3.0   | 5 Gbps    | 引入全双工(2 对差分线发送、2 对接收)           |
-| USB 3.1   | 10 Gbps   | 在 USB3.0 基础上提升                             |
-| USB 3.2   | 20 Gbps   | —                                                |
+| 版本    | 速率     | 说明                                                |
+| ------- | -------- | --------------------------------------------------- |
+| USB 1.0 | 1.5 Mbps | 1996 年正式发布,低速                               |
+| USB 1.1 | 12 Mbps  | Full-Speed(FS) 全速                                 |
+| USB 2.0 | 480 Mbps | High-Speed(HS),半双工,兼容 USB1.0;另有 FS 12Mbps |
+| USB 3.0 | 5 Gbps   | 引入全双工(2 对差分线发送、2 对接收)              |
+| USB 3.1 | 10 Gbps  | 在 USB3.0 基础上提升                                |
+| USB 3.2 | 20 Gbps  | —                                                   |
 
 > **命名规范**:USB-IF 公布新命名后不再使用 USB3.0/3.1 的旧称,统一为 USB3.2,原 USB3.0、USB3.1、USB3.2 分别称为 **USB3.2 Gen1、USB3.2 Gen2、USB3.2 Gen2x2**。
 
@@ -79,32 +79,32 @@ graph TD
 
 **描述符详细结构**(原书表 67.3.1.2 ~ 67.3.1.7):
 
-*设备描述符(18 字节,bDescriptorType=0x01)*
+_设备描述符(18 字节,bDescriptorType=0x01)_
 
-| 偏移 | 域                | 大小(B) | 描述                     |
-| ---- | ----------------- | ------- | ------------------------ |
-| 0    | bLength           | 1       | 描述符长度,18           |
-| 1    | bDescriptorType   | 1       | 类型,0x01               |
-| 2    | bcdUSB            | 2       | USB 版本号               |
-| 4    | bDeviceClass      | 1       | 设备类                   |
-| 5    | bDeviceSubClass   | 1       | 设备子类                 |
-| 6    | bDeviceProtocol   | 1       | 设备协议                 |
-| 7    | bMaxPacketSize0   | 1       | 端点 0 最大包长度        |
-| 8    | idVendor          | 2       | 厂商 ID (VID)            |
-| 10   | idProduct         | 2       | 产品 ID (PID)            |
-| 12   | bcdDevice         | 2       | 设备版本号               |
-| 14   | iManufacturer     | 1       | 厂商字符串描述符索引     |
-| 15   | iProduct          | 1       | 产品字符串描述符索引     |
-| 16   | iSerialNumber     | 1       | 序列号字符串描述符索引   |
-| 17   | bNumConfigurations| 1       | 配置描述符数目           |
+| 偏移 | 域                 | 大小(B) | 描述                   |
+| ---- | ------------------ | ------- | ---------------------- |
+| 0    | bLength            | 1       | 描述符长度,18         |
+| 1    | bDescriptorType    | 1       | 类型,0x01             |
+| 2    | bcdUSB             | 2       | USB 版本号             |
+| 4    | bDeviceClass       | 1       | 设备类                 |
+| 5    | bDeviceSubClass    | 1       | 设备子类               |
+| 6    | bDeviceProtocol    | 1       | 设备协议               |
+| 7    | bMaxPacketSize0    | 1       | 端点 0 最大包长度      |
+| 8    | idVendor           | 2       | 厂商 ID (VID)          |
+| 10   | idProduct          | 2       | 产品 ID (PID)          |
+| 12   | bcdDevice          | 2       | 设备版本号             |
+| 14   | iManufacturer      | 1       | 厂商字符串描述符索引   |
+| 15   | iProduct           | 1       | 产品字符串描述符索引   |
+| 16   | iSerialNumber      | 1       | 序列号字符串描述符索引 |
+| 17   | bNumConfigurations | 1       | 配置描述符数目         |
 
-*配置描述符(9 字节,bDescriptorType=0x02)*:关键域 `wTotalLength`(整个配置信息总长度)、`bNumInterfaces`(接口数)、`bConfigurationValue`(配置值)、`bmAttributes`(D7保留/D6自给电源/D5远程唤醒)、`bMaxPower`(总线电流,单位 2mA)。
+_配置描述符(9 字节,bDescriptorType=0x02)_:关键域 `wTotalLength`(整个配置信息总长度)、`bNumInterfaces`(接口数)、`bConfigurationValue`(配置值)、`bmAttributes`(D7保留/D6自给电源/D5远程唤醒)、`bMaxPower`(总线电流,单位 2mA)。
 
-*接口描述符(9 字节,bDescriptorType=0x04)*:`bInterfaceNumber`(接口编号,从 0 开始)、`bAlternateSetting`(备用编号)、`bNumEndpoints`(端点数量)、`bInterfaceClass`/`bInterfaceSubClass`/`bInterfaceProtocol`(类/子类/协议)、`iInterface`(字符串索引)。
+_接口描述符(9 字节,bDescriptorType=0x04)_:`bInterfaceNumber`(接口编号,从 0 开始)、`bAlternateSetting`(备用编号)、`bNumEndpoints`(端点数量)、`bInterfaceClass`/`bInterfaceSubClass`/`bInterfaceProtocol`(类/子类/协议)、`iInterface`(字符串索引)。
 
-*端点描述符(7 字节,bDescriptorType=0x05)*:`bEndpointAddress`(bit3:0 端点号,bit7 方向:0=OUT 输出端点,1=IN 输入端点)、`bmAttributes`(bit1:0 传输类型:00控制/01同步/10批量/11中断)、`wMaxPacketSize`(最大包长)、`bInterval`(轮询间隔,同步传输须为 1ms,中断传输 1~255ms)。
+_端点描述符(7 字节,bDescriptorType=0x05)_:`bEndpointAddress`(bit3:0 端点号,bit7 方向:0=OUT 输出端点,1=IN 输入端点)、`bmAttributes`(bit1:0 传输类型:00控制/01同步/10批量/11中断)、`wMaxPacketSize`(最大包长)、`bInterval`(轮询间隔,同步传输须为 1ms,中断传输 1~255ms)。
 
-*字符串描述符(bDescriptorType=0x03)*:首字节 `bLength=N+2`,随后为 `wLANGID[]` 语言标识码数组;主机指定语言与索引再次请求后,设备返回 Unicode 编码字符串。
+_字符串描述符(bDescriptorType=0x03)_:首字节 `bLength=N+2`,随后为 `wLANGID[]` 语言标识码数组;主机指定语言与索引再次请求后,设备返回 Unicode 编码字符串。
 
 ### 1.3 USB传输类型
 
@@ -131,25 +131,25 @@ USB 数据包由同步域(SYNC)、包标识符(PID)、数据域、CRC 
 
 主要包类型:
 
-| PID类型 | PID名字 | PID<3:0> | 用途                         |
-| ------- | ------- | -------- | ---------------------------- |
-| 令牌包  | OUT     | 0001     | 主机通知从机将要输出数据     |
-| 令牌包  | IN      | 1001     | 主机通知从机将要输入数据     |
-| 令牌包  | SOF     | 0101     | 帧起始包                     |
-| 令牌包  | SETUP   | 1101     | 开始一个控制传输             |
-| 数据包  | DATA0   | 0011     | 偶数据包                     |
-| 数据包  | DATA1   | 1011     | 奇数据包                     |
-| 数据包  | DATA2   | 0111     | 适用于高速和等时传输的数据包 |
-| 数据包  | MDATA   | 1111     | 用于高速分裂/等时传输        |
-| 握手包  | ACK     | 0010     | 确认包,传输正确             |
-| 握手包  | NAK     | 1010     | 不确认包,设备未准备好       |
-| 握手包  | STALL   | 1110     | 设备不支持该请求或端点挂起   |
-| 握手包  | NYET    | 0110     | 接收未响应,未准备好         |
-| 特殊包  | PRE     | 1100     | 前导,令牌包                 |
-| 特殊包  | ERR     | 1100     | 错误,握手包                 |
-| 特殊包  | SPLIT   | 1000     | 分裂传输(Split),令牌包      |
-| 特殊包  | PING    | 0100     | PING 测试,令牌包            |
-| 特殊包  | Reserved| 0000     | 保留                         |
+| PID类型 | PID名字  | PID<3:0> | 用途                         |
+| ------- | -------- | -------- | ---------------------------- |
+| 令牌包  | OUT      | 0001     | 主机通知从机将要输出数据     |
+| 令牌包  | IN       | 1001     | 主机通知从机将要输入数据     |
+| 令牌包  | SOF      | 0101     | 帧起始包                     |
+| 令牌包  | SETUP    | 1101     | 开始一个控制传输             |
+| 数据包  | DATA0    | 0011     | 偶数据包                     |
+| 数据包  | DATA1    | 1011     | 奇数据包                     |
+| 数据包  | DATA2    | 0111     | 适用于高速和等时传输的数据包 |
+| 数据包  | MDATA    | 1111     | 用于高速分裂/等时传输        |
+| 握手包  | ACK      | 0010     | 确认包,传输正确             |
+| 握手包  | NAK      | 1010     | 不确认包,设备未准备好       |
+| 握手包  | STALL    | 1110     | 设备不支持该请求或端点挂起   |
+| 握手包  | NYET     | 0110     | 接收未响应,未准备好         |
+| 特殊包  | PRE      | 1100     | 前导,令牌包                 |
+| 特殊包  | ERR      | 1100     | 错误,握手包                 |
+| 特殊包  | SPLIT    | 1000     | 分裂传输(Split),令牌包      |
+| 特殊包  | PING     | 0100     | PING 测试,令牌包            |
+| 特殊包  | Reserved | 0000     | 保留                         |
 
 > **PID 编码规则**(原书 67.3.3 节):PID 共 8 位,低 4 位 PID3~PID0 有效,高 4 位 PID7~PID4 是低 4 位的取反,传输顺序为 PID0→PID7。令牌包 PID1~0=01,数据包=11,握手包=10,特殊包=00。例如 SETUP 包 PID3~0=1101,取反得 PID7~4=0010,按传输顺序排列为 10110100=0xB4。
 
@@ -244,12 +244,12 @@ Linux USB 子系统分为三层:
 
 Linux 内核支持三种 HCD 实现:
 
-| HCD  | 全称                                 | 适用场景                          |
-| ---- | ------------------------------------ | --------------------------------- |
-| OHCI | Open Host Controller Interface       | USB 1.1(非 X86,嵌入式 USB 控制器) |
+| HCD  | 全称                                 | 适用场景                                   |
+| ---- | ------------------------------------ | ------------------------------------------ |
+| OHCI | Open Host Controller Interface       | USB 1.1(非 X86,嵌入式 USB 控制器)       |
 | UHCI | Universal Host Controller Interface  | USB 1.0/1.1(Intel 主导,X86,硬件成本低) |
 | EHCI | Enhanced Host Controller Interface   | USB 2.0 高速(全速/低速由 OHCI/UHCI 提供) |
-| xHCI | eXtensible Host Controller Interface | USB 3.0+,可支持所有速度,用于取代前三种 |
+| xHCI | eXtensible Host Controller Interface | USB 3.0+,可支持所有速度,用于取代前三种   |
 
 I.MX6ULL 内部集成两个独立的 USB2.0 控制器内核(Core0/Core1),分别连接到 **OTG1 和 OTG2**(原书 67.1.5 节):
 
@@ -460,7 +460,6 @@ int usb_interrupt_msg(struct usb_device *usb_dev,
                       int timeout);
 ```
 
-
 ### 4.4 控制传输
 
 ```c
@@ -758,10 +757,10 @@ tty1::askfirst:-/bin/sh
 
 **5) OTG 从机(Gadget)实验**:将相关驱动编译为模块 `[M]`,编译后得到并依次加载:
 
-| 实验        | 生成的 .ko 模块(按加载顺序)                                                                 |
-| ----------- | --------------------------------------------------------------------------------------------- |
-| 模拟 U 盘   | `libcomposite.ko` → `function/usb_f_mass_storage.ko` → `legacy/g_mass_storage.ko`              |
-| USB 声卡    | `libcomposite.ko` → `function/usb_f_uac1.ko` → `legacy/g_audio.ko`(UAC 1.0 Legacy)           |
+| 实验      | 生成的 .ko 模块(按加载顺序)                                                        |
+| --------- | ------------------------------------------------------------------------------------ |
+| 模拟 U 盘 | `libcomposite.ko` → `function/usb_f_mass_storage.ko` → `legacy/g_mass_storage.ko`    |
+| USB 声卡  | `libcomposite.ko` → `function/usb_f_uac1.ko` → `legacy/g_audio.ko`(UAC 1.0 Legacy) |
 
 ```bash
 # 模拟U盘:file 指定要导出的分区,removable=1 表示可移动

+ 13 - 13
X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/04-Linux总线与接口驱动/04-CAN驱动开发.md

@@ -101,24 +101,24 @@ I.MX6ULL 的 CAN 控制器称为 **FlexCAN**,符合 CAN2.0B 协议,支持标
 
 **FlexCAN 支持的 4 种工作模式**:
 
-| 模式                | 使能方式                          | 说明                                                     |
-| ------------------- | --------------------------------- | -------------------------------------------------------- |
-| 正常模式(Normal)    | 默认                              | 正常收发,所有 CAN 协议功能使能                          |
-| 冻结模式(Freeze)    | MCR.FRZ = 1                       | 无法收发,CAN 总线同步丢失                               |
-| 仅监听模式(Listen-Only) | CTRL.LOM = 1                  | 禁止发送,错误计数器冻结,只接收其他单元的 ACK,工作于被动错误模式 |
-| 回环模式(Loop-Back) | CTRL.LPB = 1                      | 内部回环,用于自测,发送数据流直接反馈给内部接收单元     |
+| 模式                    | 使能方式     | 说明                                                               |
+| ----------------------- | ------------ | ------------------------------------------------------------------ |
+| 正常模式(Normal)        | 默认         | 正常收发,所有 CAN 协议功能使能                                    |
+| 冻结模式(Freeze)        | MCR.FRZ = 1  | 无法收发,CAN 总线同步丢失                                         |
+| 仅监听模式(Listen-Only) | CTRL.LOM = 1 | 禁止发送,错误计数器冻结,只接收其他单元的 ACK,工作于被动错误模式 |
+| 回环模式(Loop-Back)     | CTRL.LPB = 1 | 内部回环,用于自测,发送数据流直接反馈给内部接收单元               |
 
 另有 2 种低功耗模式:**禁止模式(Disable)** 和 **停止模式(Stop)**。
 
 **位时序寄存器位域**(CTRL 寄存器):
 
-| 位域    | 作用              | 取值范围    | 对应段   |
-| ------- | ----------------- | ----------- | -------- |
-| PRESDIV | 分频值,决定 Tq   | —           | —        |
-| PROPSEG | 传播时间段 PTS    | 0~7 → 1~8 Tq | PTS      |
-| PSEG1   | 相位缓冲段1 PBS1  | 0~7 → 1~8 Tq | PBS1     |
-| PSEG2   | 相位缓冲段2 PBS2  | 1~7 → 2~8 Tq | PBS2     |
-| RJW     | 再同步补偿宽度 SJW | 0~3 → 1~4 Tq | SJW      |
+| 位域    | 作用               | 取值范围     | 对应段 |
+| ------- | ------------------ | ------------ | ------ |
+| PRESDIV | 分频值,决定 Tq    | —            | —      |
+| PROPSEG | 传播时间段 PTS     | 0~7 → 1~8 Tq | PTS    |
+| PSEG1   | 相位缓冲段1 PBS1   | 0~7 → 1~8 Tq | PBS1   |
+| PSEG2   | 相位缓冲段2 PBS2   | 1~7 → 2~8 Tq | PBS2   |
+| RJW     | 再同步补偿宽度 SJW | 0~3 → 1~4 Tq | SJW    |
 
 其中 `f_Tq = f_CANCLK / (PRESDIV + 1)`,SYNC_SEG 固定为 1 个 Tq。总 Tq 与波特率关系见 1.6 节。
 

+ 0 - 1
X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/04-Linux总线与接口驱动/05-RS232与485通信.md

@@ -571,7 +571,6 @@ UART3_RX 经外围电路 ─┬─▶ SP3485 DE(发送使能,高有效)
 
 关键:RE和DE通过电路设计连接到同一信号,发送时DE高电平使能发送,接收时RE低电平使能接收。这种设计将RS485完全当作串口使用,无需软件控制方向。
 
-
 RS485在驱动中的配置:
 
 ```c

+ 6 - 8
X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/05-Linux外设驱动实战/01-LED与蜂鸣器驱动.md

@@ -322,7 +322,6 @@ void led_switch(u8 sta)
 - `val &= ~(1 << 3)`:将bit3清零,GPIO输出低电平,LED点亮(低电平有效)
 - `val |= (1 << 3)`:将bit3置1,GPIO输出高电平,LED熄灭
 
-
 ### 3.3 led_init入口函数分析
 
 驱动加载时执行的初始化流程:
@@ -418,12 +417,12 @@ write系统调用触发内核`led_write`函数,通过`copy_from_user`获取用
 
 I.MX6U-ALPHA开发板上的蜂鸣器通过SNVS_TAMPER1引脚控制,复用为GPIO5_IO01。蜂鸣器驱动原理与LED类似,都是控制IO输出高低电平。
 
-| 项目     | 说明                                  |
-| -------- | ------------------------------------- |
-| 控制引脚 | SNVS_TAMPER1 → GPIO5_IO01             |
-| 有效电平 | **低电平鸣叫**(0=开,1=关)          |
-| 驱动方式 | GPIO推挽输出                          |
-| 设备类型 | 有源蜂鸣器(电平驱动即可鸣叫)        |
+| 项目     | 说明                           |
+| -------- | ------------------------------ |
+| 控制引脚 | SNVS_TAMPER1 → GPIO5_IO01      |
+| 有效电平 | **低电平鸣叫**(0=开,1=关)   |
+| 驱动方式 | GPIO推挽输出                   |
+| 设备类型 | 有源蜂鸣器(电平驱动即可鸣叫) |
 
 > [!note] 关于设备树极性
 > 💡 蜂鸣器的实际有效电平为**低电平**:驱动内 `gpio_set_value(dev->beep_gpio, 0)` 直接输出低电平开启蜂鸣器、输出高电平关闭,并未使用 `gpio_set_value_cansleep` 或极性反转逻辑。
@@ -679,7 +678,6 @@ static ssize_t beep_write(struct file *filp, const char __user *buf,
 
 通过`filp->private_data`获取设备结构体指针,使用GPIO子系统API `gpio_set_value`控制电平。
 
-
 ### 7.4 与LED驱动的关键差异
 
 | 对比项       | LED驱动                   | 蜂鸣器驱动                               |

+ 7 - 8
X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/05-Linux外设驱动实战/02-按键驱动.md

@@ -103,7 +103,6 @@ key {
 1. `UART1_CTS_B` 是否被其他pinctrl节点使用,若有则屏蔽
 2. `GPIO1_IO18` 是否被其他外设使用,若有则屏蔽
 
-
 ### 2.6 编译与验证
 
 ```bash
@@ -611,13 +610,13 @@ input_sync(dev->input);
 
 原书第五十章《Linux内核定时器实验》给出 4.1.15 内核的定时器接口签名,示例如下:
 
-| 函数 | 原型 | 说明 |
-| ---- | ---- | ---- |
-| `init_timer` | `void init_timer(struct timer_list *timer)` | 初始化定时器(新版内核已改为 `timer_setup`) |
-| `add_timer` | `void add_timer(struct timer_list *timer)` | 向内核注册并启动定时器 |
-| `mod_timer` | `int mod_timer(struct timer_list *timer, unsigned long expires)` | 修改超时时间;未激活时会激活,可用于周期性定时 |
-| `del_timer` | `int del_timer(struct timer_list *timer)` | 删除定时器(可在中断上下文调用) |
-| `del_timer_sync` | `int del_timer_sync(struct timer_list *timer)` | 同步版删除,等待其他CPU上的回调退出,不能在中断上下文调用 |
+| 函数             | 原型                                                             | 说明                                                      |
+| ---------------- | ---------------------------------------------------------------- | --------------------------------------------------------- |
+| `init_timer`     | `void init_timer(struct timer_list *timer)`                      | 初始化定时器(新版内核已改为 `timer_setup`)              |
+| `add_timer`      | `void add_timer(struct timer_list *timer)`                       | 向内核注册并启动定时器                                    |
+| `mod_timer`      | `int mod_timer(struct timer_list *timer, unsigned long expires)` | 修改超时时间;未激活时会激活,可用于周期性定时            |
+| `del_timer`      | `int del_timer(struct timer_list *timer)`                        | 删除定时器(可在中断上下文调用)                          |
+| `del_timer_sync` | `int del_timer_sync(struct timer_list *timer)`                   | 同步版删除,等待其他CPU上的回调退出,不能在中断上下文调用 |
 
 关键点(4.1.15 与 4.15+ 的差异):
 

+ 0 - 1
X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/05-Linux外设驱动实战/04-触摸屏驱动.md

@@ -829,7 +829,6 @@ hexdump /dev/input/event2
 
 其中 `ABS_X`/`ABS_Y`(code 0x0000/0x0001)由 `input_mt_report_pointer_emulation()` 为单点应用模拟上报;`ABS_MT_TRACKING_ID = -1` 表示触摸点离开。
 
-
 ### 7.3 tslib 测试
 
 原书 tslib 环境变量写入 `/etc/profile`,并将驱动编入内核后触摸设备设为 `/dev/input/event1`;若使用模块方式则 event 编号可能为 `event2`,需按实际情况修改 `TSLIB_TSDEVICE`。

+ 0 - 1
X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/05-Linux外设驱动实战/05-音频驱动.md

@@ -892,7 +892,6 @@ cd MPlayer-1.4/
 make
 ```
 
-
 编译后编辑 `config.mak`,把 `INSTALLSTRIP = -s` 后面的 `-s` 去掉,否则 `make install` 会失败。然后:
 
 ```bash

+ 4 - 4
X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/05-Linux外设驱动实战/06-RTC与PWM驱动.md

@@ -695,10 +695,10 @@ pwm3: pwm@02088000 {
 
 `#pwm-cells = <2>` 表示引用此PWM控制器时需要2个参数(以原书 73.4.1.1 的 `pwms = <&pwm1 0 5000000>` 为例):
 
-| 参数  | 说明                                      |
-| ----- | ----------------------------------------- |
+| 参数  | 说明                                              |
+| ----- | ------------------------------------------------- |
 | 第1个 | PWM通道索引(I.MX6ULL每个控制器只有1个通道,填0) |
-| 第2个 | PWM周期,单位ns(如5000000ns即5ms,对应200Hz) |
+| 第2个 | PWM周期,单位ns(如5000000ns即5ms,对应200Hz)    |
 
 引用示例:
 
@@ -746,7 +746,7 @@ backlight {
 | 属性                       | 说明                                                                 |
 | -------------------------- | -------------------------------------------------------------------- |
 | `compatible`               | 必须为`"pwm-backlight"`,匹配驱动 `drivers/video/backlight/pwm_bl.c` |
-| `pwms`                     | 指定PWM通道和周期,`<&pwm1 0 5000000>` 即200Hz                        |
+| `pwms`                     | 指定PWM通道和周期,`<&pwm1 0 5000000>` 即200Hz                       |
 | `brightness-levels`        | 背光等级数组,范围0~255对应0%~100%,必须从0开始、以255结尾           |
 | `default-brightness-level` | 默认背光**等级索引**(不是数值),这里7对应255,即100%占空比         |
 | `power-supply`             | 支持的电压,可选                                                     |

+ 7 - 10
X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/05-Linux外设驱动实战/07-ADC与IIO驱动.md

@@ -754,7 +754,6 @@ icm20608: icm20608@0 {
 };
 ```
 
-
 ### 7.2 IIO绑定文档
 
 参考:`Documentation/devicetree/bindings/iio/adc/vf610-adc.txt`
@@ -840,7 +839,6 @@ int iio_triggered_buffer_setup(struct iio_dev *indio_dev,
   - `buf_ops`:缓冲区操作函数集
 - **说明**:设置触发缓冲区模式
 
-
 ### 8.5 iio_device_unregister — 注销IIO设备
 
 ```c
@@ -1417,7 +1415,6 @@ cat in_anglvel_x_raw
 cat in_temp_raw
 ```
 
-
 ### 10.5 iio_info工具
 
 ```bash
@@ -1438,13 +1435,13 @@ iio_attr -d iio:device1
 
 IIO 的 sysfs 文件内容都是**字符串**(如 `in_accel_scale` 内容为 `"0.000488281"`),因此读取时要先按字符串取出,再用 `atof`/`atoi` 转换。原书 75.4.1 用到的标准 I/O 文件流 API:
 
-| 函数 | 原型 | 说明 |
-| ---- | ---- | ---- |
-| `fopen` | `FILE *fopen(const char *pathname, const char *mode)` | 打开文件流,`mode` 可取 `r`/`r+`/`w`/`w+`/`a`/`a+` |
-| `fclose` | `int fclose(FILE *stream)` | 关闭文件流,成功返回0,失败返回EOF |
-| `fread` | `size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)` | 从流读取对象 |
-| `fwrite` | `size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)` | 向流写入对象 |
-| `fscanf` | `int fscanf(FILE *stream, const char *format, ...)` | 格式化读取,遇空格/换行结束 |
+| 函数     | 原型                                                                      | 说明                                               |
+| -------- | ------------------------------------------------------------------------- | -------------------------------------------------- |
+| `fopen`  | `FILE *fopen(const char *pathname, const char *mode)`                     | 打开文件流,`mode` 可取 `r`/`r+`/`w`/`w+`/`a`/`a+` |
+| `fclose` | `int fclose(FILE *stream)`                                                | 关闭文件流,成功返回0,失败返回EOF                 |
+| `fread`  | `size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)`        | 从流读取对象                                       |
+| `fwrite` | `size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)` | 向流写入对象                                       |
+| `fscanf` | `int fscanf(FILE *stream, const char *format, ...)`                       | 格式化读取,遇空格/换行结束                        |
 
 核心转换逻辑(原书示例代码 75.4.2.1):
 

+ 25 - 27
X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/05-Linux外设驱动实战/08-块设备驱动.md

@@ -18,13 +18,13 @@ pdf_ref: "74_第六十八章 Linux 块设备驱动实验.pdf"
 
 块设备是针对存储设备的,比如SD卡、EMMC、NAND Flash、Nor Flash、SPI Flash、机械硬盘、固态硬盘等。块设备驱动其实就是这些存储设备的驱动,块设备驱动相比字符设备驱动的主要区别如下:
 
-| 特性     | 块设备                | 字符设备   |
-| -------- | --------------------- | ---------- |
-| 访问单位 | 块(VFS 基本传输单位,扇区为512字节) | 字节 |
-| 数据传输 | 需要缓冲区            | 不需要缓冲 |
-| 访问方式 | 随机访问              | 顺序访问   |
-| I/O调度  | 需要I/O调度器优化     | 无需调度   |
-| 生命周期 | 有擦写次数限制        | 无限制     |
+| 特性     | 块设备                                | 字符设备   |
+| -------- | ------------------------------------- | ---------- |
+| 访问单位 | 块(VFS 基本传输单位,扇区为512字节) | 字节       |
+| 数据传输 | 需要缓冲区                            | 不需要缓冲 |
+| 访问方式 | 随机访问                              | 顺序访问   |
+| I/O调度  | 需要I/O调度器优化                     | 无需调度   |
+| 生命周期 | 有擦写次数限制                        | 无限制     |
 
 > 原书 68.1 指出:块设备以块为单位读写,使用缓冲区暂存数据、满足条件后再一次性写入物理设备,以减少擦除次数、提高寿命;字符设备不需要缓冲区,实时按字节访问。因此块设备寿命受 Flash 擦写次数限制。
 
@@ -232,7 +232,6 @@ int register_blkdev(unsigned int major, const char *name)
 - 若 `major` 为 1~255,表示自定义主设备号:返回 0 表示注册成功,负值表示失败
 - 若 `major` 为 0,表示由系统自动分配主设备号:返回值为系统分配的主设备号(1~255),负值表示失败
 
-
 #### 3.1.2 unregister_blkdev
 
 注销块设备:
@@ -373,16 +372,16 @@ void blk_queue_make_request(struct request_queue *q, make_request_fn *mfn)
 
 ### 3.4 请求处理API
 
-| 函数                    | 描述                                    |
-| ----------------------- | --------------------------------------- |
-| `blk_peek_request()`    | 获取请求队列中下一个请求,无则返回NULL  |
-| `blk_start_request()`   | 开始处理指定请求                        |
-| `blk_fetch_request()`   | 一次性获取并开启请求(=peek+start)     |
-| `blk_end_request()`     | 请求中指定字节数据被处理完成            |
-| `blk_end_request_all()` | 请求中所有数据全部处理完成              |
-| `blk_end_request_cur()` | 完成当前请求中的 chunk                  |
-| `blk_end_request_err()` | 处理完请求,直到下一个错误产生          |
-| `__blk_end_request()`   | 同 `blk_end_request`,但需持有队列锁    |
+| 函数                      | 描述                                   |
+| ------------------------- | -------------------------------------- |
+| `blk_peek_request()`      | 获取请求队列中下一个请求,无则返回NULL |
+| `blk_start_request()`     | 开始处理指定请求                       |
+| `blk_fetch_request()`     | 一次性获取并开启请求(=peek+start)    |
+| `blk_end_request()`       | 请求中指定字节数据被处理完成           |
+| `blk_end_request_all()`   | 请求中所有数据全部处理完成             |
+| `blk_end_request_cur()`   | 完成当前请求中的 chunk                 |
+| `blk_end_request_err()`   | 处理完请求,直到下一个错误产生         |
+| `__blk_end_request()`     | 同 `blk_end_request`,但需持有队列锁   |
 | `__blk_end_request_all()` | 同 `blk_end_request_all`,需持有队列锁 |
 | `__blk_end_request_cur()` | 同 `blk_end_request_cur`,需持有队列锁 |
 | `__blk_end_request_err()` | 同 `blk_end_request_err`,需持有队列锁 |
@@ -412,14 +411,14 @@ void bio_endio(struct bio *bio, int error);  /* 通知 bio 处理结束,error=
 
 请求处理中还会用到这些辅助函数:
 
-| 函数 | 说明 |
-| ---- | ---- |
-| `blk_rq_pos(req)` | 获取请求要操作的扇区地址(左移9位转换为字节地址) |
-| `blk_rq_cur_bytes(req)` | 获取当前请求要处理的数据长度 |
-| `rq_data_dir(req)` | 判断请求方向(`READ`/`WRITE`) |
-| `bio_data(req->bio)` | 获取请求中 bio 的数据缓冲区 |
-| `bio_data_dir(bio)` | 判断 bio 方向(`READ`/`WRITE`) |
-| `page_address(bvec.bv_page)` | 获取 bio_vec 中页的虚拟地址 |
+| 函数                         | 说明                                              |
+| ---------------------------- | ------------------------------------------------- |
+| `blk_rq_pos(req)`            | 获取请求要操作的扇区地址(左移9位转换为字节地址) |
+| `blk_rq_cur_bytes(req)`      | 获取当前请求要处理的数据长度                      |
+| `rq_data_dir(req)`           | 判断请求方向(`READ`/`WRITE`)                    |
+| `bio_data(req->bio)`         | 获取请求中 bio 的数据缓冲区                       |
+| `bio_data_dir(bio)`          | 判断 bio 方向(`READ`/`WRITE`)                   |
+| `page_address(bvec.bv_page)` | 获取 bio_vec 中页的虚拟地址                       |
 
 ## 4. 完整源码分析
 
@@ -448,7 +447,6 @@ void bio_endio(struct bio *bio, int error);  /* 通知 bio 处理结束,error=
 #define RAMDISK_MINOR   3                   /* 表示三个磁盘分区!不是次设备号为3! */
 ```
 
-
 #### 4.1.2 设备结构体
 
 ```c

+ 11 - 16
X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/05-Linux外设驱动实战/面试-外设驱动实战.md

@@ -91,7 +91,6 @@ pwm_config(pwm, period * duty_cycle / 100, period);
 pwm_enable(pwm);
 ```
 
-
 **追问**:
 
 - PWM 频率和占空比分别影响什么?—— 频率决定音调(Hz),占空比决定音量
@@ -387,12 +386,12 @@ GPIO 背光设备树:`gpios = <&gpio1 9 GPIO_ACTIVE_HIGH>;`
 3. 电阻屏用 IIO 或直接 ADC 驱动
 4. 电容屏用 I2C/SPI + Input 子系统
 
-| 特性       | 电阻屏       | 电容屏           |
-| ---------- | ------------ | ---------------- |
-| 原理       | 压力分压     | 电容耦合         |
-| 多点触控   | 不支持       | 支持(最多10点) |
-| 透光率     | ~75%         | ~90%             |
-| 驱动接口   | ADC + GPIO   | I2C/SPI + GPIO   |
+| 特性       | 电阻屏       | 电容屏                   |
+| ---------- | ------------ | ------------------------ |
+| 原理       | 压力分压     | 电容耦合                 |
+| 多点触控   | 不支持       | 支持(最多10点)         |
+| 透光率     | ~75%         | ~90%                     |
+| 驱动接口   | ADC + GPIO   | I2C/SPI + GPIO           |
 | Linux 驱动 | IIO 或自定义 | ft5x06(FT5426)、goodix |
 
 **追问**:
@@ -414,7 +413,6 @@ GPIO 背光设备树:`gpios = <&gpio1 9 GPIO_ACTIVE_HIGH>;`
 
 设备树示例(ALPHA 板 FT5426,挂 I2C2,原书示例代码 64.3.1.4):`compatible = "edt,edt-ft5426"; reg = <0x38>;` 并配置 `reset-gpios` 与中断 GPIO(`interrupt-parent`/`interrupts`)。使用 Goodix 方案的板子则为 `compatible = "goodix,gt9147"; reg = <0x5d>;`
 
-
 MT-B 协议:input_mt_slot -> input_mt_report_slot_state -> input_report_abs(X/Y) -> input_mt_sync_frame -> input_sync
 
 **追问**:
@@ -437,12 +435,11 @@ MT-B 协议:input_mt_slot -> input_mt_report_slot_state -> input_report_abs(X/
 4. Platform 驱动:CPU 侧 DMA 和 DAI
 5. Codec 驱动:Codec 芯片寄存器和 DAI
 
-| 组件     | 职责                      | 示例(ALPHA 板)        |
-| -------- | ------------------------- | ----------------------- |
-| Platform | CPU 侧:DMA、CPU DAI      | fsl_sai.c               |
-| Codec    | Codec 芯片:DAC/ADC、DAPM | wm8960.c / es8388.c     |
-| Machine  | 绑定 Platform 和 Codec    | imx-audio-wm8960.c      |
-
+| 组件     | 职责                      | 示例(ALPHA 板)    |
+| -------- | ------------------------- | ------------------- |
+| Platform | CPU 侧:DMA、CPU DAI      | fsl_sai.c           |
+| Codec    | Codec 芯片:DAC/ADC、DAPM | wm8960.c / es8388.c |
+| Machine  | 绑定 Platform 和 Codec    | imx-audio-wm8960.c  |
 
 **追问**:
 
@@ -526,7 +523,6 @@ PCM/TDM 时序:SYNC 同步信号区分时隙,每个时隙对应一个通道
 设备树格式:`pwms = <&pwm1 0 5000000>;`,即 `<PWM控制器phandle 通道号 周期(ns)>`(I.MX6ULL `#pwm-cells = <2>`)
 驱动 API:devm_pwm_get -> pwm_config(pwm, duty_ns, period_ns) -> pwm_enable -> pwm_disable
 
-
 **追问**:
 
 - PWM 周期和频率的关系?-- 频率 = 1 / 周期
@@ -685,7 +681,6 @@ vf610_adc_probe:devm_iio_device_alloc -> devm_ioremap_resource -> devm_request
 - set_capacity 的单位?-- 扇区数(每扇区 512 字节)
 - `__blk_end_request_cur` 的作用?-- 标记当前请求的 chunk 处理完成(需持有队列锁)
 
-
 ---
 
 ### Q28: 块设备驱动中如何处理 I/O 请求?读写操作的流程?

+ 16 - 18
X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/06-系统移植与启动/01-U-Boot命令与使用.md

@@ -176,7 +176,6 @@ mm.l 80000000
 # 输入q退出
 ```
 
-
 #### mw — 填充内存
 
 ```bash
@@ -326,14 +325,14 @@ mmc erase blk# cnt
 
 #### mmc 其他命令(PDF 表 30.4.5.1)
 
-| 命令 | 描述 |
-| ---- | ---- |
-| `mmc hwpartition` | 设置 MMC 设备的分区 |
-| `mmc bootbus` | 设置指定 MMC 设备的 BOOT_BUS_WIDTH 域的值 |
-| `mmc bootpart` | 设置指定 MMC 设备的 boot 和 RPMB 分区的大小 |
-| `mmc partconf` | 设置指定 MMC 设备的 PARTITION_CONFIG 域的值 |
-| `mmc rst` | 复位 MMC 设备 |
-| `mmc setdsr` | 设置 DSR 寄存器的值 |
+| 命令              | 描述                                        |
+| ----------------- | ------------------------------------------- |
+| `mmc hwpartition` | 设置 MMC 设备的分区                         |
+| `mmc bootbus`     | 设置指定 MMC 设备的 BOOT_BUS_WIDTH 域的值   |
+| `mmc bootpart`    | 设置指定 MMC 设备的 boot 和 RPMB 分区的大小 |
+| `mmc partconf`    | 设置指定 MMC 设备的 PARTITION_CONFIG 域的值 |
+| `mmc rst`         | 复位 MMC 设备                               |
+| `mmc setdsr`      | 设置 DSR 寄存器的值                         |
 
 #### 用 mmc write 更新 U-Boot
 
@@ -411,14 +410,14 @@ nand erase.chip [clean]                    全片擦除
 
 I.MX6U-ALPHA 出厂系统 NAND 分区(共 6 个分区):
 
-| 分区 | 地址范围 | 大小 | 内容 |
-| ---- | -------- | ---- | ---- |
-| boot | 0x000000~0x3FFFFF | 4MB | uboot |
-| env | 0x400000~0x41FFFF | 128KB | 环境变量 |
-| logo | 0x420000~0x51FFFF | 1MB | 启动图标 |
-| dtb | 0x520000~0x61FFFF | 1MB | 设备树 |
-| kernel | 0x620000~0xE1FFFF | 8MB | Linux 内核 |
-| rootfs | 0xE20000~0x20000000 | 剩余 | 根文件系统 |
+| 分区   | 地址范围            | 大小  | 内容       |
+| ------ | ------------------- | ----- | ---------- |
+| boot   | 0x000000~0x3FFFFF   | 4MB   | uboot      |
+| env    | 0x400000~0x41FFFF   | 128KB | 环境变量   |
+| logo   | 0x420000~0x51FFFF   | 1MB   | 启动图标   |
+| dtb    | 0x520000~0x61FFFF   | 1MB   | 设备树     |
+| kernel | 0x620000~0xE1FFFF   | 8MB   | Linux 内核 |
+| rootfs | 0xE20000~0x20000000 | 剩余  | 根文件系统 |
 
 烧写 kernel 与 dtb 示例:
 
@@ -554,7 +553,6 @@ run mybootnand
 run mybootnet
 ```
 
-
 ### 3.5 bootdelay
 
 控制启动倒计时时间,默认为3秒。修改方法:

+ 20 - 21
X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/06-系统移植与启动/02-U-Boot启动流程.md

@@ -250,15 +250,15 @@ SECTIONS
 
 **关键地址变量(示例编译值,以实际编译为准):**
 
-| 变量                 | 数值       | 描述                    |
-| -------------------- | ---------- | ----------------------- |
-| `__image_copy_start` | 0x87800000 | U-Boot拷贝首地址        |
-| `__image_copy_end`   | 0x8785dd54 | U-Boot拷贝结束地址      |
-| `__rel_dyn_start`    | 0x8785dd54 | .rel.dyn段起始          |
-| `__rel_dyn_end`      | 0x878668f4 | .rel.dyn段结束          |
-| `_image_binary_end`  | 0x878668f4 | 镜像结束地址            |
-| `__bss_start`        | 0x8785dd54 | BSS段起始               |
-| `__bss_end`          | 0x878a8e74 | BSS段结束               |
+| 变量                 | 数值       | 描述               |
+| -------------------- | ---------- | ------------------ |
+| `__image_copy_start` | 0x87800000 | U-Boot拷贝首地址   |
+| `__image_copy_end`   | 0x8785dd54 | U-Boot拷贝结束地址 |
+| `__rel_dyn_start`    | 0x8785dd54 | .rel.dyn段起始     |
+| `__rel_dyn_end`      | 0x878668f4 | .rel.dyn段结束     |
+| `_image_binary_end`  | 0x878668f4 | 镜像结束地址       |
+| `__bss_start`        | 0x8785dd54 | BSS段起始          |
+| `__bss_end`          | 0x878a8e74 | BSS段结束          |
 
 ### 2.6 编译选项详解
 
@@ -366,13 +366,13 @@ flowchart LR
 
 **各阶段职责:**
 
-| 阶段 | 职责 | 关键函数 |
-| ---- | ---- | -------- |
-| Boot ROM | 从启动设备加载`u-boot.imx`到 DDR | 芯片固化代码 |
-| board_init_f(重定位前) | 初始化串口/定时器/DDR,`init_sequence_f[]`,计算重定位目的地址 | `board_init_f()` |
-| 重定位 | 将 U-Boot 拷贝到 DDR 高地址,修正`.rel.dyn`,重定位向量表 | `relocate_code()`、`relocate_vectors()` |
-| board_init_r(重定位后) | 初始化 MMC/NAND/网络/环境变量,进入命令行 | `board_init_r()`、`main_loop()` |
-| Linux | 挂载rootfs,启动init | `boot_jump_linux()`、`kernel_entry()` |
+| 阶段                     | 职责                                                           | 关键函数                                |
+| ------------------------ | -------------------------------------------------------------- | --------------------------------------- |
+| Boot ROM                 | 从启动设备加载`u-boot.imx`到 DDR                               | 芯片固化代码                            |
+| board_init_f(重定位前) | 初始化串口/定时器/DDR,`init_sequence_f[]`,计算重定位目的地址 | `board_init_f()`                        |
+| 重定位                   | 将 U-Boot 拷贝到 DDR 高地址,修正`.rel.dyn`,重定位向量表      | `relocate_code()`、`relocate_vectors()` |
+| board_init_r(重定位后) | 初始化 MMC/NAND/网络/环境变量,进入命令行                      | `board_init_r()`、`main_loop()`         |
+| Linux                    | 挂载rootfs,启动init                                           | `boot_jump_linux()`、`kernel_entry()`   |
 
 ### 3.3 内存布局
 
@@ -513,7 +513,6 @@ save_boot_params_ret:
     bl  _main
 ```
 
-
 ### 4.2 cpu_init_cp15 - 协处理器初始化
 
 ```armasm
@@ -870,10 +869,10 @@ int bootz_setup(ulong image, ulong *start, ulong *end)
 
 **关键魔数:**
 
-| 魔数                     | 值         | 说明               |
-| ------------------------ | ---------- | ------------------ |
+| 魔数                     | 值         | 说明                  |
+| ------------------------ | ---------- | --------------------- |
 | `LINUX_ARM_ZIMAGE_MAGIC` | 0x016f2818 | ARM Linux zImage 标识 |
-| `ZIMAGE_MAGIC`(旧书稿) | 0x016f2818 | 同一魔数,命名不同 |
+| `ZIMAGE_MAGIC`(旧书稿) | 0x016f2818 | 同一魔数,命名不同    |
 
 ---
 
@@ -954,7 +953,7 @@ flowchart LR
 | `if=u-boot.imx` | 输入文件                               |
 | `of=/dev/sdb`   | 输出设备(切勿写系统盘)               |
 | `bs=512`        | 块大小 = 一个扇区                      |
-| `seek=2`        | 跳过 2 个扇区 = 1024 字节偏移           |
+| `seek=2`        | 跳过 2 个扇区 = 1024 字节偏移          |
 | `conv=fsync`    | 同步写入,确保数据落盘(可选 notrunc) |
 
 ---

+ 11 - 11
X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/06-系统移植与启动/03-Linux内核裁剪与编译.md

@@ -22,10 +22,10 @@ pdf_ref:
 
 内核源码由 Linux 基金会管理与发布,官网 <https://www.kernel.org>。开发中并不追求最新版,而是**跟随半导体厂商的 BSP 版本**:
 
-| 来源         | 版本 / 文件                                 | 说明                            |
-| ------------ | ------------------------------------------- | ------------------------------- |
-| NXP 官方原版 | `linux-imx-rel_imx_4.1.15_2.1.0_ga.tar.bz2` | NXP 移植到 i.MX 系列后的 BSP,解压出目录`linux-imx-rel_imx_4.1.15_2.1.0_ga` |
-| 移植用目录   | `linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek` | 用`mv`重命名,避免与 NXP 官方目录混淆(书中做法) |
+| 来源         | 版本 / 文件                                  | 说明                                                                        |
+| ------------ | -------------------------------------------- | --------------------------------------------------------------------------- |
+| NXP 官方原版 | `linux-imx-rel_imx_4.1.15_2.1.0_ga.tar.bz2`  | NXP 移植到 i.MX 系列后的 BSP,解压出目录`linux-imx-rel_imx_4.1.15_2.1.0_ga` |
+| 移植用目录   | `linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek` | 用`mv`重命名,避免与 NXP 官方目录混淆(书中做法)                           |
 
 为什么用 **4.1.15**:NXP 对 i.MX6ULL 的 BSP 长期维护在这个版本,外设驱动、设备树最完整;4.x 与 5.x 在核心机制上没有本质区别,5.x 更多是新增平台和外设。中途换版本意味着设备树、驱动全部重调,得不偿失。
 
@@ -575,14 +575,14 @@ Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)
 
 ### 5.6 常见编译错误排查
 
-| 错误现象                                                        | 原因                       | 解决                              |
-| --------------------------------------------------------------- | -------------------------- | --------------------------------- |
-| `recipe for target 'arch/arm/boot/compressed/piggy.lzo' failed` | 未安装 lzop                | `sudo apt-get install lzop`       |
-| `arm-linux-gnueabihf-gcc: command not found`                    | 交叉工具链未安装/未加 PATH | 安装工具链并配置环境变量          |
-| 修改配置后配置项“复活”                                          | 直接删了 `.config` 的行    | 改成 `# CONFIG_xxx is not set`    |
+| 错误现象                                                        | 原因                       | 解决                                   |
+| --------------------------------------------------------------- | -------------------------- | -------------------------------------- |
+| `recipe for target 'arch/arm/boot/compressed/piggy.lzo' failed` | 未安装 lzop                | `sudo apt-get install lzop`            |
+| `arm-linux-gnueabihf-gcc: command not found`                    | 交叉工具链未安装/未加 PATH | 安装工具链并配置环境变量               |
+| 修改配置后配置项“复活”                                          | 直接删了 `.config` 的行    | 改成 `# CONFIG_xxx is not set`         |
 | `make mrproper`/`distclean` 后配置丢失                          | 这两个目标会删 `.config`   | 改完配置先保存(`savedefconfig` 固化) |
-| 驱动模块加载失败 / `insmod` 报版本不符                          | 内核与模块配置不一致       | 用同一份 `.config` 重编内核与模块 |
-| 编译到一半卡死或内存不足                                        | `-j` 过大                  | 降低并行度,如 `-j4`              |
+| 驱动模块加载失败 / `insmod` 报版本不符                          | 内核与模块配置不一致       | 用同一份 `.config` 重编内核与模块      |
+| 编译到一半卡死或内存不足                                        | `-j` 过大                  | 降低并行度,如 `-j4`                   |
 
 ---
 

+ 13 - 13
X-Knowledge-Base/raw/Joplin/嵌入式+Linux/嵌入式Linux驱动开发实战/06-系统移植与启动/04-根文件系统构建.md

@@ -33,20 +33,20 @@ pdf_ref: "【正点原子】I.MX6U嵌入式Linux驱动开发指南V2.0.1 - 第
 
 Linux 根文件系统采用标准的目录结构,每个目录有特定用途:
 
-| 目录    | 用途         | 说明                                                  |
-| ------- | ------------ | ----------------------------------------------------- |
-| `/bin`  | 基本命令     | 系统启动和运行必需的可执行文件,如 ls、mv、cp         |
-| `/sbin` | 系统命令     | 系统管理命令,如 ifconfig、reboot,通常只有管理员使用 |
-| `/lib`  | 共享库       | 系统库文件,供应用程序动态链接使用                    |
-| `/etc`  | 配置文件     | 系统配置文件,如 fstab、inittab、resolv.conf          |
+| 目录    | 用途         | 说明                                                       |
+| ------- | ------------ | ---------------------------------------------------------- |
+| `/bin`  | 基本命令     | 系统启动和运行必需的可执行文件,如 ls、mv、cp              |
+| `/sbin` | 系统命令     | 系统管理命令,如 ifconfig、reboot,通常只有管理员使用      |
+| `/lib`  | 共享库       | 系统库文件,供应用程序动态链接使用                         |
+| `/etc`  | 配置文件     | 系统配置文件,如 fstab、inittab、resolv.conf               |
 | `/dev`  | 设备文件     | 设备节点文件,如 /dev/ttymxc0(I.MX6ULL 串口0)、/dev/null |
-| `/proc` | 进程信息     | proc 文件系统挂载点,存储系统运行时信息               |
-| `/sys`  | 内核对象     | sysfs 文件系统挂载点,提供内核数据结构信息            |
-| `/usr`  | 用户程序     | Unix Software Resource,用户空间程序和库              |
-| `/var`  | 可变数据     | 日志、缓存等可改变的数据                              |
-| `/mnt`  | 挂载点       | 临时挂载目录,如 /mnt/sdcard、/mnt/usb                |
-| `/tmp`  | 临时文件     | 系统重启后清空的临时文件                              |
-| `/root` | root用户目录 | root 用户的家目录                                     |
+| `/proc` | 进程信息     | proc 文件系统挂载点,存储系统运行时信息                    |
+| `/sys`  | 内核对象     | sysfs 文件系统挂载点,提供内核数据结构信息                 |
+| `/usr`  | 用户程序     | Unix Software Resource,用户空间程序和库                   |
+| `/var`  | 可变数据     | 日志、缓存等可改变的数据                                   |
+| `/mnt`  | 挂载点       | 临时挂载目录,如 /mnt/sdcard、/mnt/usb                     |
+| `/tmp`  | 临时文件     | 系统重启后清空的临时文件                                   |
+| `/root` | root用户目录 | root 用户的家目录                                          |
 
 ### 1.3 文件系统类型