Verilog 实现 i2c 协议

在时钟(SCL)为高电平的时候,数据总线(SDA)必须保持稳定,所以数据总线(SDA)在时钟(SCL)为低电平的时候才能改变。

在时钟(SCL)为高电平的时候,数据总线(SDA)由高到低的跳变为总线起始信号,在时钟(SCL)为高电平的时候,数据总线(SDA)由低到高的跳变为总线停止信号。

应答,当 IIC 主机(不一定是发送端还是接受端)将 8 位数据或命令传出后,会将数据总线(SDA)释放,即设置为输入,然后等待从机应答(低电平 0 表示应答,1 表示非应答),此时的时钟仍然是主机提供的。

数据帧格式,I2C 器件通讯的时候首先是要发送“起始信号”,紧跟着就是七位器件地址,第八位是数据传送方向位(0:代表写,1:代表读),再后面就是等待从机的应答。当然传送结束后,“终止信号”也是由主机来产生的。发送数据的时候是高位先发送。


module iic #(parameter DIV_CLK = 100,parameter WR_MAX  = 8'd1,parameter RD_MAX  = 8'd1
) (input clk,input rst_n,input enable,output reg busy,input [7:0] rdlen,input [7:0] wrlen,output reg [RD_MAX*8-1:0] rddata,input [WR_MAX*8-1:0] wrdata,output reg isack,output scl,inout  sda
);// -------------------------------------------------------------------------//                           信号分频// -------------------------------------------------------------------------reg [$clog2(DIV_CLK):0] clk_cnt;reg scl_clk;always @(posedge clk or negedge rst_n) beginif (~rst_n) beginclk_cnt <= 16'd0;scl_clk <= 1'd0;end else beginif (clk_cnt == (DIV_CLK >> 1) - 1) beginclk_cnt <= 16'd0;scl_clk = ~scl_clk;end else beginclk_cnt <= clk_cnt + 16'd1;endendendlocalparam  ST_IDLE = 0, ST_START = 1, ST_WR_DATA = 2, ST_WR_READ_ACK = 3, ST_WR_CHECK_ACK = 4, ST_RD_START = 5, ST_RD_DATA = 6, ST_RD_ACK_REPLY = 7, ST_RD_ACK_DONE = 8, ST_STOP = 9;reg [3:0] state = ST_IDLE;assign scl = (state == ST_IDLE || state == ST_START) ? 1 : scl_clk;// SDA 输入输出切换reg sda_r = 1;reg sda_oe = 1;assign sda = sda_oe ? sda_r : 1'bz;// 写入和读取数据时使用的中间变量reg [7:0] byte_no = 0;reg [3:0] bit_no = 0;always @(posedge clk or negedge rst_n) beginif (~rst_n) beginisack <= 0;busy <= 0;rddata <= 0;end else begincase (state)ST_IDLE: beginsda_r <= 1;if (enable) beginbusy <= 1;endif (busy && clk_cnt == DIV_CLK >> 2 && scl_clk == 1) beginstate <= ST_START;endend// 产生开始信号, 即在 scl_clk 为高电平时 sda 由高变低ST_START: beginif (clk_cnt == DIV_CLK >> 2 && scl_clk == 1) beginsda_r <= 0;state <= ST_WR_DATA;byte_no <= wrlen;bit_no <= 4'd0;isack <= 0;endend// 写入数据, wrdata 的最高位字节是器件的 i2c 地址以及读写标志ST_WR_DATA: beginif (clk_cnt == DIV_CLK >> 2 && scl_clk == 0) beginif (bit_no == 4'd8) beginstate   <= ST_WR_READ_ACK;byte_no <= byte_no - 1'b1;bit_no  <= 4'd0;// 这里切换 sda 为读模式以便在下一个 scl_clk 高电平时接收应答sda_oe  <= 0;end else beginbit_no <= bit_no + 1'b1;sda_r  <= wrdata[byte_no*8-1-bit_no-:1];sda_oe <= 1;endendend// scl_clk 为高时读取应答信号ST_WR_READ_ACK: beginif (clk_cnt == DIV_CLK >> 2 && scl_clk == 1) beginif (sda) isack <= 1;state <= ST_WR_CHECK_ACK;endend// scl_clk 为低时检测应答信号并做出状态转移ST_WR_CHECK_ACK: beginif (clk_cnt == DIV_CLK >> 2 && scl_clk == 0) begin// 数据还没写完则继续进入写数据状态if (isack && byte_no != 0) beginstate <= ST_WR_DATA;bit_no <= bit_no + 1'b1;sda_r <= wrdata[byte_no*8-1-bit_no-:1];sda_oe <= 1;isack <= 0;// 否则进入读状态end else if (isack && rdlen > 0) beginstate  <= ST_RD_START;sda_oe <= 1;sda_r  <= 1;// 没有应答或数据写完了且不需要读模式则停止传输end else beginstate  <= ST_STOP;sda_r  <= 0;sda_oe <= 0;endendend// 在 scl_clk 为高时将 sda 输出为低进入读状态ST_RD_START: beginif (clk_cnt == DIV_CLK >> 2 && scl_clk == 1) beginsda_r <= 0;// 同时在 scl_clk 为低时将 sda 切到读模式, 以便下一个 scl_clk 为高时将 sda 读取end else if (clk_cnt == DIV_CLK >> 2 && scl_clk == 0) beginsda_oe  <= 0;state   <= ST_RD_DATA;bit_no  <= 0;byte_no <= rdlen;endend// 在 scl_clk 为高时读取 sda 的数据ST_RD_DATA: beginif (clk_cnt == DIV_CLK >> 2 && scl_clk == 1) beginbit_no <= bit_no + 1'b1;rddata[byte_no*8-1-bit_no-:1] <= sda;if (bit_no == 4'd7) beginstate   <= ST_RD_ACK_REPLY;byte_no <= byte_no - 1'b1;bit_no  <= 4'd0;endendend// 在 scl_clk 为低时读取产生应答信号, 以便在下一个高电平被对方采集到ST_RD_ACK_REPLY: beginif (clk_cnt == DIV_CLK >> 2 && scl_clk == 0) beginsda_oe = 1;sda_r <= 0;state <= ST_RD_ACK_DONE;endend// 经过了一个高电平, 在该低电平处判断数据有没有传完以进行状态转移ST_RD_ACK_DONE: beginif (clk_cnt == DIV_CLK >> 2 && scl_clk == 0) beginif (byte_no == 0) beginsda_oe = 1;state <= ST_STOP;end else beginsda_oe = 0;state <= ST_RD_DATA;endendend// 产生停止信号, 即在 scl_clk 为高电平时将 sda 由低变高ST_STOP: beginif (clk_cnt == DIV_CLK >> 2 && scl_clk == 1) beginsda_oe <= 1;sda_r  <= 1;state  <= ST_IDLE;busy   <= 0;endendendcaseendendendmodule

仿真文件 tb.v

`timescale 1ns / 1nsmodule tb;// -------------------------------------------------------------------------//                    clk and reset signal // -------------------------------------------------------------------------reg clk;reg rst_n;initial clk = 0;always #10 clk = ~clk;initial beginrst_n = 0;#100;rst_n = 1;endinitial begin$dumpvars;#5000000;$finish;endreg enable;wire busy;initial beginenable = 0;@(posedge rst_n);enable = 1;@(negedge busy);enable = 0;#10000;enable = 1;@(negedge busy);enable = 0;#10000;endwire [15:0] rddata;wire isack;iic #(.DIV_CLK(100),.WR_MAX (8'd2),.RD_MAX (8'd2)) u_iic (.clk   (clk),.rst_n (rst_n),.enable(enable),.busy  (busy),.rdlen (8'd2),.wrlen (8'd2),.rddata(rddata),.wrdata(16'hd552),.isack (isack),.scl   (scl),.sda   (sda));endmodule

通常直接使用上面的 testbench 由于没有接实际的设备,没有收到应答后 iic 模块会自动停止传输,并拉低 busy 标志, 同时 isack 也为 0

为了方便查看波形,以下是将 iic.v 的 if (sda) isack <= 1; 改为 if (1) isack <= 1; 即在 读取 ack 信号时, 总是假设能读到

并且 将读信号 rddata[byte_no*8-1-bit_no-:1] <= sda; 总是写读到 1,rddata[byte_no*8-1-bit_no-:1] <= 1; 于是有如下波形

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/13411.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

诸葛智能携手五大银行,以数据驱动的营销中台带来可预见增长

对于银行来说&#xff0c;客户是赖以生存的基础&#xff0c;也是保持活力的关键。尤其是大数据、人工智能等新兴技术的推动下&#xff0c;通过数据赋能产品升级和服务创新&#xff0c;深挖客户潜能&#xff0c;更是助推银行快步迈入高质量发展的新阶段。 在银行加速拥抱新质生…

文档分类DPCNN简介(pytorch实现)

文档分类DPCNN简介 DPCNN简介 模型结构区域嵌入等长卷积1/2池化DPCNN模型代码实现 DPCNN简介 论文中提出了一种基于 word-level 级别的网络-DPCNN&#xff0c;由于 TextCNN 不能通过卷积获得文本的长距离依赖关系&#xff0c;而论文中 DPCNN 通过不断加深网络&#xff0c;可以…

ATA-2021B高压放大器在光纤超声传感器中的应用

实验名称&#xff1a;超声传感性能研究 测试目的&#xff1a; 光纤马赫-曾德尔干涉仪是一种灵敏度高、结构灵活的传感结构。当在MZI上施加超声波信号时&#xff0c;会影响所涉及的干涉光之间的光程差&#xff0c;并导致干涉光谱的漂移。由于模式耦合是基于MZI的光纤传感器的关键…

脑中风也会出现眩晕?快速识别中风,一定要牢记这些!

眩晕是许多人都会经历的不适感&#xff0c;发作时仿佛整个世界都在旋转&#xff0c;可能还伴随着站立不稳、脚步虚浮、恶心等症状。然而&#xff0c;你可能不知道的是&#xff0c;这些症状在某些情况下可能是脑中风的前兆。如果不及时关注并采取相应措施&#xff0c;一旦发展为…

【算法】二分查找——在排序数组中查找元素的第一个和最后一个位置

本节博客主要是通过“在排序数组中查找元素的第一个和最后一个位置”总结关于二分算法的左右界代码模板&#xff0c;有需要借鉴即可。 目录 1.题目2.二分边界算法2.1查找区间左端点2.1.1循环条件2.1.2求中点的操作2.1.3总结 2.2查找区间右端点2.1.1循环条件2.1.2求中点的操作2.…

O2OA平台流程催办怎么做

O2OA平台设计了灵活的消息提醒数据交互方式&#xff0c;开发者可以根据自己的需要&#xff0c;来消费消息提醒数据&#xff0c;也可以将消息提醒数据接入到Kafka消息中间件来实现消息的准实时提醒。本篇主要介绍如何在O2OA服务器中设置流程的催办提醒消息。 催办提醒服务&#…

centos无法联网解决方案(9步完成

1.打开终端&#xff0c;输入 su - root 进入到管理员模式&#xff08;-的前后都有空格哈&#xff09; 切换后&#xff0c;显示的就是root... 2.. &#xff0c;输入命令ip addr 2. 切换当前目录 cd /etc/sysconfig/network-scripts/ 3.输入命令&#xff0c;打开文件 vi /etc…

一.常见算法--动态规划

&#xff08;1&#xff09;0-1背包问题 问题描述&#xff1a; 0-1背包问题的描述&#xff1a;在n种物品中选择1个或0个第i种物品&#xff0c;装入背包容量为m的背包&#xff0c;使得背包价值达到最大。 思路与关键点&#xff1a; 用到了max函数&#xff0c;用于返回两个数之中…

为何Linux成为你不可或缺的技能

在数字化飞速发展的今天&#xff0c;无论你是IT行业的精英&#xff0c;还是其他领域的专业人士&#xff0c;掌握Linux都已经成为一项至关重要的技能。那么&#xff0c;为什么一定要学会Linux呢&#xff1f;以下文章仅供参考 1. 开源的力量&#xff1a;无限的可能性 Linux是一…

工厂自动化升级改造(3)-Modbus与MQTT的转换

什么是MQTT,Modbus,见下面文章 工厂自动化升级改造参考(01)--设备通信协议详解及选型-CSDN博客文章浏览阅读608次,点赞9次,收藏6次。>>特点:基于标准的以太网技术,使用TCP/IP协议栈,支持高速数据传输和局域网内的设备通信。>>>特点:跨平台的通信协议,…

ssl证书价格一年多少钱?如何申请?

由于行业新规&#xff0c;现在阿里云、腾讯云等几乎所有平台都不再提供一年期免费证书&#xff0c;如果需要一年期证书则需要支付一定的费用。SSL证书的价格根据类型不同几十到几百上千不等。 一年期SSL证书申请通道https://www.joyssl.com/?nid16 一年期SSL证书申请流程&am…

人工智能(一)架构

一、引言 人工智能这个词不是很新鲜&#xff0c;早就有开始研究的&#xff0c;各种推荐系统、智能客服都是有一定的智能服务的&#xff0c;但是一直都没有体现出多高的智能性&#xff0c;很多时候更像是‘人工智障’。 但是自从chatGpt3被大范围的营销和使用之后&#xff0c;人…

python常用基础知识

目录 &#xff08;1&#xff09;print函数 &#xff08;2&#xff09;注释 &#xff08;3&#xff09;input函数 &#xff08;4&#xff09;同时赋值和连续赋值 &#xff08;5&#xff09;type函数和id函数 &#xff08;6&#xff09;python赋值是地址赋值 &#xff08;…

Qt编译和使用freetype矢量字库方法

在之前讲过QT中利用freetype提取字库生成图片的方法&#xff1a; #QT利用freetype提取字库图片_qt freetype-CSDN博客文章浏览阅读1.2k次。这是某个项目中要用到的片段&#xff0c;结合上一篇文章#QT从字体名获取字库文件路径使用// 保存位图int SaveBitmapToFile(HBITMAP hBi…

【会议征稿,ACM出版】第四届人工智能,大数据与算法国际学术会议 (CAIBDA 2024, 7/5-7)

由河南省科学院、河南大学主办&#xff0c;河南省科学院智慧创制研究所、河南大学学术发展部、河南大学人工智能学院承办的第四届人工智能&#xff0c;大数据与算法国际学术会议 (CAIBDA 2024)将于2024年7月5-7日于中国郑州隆重举行。CAIBDA 2024致力于为人工智能&#xff0c;大…

碳纳米管须状触嗅觉多模态融合传感器在皮革奢侈品真伪鉴定下的设计探索

一、设计方案 1.传感器选择 触觉传感器&#xff1a;选择基于碳纳米管&#xff08;CNT&#xff09;聚合物的柔性MEMS触觉微传感器&#xff0c;由于碳纳米管具有高度的灵敏度和选择性、柔韧性&#xff0c;可以作为触觉传感器&#xff0c;检测材料的微观结构和机械特性。嗅觉传感…

网页打开:为什么国内用新标签页,国外用当前页?

想写这个话题很久了&#xff0c;因为用百度和Google搜索时&#xff0c;打开搜索结果链接时的交互差异&#xff0c;几乎每天都要提醍我一下。 网页打开——这个交互&#xff0c;在设计里&#xff0c;算是极微小&#xff0c;但影响极广泛的操作设计。甚至&#xff0c;因此形成了…

【Python】图形用户界面设计

1、设计并编写一个窗口程序,该窗口只有一个按钮,当用户单击时可在后台输出hello world. import tkinter as tk def on_button_click():print("hello world") # 创建主窗口 root tk.Tk() root.title("Hello World Button") # 设置窗口大小 root.geometry…

代码随想录-算法训练营day41【动态规划04:01背包问题-滚动数组、分割等和子集】

代码随想录-035期-算法训练营【博客笔记汇总表】-CSDN博客 第九章 动态规划part04● 01背包问题,你该了解这些! ● 01背包问题,你该了解这些! 滚动数组 ● 416. 分割等和子集 正式开始背包问题,背包问题还是挺难的,虽然大家可能看了很多背包问题模板代码,感觉挺简单,…

SAP_SNOTE_补丁修复_全流程实战

SAP ABAP 顾问&#xff08;开发工程师&#xff09;能力模型-CSDN博客文章浏览阅读1.2k次。目标&#xff1a;基于对SAP abap 顾问能力模型的梳理&#xff0c;给一年左右经验的abaper 快速成长为三年经验提供超级燃料&#xff01;https://blog.csdn.net/java_zhong1990/article/d…