基于RISC-V软核的智能传感器数据采集系统——FPGA毕业设计实施指南

二牛学FPGA
文章2026-05-03
45

Quick Start

  1. 安装 Vivado 2023.2 或更高版本(含 Vitis 嵌入式开发套件)。
  2. 下载并配置开源 RISC-V SoC 项目(推荐 VexRiscv 或 PicoRV32 的 SoC 封装)。
  3. 在 Vivado 中创建工程,添加 SoC 的 RTL 源文件与约束文件(XDC)。
  4. 综合、实现并生成比特流,下载到 FPGA 开发板(如 Nexys A7-100T)。
  5. 使用 Vitis 编写 C 语言程序,通过 JTAG 下载并调试,验证串口打印“Hello World”。
  6. 连接 I2C/SPI 接口的传感器(如 BME280 温度湿度传感器),编写驱动读取数据。
  7. 将传感器数据通过 UART 发送到上位机,或存储到板载 DDR,验证数据采集正确性。

前置条件与环境

项目推荐值/说明替代方案
FPGA 开发板Xilinx Artix-7(如 Nexys A7-100T)Zynq-7000 系列(需调整 SoC 配置)
EDA 版本Vivado 2023.2 + Vitis 2023.2Vivado 2021.1 以上(需兼容 RISC-V IP)
仿真器Vivado Simulator 或 ModelSim SE-64 2020.4Verilator(仅支持 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 MHzVivado 时序报告,最差 PVT
LUT 使用7,234VexRiscv 含 I-Cache 4KB,D-Cache 4KB
FF 使用5,801同上
BRAM 使用28 块(36Kb)含 SoC 内存与缓存
I2C 采样率12.5 Hz每次读取 3 字节,100kHz 总线
UART 吞吐11.5 KB/s115200-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。

扩展与下一步

  1. 添加 Wi-Fi 模块(ESP8266),通过 UART 将传感器数据上传到云平台。
  2. 使用 FreeRTOS 实现多任务调度,同时采集多个传感器并处理数据。
  3. 将 I2C 控制器改为 AXI 接口,方便集成到 Zynq 硬核系统中。
  4. 加入硬件浮点单元(FPU),提升传感器数据校准计算的精度与速度。
  5. 使用 SystemVerilog 断言(SVA)验证 I2C 时序,确保设计正确性。

参考与信息来源

  • 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 × 分频值)。

分类
技术分享
标签
fpgaRISC-V传感器数据采集
浏览 45
分享:

相关推荐

同频道 · 相近分类

暂无相关推荐

作者

二牛学FPGA查看主页

同分类阅读

文章

延伸阅读与实操

  • 文章 + 课程联动深度文章常对应体系课章节,可一键选课。
  • 学习产出可参考笔记与作业案例在学习产出广场持续更新。

探索全站