第四章:配置接口协议——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,帧格式设计时要注意几点:

  1. 地址对齐:寄存器地址最好按字节对齐,方便软件处理
  2. 保留位处理:帧格式中的保留位要固定为0或1,不能悬空
  3. 读写区分:操作位要放在帧的最前面,方便硬件解析
  4. 数据宽度:根据PLL参数精度选择8位、16位或24位
  5. 校验机制:关键配置建议加CRC或奇偶校验

避坑指南:我曾经设计过一个帧格式,把操作位放在了地址后面。结果硬件解析时先收到地址,不知道是读还是写,只能缓存起来等操作位到了再处理。白白浪费了寄存器资源。所以操作位一定要放在最前面!

4.6 本章小结

SPI和I2C是PLL配置的两大主流协议。SPI快、简单,适合高速场景;I2C省引脚、支持多设备,适合低速场景。选择哪种协议,取决于你的系统需求。

帧格式设计时,记住“操作位在前、地址居中、数据在后”的原则。读写命令构造要仔细核对bit位置,尤其是I2C的读操作需要先写内部地址再切换读模式。

嗯,这些经验都是我用实际加班换来的。希望你们能少走弯路。

核心记忆点:配置接口的本质就是“地址+数据”的传输。不管协议多花哨,把正确的值写到正确的地址上,PLL就能乖乖工作。

PLL配置接口协议选择流程 开始选择配置接口 引脚数量是否充足(≥4根可用)? (考虑GPIO复用后剩余引脚) 是 否 选SPI协议 4线:SCK/MOSI/MISO/CS 选I2C协议 2线:SCL/SDA 配置速度要求 >1MHz? 多设备数量 >3个? SPI(高速模式) 时钟可达50MHz+ I2C(多设备模式) 支持127个设备寻址 注:实际选择还需考虑功耗、EMI、PCB布局等因素

可可精品资料库