当前位置: 首页 > news >正文

数字IC前端学习笔记:FIFO的Verilog实现(二)

 相关文章

数字IC前端学习笔记:LSFR(线性反馈移位寄存器)

数字IC前端学习笔记:跨时钟域信号同步

数字IC前端学习笔记:信号同步和边沿检测

数字IC前端学习笔记:锁存器Latch的综合

数字IC前端学习笔记:格雷码(含Verilog实现的二进制格雷码转换器)

数字IC前端学习笔记:FIFO的Verilog实现(一)


目录

4.异步FIFO原理

5.异步FIFO的Verilog实现


4.异步FIFO原理

        在之前,我们讨论了了同步FIFO,因为其具有单一的时钟,因此应用范围有限。在实际的引用中,我们经常遇到多个时钟域的情况,此时数据需要在两个时钟域之间实现传送,并且不能出现毛刺和亚稳态。我们以PCIe插槽上的以太网适配器板卡为例加以说明。该板卡从局域网(LAN)或以太网接收数据包,然后将数据传送给系统存储器。反过来,它从系统存储器接受数据包,然后传送给网络。板卡的一侧和网络通信,用以太网本地处理相关操作。板卡的另一侧与PCEe接口交互,以板卡自身的时钟工作。这两个时钟不仅频率不同,而且是异步的(频率不是倍数关系,如果石是倍数关系,可以认为这是同步时钟,因为相位差恒定)。此时需要使用异步FIFO将数据从一个时钟域传送到另一个时钟域。

        尽管异步FIFO的操作原理与同步FIFO类似,但由于前者与两个时钟有关,电路的复杂度也会增加。对异步FIFO进行数据写入和读出操作的方式与同步FIFO极其相似,写入与读出操作也有自己的信号集,其复杂度主要体现于产生FIFO_full、FIFO_empty、room_avaliable、data_avaliable等标识。异步FIFO中产生这些标识的方法比同步FIFO中要复杂得多。

        在这里我们不能使用计数器根据读取或存储信号保存FIFO中的数据量,因为他们是两个时钟域的信号,不能用两个时钟对同一个reg赋值。我们知道,当FIFO为满或空时,写入指针和读取指针是相等的。但这是不够的,我们需要另外的条件将“空”和“满”进行区分。前面介绍过,FIFO工作时,写入指针在前,读出指针跟随写入指针。当FIFO为满时,写入指针的状态是到达顶部后返回底部最后和读取指针相同,即超越读取指针一轮(FIFO深度),如果我们在指针最高位增加一个辅助位给写入和读取指针,则可以用来指示当这两个指针相同(不包括辅助位)时,是没有超越的相同,还是超越一轮的相同。

        我们以一个深度为4的FIFO为例说明。此时,计数器需要两位表示,计数序列为00→01

10→11→00,在最高位增加一位辅助位后,计数序列为000→001→010→011→100→101→110

→111。正如我们所看到的,除了最高位(辅助位),其他位将循环两次,通过比较辅助位,我们就可以判断FIFO状态是满还是空。

        虽然解决了空满状态的标识,但仍然存在问题,即读指针和写指针分别产生于各自时钟域,不能互相比较,否则会因时序问题产生亚稳态。解决这个问题的办法是将指针从一个时钟域传递到另一个时钟域,然后做比较。而且我们要注意,传递的是多位信号而不是一位信号,此时需要使用格雷码编码和译码电路将指针进行跨时钟域安全传送。在格雷码编码方案中,相邻编码中只有一位发生变化,该特性被用于跨时钟域矢量传递(还有其他方法,可见数字IC前端学习笔记:跨时钟域信号同步一文)。我们将所有这些零散的知识放在一个图中以便于浏览和理解具体的操作方法,如下图所示。

        写指针被转换为格雷码编码,并经过触发器保存,然后经过两级寄存器同步到读时钟域并解码为二进制编码,最后与读指针比教产生fifo_empty信号。读指针的行为类似,在写时钟域产生fifo_full信号。

        需要注意的是,当读指针被传送到写入时钟域时,相对于读时钟域的读指针来说,可能会存在3到4个周期的延时,也就是说,可能出现读指针已经增加,而在写时钟域看来并未增加,这会导致fifo在仍有空位时给出fifo_full信号,这是异步FIFO保守的一面,如此可以确保不产生数据上溢。

写指针也有类似问题,会出现FIFO仍有数据而FIFO给出fifo_empty信号的情况。这些不会影响FIFO的正确操作,在停止写入和读出后几个周期时,就可以给出正确的fifo_emty和fifo_full信号。

5.异步FIFO的Verilog实现

module asynch_fifo #(parameter FIFO_PTR=4,FIFO_WIDTH=32)(wrclk, rstb_wrclk,write_en, write_data,snapshot_wrptr, rollback_wrptr,reset_wrptr,rdclk, rstb_rdclk,read_en, read_data,snapshot_rdptr, rollback_rdptr,reset_rdptr,fifo_full, fifo_empty,room_avail, data_avail);input wrclk;input rstb_wrclk;input write_en;input [FIFO_WIDTH-1:0] write_data;input snapshot_wrptr; //记录写指针快照input rollback_wrptr; //恢复写指针快照input reset_wrptr; //写指针重置为0input rdclk;input rstb_rdclk;input read_en;output [FIFO_WIDTH-1:0] read_data;input snapshot_rdptr; //记录读指针快照input rollback_rdptr; //恢复读指针快照input reset_rdptr; //读指针重置为0output reg fifo_full, fifo_empty;output reg [FIFO_PTR:0] room_avail, data_avail;localparam FIFO_DEPTH = 1 << FIFO_PTR //2^FIFO_PTRlocalparam FIFO_TWICEDEPTH_MINUS1 = 2*FIFO_DEPTH - 1reg [FIFO_PTR:0] wr_ptr_wab, wr_ptr_wab_nxt;//有辅助位的写指针wire [FIFO_PTR:0] room_avail_nxt, data_avail_nxt; reg [FIFO_PTR:0] wr_ptr_snapshot_value;wire [FIFO_PTR:0] wr_ptr_snapshot_value_nxt;wire fifo_full_nxt, fifo_empty_nxt;reg [FIFO_PTR:0] rd_ptr_snapshot_value;wire [FIFO_PTR:0] rd_ptr_snapshot_value_nxt;       wire [FIFO_PTR-1:0] wr_ptr,rd_ptr;reg [FIFO_PTR:0] rd_ptr_wab, rd_ptr_wab_nxt;//有辅助位的读指针      //写指针控制逻辑  //*********************************************always@(*) beginwr_ptr_wab_nxt=wr_ptr_wab;if(reset_wrptr)wr_ptr_wab_nxt = 0;else if(rollback_wrptr)wr_ptr_wab_nxt = wr_ptr_snapshot_value;else if(write_en && (wr_ptr_wab == FIFO_TWICEDEPTH_MINUS1))wr_ptr_wab_nxt = 0;else if(write_en)wr_ptr_wab_nxt = wr_ptr_wab + 1;end//写指针快照//*********************************************assign wr_ptr_snapshot_value_nxt = snapshot_wrptr ? wr_ptr_wab : wr_ptr_snapshot_value;//寄存器操作//*********************************************always@(posedge wrclk or negedge rstb_wrclk) beginif(!rstb_wrclk)beginwr_ptr_wab <= 0;wr_ptr_snapshot_value <= 0;end    else beginwr_ptr_wab <= wr_ptr_wab_nxt;wr_ptr_snapshot_value <= wr_ptr_snapshot_value_nxt;endend//写指针二进制转格雷码//*********************************************reg [FIFO_PTR:0] wr_ptr_wab_gray;wire [FIFO_PTR:0] wr_ptr_wab_gray_nxt;//实例化转码模块(在之前的文章中已设计)binary_to_gray #(.PTR(FIFO_PTR)) binary_to_gray_wr(.binary (wr_ptr_wab_nxt),.gray_value (wr_ptr_wab_gray_nxt));always@(posedge wrclk or negedge rstb_wrclk)beginif(!rst_wrclk)wr_ptr_wab_gray <= 0;else wr_ptr_wab_gray <= wr_ptr_wab_gray_nxt;end//写指针同步到读时钟域//*********************************************reg [FIFO_PTR:0] wr_ptr_wab_gray_sync1;reg [FIFO_PTR:0] wr_ptr_wab_gray_sync2;always@(posedge rdclk or negedge rstb_rdclk) beginif(!rstb_rdclk) beginwr_ptr_wab_gray_sync1 <= 0;wr_ptr_wab_gray_sync2 <= 0;elsewr_ptr_wab_gray_sync1 <= wr_ptr_wab_gray;wr_ptr_wab_gray_sync2 <= wr_ptr_wab_gray_sync1;endend//格雷码写指针转二进制//*********************************************reg [FIFO_PTR:0] wr_ptr_wab_rdclk;wire [FIFO_PTR:0] wr_ptr_wab_rdclk_nxt;gray_to_binary #(.PTR(FIFO_PTR)) gray_to_binary_wr(.gray_value(wr_ptr_wab_gray_sync2),.binary(wr_ptr_wab_rdclk_nxt));always@(posedge rdclk or negedge rstb_rdclk) beginif(!rstb_rdclk) beginwr_ptr_wab_rdclk <= 0;elsewr_ptr_wab_rdclk <= wr_ptr_wab_rdclk_nxt;endend//读指针控制逻辑  //*********************************************always@(*) beginrd_ptr_wab_nxt=rd_ptr_wab;if(reset_rdptr)rd_ptr_wab_nxt = 0;else if(rollback_rdptr)rd_ptr_wab_nxt = rd_ptr_snapshot_value;else if(read_en && (rd_ptr_wab == FIFO_TWICEDEPTH_MINUS1))rd_ptr_wab_nxt = 0;else if(read_en)rd_ptr_wab_nxt = rd_ptr_wab + 1;end//读指针快照//*********************************************assign rd_ptr_snapshot_value_nxt = snapshot_rdptr ? rd_ptr_wab : rd_ptr_snapshot_value;//寄存器操作//*********************************************always@(posedge rdclk or negedge rstb_rdclk) beginif(!rstb_rdclk)beginrd_ptr_wab <= 0;rd_ptr_snapshot_value <= 0;end    else beginrd_ptr_wab <= rd_ptr_wab_nxt;rd_ptr_snapshot_value <= rd_ptr_snapshot_value_nxt;endend/读指针二进制转格雷码//*********************************************reg [FIFO_PTR:0] rd_ptr_wab_gray;wire [FIFO_PTR:0] rd_ptr_wab_gray_nxt;//实例化转码模块(在之前的文章中已设计)binary_to_gray #(.PTR(FIFO_PTR)) binary_to_gray_rd(.binary (rd_ptr_wab_nxt),.gray_value (rd_ptr_wab_gray_nxt));always@(posedge rdclk or negedge rstb_rdclk)beginif(!rst_rdclk)rd_ptr_wab_gray <= 0;else rd_ptr_wab_gray <= rd_ptr_wab_gray_nxt;end//读指针同步到写时钟域//*********************************************reg [FIFO_PTR:0] rd_ptr_wab_gray_sync1;reg [FIFO_PTR:0] rd_ptr_wab_gray_sync2;always@(posedge wrclk or negedge rstb_wrclk) beginif(!rstb_wrclk) beginrd_ptr_wab_gray_sync1 <= 0;rd_ptr_wab_gray_sync2 <= 0;elserd_ptr_wab_gray_sync1 <= rd_ptr_wab_gray;rd_ptr_wab_gray_sync2 <= rd_ptr_wab_gray_sync1;endend//格雷码读指针转二进制//*********************************************reg [FIFO_PTR:0] rd_ptr_wab_rdclk;wire [FIFO_PTR:0] rd_ptr_wab_rdclk_nxt;gray_to_binary #(.PTR(FIFO_PTR)) gray_to_binary_rd(.gray_value(rd_ptr_wab_gray_sync2),.binary(rd_ptr_wab_rdclk_nxt));always@(posedge wrclk or negedge rstb_wrclk) beginif(!rstb_wrclk) rd_ptr_wab_rdclk <= 0;elserd_ptr_wab_rdclk <= rd_ptr_wab_wrclk_nxt;endassign wr_ptr = wr_ptr_wab[FIFO_PTR-1:0];assign rd_ptr = rd_ptr_wab[FIFO_PTR-1:0];//SRAM 存储器实例化//*********************************************sram #(.FIFO_PTR(FIFO_PTR),.FIFO_WIDTH(FIFO_WIDTH)) sram_0(.wrclk(wrclk),.wren(write_en),.wrptr(wr_ptr),.wrdata(write_data),.rdclk(rdclk),.rden(read_en),.rdptr(rd_ptr),.rddata(read_data));//fifo_full和room_avail信号产生//*********************************************assign fifo_full_nxt = (wr_ptr_wab_nxt[FIFO_PTR] != rd_ptr_wab_wrclk_nxt[FIFO_PTR])&&(wr_ptr_wab_nxt[FIFO_PTR-1:0] == rd_ptr_wab_wrclk_nxt[FIFO_PTR-1:0]);assign room_avail_nxt = (wr_ptr_wab_nxt[FIFO_PTR] == rd_ptr_wab_wrclk_nxt[FIFO_PTR])?(FIFO_DEPTH-(wr_ptr_wab_nxt[FIFO_PTR-1:0] - rd_ptr_wab_wrclk_nxt[FIFO_PTR-1:0])):(rd_ptr_wab_wrclk_nxt[FIFO_PTR-1:0] - wr_ptr_wab_nxt[FIFO_PTR-1:0]);  always@(posedge wrclk or negedge rstb_wrclk) beginif(!rstb_wrclk) beginfifo_full <= 0;room_avail <= 0;end        else beginfifo_full <= fifo_full_nxt;room_avail <= room_avail_nxt;endend //如果两者没有差一轮,则指针相减代表着FIFO内数据量,用深度减去数据量则为剩余空间,否则直接相减(不包括辅助位)就可得到剩余空间//fifo_empty和room_empty信号产生//*********************************************assign fifo_empty_nxt = (rd_ptr_wab_nxt[FIFO_PTR] != wr_ptr_wab_rdclk_nxt[FIFO_PTR])&&(rd_ptr_wab_nxt[FIFO_PTR-1:0] == wr_ptr_wab_dclk_nxt[FIFO_PTR-1:0]);assign data_avail_nxt = (rd_ptr_wab_nxt[FIFO_PTR] == wr_ptr_wab_rdclk_nxt[FIFO_PTR])?(FIFO_DEPTH-(rd_ptr_wab_nxt[FIFO_PTR-1:0] - wr_ptr_wab_rdclk_nxt[FIFO_PTR-1:0])):(wr_ptr_wab_rdclk_nxt[FIFO_PTR-1:0] - rd_ptr_wab_nxt[FIFO_PTR-1:0]);   always@(posedge rdclk or negedge rstb_rdclk) beginif(!rstb_rdclk) beginfifo_empty <= 0;data_avail <= 0;end        else beginfifo_empty <= fifo_empty_nxt;data_avail <= data_avail_nxt;endend 
endmodule

以上内容来源于《Verilog高级数字系统设计技术和实例分析》

相关文章:

数字IC前端学习笔记:FIFO的Verilog实现(二)

相关文章 数字IC前端学习笔记&#xff1a;LSFR&#xff08;线性反馈移位寄存器&#xff09; 数字IC前端学习笔记&#xff1a;跨时钟域信号同步 数字IC前端学习笔记&#xff1a;信号同步和边沿检测 数字IC前端学习笔记&#xff1a;锁存器Latch的综合 数字IC前端学习笔记&am…...

2.2 搭建Spark开发环境

一、Spark开发环境准备工作 由于Spark仅仅是一种计算框架&#xff0c;不负责数据的存储和管理&#xff0c;因此&#xff0c;通常都会将Spark和Hadoop进行统一部署&#xff0c;由Hadoop中的HDFS、HBase等组件负责数据的存储管理&#xff0c;Spark负责数据计算。 安装Spark集群前…...

webpack指定输出资源的路径和名称

如图&#xff0c;在前面的章节我们打包后的文件默认都输出到了dist目录下&#xff0c;无论是图片、还是js都在同一级别目录&#xff0c;这里目前处理的资源比较少&#xff0c;如果资源一多&#xff0c;所有的资源都在同一级目录&#xff0c;看起来很费劲。 那么这节就介绍一下…...

Spring事务四

spring 事务的隔离级别 当多个事务同时访问数据库中的同一数据时&#xff0c;可能会出现数据不一致的情况&#xff0c;为了避免这种情况发生&#xff0c;就需要使用事务隔离机制。Spring框架中定义了5种事务隔离级别&#xff0c;分别为&#xff1a; DEFAULT&#xff08;默认隔…...

项目管理专业人员能力评价等级证书(CSPM)的级别介绍

2021年10月&#xff0c;中共中央、国务院发布的《国家标准化发展纲要》明确提出构建多层次从业人员培养培训体系&#xff0c;开展专业人才培养培训和国家质量基础设施综合教育。建立健全人才的职业能力评价和激励机制。由中国标准化协会&#xff08;CAS&#xff09;组织开展的项…...

设计模式-创建型模式(单例、工厂、建造、原型)

Concept-概念前置 设计模式&#xff1a;软件设计中普遍存在&#xff08;反复出现&#xff09;的各种问题&#xff0c;所提出的解决方案。 面向对象三大特性&#xff1a;封装、继承、多态。 面向对象设计的SOLID原则&#xff1a; &#xff08;1&#xff09;开放封闭原则&#…...

用饭店来形象比喻线程池的工作原理

一、线程池解决的问题&#xff1f; 使用线程池主要解决在程序中频繁创建和销毁线程导致的资源浪费&#xff0c;线程池可以维护一定量的线程来执行所需要的任务&#xff0c;维护的线程也可以重复使用。 二、用形象的饭店来解释工作原理 线程池就相当于一家饭店&#xff0c; 任…...

GO学习笔记之表达式

GO学习笔记之表达式 保留字运算符优先级二元运算符位运算符自增指针 保留字 Go语言仅25个保留关键字&#xff08;keyword&#xff09;&#xff0c;这是最常见的宣传语&#xff0c;虽不是主流语言中最少的&#xff0c;但也确实体现了Go语法规则的简洁性。保留关键字不能用作常量…...

005Mybatis返回值(ResultMap 一对多,多对多)

属性 id 应该总是指定一个或多个可以唯一标识结果的属性。 虽然&#xff0c;即使不指定这个属性&#xff0c;MyBatis 仍然可以工作&#xff0c;但是会产生严重的性能问题。 只需要指定可以唯一标识结果的最少属性。显然&#xff0c;你可以选择主键&#xff08;复合主键也可以…...

把玩数据在内存中的存储

前言&#xff1a;时光如梭&#x1f4a6;&#xff0c;今天到了C语言进阶啦&#x1f60e;&#xff0c;基础知识我们已经有了初步认识&#xff0c; 是时候该拔高拔高自己了&#x1f63c;。 目标&#xff1a;掌握浮点数在内存的存储&#xff0c;整形在内存的存储。 鸡汤&#xff1a…...

Nginx运行原理与基本配置文件讲解

文章目录 Nginx基本运行原理Nginx的基本配置文件serverlocationroot 与 alias 的区别server 和 location 中的 rootnginx欢迎页 本文参考文章Nginx相关文章 Nginx基本运行原理 Nginx的进程是使用经典的「Master-Worker」模型,Nginx在启动后&#xff0c;会有一个master进程和多个…...

openGauss5 企业版之SQL语法和数据结构

文章目录 1.openGauss SQL 语法2. 数据类型2.1数值类型2.2 布尔类型2.3 字符类型2.4 二进制类型2.5日期/时间类型2.6 几何类型2.7 网络地址类型2.8 位串类型2.9 文本搜索类型2.10 UUID数据类型2.11 JSON/JSONB类型2.11 HLL数据类型2.12 范围类型2.13 索引2.14 对象标识符类型2.…...

TClientDataSet 模拟 EXCEL表

日常处理数据时&#xff0c;经常需要&#xff0c;从EXCEL表格中&#xff0c;批量导入数据&#xff0c;通过 XLSReadWriteII编程&#xff0c;会很快导入。 但是&#xff0c;客户提供的EXCEL表的字段&#xff0c;数据格式&#xff0c;字段的排序&#xff0c;有很大的区别。因此&a…...

Hazel游戏引擎(012)GLFW窗口事件

文中若有代码、术语等错误&#xff0c;欢迎指正 文章目录 前言如何确定GLFW窗口事件的回调函数参数Application接收事件回调流程原项目流程(12345)自己写的简单Demo与流程(123) 前言 此节目的 为了完成008计划窗口事件的接收glfw窗口事件以及回调部分 此节要完成 使用glfw函数…...

Nenu算法复习第六章

目录 补充知识点 1160: 6001 第几天&#xff1f; 1161: 6002 时间格式转换 1162: 6003 星期几&#xff1f; 1163: 6004 18岁生日、 补充知识点 闰年的判断方法&#xff1a; 能被四整除但是不能一百整除或者能被400整除 例题: 题目描述 经常会有人问你怎么判断闰年&…...

知识付费社群:最好的知识传播方式

知识付费是一种网络内容付费方式&#xff0c;它让知识传播者通过网络以付费的方式向社会大众或特定平台传递知识、技能和智力资源。 知识付费传播的成功离不开用户&#xff0c;他们是核心节点&#xff0c;也是受众和粉丝的重要组成部分。用户不仅可以生产和传播知识&#xff0…...

局域网内不同网段的设备互相连接设置

目录 介绍1、打开网络连接&#xff0c;找到本地网络->属性->ipv4->属性->高级&#xff1a;2、在高级设置页面&#xff0c;我们添加一个IP&#xff0c;这个IP和板子在一个网段&#xff0c;我这里设置的是192.168.253.101&#xff1a;3、设置完成即可生效&#xff0c…...

LVS+Keepalived 群集

目录 一、keepalived概述 1.keepalived工作原理 2.keepalived体系主要模块及其作用 3.判断服务器主备&#xff0c;及如何配置浮动IP 二、keepalived的抢占与非抢占模式 三、部署LVSkeepalived 1.配置负载调度器&#xff08;主备相同&#xff09; 1.1配置keepalived&…...

windows系统cmd命令设置别名,并添加到环境变量

众所周知&#xff0c;Linux 命令很强大&#xff0c;使用起来也很方便&#xff0c;但是想在 windows 系统上使用 Linux 命令有些困难&#xff0c;要么下载第三方终端工具&#xff0c;要么就是安装一系列命令环境。 作为一个前端开发&#xff0c;其实可以全局安装一下 npm 命令行…...

智能学习 | MATLAB实现GWO-SVM多输入单输出回归预测(灰狼算法优化支持向量机)

智能学习 | MATLAB实现GWO-SVM多输入单输出回归预测(灰狼算法优化支持向量机) 目录 智能学习 | MATLAB实现GWO-SVM多输入单输出回归预测(灰狼算法优化支持向量机)预测效果基本介绍模型原理程序设计参考资料预测效果 基本介绍 Matlab实现GWO-SVM灰狼算法优化支持向量机的多输…...

PCD8544 LCD驱动库:嵌入式低功耗显示的底层实现与硬件适配

1. PCD8544 LCD驱动库深度解析&#xff1a;面向嵌入式工程师的底层实现与工程实践1.1 库定位与核心设计哲学PCD8544 是一款专为 Philips PCD8544 及其兼容控制器&#xff08;如 PCF8833、Nokia 3310/5110 显示模组&#xff09;设计的轻量级单色 LCD 驱动库。其本质并非通用图形…...

告别版本冲突:在Rstudio中无缝集成Conda管理的R环境

1. 为什么需要Conda管理R环境&#xff1f; 做过数据分析的朋友应该都遇到过这样的场景&#xff1a;手头同时跑着三个项目&#xff0c;一个要用最新的R 4.3.1跑机器学习模型&#xff0c;另一个老项目必须用R 3.6.3才能兼容某些祖传代码&#xff0c;第三个项目又需要特定版本的gg…...

Materials Project API终极指南:解锁材料科学数据宝库

Materials Project API终极指南&#xff1a;解锁材料科学数据宝库 【免费下载链接】mapidoc Public repo for Materials API documentation 项目地址: https://gitcode.com/gh_mirrors/ma/mapidoc 你是否曾经为寻找特定材料的晶体结构数据而烦恼&#xff1f;或者需要批量…...

嵌入式C全局变量工程化约束与替代方案

1. 嵌入式C开发中全局变量的工程化约束原则在资源受限的单片机无操作系统&#xff08;OS-less&#xff09;环境中&#xff0c;全局变量的滥用已成为系统性缺陷的首要技术诱因。本文不讨论语法层面的“能否使用”&#xff0c;而是从硬件资源约束、软件可维护性、实时性保障三个维…...

RK3566 SPI设备节点实战:从内核配置到用户空间spidev3.0测试

1. RK3566 SPI开发基础与实战意义 SPI总线作为嵌入式系统中最常用的通信协议之一&#xff0c;在RK3566这类高性能处理器上的应用尤为广泛。我最近在立创泰山派开发板上折腾SPI设备时&#xff0c;发现很多新手都会卡在内核配置和用户空间测试的衔接环节。这篇文章就来手把手带你…...

CYBER-VISION零号协议快速入门:Ubuntu 20.04系统下的环境部署详解

CYBER-VISION零号协议快速入门&#xff1a;Ubuntu 20.04系统下的环境部署详解 最近有不少朋友在问&#xff0c;怎么在Ubuntu系统上快速把CYBER-VISION零号协议跑起来。这个开源模型在视觉理解方面表现挺不错的&#xff0c;但第一次部署可能会遇到些小麻烦&#xff0c;比如驱动…...

李慕婉-仙逆-造相Z-Turbo 黑马点评项目AI升级实战:智能推荐与评论情感分析

李慕婉-仙逆-造相Z-Turbo 黑马点评项目AI升级实战&#xff1a;智能推荐与评论情感分析 不知道你有没有遇到过这种情况&#xff1a;打开一个点评类应用&#xff0c;首页推荐的店铺好像总是那么几家&#xff0c;推荐的“理由”也千篇一律&#xff0c;写着“人气爆棚”、“口味正…...

手把手解决OpenWRT编译中的6大经典错误:从freadahead异常到mkfs.jffs2问题

OpenWRT编译实战&#xff1a;6大经典错误分析与解决方案精要 1. 编译环境准备与常见陷阱 在Ubuntu 22.04环境下编译OpenWRT时&#xff0c;系统工具链的版本兼容性是首要考虑因素。许多开发者容易忽视宿主环境与目标平台的差异&#xff0c;导致后续出现各种编译异常。以下是关键…...

AI优化效果不可控?矩阵跃动龙虾机器人,数据驱动排名稳定提升

在当下AI技术全面渗透业务优化、智能运维、流量运营等领域的背景下&#xff0c;越来越多开发者和企业团队陷入了一个共性困境&#xff1a;AI模型优化效果飘忽不定&#xff0c;排名波动剧烈、结果不可复现、异常波动无预警&#xff0c;看似高效的AI自动化优化&#xff0c;反而成…...

zgovps美国CMIN2网络VPS实测:三网直连速度到底有多快?

zgovps美国CMIN2网络VPS三网实测&#xff1a;速度与稳定性的深度剖析 作为一名长期关注跨境网络性能的技术顾问&#xff0c;我最近对zgovps新推出的CMIN2网络VPS进行了为期两周的实测。这款主打三网直连的美国洛杉矶节点服务&#xff0c;究竟能否满足高要求的跨境业务需求&…...