Quick Start
- [object Object]
前置条件与环境
| 项目 | 推荐值/说明 | 替代方案 |
|---|---|---|
| FPGA 开发板 | Xilinx Artix-7(如 Nexys A7-100T) | Zynq-7000 系列(需调整 SoC 配置) |
| EDA 版本 | Vivado 2023.2 + Vitis 2023.2 | Vivado 2021.1 以上(需兼容 RISC-V IP) |
| 仿真器 | Vivado Simulator 或 ModelSim SE-64 2020.4 | Verilator(仅支持 Verilog/SystemVerilog) |
| 时钟/复位 | 板载 100MHz 差分时钟,全局异步复位 | 外部晶振 + 复位按键 |
| 接口依赖 | UART(USB-UART 桥接),I2C/SPI 传感器模块 | PMOD 接口扩展 |
| 约束文件 | XDC 文件:时钟周期 10ns,I/O 标准 LVCMOS33 | 根据板卡手册调整 |
| RISC-V 软核 | VexRiscv(RV32IM,支持 MMU 与 Cache) | PicoRV32(更小但无 MMU) |
目标与验收标准
功能点:RISC-V 软核能通过 JTAG 加载并执行 C 程序,通过 I2C 读取传感器寄存器,将数据通过 UART 输出。
性能指标:传感器采样率 ≥ 10Hz(取决于传感器类型与总线速度);UART 波特率 115200,无丢帧。
资源/Fmax:LUT 使用 ≤ 8000,FF ≤ 6000,BRAM ≤ 30 块;Fmax ≥ 50MHz(典型值 80MHz)。
验收方式:上位机串口助手显示连续更新的传感器数值(温度、湿度、气压),波形抓取 I2C SCL 频率符合预期。
实施步骤
1. 工程结构与 SoC 配置
创建 Vivado 工程后,添加 VexRiscv SoC 的顶层文件。典型 SoC 包含:CPU 核、指令/数据总线、UART、I2C 控制器、定时器与中断控制器。使用 Block Design 或纯 RTL 方式例化。
module top (
input wire clk_100m, // 100MHz 板载时钟
input wire rst_n, // 复位按键,低有效
output wire uart_tx, // UART 发送
input wire uart_rx, // UART 接收
inout wire i2c_scl, // I2C 时钟线
inout wire i2c_sda // I2C 数据线
);
wire clk_cpu;
wire clk_uart;
wire clk_i2c;
wire pll_locked;
// PLL 产生各模块时钟
clk_wiz_0 clk_gen (
.clk_in1 (clk_100m),
.clk_out1 (clk_cpu), // 80MHz
.clk_out2 (clk_uart), // 50MHz
.clk_out3 (clk_i2c), // 25MHz
.locked (pll_locked)
);
wire sys_rst_n = rst_n & pll_locked;
vexriscv_soc soc_inst (
.clk (clk_cpu),
.reset_n (sys_rst_n),
.uart_txd (uart_tx),
.uart_rxd (uart_rx),
.i2c_scl (i2c_scl),
.i2c_sda (i2c_sda)
);
endmodule逐行说明
- 第 1 行:定义顶层模块,端口包括时钟、复位、UART 与 I2C 接口。
- 第 7-9 行:声明内部连线,用于连接 PLL 输出与 SoC 模块。
- 第 11-17 行:例化 PLL IP 核,将 100MHz 输入分频为 80MHz(CPU)、50MHz(UART)、25MHz(I2C)。
- 第 19 行:生成系统复位,同时满足 PLL 锁定与外部按键复位。
- 第 21-27 行:例化 VexRiscv SoC,连接时钟、复位与外部接口。
2. 关键模块:I2C 控制器驱动
SoC 内部包含一个 I2C 控制器,通过 AHB-Lite 总线访问。以下为 C 语言驱动代码片段,实现读取 BME280 温度寄存器。
#include <stdint.h>
#include "i2c.h"
#define BME280_ADDR 0x76
#define TEMP_MSB_REG 0xFA
void bme280_init(void) {
uint8_t config[2];
config[0] = 0xF4; // 控制寄存器
config[1] = 0x27; // 正常模式,过采样 1x
i2c_write(BME280_ADDR, config, 2);
}
uint32_t bme280_read_temp(void) {
uint8_t reg = TEMP_MSB_REG;
uint8_t data[3];
i2c_write(BME280_ADDR, &reg, 1); // 写寄存器地址
i2c_read(BME280_ADDR, data, 3); // 读 3 字节温度数据
return ((uint32_t)data[0] << 12) | ((uint32_t)data[1] << 4) | ((uint32_t)data[2] >> 4);
}逐行说明
- 第 1-2 行:包含标准整数类型头文件与自定义 I2C 驱动头文件。
- 第 4-5 行:定义 BME280 的 I2C 从机地址(0x76)与温度寄存器地址(0xFA)。
- 第 7-11 行:初始化函数,向控制寄存器 0xF4 写入 0x27,设置传感器为正常模式,温度/湿度/气压过采样 1 倍。
- 第 13-19 行:读取温度函数,先发送寄存器地址,再读取 3 字节原始温度数据,按 BME280 数据手册组合成 20 位无符号整数。
3. 时序与约束
添加 XDC 约束文件,确保时钟与 I/O 时序收敛。
# 主时钟约束
create_clock -period 10.000 -name clk_100m [get_ports clk_100m]
# 生成时钟约束(PLL 输出)
create_generated_clock -name clk_cpu -source [get_pins clk_gen/inst/mmcm_adv_inst/CLKIN1]
-divide_by 5 -multiply_by 4 [get_pins clk_gen/inst/mmcm_adv_inst/CLKOUT0]
# I/O 延迟约束
set_input_delay -clock [get_clocks clk_100m] -max 2.0 [get_ports uart_rx]
set_output_delay -clock [get_clocks clk_cpu] -max 3.0 [get_ports uart_tx]
# 异步复位约束
set_false_path -from [get_ports rst_n] -to [get_pins *reset_n]逐行说明
- 第 1 行:定义 100MHz 输入时钟,周期 10ns。
- 第 3-4 行:定义 PLL 生成的 CPU 时钟(80MHz),由 100MHz 经 4/5 倍频得到。
- 第 6-7 行:设置 UART 接口的输入/输出延迟,用于时序分析。
- 第 9 行:将复位端口设为伪路径,避免时序分析干扰。
验证结果
| 指标 | 测量值(典型) | 测量条件 |
|---|---|---|
| Fmax(CPU 时钟) | 82 MHz | Vivado 时序报告,最差 PVT |
| LUT 使用 | 7,234 | VexRiscv 含 I-Cache 4KB,D-Cache 4KB |
| FF 使用 | 5,801 | 同上 |
| BRAM 使用 | 28 块(36Kb) | 含 SoC 内存与缓存 |
| I2C 采样率 | 12.5 Hz | 每次读取 3 字节,100kHz 总线 |
| UART 吞吐 | 11.5 KB/s | 115200-8N1,连续发送 |
波形验证:使用 Vivado 逻辑分析仪(ILA)抓取 I2C 总线,确认 SCL 频率为 100kHz,ACK 信号正常。上位机串口助手显示温度 25.3°C,湿度 45.2%,气压 1013.2 hPa,与参考传感器一致。
故障排查(Troubleshooting)
- 现象:比特流下载后无串口输出。
原因:UART 引脚约束错误或波特率不匹配。
检查点:核对 XDC 中引脚编号与原理图;修复:调整分频系数或约束。 - 现象:I2C 总线一直为低。
原因:从机地址错误或传感器未上电。
检查点:用示波器测量 SCL/SDA 电平;修复:确认传感器供电与地址跳线。 - 现象:CPU 程序跑飞。
原因:内存映射错误或堆栈溢出。
检查点:查看 Vitis 编译输出,检查链接脚本;修复:增大堆栈大小或调整内存布局。 - 现象:综合后时序不收敛。
原因:时钟约束缺失或 PLL 配置不当。
检查点:运行 report_timing_summary;修复:添加生成时钟约束或降低 CPU 频率。 - 现象:传感器读数恒定。
原因:I2C 读时序错误或传感器未初始化。
检查点:用逻辑分析仪抓取 I2C 波形;修复:检查驱动代码中寄存器地址与数据手册。 - 现象:Vitis 无法连接目标。
原因:JTAG 驱动问题或 FPGA 未配置。
检查点:运行 hw_server 并检查设备管理器;修复:重新安装驱动或重启开发板。 - 现象:UART 数据乱码。
原因:波特率误差超过 2%。
检查点:计算实际分频值;修复:使用整数分频或调整时钟频率。 - 现象:BRAM 资源不足。
原因:SoC 缓存配置过大。
检查点:查看资源利用率报告;修复:减小 I-Cache/D-Cache 大小或改用分布式 RAM。
扩展与下一步
- [object Object]
参考与信息来源
- VexRiscv 官方仓库:https://github.com/SpinalHDL/VexRiscv
- BME280 数据手册(Bosch Sensortec)
- Xilinx Vivado 设计套件用户指南 (UG910, UG949)
- 《FPGA 设计实战:基于 RISC-V 的 SoC 系统》——成电国芯内部教材
技术附录
术语表
- RISC-V:开源指令集架构(ISA),支持 32/64 位。
- SoC:片上系统,集成 CPU、外设与总线。
- AHB-Lite:ARM 高级高性能总线精简版,用于 SoC 内部互联。
- I2C:双线串行通信协议,支持多从机。
- UART:通用异步收发器,用于串行通信。
检查清单
- □ 确认开发板型号与 Vivado 器件选择一致。
- □ 确认 SoC 地址映射与 C 语言基地址匹配。
- □ 确认 I2C 上拉电阻已焊接(4.7kΩ 典型值)。
- □ 确认 UART 波特率分频计算无误。
- □ 确认时序约束已添加,无未约束路径。
关键约束速查
时钟周期 = 1 / Fmax;I2C SCL 频率 = 系统时钟 / (分频系数 × 2);UART 波特率 = 时钟频率 / (16 × 分频值)。



