个人笔记2
【代码】个人笔记2。
·
1. volatile 与 const 修饰符
volatile 修饰符
- 作用:告诉编译器,这个变量的值可能会被硬件、中断或其他线程意外改变,禁止编译器对其进行优化(如缓存到寄存器、消除重复读取)。
- 典型场景:
- 访问外设寄存器(如 I2C、SPI 控制寄存器)。
- 中断服务程序(ISR)中修改、主循环中读取的全局标志位。
- 多线程 / 多核环境下的共享变量。
- 组合使用
volatile const:表示一个 “只读但可能被硬件改变” 的变量,例如硬件状态寄存器。
const 修饰符
- 作用:表示变量的值在程序逻辑中不应被修改,编译器会在编译期检查赋值操作。
- 注意:
const是编译期约束,不代表物理上的只读;如果是指向硬件寄存器的指针,仍需配合volatile使用。
2. I2C 与 SPI 通信(完整驱动时序)
I2C
- 两线制(SCL 时钟 + SDA 数据),半双工,多主多从。
- 时序要点:起始条件、地址帧(含读写位)、应答 / 非应答、数据传输、停止条件。
- 常见问题:总线死锁、从机无应答、时钟 stretching 处理。
SPI
- 四线制(SCLK、MOSI、MISO、CS),全双工,主从模式。
- 时序要点:时钟极性(CPOL)、时钟相位(CPHA)的四种组合模式。
- 常见问题:CS 片选信号控制不当、高速传输下的信号完整性、DMA 配合使用。
3. SPI 中 “收发” 的本质
- SPI 是全双工同步串行通信,发送和接收是同时进行的。
- 所谓 “发送”,本质上是在时钟驱动下,主从设备同时移位交换数据。
- 当你只需要 “发送” 时,也要读取 DR 寄存器,否则会导致 FIFO 溢出;只需要 “接收” 时,也要发送 dummy 数据来触发时钟。
与 “寄存器长度 / CPU 位” 的关系
- SPI 数据寄存器(DR)的宽度通常与 CPU 字长(如 8/16/32 位)或外设设计相关。
- 传输时要注意:
- 数据对齐(MSB first / LSB first)。
- 单次传输的字节数与寄存器位宽匹配,避免截断或填充。
4. DMA 使用的问题
核心知识点
- DMA(直接内存访问)允许外设直接与内存交换数据,无需 CPU 干预,大幅提升吞吐量并降低 CPU 负载。
常见问题与注意点
- 缓存一致性(Cache Coherence)
- CPU 缓存(Cache)中的数据可能与内存中的 “最新” DMA 数据不一致。
- 解决:在 DMA 传输前后,对相关内存区域进行 cache invalidate(无效化) 或 clean(回写) 操作。
- 内存对齐(Memory Alignment)
- DMA 控制器通常要求源 / 目标地址按其数据宽度(如 32 位)对齐,否则会触发异常或性能下降。
- 对齐要求取决于具体 CPU 架构和 DMA 控制器设计。
- 传输完整性
- 必须处理 DMA 传输完成中断和错误中断,避免数据丢失。
- 注意缓冲区溢出和边界检查。
5. 代码与任务、中断的关系(“内核 vs 消息”)
中断 vs 任务上下文
- 中断上下文:执行中断服务程序(ISR),特点是:
- 不能阻塞、不能调用会导致调度的函数(如
vTaskDelay)。 - 执行时间必须极短,只做必要的标记和数据拷贝。
- 不能阻塞、不能调用会导致调度的函数(如
- 任务上下文:执行应用任务,特点是:
- 可以阻塞、等待信号量 / 队列。
- 负责处理中断中标记的复杂业务逻辑。
设计原则
- 中断里 “只做标记,不做处理”,把耗时工作放到任务中去做。
- 使用信号量、队列等 IPC 机制,实现中断与任务之间的解耦和同步。
6. Clang / LLVM 与反汇编指令
Clang / LLVM
- Clang 是基于 LLVM 架构的 C/C++/Objective-C 编译器前端。
- 相比 GCC,它在诊断信息、静态分析和模块化设计上有优势,常用于嵌入式和高性能场景。
反汇编指令
- 在调试 bootloader、驱动或性能优化时,经常需要将二进制文件反汇编成汇编代码,分析:
- 函数调用栈。
- 编译器优化后的指令序列。
- 内存访问模式和性能瓶颈。
- 常用工具:
objdump,llvm-objdump,arm-none-eabi-objdump等。
更多推荐


所有评论(0)