好看的电商网站模板下载郑州做网站和推广哪家好
news/
2025/9/24 3:32:26/
文章来源:
好看的电商网站模板下载,郑州做网站和推广哪家好,国外 设计网站,wordpress充流量文章目录 前言一、代码设计框图二、IIC_drive模块设计2.1、模块接口#xff1a;2.2、代码功能描述#xff1a;2.3、IIC协议实现过程#xff1a; 三、EEPROM_ctrl模块设计3.1、模块接口#xff1a;3.2、代码功能描述 四、EEPROM_drive模块五、iic_top模块 前言
继上一篇FPG… 文章目录 前言一、代码设计框图二、IIC_drive模块设计2.1、模块接口2.2、代码功能描述2.3、IIC协议实现过程 三、EEPROM_ctrl模块设计3.1、模块接口3.2、代码功能描述 四、EEPROM_drive模块五、iic_top模块 前言
继上一篇FPGA学习_I2C总线协议内容本文将基于FPGA通过I2C控制AT24C64EEPROM芯片芯片
一、代码设计框图 完整代码GitHub连接https://github.com/shun6-6/IIC_EEPROM_Pro
二、IIC_drive模块设计
参考FPGA奇哥系列网课
2.1、模块接口
module iic_drive#(parameter P_ADDR_WIDTH 16
)(input i_clk ,input i_rst ,/*----user interface----*/input [6 :0] i_device_addr ,//用户输入设备地址input [15:0] i_operation_addr ,//用户输入读写数据地址input [7 :0] i_operation_len ,//用户输入读写数据长度input [1 :0] i_operation_type ,//用户输入读写类型input i_operation_valid ,//用户输入操作有效信号output o_operation_ready ,//用户输出操作准备信号input [7 :0] i_write_date ,//用户写入数据output o_write_req ,//用户写数据请求output [7 :0] o_read_date ,//输出IIC读到的数据output o_read_valid ,//数据有效信号/*----IIC interface----*/output o_iic_scl ,//IIC时钟线inout io_iic_sda //IIC双向数据线
);2.2、代码功能描述
该模块将输入的指令以及相关地址和数据通过IIC协议传递给EEPROM芯片其中状态机一共有11个状态
localparam P_ST_IDLE 0 ,//状态机-空闲P_ST_START 1 ,//状态机-起始位P_ST_UADDR 2 ,//状态机-设备地址P_ST_DADDR1 3 ,//状态机-数据地址高位P_ST_DADDR2 4 ,//状态机-数据地址低位P_ST_WRITE 5 ,//状态机-写数据P_ST_REATART 6 ,//状态机-重启iic总线P_ST_READ 7 ,//状态机-读数据P_ST_WATI 8 ,//等待应答后再发生停止位P_ST_STOP 9 ,//状态机-停止P_ST_EMPTY 10 ;//空状态状态转移过程 P_ST_IDLE 一次操作指令握手成功后进入START状态 P_ST_START 该状态下控制SCL和SDA线启动IIC随后进入写设备地址UADDR状态 P_ST_UADDR w_st_turn 信号表示一个byte写入结束即设备地址和读写指令写入俩个一共为8bit结束随后会判断r_st_restart 信号该信号表示当前操作为读数据操作因为只有在读数据时我们采用随机地址读操作有一次虚写操作虚写结束后需要重新启动总线因此若此信号为高需要进入READ读阶段否则进入写数据地址1P_ST_DADDR1阶段 P_ST_DADDR1 r_slave_ack 信号表示从机响应信号此时响应的是写设备地址阶段的响应信号如果响应为0即未响应则直接进入STOP停止阶段以重新启动总线这是由于刚刚写完数据如果立马进行操作总线总线处于忙状态不会响应若正常响应则会在顺利写完8bit数据后进入P_ST_DADDR2 阶段。 P_ST_DADDR2 在写完8bit的低8为地址后即w_st_turn 拉高判断当前是读操作还是写操作写操作则顺利进入写数据WRITE阶段读操作则需要进入总线重新启动阶段即P_ST_REATART 。 P_ST_WRITE 当写如byte字节数与用户输入的写数据长度一致时进入等待WAIT状态否则继续写 P_ST_REATART 重启总线先进入停止STOP阶段执行停止操作。 P_ST_READ 字节读此模块只支持字节读操作但用户要实现多字节读操作也是可以的该过程会在EEPROM_drive当中被实现因为EEPROM_drive模块会执行多次字节读。以此实现连续读操作。 P_ST_WATI 等待一拍等从机ACK结束后进入停止位STOP阶段。 P_ST_STOP 控制SCL和SDA线结束IIC操作 注这里需要注意的是接收完ACK后不可以直接停止时钟产生然后直接拉高SDA需要多产生一个周期SCL然后在SCL高电平期间拉高SDA以产生停止信号。 P_ST_EMPTY emmmmm没啥用的一个状态完全可以将停止位多计数一个时钟执行响应的判断不过这样写清晰一点主要是判断是不是需要重启总线r_st_restart说明是由于读操作导致的重启操作r_ack_lock说明是由于从机忙没有回应导致的重启总线如果是则进入START状态不是就回到IDLE状态。
always (*)begincase (r_st_cur)P_ST_IDLE : r_st_nxt w_operation_active ? P_ST_START : P_ST_IDLE;P_ST_START : r_st_nxt P_ST_UADDR;P_ST_UADDR : r_st_nxt w_st_turn ? r_st_restart ? P_ST_READ : P_ST_DADDR1: P_ST_UADDR;P_ST_DADDR1 : r_st_nxt r_slave_ack ? P_ST_STOP : w_st_turn ? P_ST_DADDR2 : P_ST_DADDR1;P_ST_DADDR2 : r_st_nxt w_st_turn ri_operation_type P_W ? P_ST_WRITE : w_st_turn ri_operation_type P_R ? P_ST_REATART :P_ST_DADDR2;P_ST_WRITE : r_st_nxt w_st_turn r_wr_cnt ri_operation_len - 1 ? P_ST_WATI : P_ST_WRITE;P_ST_REATART : r_st_nxt P_ST_STOP;P_ST_READ : r_st_nxt w_st_turn ? P_ST_WATI : P_ST_READ;//随机读一次一个byteP_ST_WATI : r_st_nxt P_ST_STOP;P_ST_STOP : r_st_nxt r_st_cnt 1 ? P_ST_EMPTY : P_ST_STOP;P_ST_EMPTY : r_st_nxt r_st_restart | r_ack_lock ? P_ST_START : P_ST_IDLE;default : r_st_nxt P_ST_IDLE;endcase
end2.3、IIC协议实现过程
过程和之前介绍的SPI总线协议类似通过维护一个计数器来使数据在SCL时钟下降沿改变在SCL时钟上升沿被采样 主要难点是停止位的部分
写数据结束的停止位在第一张波形图哪里做了详细说明读数据结束的停止位如下图所示在黄线部分已经读完了数据后面需要加一个时钟周期传输NO ACK图中红线部分表示此次字节读结束然后停止位的产生一定还需要多一个时钟周期并且在此时钟周期最后拉高SDA其实和写数据停止位一样重复说明防止出错 三、EEPROM_ctrl模块设计
3.1、模块接口
module eeprom_ctrl(input i_clk ,input i_rst ,/*----user interface----*/input [2 :0] i_eeprom_addr ,input [15:0] i_user_operation_addr ,input [1 :0] i_user_operation_type ,input [7 :0] i_user_operation_len ,input i_user_operation_valid ,output o_user_operation_ready ,input [7 :0] i_user_write_date ,input i_user_write_valid ,input i_user_write_sop ,input i_user_write_eop ,output [7 :0] o_user_read_date ,output o_user_read_valid ,/*----iic drive interface----*/output [6 :0] o_device_addr ,output [15:0] o_operation_addr ,output [7 :0] o_operation_len ,output [1 :0] o_operation_type ,output o_operation_valid ,input i_operation_ready ,output [7 :0] o_write_date ,input i_write_req ,input [7 :0] i_read_date ,input i_read_valid
);3.2、代码功能描述
该模块主要讲用户输入的读写指令转化为驱动读写指令并且将用户输入的写数据存入FIFO一个一个把8bit数据吐给IIC驱动因为IIC_drive是串行传输的同时也把从EEPROM读出的数据暂存入FIFO读完后一次性连续的传递给用户模块。同时在该模块当中完成了一个上面刚刚提到的操作连续读 IIC_drive模块只支持字节读操作但用户要实现多字节读操作也是可以的因为EEPROM_drive模块会执行多次字节读。以此实现连续读操作。
localparam P_ST_IDLE 0 ,P_ST_WRITE 1 ,P_ST_WAIT 2 ,P_ST_READ 3 ,P_ST_REREAD 4 ,P_ST_OUT_DATA 5 ;always (*)begincase (r_st_cur)P_ST_IDLE : r_st_nxt w_user_active i_user_operation_type P_W ? P_ST_WRITE :w_user_active i_user_operation_type P_R ? P_ST_WAIT :P_ST_IDLE;P_ST_WRITE : r_st_nxt w_drive_end ri_user_operation_type P_W ? P_ST_IDLE : P_ST_WRITE;P_ST_WAIT : r_st_nxt P_ST_READ;P_ST_READ : r_st_nxt w_drive_end ? r_read_cnt ri_user_operation_len - 1 ? P_ST_OUT_DATA : P_ST_REREAD: P_ST_READ; P_ST_REREAD : r_st_nxt P_ST_READ; P_ST_OUT_DATA : r_st_nxt w_fifo_read_empty ? P_ST_IDLE : P_ST_OUT_DATA;default : r_st_nxt P_ST_IDLE;endcase
end该模块状态机以及相应跳转条件 该功能较为简单 P_ST_IDLE 根据输入操作类型分别进入写WRITE状态或者是等待WAIT状态这是因为用户输入的操作指令都会在本地先打一拍然后寄存下来对于写数据而言会先将数据存入FIFO然后再进行握手操作然后再把本地寄存的用户指令再发给IIC驱动这期间因为FIFO存数据所以指令赋值推后了好多拍因此指令赋值不会出错但是进行读数据操作时用户指令i_user_operation_type先赋值给ri_user_operation_type以寄存然后将ri_user_operation_type赋值给驱动ro_operation_type在这个过程中就需要先等待一拍否则就会出现上一次操作的的ri_user_operation_type给了ro_operation_type错过了本次正确的i_user_operation_type。 这就是为什么进入读操作时先要进入一次WAIT状态以打一排。 之后的状态都很简单了
四、EEPROM_drive模块
该模块就是例化了上述俩个模块
五、iic_top模块
该模块则是简单实现了一个不断翻转读写状态的的用户模块。
module iic_top(input i_clk ,output o_iic_scl ,//IIC时钟线inout io_iic_sda //IIC双向数据线);
localparam P_WRITE_NUM 8;
localparam P_W 1 ,//写数据P_R 2 ;//读数据
reg [2 :0] ri_eeprom_addr ;
reg [15:0] ri_user_operation_addr ;
reg [1 :0] ri_user_operation_type ;
reg [7 :0] ri_user_operation_len ;
reg ri_user_operation_valid ;
wire o_user_operation_ready ;
reg [7 :0] ri_user_write_date ;
reg ri_user_write_valid ;
reg ri_user_write_sop ;
reg ri_user_write_eop ;
wire [7 :0] o_user_read_date ;
wire o_user_read_valid ;
reg [7 :0] r_write_cnt ;
reg r_wr_st ;
wire w_user_active ;
wire w_clk_5mhz ;
wire w_clk_5mhz_lock ;
wire w_clk_125khz ;
wire w_clk_125khz_rst ;
assign w_user_active ri_user_operation_valid o_user_operation_ready;
SYSCLK_div SYSCLK_div_5mhz(.clk_out1 (w_clk_5mhz ), .locked (w_clk_5mhz_lock), .clk_in1 (i_clk )
);
CLK_DIV_module#(.P_CLK_DIV_CNT (40) //MAX 65535
)CLK_DIV_module_U(.i_clk (w_clk_5mhz ),.i_rst (~w_clk_5mhz_lock),.o_clk_div (w_clk_125khz ));
rst_gen_module#(.P_RST_CYCLE (1)
)rst_gen_module_u0( .i_clk (w_clk_125khz ),.o_rst (w_clk_125khz_rst));
eeprom_drive eeprom_drive_u0(.i_clk (w_clk_125khz ),.i_rst (w_clk_125khz_rst),.i_eeprom_addr (ri_eeprom_addr ),.i_user_operation_addr (ri_user_operation_addr ),.i_user_operation_type (ri_user_operation_type ),.i_user_operation_len (ri_user_operation_len ),.i_user_operation_valid (ri_user_operation_valid),.o_user_operation_ready (o_user_operation_ready ),.i_user_write_date (ri_user_write_date ),.i_user_write_valid (ri_user_write_valid ),.i_user_write_sop (ri_user_write_sop ),.i_user_write_eop (ri_user_write_eop ),.o_user_read_date (o_user_read_date ),.o_user_read_valid (o_user_read_valid ),.o_iic_scl (o_iic_scl ),//IIC时钟线.io_iic_sda (io_iic_sda) //IIC双向数据线);
always (posedge w_clk_125khz or posedge w_clk_125khz_rst)beginif(w_clk_125khz_rst)beginri_eeprom_addr d0;ri_user_operation_addr d0;ri_user_operation_type d0;ri_user_operation_len d0;ri_user_operation_valid d0;endelse if(o_user_operation_ready r_wr_st 0)beginri_eeprom_addr 3b011;ri_user_operation_addr d0;ri_user_operation_type P_W;ri_user_operation_len P_WRITE_NUM;ri_user_operation_valid d1;endelse if(o_user_operation_ready r_wr_st 1)beginri_eeprom_addr 3b011;ri_user_operation_addr d0;ri_user_operation_type P_R;ri_user_operation_len P_WRITE_NUM;ri_user_operation_valid d1;endelse beginri_eeprom_addr d0;ri_user_operation_addr d0;ri_user_operation_type d0;ri_user_operation_len d0;ri_user_operation_valid d0;end
end
always (posedge w_clk_125khz or posedge w_clk_125khz_rst)beginif(w_clk_125khz_rst)ri_user_write_date d0;else if(ri_user_write_valid)ri_user_write_date ri_user_write_date 1;elseri_user_write_date ri_user_write_date;
end always (posedge w_clk_125khz or posedge w_clk_125khz_rst)beginif(w_clk_125khz_rst)ri_user_write_sop d0;else if(w_user_active ri_user_operation_type P_W)ri_user_write_sop d1;elseri_user_write_sop d0;
end
always (posedge w_clk_125khz or posedge w_clk_125khz_rst)beginif(w_clk_125khz_rst)ri_user_write_valid d0;else if(ri_user_write_eop)ri_user_write_valid d0;else if(w_user_active ri_user_operation_type P_W)ri_user_write_valid d1;elseri_user_write_valid ri_user_write_valid;
end
always (posedge w_clk_125khz or posedge w_clk_125khz_rst)beginif(w_clk_125khz_rst)ri_user_write_eop d0;// else if((w_user_active || ri_user_write_valid) r_write_cnt P_WRITE_NUM - 2)// ri_user_write_eop d1;else if(w_user_active P_WRITE_NUM 1)ri_user_write_eop d1;//write 1 byteelse if(ri_user_write_valid r_write_cnt P_WRITE_NUM - 2)ri_user_write_eop d1;//write over 1 byteelseri_user_write_eop d0;
end
always (posedge w_clk_125khz or posedge w_clk_125khz_rst)beginif(w_clk_125khz_rst)r_write_cnt d0;else if(r_write_cnt P_WRITE_NUM - 1)r_write_cnt d0;else if(ri_user_write_valid)r_write_cnt r_write_cnt 1d1;elser_write_cnt r_write_cnt;
end
always (posedge w_clk_125khz or posedge w_clk_125khz_rst)beginif(w_clk_125khz_rst)r_wr_st d0;else if(w_user_active)r_wr_st r_wr_st 1d1;elser_wr_st r_wr_st;
end
endmodule
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/914729.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!