1. GD32V通信协议概述:UART、SPI、I2C基础概念与GD32V外设特性
各位同学,咱们今天正式开篇。做嵌入式开发,说白了就是让芯片跟外界“说话”。不管是跟传感器要个温度数据,还是往显示屏上刷个画面,都离不开通信协议。GD32V这颗RISC-V内核的芯片,它的通信外设设计得挺扎实,但用好它,你得先理解这些协议到底在干什么。
我个人习惯,拿到一款新芯片,第一件事不是翻数据手册的寄存器列表,而是先看它的通信外设框图。为什么?因为通信是系统的“血管”,血管不通,CPU再强也没用。今天这一章,咱们就把UART、SPI、I2C这三个最常用的协议,结合GD32V的外设特性,掰开揉碎了讲清楚。
1.1 为什么是串行通信?
你可能会问,为什么不用并行通信?一次传8位、16位,不是更快吗?嗯,这里要注意——并行通信在短距离、高频场景下,信号之间的串扰和时序偏差会让你头疼到怀疑人生。我早年做一款图像采集卡,8位并行数据线在50MHz下,布线稍微长一点,数据就全乱了。
串行通信的优势在于:
- 引脚少——节省芯片封装成本和PCB面积
- 抗干扰强——差分信号(如RS485)可以传几百米
- 时序简单——时钟和数据的关系清晰,调试相对容易
GD32V系列芯片,根据型号不同,通常提供2~8个UART、2~3个SPI、1~2个I2C。数量不算多,但覆盖绝大多数嵌入式场景足够了。
1.2 UART:最通用的“老黄牛”
UART(Universal Asynchronous Receiver/Transmitter),通用异步收发器。注意“异步”这两个字——它没有独立的时钟线,收发双方靠约定的波特率来同步。
我刚开始学嵌入式时,总觉得异步通信不靠谱:两边时钟精度不一样,时间长了不就对不上了吗?其实UART在每个字节的开头都有一个起始位,相当于“我要开始发了,你准备好”,然后接收方用本地时钟采样。只要波特率误差在±2%以内,基本不会出错。
GD32V的UART特性
| 特性 | 说明 |
|---|---|
| 支持波特率 | 最高可达4.5Mbps(取决于系统时钟和分频配置) |
| 数据位 | 7位、8位、9位可选 |
| 停止位 | 0.5、1、1.5、2位 |
| 校验位 | 无校验、奇校验、偶校验 |
| 硬件流控 | 支持RTS/CTS(部分型号) |
| FIFO深度 | 发送和接收各16字节 |
| 中断源 | 发送完成、接收非空、接收溢出、错误等 |
GD32V的UART还有一个很实用的特性——支持单线半双工模式。这意味着你可以用一根线既发又收,适合与某些单总线协议的传感器通信。不过要注意,半双工模式下需要软件控制收发切换,否则会冲突。
1.3 SPI:高速“同步”通道
SPI(Serial Peripheral Interface),串行外设接口。它跟UART最大的区别是:有独立的时钟线(SCK)。收发双方在时钟的上升沿或下降沿同步采样数据,所以速度可以做得非常高。
SPI总线通常有4根线:
- SCK——时钟,由主机产生
- MOSI——主机输出,从机输入
- MISO——主机输入,从机输出
- CS——片选,低电平有效,用于选择从机
你想想看,SPI的通信模型其实很简单:主机拉低某个从机的CS线,然后开始产生时钟,同时在MOSI上发送数据,从MISO上接收数据。一个时钟周期内,数据双向流动。
GD32V的SPI特性
| 特性 | 说明 |
|---|---|
| 最大速率 | 系统时钟的一半(如108MHz主频下可达54MHz) |
| 数据帧格式 | 4~16位可编程 |
| 时钟极性/相位 | CPOL和CPHA可配置,共4种模式 |
| 片选控制 | 硬件自动控制或软件手动控制 |
| FIFO深度 | 发送和接收各16位(单级缓冲) |
| DMA支持 | 支持,可配合DMA实现高速连续传输 |
GD32V的SPI还支持TI模式(与德州仪器的SPI兼容)和I2S模式(用于音频数据)。不过I2S模式在GD32V上属于“附加功能”,实际使用时要注意时钟精度,否则音频会有杂音。
1.4 I2C:两线制的“多面手”
I2C(Inter-Integrated Circuit),集成电路间总线。它只用两根线:SDA(数据线)和SCL(时钟线),但可以挂载多个设备,每个设备有唯一的地址。
I2C的通信过程有点像“打电话”:主机先拨号(发送起始条件和从机地址),从机应答(ACK),然后开始传输数据。传输结束后,主机挂断(发送停止条件)。
为什么I2C只有两根线却能实现多设备通信?因为它是开漏输出,加上上拉电阻。所有设备的SDA和SCL引脚都是“线与”关系——任何一个设备拉低,总线就是低电平。这就避免了多设备同时驱动总线导致的冲突。
GD32V的I2C特性
| 特性 | 说明 |
|---|---|
| 工作模式 | 标准模式(100kHz)、快速模式(400kHz) |
| 地址长度 | 7位或10位 |
| 主从模式 | 支持主机和从机模式 |
| 多主机仲裁 | 硬件支持,自动检测总线冲突 |
| FIFO深度 | 无独立FIFO,靠移位寄存器和中断 |
| DMA支持 | 支持,但需注意时序配合 |
GD32V的I2C有一个容易忽略的细节:它的SCL时钟频率是通过APB时钟分频得到的,分频系数是一个整数。这意味着你无法得到任意精确的100kHz或400kHz,只能取近似值。比如APB时钟为54MHz时,要得到400kHz,分频系数为54M/400k=135,实际频率为54M/135=400kHz,刚好。但如果APB时钟是50MHz,分频系数125,实际频率就是400kHz,也刚好。但如果是48MHz,分频系数120,实际频率400kHz——嗯,还是刚好。但如果是72MHz,分频系数180,实际频率400kHz——你发现规律了吗?
其实我想说的是:只要分频后的实际频率不超过目标频率的±10%,大多数I2C从机都能正常工作。别太纠结那几kHz的偏差。
1.5 三大协议对比与选型建议
咱们用一张表来总结一下UART、SPI、I2C的核心差异:
| 特性 | UART | SPI | I2C |
|---|---|---|---|
| 信号线数量 | 2(TX/RX) | 4(SCK/MOSI/MISO/CS) | 2(SDA/SCL) |
| 同步方式 | 异步(波特率约定) | 同步(时钟线) | 同步(时钟线) |
| 最大速率 | ~4.5Mbps | ~54MHz | 400kHz(快速模式) |
| 多设备支持 | 点对点(或RS485多机) | 一主多从(片选) | 多主多从(地址) |
| 硬件复杂度 | 低 | 中 | 中高(开漏+上拉) |
| 典型应用 | 调试日志、GPS、蓝牙模块 | Flash、LCD、SD卡、ADC | 传感器、EEPROM、RTC |
选型建议其实很简单:
- 如果只是跟PC通信或者传日志,用UART,简单可靠。
- 如果需要高速传输大量数据(比如刷屏、读写Flash),用SPI。
- 如果引脚紧张且需要挂多个低速设备,用I2C。
但实际项目中,往往是三种协议混着用。比如一个智能家居网关,用UART接4G模块,用SPI接以太网芯片,用I2C接温湿度传感器。GD32V的外设资源刚好能覆盖这些需求。
1.6 GD32V通信外设的共性设计
最后,我想聊聊GD32V在通信外设设计上的一些共性特点。这些特点在你后续写驱动时会反复遇到:
- 寄存器映射清晰——每个外设的控制寄存器、状态寄存器、数据寄存器都有固定的偏移地址,且命名规范。比如UART的USART_STAT寄存器,bit0是TC(发送完成),bit5是RXNE(接收非空)。
- 中断向量独立——每个通信外设都有独立的中断向量,不像某些MCU多个外设共享一个中断号。这意味着你可以为每个外设单独写中断服务函数,代码更清晰。
- DMA支持完善——UART、SPI、I2C都支持DMA传输。我个人建议,只要数据量超过16字节,就用DMA。CPU可以腾出手来处理其他任务,系统整体吞吐量会明显提升。
- 时钟门控——每个外设的时钟都可以独立使能或关闭。不用的外设记得关掉时钟,能省不少功耗。我见过有人把所有外设时钟都开着,结果待机电流多了好几毫安。