4. 软硬件接口设计基础
在 Lattice FPGA 的软硬件协同开发中,接口是连接“软件意图”和“硬件行为”的桥梁。软件侧通常运行在嵌入式软核(如 Lattice 的 RISC-V 软核或 Micro8/Mico32)或外部主控 MCU/SoC 上,硬件侧则是 FPGA 内部逻辑、外设 IP 和片外器件。接口设计要回答三个问题:用什么协议传数据、数据落在哪个地址、如何知道事件发生并高效搬运数据。这分别对应总线协议、寄存器映射、中断与 DMA 机制。
4.1 总线协议的选择与实现方式
Lattice FPGA 中常见的接口可分为片内总线和串行外设总线两类。片内总线用于软核与自定义逻辑之间通信,典型有 AXI4-Lite、AHB-Lite 和 Wishbone;串行总线用于连接片外传感器、存储器和调试设备,典型有 SPI、I2C、UART。
AXI4-Lite 采用五通道分离结构:写地址 AW、写数据 W、写响应 B、读地址 AR、读数据 R。每个通道都有独立的 VALID/READY 握手,支持非阻塞传输。在 Lattice 中,若使用 RISC-V 软核(如 Lattice Propel 生成的子系统),CPU 侧通常暴露 AXI4-Lite 主接口,用户只需实现从接口逻辑。一个最小 AXI4-Lite 从设备需要处理 AW/W 通道的先后到达问题,通常用状态机等待两者同时有效后再写入寄存器并返回 BRESP。
AHB-Lite 是单主设备总线,结构比 AXI 简单,只有 HADDR、HWDATA、HRDATA、HWRITE、HREADY、HRESP 等信号。它适合低资源 FPGA 中软核与少量外设的连接。传输分地址阶段和数据阶段,HREADY 为低时插入等待周期。相比 AXI,AHB-Lite 不需要处理多通道乱序,逻辑面积更小,但吞吐和并发能力有限。
Wishbone 是开源社区常用的轻量总线,信号极简:cyc、stb、we、adr、dat_i、dat_o、ack。一次传输由主设备拉高 cyc 和 stb 发起,从设备在完成时拉高 ack。它没有突发和乱序概念,非常适合寄存器型外设和教学项目。在 Lattice 的 Diamond 或 Radiant 工程中,Wishbone 常作为软核与自定义 IP 之间的内部互联。
串行接口方面,SPI 适合高速短距离通信,典型四线:SCLK、MOSI、MISO、CS_N,速率可达数十 MHz;I2C 只需 SCL、SDA 两根线,支持多设备寻址,速率通常 100 kHz~400 kHz;UART 异步点对点,需约定波特率、数据位、停止位和校验位。在 FPGA 中实现这些接口,既可以用硬核(部分 Lattice 器件集成 I2C/SPI 硬核),也可以用软核逻辑自行编写状态机。
4.2 寄存器映射:软件看到的世界
寄存器映射是软硬件之间的“契约”。硬件设计者把控制位、状态位和数据缓冲映射到一段连续地址空间,软件通过读写这些地址来操作硬件。一个典型的自定义外设寄存器组如下(示例参数,非实测):
#define MYIP_BASE 0x80001000
#define MYIP_CTRL (MYIP_BASE + 0x00) // bit0: enable, bit1: soft_reset
#define MYIP_STATUS (MYIP_BASE + 0x04) // bit0: busy, bit1: done, bit2: error
#define MYIP_DATA_IN (MYIP_BASE + 0x08) // 写入待处理数据
#define MYIP_DATA_OUT (MYIP_BASE + 0x0C) // 读取处理结果
#define MYIP_IRQ_EN (MYIP_BASE + 0x10) // 中断使能
#define MYIP_IRQ_CLR (MYIP_BASE + 0x14) // 写1清除中断
设计寄存器时要注意三点:位域定义要稳定,一旦软件依赖就不能随意改动;读写属性要明确,只读状态位不能被写操作影响;保留位要写0或读回0,避免未来扩展时产生兼容问题。在 Lattice 中,寄存器通常用 always 块实现,写通道在总线写有效时更新,读通道用组合逻辑或同步逻辑返回当前值。
4.3 中断机制:从事件到响应
中断让硬件可以主动通知软件,避免软件轮询浪费 CPU。一个完整的中断通路包括:外设产生中断事件 → 中断控制器汇总 → 软核/CPU 接收 → 跳转 ISR → 软件清除中断源。在 Lattice 软核系统中,中断控制器通常提供使能寄存器、挂起寄存器和优先级配置。
关键设计点是中断清除时序。常见错误是软件在 ISR 中先清中断再处理数据,导致处理期间新事件丢失;正确做法通常是先读取数据或状态,再清除中断标志。另一个要点是中断与轮询的配合:高速数据流可用中断触发 DMA,DMA 完成后再产生一次中断通知软件,而不是每个字节都中断。
4.4 DMA:让数据搬运不占用 CPU
DMA 在软硬件协同中承担大块数据搬运。以“FPGA 采集 → DDR → 软件处理”为例,软件先配置 DMA 描述符:源地址、目的地址、传输长度、方向,然后启动 DMA。DMA 引擎通过总线直接读写内存,完成后置位完成标志并产生中断。CPU 在此期间可以执行其他任务。
在 Lattice FPGA 中实现 DMA 有两种常见方式:一是使用软核自带的 DMA 控制器;二是用自定义逻辑实现简单的描述符搬运。无论哪种方式,都要注意缓存一致性:如果软核有数据缓存,DMA 写入内存后软件可能读到旧缓存,需要在启动 DMA 前清理缓存或在完成后无效化缓存。此外,DMA 的源/目的地址要按总线位宽对齐,长度最好是突发长度的整数倍,以提升效率。
综合来看,AXI/AHB/Wishbone 解决“怎么连”,寄存器映射解决“怎么控”,中断解决“怎么通知”,DMA 解决“怎么高效搬”。四者配合,才能让 Lattice FPGA 的软硬件协同既正确又高效。实际项目中,建议先用 Wishbone 或 AHB-Lite 搭建最小可运行系统,验证寄存器读写和中断响应,再逐步引入 AXI 和 DMA 提升吞吐。