第四章:配置接口协议——SPI/I2C在PLL配置中的应用
各位同学,今天我们来聊聊PLL配置中绕不开的话题——接口协议。说白了,就是你的芯片怎么跟外部“说话”,怎么把寄存器值写进去、读出来。
我在做第一个PLL项目时,就吃过接口协议的亏。当时图省事,随便选了个I2C地址,结果跟板上另一个器件冲突了,调了整整两天。嗯,从那以后我再也不敢轻视协议帧格式的设计了。
4.1 为什么需要配置接口?
PLL内部有几十个寄存器,控制着分频比、电荷泵电流、环路带宽等等参数。这些寄存器在上电时都是默认值,你得通过配置接口把它们设成你想要的数值。
你想想看,如果没有配置接口,每次改参数都得重新流片——那成本谁受得了?
常见的配置接口就两种:SPI和I2C。我个人的习惯是:
- 高速场景(>10MHz配置时钟)→ 选SPI
- 引脚受限场景(只有2根线可用)→ 选I2C
- 多器件级联场景 → SPI菊花链模式
核心要点:配置接口的本质就是“地址+数据”的传输通道。不管协议多花哨,最终目的就是把正确的值写到正确的寄存器地址上。
4.2 SPI协议在PLL配置中的应用
SPI全称Serial Peripheral Interface,四根线:SCK、MOSI、MISO、CS。简单粗暴,全双工通信。
我在项目中遇到过一种情况:某款PLL芯片的SPI时序要求CS拉低后必须等至少一个SCK周期才能开始传数据。当时没仔细看数据手册,直接按通用SPI时序写,结果前两个bit总是错位。后来加了条NOP指令才搞定。
4.2.1 SPI协议帧格式
PLL配置常用的SPI帧格式长这样:
| 操作位(1bit) | 地址位(7bit) | 数据位(16bit) |
| 0/1 | A[6:0] | D[15:0] |
操作位:0=写操作,1=读操作
地址位:寄存器地址,高7位
数据位:要写入或读出的数据
为什么地址是7位?因为大部分PLL的寄存器数量不超过128个。16位数据宽度则是因为PLL参数通常需要较高的精度,比如分频比N可能需要12~14位。
我的小技巧:SPI的时钟极性(CPOL)和相位(CPHA)一定要跟PLL芯片匹配。我习惯先配成mode 0(CPOL=0, CPHA=0),如果通信不正常再试mode 3。90%的芯片都支持这两种模式。
4.2.2 寄存器读写命令构造
写操作示例:往地址0x23写入0xABCD
CS拉低
发送 0x23 >> 1 | 0x00 // 操作位=0,地址=0x23,拼成1字节
发送 0xAB // 数据高8位
发送 0xCD // 数据低8位
CS拉高
读操作示例:读取地址0x45的寄存器值
CS拉低
发送 0x45 >> 1 | 0x80 // 操作位=1,地址=0x45
接收 0x?? // 读取高8位
接收 0x?? // 读取低8位
CS拉高
我曾经犯过一个低级错误:读操作时忘了把操作位置1,结果读回来的全是0。查了半天才发现是命令构造错了。所以写代码时一定要仔细核对bit位置。
4.3 I2C协议在PLL配置中的应用
I2C只有两根线:SCL和SDA。相比SPI,它多了设备寻址的步骤,但省引脚啊!
我建议:如果你的系统里只有一颗PLL需要配置,用I2C就够了。但如果要同时配置多颗PLL,SPI的菊花链模式会更方便。
4.3.1 I2C协议帧格式
I2C的帧格式比SPI复杂一些,因为它需要设备地址和内部地址两级寻址:
| 起始位 | 设备地址(7bit) | R/W | ACK | 内部地址(8bit) | ACK | 数据(8bit) | ACK | 停止位 |
设备地址:PLL芯片的I2C地址,由硬件引脚决定
R/W:0=写,1=读
内部地址:寄存器地址
数据:要写入或读出的值
注意:I2C的ACK信号一定要检查!我遇到过一颗PLL芯片,它在写操作时如果检测到校验错误,会回复NACK。如果不检查ACK,你根本不知道数据有没有写进去。
4.3.2 寄存器读写命令构造
写操作示例:往地址0x10写入0xA5
起始位
发送 0x50 << 1 | 0x00 // 设备地址0x50 + 写操作
等待ACK
发送 0x10 // 内部地址(寄存器地址)
等待ACK
发送 0xA5 // 数据
等待ACK
停止位
读操作示例:读取地址0x20的寄存器值
起始位
发送 0x50 << 1 | 0x00 // 设备地址 + 写操作(先写内部地址)
等待ACK
发送 0x20 // 内部地址
等待ACK
重复起始位
发送 0x50 << 1 | 0x01 // 设备地址 + 读操作
等待ACK
接收 0x?? // 读取数据
发送NACK // 读最后一个字节后发NACK
停止位
这里有个坑:读操作需要先写内部地址,再重新发起起始位切换为读模式。我刚开始做的时候忘了这个步骤,直接发读命令,结果读回来的永远是0x00。
4.4 SPI vs I2C:怎么选?
| 对比项 | SPI | I2C |
|---|---|---|
| 引脚数 | 4根(可减为3根) | 2根 |
| 速度 | 可达50MHz+ | 标准100kHz/400kHz,快速1MHz |
| 多设备支持 | 片选线控制 | 设备地址寻址 |
| 全双工 | 是 | 否 |
| 硬件复杂度 | 低 | 中(需状态机) |
| 典型应用 | 高速PLL、多PLL级联 | 低速PLL、引脚受限场景 |
我个人经验:如果PLL的配置频率超过1MHz,果断选SPI。I2C在高速下容易受总线电容影响,波形会变差。有一次我在I2C总线上挂了4颗PLL,结果SCL的上升沿变得跟山坡一样缓,通信直接挂掉。后来加了上拉电阻才解决。
4.5 协议帧格式设计要点
不管用SPI还是I2C,帧格式设计时要注意几点:
- 地址对齐:寄存器地址最好按字节对齐,方便软件处理
- 保留位处理:帧格式中的保留位要固定为0或1,不能悬空
- 读写区分:操作位要放在帧的最前面,方便硬件解析
- 数据宽度:根据PLL参数精度选择8位、16位或24位
- 校验机制:关键配置建议加CRC或奇偶校验
避坑指南:我曾经设计过一个帧格式,把操作位放在了地址后面。结果硬件解析时先收到地址,不知道是读还是写,只能缓存起来等操作位到了再处理。白白浪费了寄存器资源。所以操作位一定要放在最前面!
4.6 本章小结
SPI和I2C是PLL配置的两大主流协议。SPI快、简单,适合高速场景;I2C省引脚、支持多设备,适合低速场景。选择哪种协议,取决于你的系统需求。
帧格式设计时,记住“操作位在前、地址居中、数据在后”的原则。读写命令构造要仔细核对bit位置,尤其是I2C的读操作需要先写内部地址再切换读模式。
嗯,这些经验都是我用实际加班换来的。希望你们能少走弯路。
核心记忆点:配置接口的本质就是“地址+数据”的传输。不管协议多花哨,把正确的值写到正确的地址上,PLL就能乖乖工作。
可可精品资料库