news 2026/6/23 4:18:19

Lattice LFCPNX-100 Fpga开发+源码:基于I2c协议的IMU驱动控制

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Lattice LFCPNX-100 Fpga开发+源码:基于I2c协议的IMU驱动控制

1、概述

根据实际项目需求,设计和开发一个基于I2C总线的IMU驱动控制,实现FPGA对 IMU(BMI088)的数据采集,并实际验证。

2、 逻辑视图

把系统功能分解,模块划分,梳理出数据流和控制流如下:

核心模块

  • IMU 控制器:通过 I2C 读取 IMU 原始数据(加速度/角速度),产生采样有效信号和包起始/结束标志。

  • 数据打包模块:将 IMU 数据按照自定义协议(如 UDP/RoCE)打包成 AXI-Stream 流。

  • 10GbE MAC+PHY:将以太网帧发送到 SFP+ 光模块。

3、IMU控制器

这边采用的是ICM-42688-P型号,这是 是 TDK InvenSense 推出的一款 6 轴惯性测量单元(IMU),专为无人机和机器人应用而设计。集成了一个 16 位三轴加速度计和一个汽车级 16 位三轴陀螺仪;

4、IMU控制器+FSM

imu_top是一个可配置的惯性测量单元(IMU)数据采集与打包模块,实现 IMU 数据与图像数据的精确时间对齐,并通过 10GbE 网络发送,主要完成以下任务:

  • 通过I2C接口读取外部 IMU 传感器(如加速度计、陀螺仪)的原始数据(8-bit 字节流)。

  • 为每一次完整的采样(一个数据包)打上来自PTP(精确时间协议)64 位时间戳(秒 + 纳秒)。

  • [时间戳 + IMU 数据]打包成AXI-Stream格式输出,供后续模块(如网络打包、DMA 等)使用。

  • 提供APB 从接口,允许外部处理器(或软核)配置内部寄存器(例如设置采样率、滤波参数等)。

具体代码如下:

// SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // //功能: //通过I2C接口读取IMU传感器(如加速度计/陀螺仪)的原始数据,为每一帧(或每一次采样)打上来自PTP(精确时间协议)的64位时间戳,然后将数据打包成AXI-Stream格式输出。同时支持APB总线配置内部寄存器 // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. module imu_top import apb_pkg::*; import regmap_pkg::*; #( parameter RAM_DEPTH = 128, //内部可以缓存 128个采样点 parameter W_DATA = 64, localparam W_KEEP = W_DATA/8 ) ( // PTP PTP 时钟域 input i_ptp_clk, //PTP 时钟(通常来自10GbE恢复时钟) input i_ptp_rst, //PTP 域复位 input [63:0] i_ptp_ts, //PTP 时间戳(秒+纳秒) // Register Interface APB 配置接口 input i_aclk, //APB/IMU 采样时钟(通常50MHz) input i_arst, //APB 域复位 input apb_m2s i_apb_m2s, //APB 主到从信号(地址、数据、控制) output apb_s2m o_apb_s2m, //APB 从到主信号(就绪、读数据) // AXIS Interface AXIS 输出 output [W_DATA-1:0] o_axis_tdata, //输出数据(打包后的IMU+时间戳) output o_axis_tvalid, //数据有效 output o_axis_tlast, //帧/包结束标志 output o_axis_tuser, //用户定义(本模块置0) output [W_KEEP-1:0] o_axis_tkeep, //每个字节有效掩码(64位对应8个字节) input i_axis_tready, //下游模块准备好接收 // Interrupt IMU控制和I2C input [1:0] i_start, //启动采样触发信号(比如来自VSYNC) //I2C Ports input scl_i, output scl_o, input sda_i, output sda_o ); logic imu_data_valid; //数据有效 logic [7:0] imu_data; //原始IMU数据 8bit logic eop; //End of Packet logic sop; //表示一帧数据的开始(例如一次完整采样的第一个字节) logic sample_last; //本采样点最后一个字节 logic [63:0] imu_ts; logic imu_ts_vld; logic imu_sop_ptp_sync; logic [7:0] axis_tdata; logic axis_tvalid; imu #( .NUM_INST ( 1 ), .RAM_DEPTH ( RAM_DEPTH ) ) imu_inst ( .i_aclk ( i_aclk ), .i_arst ( i_arst ), .scl_i ( scl_i ), .sda_i ( sda_i ), .scl_o ( scl_o ), .sda_o ( sda_o ), .i_start ( i_start ), .o_data ( imu_data ), //原始IMU数据 8bit .o_data_valid ( imu_data_valid ), //数据有效 .o_busy ( ), .o_sample_last ( sample_last ), ////本采样点最后一个字节 .o_eop ( eop ), //End of Packet .o_sop ( sop ), //表示一帧数据的开始(例如一次完整采样的第一个字节) .o_bus_en ( ), .i_apb_m2s ( i_apb_m2s ), .o_apb_s2m ( o_apb_s2m ) ); // Append PTP timestamp to each sample 跨时钟域模块 //将i_aclk域的脉冲sop转换成i_ptp_clk域的单周期脉冲imu_sop_ptp_sync。 //作用:告诉PTP域“有一个新的IMU采样开始了,请记录当前时间”。 pulse_sync imu_data_pulse_ptp_sync_inst ( .src_clk ( i_aclk ), .src_rst ( i_arst ), .dst_clk ( i_ptp_clk ), .dst_rst ( i_ptp_rst ), .i_src_pulse ( sop ), .o_dst_pulse ( imu_sop_ptp_sync ) ); //跨时钟域模块 因为PTP时间戳来自独立时钟域(i_ptp_clk),而IMU数据在i_aclk域,需要将采样启动事件(sop)同步到PTP域,再把PTP时间戳采样回来。 //当imu_sop_ptp_sync有效时,将PTP时间寄存器i_ptp_ts的值“抓拍”并传递到i_aclk域,输出imu_ts_vld和imu_ts。 reg_cdc # ( .NBITS ( 64 ), .REG_RST_VALUE ( '0 ) ) u_ptp_cdc ( .i_a_clk ( i_ptp_clk ), .i_a_rst ( i_ptp_rst ), .i_a_val ( imu_sop_ptp_sync ), .i_a_reg ( i_ptp_ts ), .i_b_clk ( i_aclk ), .i_b_rst ( i_arst ), .o_b_val ( imu_ts_vld ), .o_b_reg ( imu_ts ) ); typedef enum logic [3:0] { IMU_IDLE, IMU_WAIT_TS, IMU_TS, IMU_DATA, IMU_SOP } imu_fsm_t; //状态机 imu_fsm_t ,状态机在i_aclk域运行,负责将IMU数据与时间戳组合成AXIS流。 imu_fsm_t imu_state; logic [2:0] cnt; logic [7:0] imu_data_r; always_ff @ (posedge i_aclk) begin if (i_arst) begin imu_state <= IMU_IDLE; //空闲,等待sop(IMU采样开始) cnt <= '0; imu_data_r <= '0; end else begin imu_state <= imu_state; case (imu_state) IMU_IDLE: begin ////空闲,等待sop(IMU采样开始) if (sop) begin imu_state <= IMU_WAIT_TS; imu_data_r <= imu_data; end cnt <= '0; end IMU_WAIT_TS: begin //等待reg_cdc返回有效时间戳(imu_ts_vld) if (imu_ts_vld) begin imu_state <= IMU_TS; end end IMU_TS: begin //输出64位时间戳(8个字节,每个周期输出1字节,共8周期) cnt <= cnt + 1; if (cnt == 3'd7) begin imu_state <= IMU_SOP; end end IMU_SOP: begin //输出IMU数据的第一个字节(在sop时锁存的imu_data_r) imu_state <= IMU_DATA; end IMU_DATA: begin //连续输出后续IMU数据(imu_data_valid有效时)直到eop拉高,回到IDLE if (eop) begin imu_state <= IMU_IDLE; end end endcase end end always_comb begin case (imu_state) IMU_IDLE: begin //空闲,等待sop(IMU采样开始) axis_tdata = '0; axis_tvalid = '0; end IMU_WAIT_TS: begin //等待reg_cdc返回有效时间戳(imu_ts_vld) axis_tdata = '0; axis_tvalid = '0; end IMU_TS: begin //输出64位时间戳(8个字节,每个周期输出1字节,共8周期) axis_tdata = imu_ts[cnt*8+:8]; axis_tvalid = '1; end IMU_SOP: begin //输出IMU数据的第一个字节(在sop时锁存的imu_data_r) axis_tdata = imu_data_r; axis_tvalid = '1; end IMU_DATA: begin //连续输出后续IMU数据(imu_data_valid有效时)直到eop拉高,回到IDLE axis_tdata = imu_data; axis_tvalid = imu_data_valid; end endcase end //通用AXIS宽度转换+缓冲模块 //它将输入的8-bit数据流收集到内部FIFO中,当凑满64位时,输出一个64位的AXIS包。 //同时传递tlast(这里接sample_last,即采样点最后一个字节标志)和tkeep(指示输出64位中哪些字节有效) //因为IMU数据长度不一定正好是8的倍数,tkeep可以标记最后一个非完整64位字中的有效字节。 //个典型的数据包结构(假设IMU一次采样输出12字节): // [ 时间戳 0-7 ] [ IMU字节0 ] [ IMU字节1 ] ... [ IMU字节11 ] // └───────── 8字节 ─────────┘└────────── 12字节 ──────────┘ axis_buffer #( .IN_DWIDTH ( 8 ), .OUT_DWIDTH ( W_DATA ), .BUF_DEPTH ( 16 ), .WAIT2SEND ( 0 ), .DUAL_CLOCK ( 0 ) ) u_axis_buffer ( .in_clk ( i_aclk ), .in_rst ( i_arst ), .out_clk ( i_aclk ), .out_rst ( i_arst ), .i_axis_rx_tvalid ( axis_tvalid ), .i_axis_rx_tdata ( axis_tdata ), .i_axis_rx_tlast ( sample_last ), .i_axis_rx_tuser ( '0 ), .i_axis_rx_tkeep ( '1 ), .o_axis_rx_tready ( ), .o_axis_tx_tvalid ( o_axis_tvalid ), .o_axis_tx_tdata ( o_axis_tdata ), .o_axis_tx_tlast ( o_axis_tlast ), .o_axis_tx_tuser ( o_axis_tuser ), .o_axis_tx_tkeep ( o_axis_tkeep ), .i_axis_tx_tready ( i_axis_tready ) ); endmodule

5、总结

imu_top是一个高度模块化、参数化、支持跨时钟域的 IMU 数据采集 IP 核。它解决了三个关键问题:

  1. 低延迟 I2C 读取:通过imu控制器高效获取传感器字节流。

  2. 精确时间戳:利用 PTP 时钟和 CDC 电路,为每个采样点打上纳秒级时间标签。

  3. 标准化输出:将变长的 IMU 数据打包成 AXI-Stream,方便集成到更大的数据通路(如 DMA、网络、存储)。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/20 8:48:45

BepInEx游戏插件框架:从零构建到高级部署的完整指南

BepInEx游戏插件框架&#xff1a;从零构建到高级部署的完整指南 【免费下载链接】BepInEx Unity / XNA game patcher and plugin framework 项目地址: https://gitcode.com/GitHub_Trending/be/BepInEx BepInEx&#xff08;Bepis Injector Extensible&#xff09;是一款…

作者头像 李华
网站建设 2026/5/20 8:47:14

API数据格式认证方式框架及工具:技术代码与实践指南

API安全是数据交互的核心保障。本文聚焦API认证的主流框架与工具&#xff0c;通过技术代码示例解析API Key、JWT令牌和HMAC签名三种核心认证方式&#xff0c;助力开发者快速构建安全可靠的API服务。 一、API Key认证&#xff1a;轻量级身份验证 适用于内部系统或低风险场景&…

作者头像 李华
网站建设 2026/5/20 8:46:15

前端技术查漏补缺

1.html标签1.1img标签显示图片的标签&#xff0c;两个重要属性 src &#xff08;图片的路径&#xff0c;可以写相对路径和绝对路径&#xff09;alt 但图片显示不出来之后&#xff0c;显示的提示信息<!DOCTYPE html> <html lang"en"> <head><met…

作者头像 李华
网站建设 2026/5/20 8:44:09

从Word到LaTeX:探索docx2tex如何实现学术文档的无缝转换

从Word到LaTeX&#xff1a;探索docx2tex如何实现学术文档的无缝转换 【免费下载链接】docx2tex Converts Microsoft Word docx to LaTeX 项目地址: https://gitcode.com/gh_mirrors/do/docx2tex 还在为学术论文的格式转换而头疼吗&#xff1f;每次将精心撰写的Word文档转…

作者头像 李华
网站建设 2026/5/20 8:40:12

从虚拟到现实:用FactoryIO仿真智能仓储,为实体项目避坑的5个关键点

从虚拟到现实&#xff1a;用FactoryIO仿真智能仓储&#xff0c;为实体项目避坑的5个关键点 在工业自动化领域&#xff0c;虚拟仿真已成为项目落地的必经之路。FactoryIO与博图V16的组合&#xff0c;为工程师们提供了一个近乎真实的测试环境&#xff0c;让智能仓储系统的逻辑验证…

作者头像 李华