📡 第4课:四种外设详解
I2C、SPI、UART、GPIO——嵌入式芯片最常用的四种通信接口,每种都实现了完整的工业协议。
理解每种外设的通信原理、为什么这样设计、在 rv_control 中各用了多少资源。
1. I2C —— 两根线的"总线"
I2C(Inter-Integrated Circuit)只需两根线(SCL时钟 + SDA数据)就能挂载上百个设备。每个设备有唯一地址(7位=128个),主机轮询呼叫。
I2C 9状态FSM
开漏输出:I2C 引脚不主动输出高电平——它只"拉低"(输出0)或"放手"(高阻态)。外接上拉电阻把线拉到高电平。这样做的好处:多个设备可以共享同一根线而不会短路(两个设备同时输出0和1时,0"赢")。
rv_control 的 I2C 是主机模式(只有 CPU 发起通信),不支持多主机仲裁和时钟拉伸(从设备不能拉慢时钟)。397 行代码,~470 个逻辑单元。
2. SPI —— 四根线的"高速通道"
SPI(Serial Peripheral Interface)比 I2C 快得多(可达 MHz 级别),但需要四根线:SCK(时钟)、MOSI(主机出从机入)、MISO(从机出主机入)、CS_N(片选,低有效)。
CPOL/CPHA 四种模式:配置"时钟空闲时是高还是低"和"在第几个边沿采样数据",可以适配不同 SPI 设备。rv_control 支持全部 4 种模式。207 行代码,~300 个逻辑单元。
3. UART —— 最经典的"串口"
UART(Universal Asynchronous Receiver/Transmitter)不需要时钟线——双方约定好波特率(比如 115200),各自用内部时钟判断每个 bit 的边界。
UART 数据帧格式
起始位"] --> D0["D0
Bit0"] --> D1["D1"] --> D2["D2"] --> D3["D3"] --> D4["D4"] --> D5["D5"] --> D6["D6"] --> D7["D7
Bit7"] --> PARITY["校验位
(可选)"] --> STOP["1
停止位(1或2)"] style START fill:#d03b3b,color:#fff style STOP fill:#0ca30c,color:#fff
16× 过采样:每个 bit 周期内采样 16 次,取中间的第 8 次作为可靠值——避开 bit 边界的过渡区域。
8 字节 FIFO:发送和接收各有一个 8 字节深度的缓冲队列。CPU 可以一次性写入 8 个字符然后去干别的事,UART 慢慢发。rv_control 有 4 个 UART(UART0-3),每个 ~750 个逻辑单元——4 个 UART 合计 ~3000 单元,占芯片总面积的 37%,仅次于 CPU。
4. GPIO —— 16根"万能引脚"
GPIO(General-Purpose I/O)是最灵活的外设——每根引脚可以独立配置为输入或输出,还可以设置中断(电平触发或边沿触发)。
GPIO 中断类型
2级同步器:外部引脚信号是"异步"的(随时可能变化),直接读可能导致亚稳态。GPIO 用两个串联的触发器做"同步器"——第一个 FF 可能产生亚稳态,但第二个 FF 给它一整周期时间稳定下来。
5. 四种外设对比
| 外设 | 线数 | 速度 | 拓扑 | 代码量 | 单元数 | 特点 |
|---|---|---|---|---|---|---|
| I2C | 2 | 100k/400k Hz | 多设备总线 | 397行 | ~470 | 开漏、地址寻址、9状态FSM |
| SPI | 4 | ~MHz | 点对点 | 207行 | ~300 | 全双工、4种模式 |
| UART×4 | 2×4 | 115.2k bps | 点对点 | 338行 | ~750×4 | FIFO、16×过采样、校验 |
| GPIO | 16 | — | 独立引脚 | 158行 | ~380 | 双向、中断、同步器 |