I2C E2PROM通信
这个程序写了一天,大概10个小时吧
首先:最重要的就是理解I2C的通讯协议,这点非常重要
I2C:有两个引脚:SCL(时钟) SDA(数据)
下面是我自己画的I2C的协议,
我还是讲讲如何写FPGA的代码吧
SCL时钟频率我设置为:250K
我们还需要一个时钟:CLOCK为:250K*4=1M ,这个时钟可以通过系统分频产生
写E2PROM的过程:
读E2PROM的过程:
我们需要注意的是SDA是个inout的信号,在从机应答的周期里,记得要提前切换sda的输出方向。
写程序的时候,一定要看时序图。看着时序图写。稳住。
module e2prom(input clk , input rst_n, output [1:0] led, output scl, //时钟线,作为输出,驱动恶e2prom芯片工作inout sda, // 数据线output [5:0] seg_sel, // 数码管位选信号output [7:0] seg_led // 数码管段选信号);wire clk_div;
wire read_en;
wire read_done;
wire [7:0] read_data;
wire [15:0] read_address;
wire write_en;
wire write_done;
wire [7:0] write_data;
wire [15:0] write_address;//数码管动态显示模块
seg_num seg_num_inst(.clk (clk ), // 时钟信号.rst_n (rst_n), // 复位信号.seg_sel (seg_sel ), // 位选.segment (seg_led ), // 段选.data (read_data) // 显示的数值
);//读写E2PROM中的地址
rw_e2prom rw_e2prom_inst(.clk (clk_div), // 时钟信号1M.rst_n (rst_n), // 复位信号.read_en (read_en),.read_done (read_done),.read_data (read_data),.read_address (read_address),.write_en (write_en),.write_done (write_done),.write_data (write_data),.write_address (write_address));//E2PROM I2C驱动代码
e2prom_dri e2prom_dri_inst( .clk (clk), .rst_n (rst_n), .led (led),.scl_clk (scl), .sda (sda), .read_en (read_en),.read_done (read_done),.read_data (read_data),.read_address (read_address),.write_en (write_en),.write_done (write_done),.write_data (write_data),.write_address (write_address),.clk_div (clk_div)
);
endmodule///
module e2prom_dri(input clk , //50Minput rst_n , output reg [1:0] led, //测试用的ledoutput reg scl_clk, //II2C时钟驱动,inout sda , //数据线input read_en, //读使能output reg read_done, //读完成,一个脉冲信号output reg [7:0] read_data, //读出来的数据input [15:0] read_address,//读的地址input write_en, //写使能output reg write_done, //写完成,一个脉冲信号input [7:0] write_data, //写入的数据input [15:0] write_address, //要写的地址output reg clk_div //1M时钟信号
);parameter ADDRESS = 8'b1010_0000; //器件地址(7位)+写(0)reg start_flag;
reg start_flag2;
reg sda_dir ; // I2C数据(SDA)方向控制
reg sda_out ; // SDA输出信号
wire sda_in ; // SDA输入信号
reg [4:0] cnt0;
wire add_cnt0;
wire end_cnt0;reg [7:0] cnt1;
wire add_cnt1;
wire end_cnt1;reg [7:0] cnt2;
wire add_cnt2;
wire end_cnt2;//t=20ns
//1us=50*20ns; cnt=50/2
always @(posedge clk or negedge rst_n)beginif(!rst_n)begincnt0 <= 0;endelse if(add_cnt0)beginif(end_cnt0)cnt0 <= 0;elsecnt0 <= cnt0 + 1;end
end
assign add_cnt0 = 1;
assign end_cnt0 = add_cnt0 && cnt0== 25-1;//产生1M的信号,周期为1us
always @(posedge clk or negedge rst_n)beginif(rst_n==1'b0)beginclk_div<=1'b0;endelse if(end_cnt0) beginclk_div<=~clk_div;end
end//写数据
always @(posedge clk_div or negedge rst_n)beginif(!rst_n)begincnt1 <= 0;endelse if(add_cnt1)beginif(end_cnt1)cnt1 <= 0;elsecnt1 <= cnt1 + 1;end
endassign add_cnt1 = start_flag;
assign end_cnt1 = add_cnt1 && cnt1==153-1; //读数据
always @(posedge clk_div or negedge rst_n)beginif(!rst_n)begincnt2 <= 0;endelse if(add_cnt2)beginif(end_cnt2)cnt2 <= 0;elsecnt2 <= cnt2 + 1;end
endassign add_cnt2 = start_flag2;
assign end_cnt2 = add_cnt2 && cnt2== 194-1; assign sda = sda_dir ? sda_out : 1'bz; // SDA数据输出或高阻
assign sda_in = sda ; // SDA数据输入always @(posedge clk_div or negedge rst_n)beginif(rst_n==1'b0)beginscl_clk<=1;sda_dir<=1; //刚开始设置为输出sda_out<=1;read_data<=0;endelse if(start_flag)begin //写数据case(cnt1) 8'd1:scl_clk<=1; 8'd2:sda_out<=1;8'd3:sda_out<=0; 8'd4:scl_clk<=0;8'd5:sda_out<=ADDRESS[7]; //器件地址8'd6:scl_clk<=1;8'd8:scl_clk<=0;8'd9:sda_out<=ADDRESS[6];8'd10:scl_clk<=1;8'd12:scl_clk<=0;8'd13:sda_out<=ADDRESS[5];8'd14:scl_clk<=1;8'd16:scl_clk<=0;8'd17:sda_out<=ADDRESS[4];8'd18:scl_clk<=1;8'd20:scl_clk<=0;8'd21:sda_out<=ADDRESS[3];8'd22:scl_clk<=1;8'd24:scl_clk<=0;8'd25:sda_out<=ADDRESS[2];8'd26:scl_clk<=1;8'd28:scl_clk<=0;8'd29:sda_out<=ADDRESS[1];8'd30:scl_clk<=1;8'd32:scl_clk<=0;8'd33:sda_out<=ADDRESS[0];8'd34:scl_clk<=1;8'd36:begin scl_clk<=0; sda_dir<=0;end //应答信号8'd38:scl_clk<=1;8'd40:begin scl_clk<=0; sda_dir<=1;end8'd41:sda_out<=write_address[15]; //数据地址8'd42:scl_clk<=1;8'd44:scl_clk<=0;8'd45:sda_out<=write_address[14];8'd46:scl_clk<=1;8'd48:scl_clk<=0;8'd49:sda_out<=write_address[13];8'd50:scl_clk<=1;8'd52:scl_clk<=0;8'd53:sda_out<=write_address[12];8'd54:scl_clk<=1;8'd56:scl_clk<=0;8'd57:sda_out<=write_address[11];8'd58:scl_clk<=1;8'd60:scl_clk<=0;8'd61:sda_out<=write_address[10];8'd62:scl_clk<=1;8'd64:scl_clk<=0;8'd65:sda_out<=write_address[9];8'd66:scl_clk<=1;8'd68:scl_clk<=0;8'd69:sda_out<=write_address[8];8'd70:scl_clk<=1;8'd72:begin scl_clk<=0; sda_dir<=0;end //应答信号 8'd74:scl_clk<=1;8'd76:begin scl_clk<=0; sda_dir<=1;end 8'd77:sda_out<=write_address[7]; //数据地址8'd78:scl_clk<=1;8'd80:scl_clk<=0;8'd81:sda_out<=write_address[6];8'd82:scl_clk<=1;8'd84:scl_clk<=0;8'd85:sda_out<=write_address[5];8'd86:scl_clk<=1;8'd88:scl_clk<=0;8'd89:sda_out<=write_address[4];8'd90:scl_clk<=1;8'd92:scl_clk<=0;8'd93:sda_out<=write_address[3];8'd94:scl_clk<=1;8'd96:scl_clk<=0;8'd97:sda_out<=write_address[2];8'd98:scl_clk<=1;8'd100:scl_clk<=0;8'd101:sda_out<=write_address[1];8'd102:scl_clk<=1;8'd104:scl_clk<=0;8'd105:sda_out<=write_address[0];8'd106:scl_clk<=1;8'd108:begin scl_clk<=0; sda_dir<=0;end //应答信号 8'd110:scl_clk<=1;8'd112:begin scl_clk<=0; sda_dir<=1;end8'd113:sda_out<=write_data[7]; //存的数据8'd114:scl_clk<=1;8'd116:scl_clk<=0;8'd117:sda_out<=write_data[6];8'd118:scl_clk<=1;8'd120:scl_clk<=0;8'd121:sda_out<=write_data[5];8'd122:scl_clk<=1;8'd124:scl_clk<=0;8'd125:sda_out<=write_data[4];8'd126:scl_clk<=1;8'd128:scl_clk<=0;8'd129:sda_out<=write_data[3];8'd130:scl_clk<=1;8'd132:scl_clk<=0;8'd133:sda_out<=write_data[2];8'd134:scl_clk<=1;8'd136:scl_clk<=0;8'd137:sda_out<=write_data[1];8'd138:scl_clk<=1;8'd140:scl_clk<=0;8'd141:sda_out<=write_data[0];8'd142:scl_clk<=1;8'd144:begin scl_clk<=0; sda_dir<=0;end //应答信号 8'd146:scl_clk<=1;8'd148:begin scl_clk<=0; sda_dir<=1;end 8'd149:sda_out<=0;8'd150:scl_clk<=1; 8'd151:sda_out<=1;default : ;endcase endelse if (start_flag2)begin //读数据case(cnt2) 8'd1:scl_clk<=1; 8'd2:sda_out<=1;8'd3:sda_out<=0; 8'd4:scl_clk<=0;8'd5:sda_out<=ADDRESS[7]; //器件地址8'd6:scl_clk<=1;8'd8:scl_clk<=0;8'd9:sda_out<=ADDRESS[6];8'd10:scl_clk<=1;8'd12:scl_clk<=0;8'd13:sda_out<=ADDRESS[5];8'd14:scl_clk<=1;8'd16:scl_clk<=0;8'd17:sda_out<=ADDRESS[4];8'd18:scl_clk<=1;8'd20:scl_clk<=0;8'd21:sda_out<=ADDRESS[3];8'd22:scl_clk<=1;8'd24:scl_clk<=0;8'd25:sda_out<=ADDRESS[2];8'd26:scl_clk<=1;8'd28:scl_clk<=0;8'd29:sda_out<=ADDRESS[1];8'd30:scl_clk<=1;8'd32:scl_clk<=0;8'd33:sda_out<=ADDRESS[0]; //写状态8'd34:scl_clk<=1;8'd36:begin scl_clk<=0; sda_dir<=0;end //应答信号8'd38:scl_clk<=1;8'd40:begin scl_clk<=0; sda_dir<=1;end8'd41:sda_out<=read_address[15]; //数据地址8'd42:scl_clk<=1;8'd44:scl_clk<=0;8'd45:sda_out<=read_address[14];8'd46:scl_clk<=1;8'd48:scl_clk<=0;8'd49:sda_out<=read_address[13];8'd50:scl_clk<=1;8'd52:scl_clk<=0;8'd53:sda_out<=read_address[12];8'd54:scl_clk<=1;8'd56:scl_clk<=0;8'd57:sda_out<=read_address[11];8'd58:scl_clk<=1;8'd60:scl_clk<=0;8'd61:sda_out<=read_address[10];8'd62:scl_clk<=1;8'd64:scl_clk<=0;8'd65:sda_out<=read_address[9];8'd66:scl_clk<=1;8'd68:scl_clk<=0;8'd69:sda_out<=read_address[8];8'd70:scl_clk<=1;8'd72:begin scl_clk<=0; sda_dir<=0;end //应答信号 8'd74:scl_clk<=1;8'd76:begin scl_clk<=0; sda_dir<=1;end 8'd77:sda_out<=read_address[7]; //数据地址8'd78:scl_clk<=1;8'd80:scl_clk<=0;8'd81:sda_out<=read_address[6];8'd82:scl_clk<=1;8'd84:scl_clk<=0;8'd85:sda_out<=read_address[5];8'd86:scl_clk<=1;8'd88:scl_clk<=0;8'd89:sda_out<=read_address[4];8'd90:scl_clk<=1;8'd92:scl_clk<=0;8'd93:sda_out<=read_address[3];8'd94:scl_clk<=1;8'd96:scl_clk<=0;8'd97:sda_out<=read_address[2];8'd98:scl_clk<=1;8'd100:scl_clk<=0;8'd101:sda_out<=read_address[1];8'd102:scl_clk<=1;8'd104:scl_clk<=0;8'd105:sda_out<=read_address[0];8'd106:scl_clk<=1;8'd108:begin scl_clk<=0; sda_dir<=0;end //应答信号 8'd110:scl_clk<=1;8'd112:begin scl_clk<=0; sda_dir<=1;end8'd114:scl_clk<=1; //起始信号8'd115:sda_out<=1;8'd116:sda_out<=0;8'd117:scl_clk<=0;8'd118:sda_out<=ADDRESS[7];8'd119:scl_clk<=1;8'd121:scl_clk<=0;8'd122:sda_out<=ADDRESS[6];8'd123:scl_clk<=1;8'd125:scl_clk<=0;8'd126:sda_out<=ADDRESS[5];8'd127:scl_clk<=1;8'd129:scl_clk<=0;8'd130:sda_out<=ADDRESS[4];8'd131:scl_clk<=1;8'd133:scl_clk<=0;8'd134:sda_out<=ADDRESS[3];8'd135:scl_clk<=1;8'd137:scl_clk<=0;8'd138:sda_out<=ADDRESS[2];8'd139:scl_clk<=1;8'd141:scl_clk<=0;8'd142:sda_out<=ADDRESS[1];8'd143:scl_clk<=1;8'd145:scl_clk<=0;8'd146:sda_out<=1; //读状态8'd147:scl_clk<=1;8'd149:begin scl_clk<=0; sda_dir<=0;end //应答信号8'd151:scl_clk<=1;8'd153:begin scl_clk<=0; sda_dir<=0;end8'd155: scl_clk<=1;8'd156: read_data[7]<=sda_in;8'd157: scl_clk<=0;8'd159: scl_clk<=1;8'd160: read_data[6]<=sda_in;8'd161: scl_clk<=0;8'd163: scl_clk<=1;8'd164: read_data[5]<=sda_in;8'd165: scl_clk<=0;8'd167: scl_clk<=1;8'd168: read_data[4]<=sda_in;8'd169: scl_clk<=0;8'd171: scl_clk<=1;8'd172: read_data[3]<=sda_in;8'd173: scl_clk<=0;8'd175: scl_clk<=1;8'd176: read_data[2]<=sda_in;8'd177: scl_clk<=0;8'd179: scl_clk<=1;8'd180: read_data[1]<=sda_in;8'd181: scl_clk<=0;8'd183: scl_clk<=1;8'd184: read_data[0]<=sda_in;8'd185: begin scl_clk<=0;sda_dir<=1;end8'd186: sda_out<=1;8'd187: scl_clk<=1;8'd189: scl_clk<=0;8'd190: sda_out<=0;8'd191: scl_clk<=1;8'd192: sda_out<=1;default : ;endcase end
end//给一个写使能信号,脉冲
always @(posedge clk_div or negedge rst_n)beginif(rst_n==1'b0)beginstart_flag<=0;endelse if(write_en) beginstart_flag<=1;endelse if(end_cnt1) beginstart_flag<=0;end
endalways @(posedge clk_div or negedge rst_n)beginif(rst_n==1'b0)beginwrite_done<=0;endelse if(end_cnt1) beginwrite_done<=1;endelse beginwrite_done<=0;end
endalways @(posedge clk_div or negedge rst_n)beginif(rst_n==1'b0)beginread_done<=0;endelse if(end_cnt2) beginread_done<=1;endelse beginread_done<=0;end
end//给一个写使能信号,脉冲
always @(posedge clk_div or negedge rst_n)beginif(rst_n==1'b0)beginstart_flag2<=0;endelse if(read_en) beginstart_flag2<=1;endelse if(end_cnt2) beginstart_flag2<=0;end
end//测试
always @(posedge clk or negedge rst_n)beginif(rst_n==1'b0)beginled[0]<=0;endelse if(start_flag) beginled[0]<=1;end
endalways @(posedge clk or negedge rst_n)beginif(rst_n==1'b0)beginled[1]<=0;endelse if(start_flag2) beginled[1]<=1;end
endendmodule////功能说明:向0--200地址,写入数据之后,然后只读取其中一个地址的值,看看自己是否写对了
module rw_e2prom(input clk , //50Minput rst_n , output reg read_en,input read_done,input read_data,output reg [15:0] read_address,output reg write_en,input write_done,output reg [7:0] write_data,output reg [15:0] write_address
);reg [15:0] cnt2;
wire add_cnt2;
wire end_cnt2;
reg flag;reg [7:0] cnt;
wire add_cnt;
wire end_cnt;reg [7:0] cnt1;
wire add_cnt1;
wire end_cnt1;
reg flag_cnt;reg flag_cnt1;always @(posedge clk or negedge rst_n)beginif(!rst_n)begincnt1 <= 0;endelse if(add_cnt1)beginif(end_cnt1)cnt1 <= 0;elsecnt1 <= cnt1 + 1;end
end
assign add_cnt1 = flag_cnt==0;
assign end_cnt1 = add_cnt1 && cnt1==100-1; always @(posedge clk or negedge rst_n)beginif(rst_n==1'b0)beginflag_cnt<=0;endelse if(end_cnt1)beginflag_cnt<=1;end
endalways @(posedge clk or negedge rst_n)beginif(rst_n==1'b0)beginwrite_en<=0;write_address<=0;write_data<=12;endelse beginif(flag_cnt1==0) beginif(end_cnt1)beginwrite_en<=1; endelse if(end_cnt2)beginwrite_en<=1;write_address<=write_address+1;write_data<=write_data+1;endelse beginwrite_en<=0;endendelse beginwrite_en<=0;endend
endalways @(posedge clk or negedge rst_n)beginif(!rst_n)begincnt2 <= 0;endelse if(add_cnt2)beginif(end_cnt2)cnt2 <= 0;elsecnt2 <= cnt2 + 1;end
endassign add_cnt2 = flag ;
assign end_cnt2 = add_cnt2 && cnt2==5200-1 ; always @(posedge clk or negedge rst_n)beginif(rst_n==1'b0)beginflag<=0;endelse if(write_done) beginflag<=1; endelse if(end_cnt2) beginflag<=0; end
endalways @(posedge clk or negedge rst_n)beginif(rst_n==1'b0)beginflag_cnt1<=0;endelse if(end_cnt)beginflag_cnt1<=1;end
endalways @(posedge clk or negedge rst_n)beginif(!rst_n)begincnt <= 0;endelse if(add_cnt)beginif(end_cnt)cnt <= 0;elsecnt <= cnt + 1;end
endassign add_cnt = write_done;
assign end_cnt = add_cnt && cnt==200-1;always @(posedge clk or negedge rst_n)beginif(rst_n==1'b0)beginread_en<=0;read_address<=0;endelse if(end_cnt2)beginread_en<=1;read_address<=2; //将写入地址2的值读出来,显示到数码管上end else beginread_en<=0;endendendmodule
I2C E2PROM通信相关推荐
- 双机通信c语言程序,上传一个自己编写的I2C双机通信程序
本帖最后由 micro_听海 于 2012-11-24 19:58 编辑 这几天一直在搞AVR的twi(twi就是i2c)双机通信程序,使用的是两块arduino开发板.因为最总要这个通信程序最总是要 ...
- 蓝牙BLE芯片PHY6222之I2C主从通信
蓝牙BLE芯片PHY6222之I2C主从通信 开发环境 I2C主机 I2C从机 注意事项 开发环境 1.PHY6222开发板 2.SDK版本以及路径:SDK\release_bbb_sdk-PHY62 ...
- CSR8675学习笔记:I2C Master通信
为了让CSR867x的开发更容易,现与思度科技联合推出CSR867x学习板[淘宝链接:思度科技CSR开发板]. 技术交流QQ群号:743434463 开发板会员QQ群号:725398389(凭订单号入 ...
- STM32F10x_硬件I2C主从通信(轮询发送,中断接收)
推荐 分享一个大神的人工智能教程.零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到人工智能的队伍中来!http://www.captainbed.net/strongerhuang Ⅰ.写在前面 ...
- I2C总线通信——时序/示波器分析
I2C总线通信--时序/示波器分析 通信概述 I2C是一种芯片间的双向数据传输协议. 只需要2根信号线:SCL:串行时钟线:SDA:串行数据线. 时序分析 这里以TM4C123GXL核心板及DY-Ti ...
- I2C+E2PROM再回顾ing~
第二更~~~~ 今天是准备学习A/D,D/A转换的,然后看了一下代码发现用到的都是I2C的底层,那就先回顾一下I2C叭. 1. I2C时序 首先明确I2C总线是由时钟总线SCL和数据总线SDA构成的, ...
- .NET Core IoT 入门指南:(三)使用 I2C 进行通信
什么是 I2C 总线 I2C 总线(Inter-Integrated Circuit Bus)是设备与设备间通信方式的一种.它是一种串行通信总线,由飞利浦公司在1980年代为了让主板.嵌入式系统或手机 ...
- FPGA之IIC(I2C)通信EEPROM控制器设计
关于IIC通信用一个具体实例来进行说明(含设计代码) 几个重要的信号 空闲状态:SDA,SCL均处于高电平状态. 起始信号:SCL为高电平时SDA由高到低跳变 停止信号:SCL为高电平时SDA由低到高 ...
- STM32 HAL I2C(IIC)通信的序列传输(restart condition)
STM32 HAL I2C(IIC)通信的序列(Seq)传输函数(restart condition) neozng1@hnu.edu.cn 文章目录 STM32 HAL I2C(IIC)通信的序列( ...
最新文章
- 灰色预测原理及JAVA实现
- C#中的where泛型约束中的new()使用(转)
- 我做的百度飞桨PaddleOCR .NET调用库
- 2019.01.29【NOIP普及组】模拟赛C组总结
- 人工智能是一个骗局?
- vs2015安装vax助手
- java定时任务_定时任务3种实现方式
- 生存分析 R语言(六)—— Extended and Stratified Cox
- OSWorkflow(转载)
- Innodb解决幻读
- 用vue写一个npm包(package),发布及引用
- 学Linux到底学什么?老司机来告诉你!
- java垃圾回收浅析
- AutoCAD打开报错,致命错误:无效的配置路径/文件名
- 程序员.恋曲.人生(3)
- 基于视频流传输 — 在线教育白板技术
- 开博记录-二零一捌零柒二捌
- python可以考的资格认证有哪些?
- C++标准模板库STL学习
- 腾讯文档智能表格定时自动提醒如何设置?
热门文章
- avl树左旋右旋的理解
- Java api 调用Sqoop2进行MySQL--Hive的数据同步
- 通过js实现在线计算器
- 基于FFMpeg实现音频mp3/aac/wav解码
- 华文慕课北大陆俊林计算机组成原理第十章课后习题解析
- 两边同时取对数求复合函数_e2x求导(复合函数求导例题大全)
- 台达服务器显示al003,台达伺服放大器AL003报警代码|DELTA驱动器低电压故障维修...
- 吃一堑长一智!2021最新Java面试真题解析
- linux7+恢复密码,CentOS7密码恢复
- sinusoidal sweep正弦扫频信号