第 30 / 50 课 · 核心课程。返回课程合集。
SPI 没有统一的寄存器命令格式
控制器提供时钟、数据和片选,外设规定命令、地址、dummy cycle 与返回数据。CPOL 定义空闲电平,CPHA 影响在哪个边沿采样;还要核对位序、字长和片选保持时间。
发送 dummy 字节常用于产生读取时钟,它不是一定要写进外设的业务数据。片选在命令与返回之间意外抬高,可能使设备重新开始解释命令。
多线模式分阶段定义
QSPI 常指四数据线能力,但某次事务可能是 1-1-4、1-4-4 等组合,分别表示命令、地址、数据阶段的线数。控制器与 Flash 需一致配置,进入某种模式还可能需要器件状态位或专用命令。
时钟提高后读错,可能来自采样延迟、dummy 配置、电气质量或工作电压,而不是笼统的“SPI 不稳定”。写 Flash 还要遵守写使能、忙状态、页边界与擦除规则。
练习与参考结论
手算 8 位命令、24 位地址、8 个 dummy 时钟和 256 字节数据,在单线 SDR 与仅数据四线 SDR 下分别占多少时钟。答案为 2088 与 552;不包含片选间隔。
用逻辑分析仪比较实际片选和边沿,先降低到器件支持的保守模式建立参考,再按手册调整。不要在未知 Flash 内容上试写命令验证接口。
配套代码
下载包包含独立运行所需文件,使用 Python 标准库;这里验证机制和计算,不代表开发板测量结果。
运行本课机制与计算示例
查看完整代码:main.py
def clocks(payload_bytes, data_lanes):
bits = payload_bytes * 8
if bits % data_lanes:
raise ValueError("whole data clocks required in this example")
return 8 + 24 + 8 + bits // data_lanes
def main():
single, quad = clocks(256, 1), clocks(256, 4)
assert (single, quad) == (2088, 552)
print("single/1-1-4 assumed SDR clocks:", single, quad, "ratio", single / quad)
print("指令、地址和 dummy 仍为本例给定阶段;不是所有器件事务定义")
if __name__ == "__main__":
main()
在项目根目录执行;下载包解压后,在解压目录执行 python3 main.py。
cd 'content/posts/驱动、bootloader、文件系统/嵌入式SoC与接口/30-SPI、QSPI 与 Flash 访问/code' && python3 main.py