赞
踩
内容用FPGA芯片Cylone IV E:EP4CE6F17C8 实现对flash读写操作,数据通过uart寄存在FIFO_0,按键_0按下读取数据通过SPI协议写入flash,再按键_1按下通过SPI协议读出数据寄存在FIFO_2经uart协议输出
SPI(Serial Peripheral interface)是由摩托罗拉公司定义的一种串行外围设备接口, 是一种全双工、同步的通信总线,只需要四根信号线即可,节约引脚,同时有利于 PCB 的布局。正是出于这种简单易用的特性,现在越来越多的芯片集成了 SPI 通信协议,如 FLASH、AD 转换器等。
SPI 协议支持一主多从、全双工、半双工模式。
SPI 通信需要四根线,分别为 cs_n、sclk、mosi 和 miso。其中 cs_n、sclk、mosi 是由主机输出给从机,而 miso 由从机输出给主机。cs_n 用于控制从机是否被选中,也就是说只有片选信号有效时,对从机的操作才有效;sclk 是由主机产生的同步时钟,用于同步数据;mosi 和 miso 是主机发送和接收的数据脚。传输数据时,以 MSB 的形式传输
SPI 通信一般有 4 种不同的模式,不同的从设备在出厂时被厂家配置为其中几种通信模式,通信模式是不允许用户修改的。主设备和从设备必须在同一模式下进行通信,否则数据会接收错误。SPI 的通信模式是由 CPOL(时钟极性)和 CPHA(时钟相位)来决定的;
模式 0:CPOL = 0,CPHA = 0;
模式 1:CPOL = 0,CPHA = 1;
模式 2:CPOL = 1,CPHA = 0;
模式 3:CPOL = 1,CPHA = 1。
当 CPOL = 1 时,sclk 在空闲时为高电平,发起通信后的第一个时钟沿为下降沿;
当 CPOL = 0 时,SPI 时钟信号 sclk 空闲时为低电平,发起通信后的第一个时钟沿为上升沿
当 CPHA = 1 时,时钟的第一个变化沿(上升沿或者下降沿)数据开始改变, 那么也就意味着时钟的第 2 个变化沿(与第一个变化沿相反)锁存数据;
当 CPHA = 0 时,数据在时钟的第一个变化沿之前就已经改变,并且保持稳定,也就意味着在时钟的第一个变化沿锁存数据。
M25P16 是一款带有写保护机制的串行 Flash 存储芯片,容量为 16Mbit(2MB);一共
分为 32 个 sector,每个 sector 共 256B 存储容量,每个 sector 擦写次数为 10 万次、数
据保存期限至少 20 年。支持 SPI 通信模式 0 和模式 3。在对 Flash 芯片写数据之前,需要先执行擦除操作,将所有数据变为 FF。
flash指令表
实现读写操作只用了WREN、RDID、WRSR、READ、PP、SE命令
在手册已经说了写使能必须在每个PP、SE、BE、WRSR指令前设置,在写使能发送结束后片选信号拉高
读取标识(RDID)指令允许读取8位的制造商标识,然后是两个字节的设备标识。制造商标识由JEDEC指定,意法半导体的识别值为20小时。设备标识由设备制造商指定,表示第一个字节的内存类型(20小时),以第二个字节表示设备的内存容量(15小时)。同样数据读取结束后片选信号拉高
读取状态寄存器(RDSR)指令允许读取状态寄存器。状态寄存器可以在任何时候被读取,即使在一个程序、擦除或写状态寄存器周期正在进行中。这个命令我认为是在读取其状态的一个命令可有可无有需要可以去看手册,其时序图如下
首先通过驱动芯片选择低来选择设备。读取数据字节(READ)指令的指令代码后面是一个3字节地址,每个位在串行时钟的上升边缘期间被锁定然后,在该地址的内存内容在串行数据输出上移出,在串行时钟的下降边缘期间
这里指出下flash只支持SPI的模式0、模式3,
时序图如下
页面程序(PP)指令允许在内存中编程字节(将位从1改为0)当页面程序周期正在进行时,可以读取状态寄存器以检查正在写入(WIP)位的值。在自定时页面程序周期中,正在写入(WIP)位为1,完成时为0。
扇区擦除(SE)指令将选定扇区内的所有位设置为1(FFh)。在接受它之前,必须先执行了写入启用(WREN)指令。在写入启用(WREN)指令被解码后,设备将设置写入启用锁存器(WEL)。扇区擦除(SE)指令通过驱动芯片选择低输入,然后是指令代码和串行数据输入.
下表有时钟频率、擦除、写入、片选信号拉高再次拉低的时间
always @(*)begin case (spi_mode) 0 : begin if(spi_vld && (cnt_sck <= `SCK_HALF-1))begin sck <= 0; end else if(cnt_sck > `SCK_HALF-1)begin sck <= 1; end else begin sck <= 0; end end 1 : begin if(spi_vld && (cnt_sck <= `SCK_HALF-1))begin sck <= 1; end else if(cnt_sck > `SCK_HALF-1)begin sck <= 0; end else begin sck <= 0; end end 2 : begin if(spi_vld && (cnt_sck <= `SCK_HALF-1 ))begin sck <= 1; end else if(cnt_sck > `SCK_HALF-1 )begin sck <= 0; end else begin sck <= 1; end end 3 : begin if(spi_vld && (cnt_sck <= `SCK_HALF-1))begin sck <= 0; end else if(cnt_sck > `SCK_HALF-1 )begin sck <= 1; end else begin sck <= 1; end end default: sck <= sck; endcase end
SPI时钟的产生思路是以时钟去对齐数据,这里SPI四种模式都写出来了的再数据读取只写了模式0
数据传输时序图
因为这次没画完时序图,代码写的时候有点小乱,整里了下
//参数定义 //spi时钟参数 `define SCK_PERIOD 20 `define SCK_HALF 10 //spi command `define CMD_WREN 8'h06 // `define CMD_WRDI 8'h04 // `define CMD_RDID 8'h9f // `define CMD_RDSR 8'h05 // `define CMD_WRSR 8'h01 // `define CMD_READ 8'h03 // `define CMD_FAST_READ 8'h0b // `define CMD_PP 8'h02 // `define CMD_SE 8'hd8 // `define CMD_BE 8'hc7 // `define CMD_DP 8'hb9 // `define CMD_RES 8'hab // //spi byte `define CMD_BYTE 1 // 命令1字节 `define ADDR_BYTE 3 // 地址3字节 `define ID_BYTE 3 // id3字节 `define DATA_BYTE 1 // id3字节 `define RDSR_BYTE 100 // 读状态寄存器最大可读1000次 `define DELAY_5MS 250_000 // 5ms 数据写入后需要等待5ms才能读出 //波特率 `define BAUD_9600 5208 `define BAUD_19200 2604 `define BAUD_38400 1302 `define BAUD_115200 434 `define STOP_BIT 1'b1 //数据停止位 `define START_BIT 1'b0 //数据开始位
module test( input clk , input rst_n , input [2:0] key_in , input uart_rxd, input miso , output sck , output mosi , output cs_n , output uart_txd ); //中间信号定义 wire [2:0] key_out ; wire [7:0] rx_byte ; wire rx_byte_vld ; wire [7:0] dout_m ; wire [7:0] dout ; wire dout_vld ; wire spi_vld ; wire en ; wire [7:0] din_m ; wire busy_m ; wire wr_done ; wire busy_t ; //模块例化 key_filter_fsm # (.KEY_W(3),.TIME_20MS(1_000_000))u_key_filter_fsm ( /*input */.clk (clk ), /*input */.rst_n (rst_n ), /*input [KEY_W - 1:0] */.key_in (key_in ), /*output [KEY_W - 1:0] */.key_out (key_out ) ); uart_rx u_uart_rx ( /*input */.clk (clk ), /*input */.rst_n (rst_n ), /*input */.rx_din (uart_rxd ), /*input [1:0] */.baud_sel (2'b0 ), /*output [7:0] */.rx_byte (rx_byte ), /*output */.rx_byte_vld (rx_byte_vld ) ); wr_control u_wr_control( /*input */.clk (clk ), /*input */.rst_n (rst_n ), /*input [2:0] */.key_in (key_out ), /*input */.busy_m (busy_m ), /*input */.busy_t (busy_t ), /*input */.wr_done (wr_done ), /*input [7:0] */.din (rx_byte ), /*input */.din_vld (rx_byte_vld ), /*input [7:0] */.din_m (din_m ), /*output reg [7:0] */.dout_m (dout_m ), /*output [7:0] */.dout (dout ), /*output */.dout_vld (dout_vld ), /*output */.en (en ), /*output */.spi_vld (spi_vld ) ); spi_master u_spi_master( /*input */.clk (clk ), /*input */.rst_n (rst_n ), /*input */.en (en ), /*input [1:0] */.spi_mode (2'b00 ), /*input */.spi_vld (spi_vld ), /*input [7:0] */.din (dout_m ), /*input */.miso (miso ), /*output reg */.sck (sck ), /*output reg */.cs_n (cs_n ), /*output */.mosi (mosi ), /*output reg [7:0] */.dout (din_m ), /*output reg */.busy (busy_m ), /*output */.wr_done (wr_done ) ); uart_tx u_uart_tx ( /*input */.clk (clk ), /*input */.rst_n (rst_n ), /*input [1:0] */.baud_sel (2'b00 ), /*input [7:0] */.tx_byte (dout ), /*input */.tx_byte_vld (dout_vld ), /*output */.tx_dout (uart_txd ), /*output */.busy (busy_t ) ); endmodule
`include "param.v" module spi_master( input clk , input rst_n , input en , input [1:0] spi_mode, input spi_vld , input [7:0] din , input miso , output reg sck , output reg cs_n , output mosi , output reg [7:0] dout , output reg busy , output wr_done ); //中间信号定义 reg [4:0] cnt_bit ; wire add_cnt_bit ; wire end_cnt_bit ; reg [8:0] cnt_sck ; wire add_cnt_sck ; wire end_cnt_sck ; reg end_cnt_sck_r ; //计数器 //cnt_sck always @(posedge clk or negedge rst_n)begin if(!rst_n)begin cnt_sck <= 0; end else if(add_cnt_sck)begin if(end_cnt_sck | en)begin cnt_sck <= 0; end else begin cnt_sck <= cnt_sck + 1; end end else begin cnt_sck <= cnt_sck; end end assign add_cnt_sck = spi_vld; assign end_cnt_sck = add_cnt_sck && cnt_sck == `SCK_PERIOD-1; //cnt_bit always @(posedge clk or negedge rst_n)begin if(!rst_n)begin cnt_bit <= 0; end else if(add_cnt_bit )begin if(end_cnt_bit | en)begin cnt_bit <= 0; end else begin cnt_bit <= cnt_bit + 1; end end else begin cnt_bit <= cnt_bit; end end assign add_cnt_bit = (cs_n == 0)&& end_cnt_sck; assign end_cnt_bit = add_cnt_bit && cnt_bit == 8-1; //sck always @(*)begin case (spi_mode) 0 : begin if(spi_vld && (cnt_sck <= `SCK_HALF-1))begin sck <= 0; end else if(cnt_sck > `SCK_HALF-1)begin sck <= 1; end else begin sck <= 0; end end 1 : begin if(spi_vld && (cnt_sck <= `SCK_HALF-1))begin sck <= 1; end else if(cnt_sck > `SCK_HALF-1)begin sck <= 0; end else begin sck <= 0; end end 2 : begin if(spi_vld && (cnt_sck <= `SCK_HALF-1 ))begin sck <= 1; end else if(cnt_sck > `SCK_HALF-1 )begin sck <= 0; end else begin sck <= 1; end end 3 : begin if(spi_vld && (cnt_sck <= `SCK_HALF-1))begin sck <= 0; end else if(cnt_sck > `SCK_HALF-1 )begin sck <= 1; end else begin sck <= 1; end end default: sck <= sck; endcase end //end_cnt_sck_r always @(posedge clk or negedge rst_n)begin if(!rst_n)begin end_cnt_sck_r <= 0; end else begin end_cnt_sck_r <= end_cnt_sck; end end //输出 //cs_n always @(posedge clk or negedge rst_n)begin if(!rst_n)begin cs_n <= 1; end else if(en)begin cs_n <= 0; end else if(cs_n == 0 && (!spi_vld) && end_cnt_sck_r)begin cs_n <= 1; end end //mosi assign mosi = din[7-cnt_bit]; //dout always @(posedge clk or negedge rst_n)begin if(!rst_n)begin dout <= 0; end else if(cs_n == 0 && cnt_sck == `SCK_PERIOD-1)begin dout[7-cnt_bit] <= miso; end else begin dout <= dout; end end //wr_done assign wr_done = end_cnt_bit; //busy always @(posedge clk or negedge rst_n)begin if(!rst_n)begin busy <= 0; end else if(add_cnt_bit && end_cnt_bit == 0)begin busy <= 1; end else if(end_cnt_bit)begin busy <= 0; end end endmodule
`include "param.v" module wr_control( input clk , input rst_n , input [2:0] key_in , input busy_m , input busy_t , input wr_done , input [7:0] din , input din_vld , input [7:0] din_m , output reg [7:0] dout_m , output [7:0] dout , output dout_vld , output en , output reg spi_vld ); //参数定义 //中间信号定义 reg flag ; reg flag0 ; reg en_r ; wire en_dge_n ; reg data_vld ; //例化中间信号 wire data_req ; wire [7:0] dout1 ; wire [7:0] dout2 ; wire [1:0] en_ ; wire [1:0] data_m_vld ; wire write_done ; wire read_done ; wire busy_write ; wire rxf_rdreq ; wire rxf_wrreq ; wire rxf_empty ; wire rxf_full ; wire [7:0] rxf_dout ; wire [8:0] rxf_usedw ; wire [7:0] txf_din ; wire txf_rdreq ; wire txf_wrreq ; wire txf_empty ; wire txf_full ; wire [8:0] txf_usedw ; //标志信号 //flag 1: uart 发送数据 0:停止发送数据 always @(posedge clk or negedge rst_n)begin if(!rst_n)begin flag <= 0; end else if(txf_usedw >= 1)begin flag <= 1; end else if(txf_empty)begin flag <= 0; end end //flag0 0:fish读模块输出数据(命令、地址)1:fish写模块发送数据(命令、地址、写入数据) always @(posedge clk or negedge rst_n)begin if(!rst_n)begin flag0 <= 0; end else if(en_[0])begin flag0 <= 1; end else if(en_[1])begin flag0 <= 0; end end //en_r 打拍 检测en信号边沿 always @(posedge clk or negedge rst_n)begin if(!rst_n)begin en_r <= 0; end else begin en_r <= en; end end assign en_dge_n = !en & en_r; //data_vld always @(posedge clk or negedge rst_n)begin if(!rst_n)begin data_vld <= 0; end else begin data_vld <= (data_m_vld[0] | data_m_vld[1]); end end //输出 //dout_m 数据输出给spi_master模块 always @(*)begin if(flag0)begin dout_m = dout1; end else if(flag0 == 0)begin dout_m = dout2; end else begin dout_m = dout_m; end end //en assign en = en_[0] | en_[1]; //spi_vld always @(posedge clk or negedge rst_n)begin if(!rst_n)begin spi_vld <= 0; end else if(en_dge_n)begin spi_vld <= 1; end else if(write_done | read_done)begin spi_vld <= 0; end else begin spi_vld <= spi_vld; end end flash_write u_flash_write ( /*input */.clk (clk ), /*input */.rst_n (rst_n ), /*input [2:0] */.key_in (key_in ), /*input */.done_m (wr_done ), /*input [7:0] */.din (rxf_dout ), /*output */.data_req (data_req ), //写入flash数据请求 /*output */.en (en_[0] ), /*output */.done (write_done ), /*output */.data_m_vld (data_m_vld[0] ), /*output */.busy (busy_write ), /*output reg [7:0] */.dout (dout1 ) ); flash_read u_flash_read ( /*input */.clk (clk ), /*input */.rst_n (rst_n ), /*input [2:0] */.key_in (key_in ), /*input */.busy (busy_write ), /*input */.done_m (wr_done ), /*output */.en (en_[1] ), /*output */.done (read_done ), /*output */.data_m_vld (data_m_vld[1] ), /*output reg [7:0] */.dout (dout2 ) ); //fifo例化 rx_fifo rx_fifo_inst ( .aclr ( !rst_n ), .clock ( clk ), .data ( din ), //uart输入数据 .rdreq ( rxf_rdreq ), .wrreq ( rxf_wrreq ), .empty ( rxf_empty ), .full ( rxf_full ), .q ( rxf_dout ), .usedw ( rxf_usedw ) ); assign rxf_wrreq = !rxf_full && din_vld; assign rxf_rdreq = !rxf_empty && data_req; fifo_tx fifo_tx_inst ( .aclr ( !rst_n ), .clock ( clk ), .data ( din_m ), .rdreq ( txf_rdreq ), .wrreq ( txf_wrreq ), .empty ( txf_empty ), .full ( txf_full ), .q ( dout ), //uart输出数据 .usedw ( txf_usedw ) ); assign txf_wrreq = !txf_full && data_vld ; assign txf_rdreq = flag && (!txf_empty) && (!busy_t); assign dout_vld = txf_rdreq; //uart数据输出有效 endmodule
`include "param.v" module flash_read( input clk , input rst_n , input [2:0] key_in , input busy , input done_m , output en , output done , output data_m_vld , output reg [7:0] dout ); //参数定义 parameter IDLE =7'b000_0001, RDID_CMD =7'b000_0010, RDID_DATA =7'b000_0100, RDAD_CMD =7'b000_1000, RDAD_ADDR =7'b001_0000, RDAD_DATA =7'b010_0000, RD_DONE =7'b100_0000; //中间信号定义 reg [6:0] state_c ; reg [6:0] state_n ; reg [2:0] cnt_byte ; wire add_cnt_byte ; wire end_cnt_byte ; reg [2:0] byte_num ; reg [23:0] addr_rd ; wire idle2rdid_cmd ; wire idle2rdad_cmd ; wire rdid_cmd2rdid_data ; wire rdad_cmd2rdad_addr ; wire rdad_addr2rdad_data ; wire rdid_data2rd_done ; wire rdad_data2rd_done ; wire rd_done2idle ; //状态机 always @(posedge clk or negedge rst_n)begin if(!rst_n)begin state_c <= IDLE; end else begin state_c <= state_n; end end always @(*)begin case (state_c) IDLE : begin if (idle2rdid_cmd) begin state_n <= RDID_CMD; end else if(idle2rdad_cmd) begin state_n <= RDAD_CMD; end else begin state_n <= state_c; end end RDID_CMD : begin if(rdid_cmd2rdid_data)begin state_n <= RDID_DATA; end else begin state_n <= state_c; end end RDID_DATA : begin if (rdid_data2rd_done) begin state_n <= RD_DONE; end else begin state_n <= state_c; end end RDAD_CMD : begin if (rdad_cmd2rdad_addr) begin state_n <= RDAD_ADDR; end else begin state_n <= state_c; end end RDAD_ADDR : begin if (rdad_addr2rdad_data ) begin state_n <= RDAD_DATA; end else begin state_n <= state_c; end end RDAD_DATA : begin if(rdad_data2rd_done)begin state_n <= RD_DONE; end else begin state_n <= state_c; end end RD_DONE : begin if(rd_done2idle)begin state_n <= IDLE; end else begin state_n <= state_c; end end default: state_n <= state_c; endcase end assign idle2rdid_cmd = state_c == IDLE && key_in[0] && busy == 0; assign idle2rdad_cmd = state_c == IDLE && key_in[1] && busy == 0; assign rdid_cmd2rdid_data = state_c == RDID_CMD && end_cnt_byte; assign rdad_cmd2rdad_addr = state_c == RDAD_CMD && end_cnt_byte; assign rdad_addr2rdad_data = state_c == RDAD_ADDR && end_cnt_byte; assign rdid_data2rd_done = state_c == RDID_DATA && end_cnt_byte; assign rdad_data2rd_done = state_c == RDAD_DATA && end_cnt_byte; assign rd_done2idle = state_c == RD_DONE && 1'b1; //计数器 always @(posedge clk or negedge rst_n)begin if(!rst_n)begin cnt_byte <= 0; end else if(add_cnt_byte)begin if(end_cnt_byte)begin cnt_byte <= 0; end else begin cnt_byte <= cnt_byte + 1; end end else begin cnt_byte <= cnt_byte; end end assign add_cnt_byte = (state_c == RDID_CMD | state_c == RDID_DATA | state_c == RDAD_CMD | state_c == RDAD_ADDR |state_c == RDAD_DATA) && done_m; assign end_cnt_byte = add_cnt_byte && cnt_byte == byte_num-1; always @(posedge clk or negedge rst_n)begin if(!rst_n)begin byte_num <= 0; end else if(state_c == RDID_CMD | state_c == RDAD_CMD )begin byte_num <= `CMD_BYTE; end else if(state_c == RDID_DATA)begin byte_num <= `ID_BYTE; end else if (state_c == RDAD_ADDR) begin byte_num <= `ADDR_BYTE; end else if(state_c == RDAD_DATA)begin byte_num <= `DATA_BYTE; end end //addr_rd always @(posedge clk or negedge rst_n)begin if(!rst_n)begin addr_rd <= 24'h100; end // else if(rdad_data2rd_done)begin // addr_rd <= addr_rd + 1; // end else begin addr_rd <= addr_rd; end end //输出 //dout always @(posedge clk or negedge rst_n)begin if(!rst_n)begin dout <= 0; end else if(state_c == RDID_CMD)begin dout <= `CMD_RDID; end else if(state_c == RDAD_CMD)begin dout <= `CMD_READ; end else if(state_c == RDAD_ADDR)begin if(cnt_byte == 0) begin dout <= addr_rd[23:16]; end else if(cnt_byte == 1) begin dout <= addr_rd[15:8]; end else if(cnt_byte == 2) begin dout <= addr_rd[7:0]; end end else begin dout <= dout; end end //en done dtat_m_vld assign en =(key_in[0] | key_in[1]) & state_c == IDLE; assign done = rdid_data2rd_done | rdad_data2rd_done; assign data_m_vld = done_m && (state_c == RDID_DATA | state_c == RDAD_DATA); endmodule
`include "param.v" module flash_write( input clk , input rst_n , input [2:0] key_in , input done_m , input [7:0] din , output data_req , //写入flash数据请求 output en , output done , output busy , output data_m_vld , output reg [7:0] dout ); //参数定义 parameter M_IDLE =5'b0_0001, M_WREN =5'b0_0010, M_SE =5'b0_0100, M_RDSR =5'b0_1000, M_PP =5'b1_0000; parameter S_IDLE = 5'b00001, S_CMD = 5'b00010, S_ADDR = 5'b00100, S_DATA = 5'b01000, S_DELAY = 5'b10000; //中间信号定义 reg [4:0] m_state_c ; reg [4:0] m_state_n ; reg [4:0] s_state_c ; reg [4:0] s_state_n ; reg [2:0] cnt_100ns ; wire add_cnt_100ns ; wire end_cnt_100ns ; reg [18:0] cnt_pp ; wire add_cnt_pp ; wire end_cnt_pp ; reg end_cnt_pp_r ; reg [10:0] cnt_se ; wire add_cnt_se ; wire end_cnt_se ; reg end_cnt_se_r ; reg [2:0] cnt_byte ; wire add_cnt_byte ; wire end_cnt_byte ; reg [2:0] byte_num ; reg [23:0] addr_wr ; reg [1:0] flag ; reg req_r ; //主 wire m_idle2m_wren ; wire m_wren2m_rdsr ; wire m_rdsr2m_wren ; wire m_wren2m_se ; wire m_wren2m_pp ; wire m_se2m_wren ; wire m_pp2m_idle ; //从 wire s_idle2s_cmd ; wire s_cmd2s_addr ; wire s_cmd2s_data ; wire s_cmd2s_delay ; wire s_addr2s_data ; wire s_addr2s_delay ; wire s_data2s_idle ; wire s_data2s_delay ; wire s_delay2s_idle ; //状态机 //主状态机 always @(posedge clk or negedge rst_n)begin if(!rst_n)begin m_state_c <= M_IDLE; end else begin m_state_c <= m_state_n; end end always @(*)begin case (m_state_c) M_IDLE : begin if(m_idle2m_wren)begin m_state_n = M_WREN; end else begin m_state_n = m_state_c; end end M_WREN : begin if (m_wren2m_rdsr) begin m_state_n = M_RDSR; end else if (m_wren2m_se) begin m_state_n = M_SE; end else if (m_wren2m_pp) begin m_state_n = M_PP; end else begin m_state_n = m_state_c; end end M_SE : begin if (m_se2m_wren) begin m_state_n = M_WREN; end else begin m_state_n = m_state_c; end end M_RDSR : begin if (m_rdsr2m_wren) begin m_state_n = M_WREN; end else begin m_state_n = m_state_c; end end M_PP : begin if (m_pp2m_idle) begin m_state_n = M_IDLE; end else begin m_state_n = m_state_c; end end default: m_state_n = m_state_c; endcase end //从状态机 always @(posedge clk or negedge rst_n)begin if(!rst_n)begin s_state_c <= S_IDLE; end else begin s_state_c <= s_state_n; end end always @(*)begin case (s_state_c) S_IDLE : begin if (s_idle2s_cmd) begin s_state_n = S_CMD; end else begin s_state_n = s_state_c; end end S_CMD : begin if (s_cmd2s_addr) begin s_state_n = S_ADDR; end else if (s_cmd2s_data) begin s_state_n = S_DATA; end else if (s_cmd2s_delay) begin s_state_n = S_DELAY; end else begin s_state_n = s_state_c; end end S_ADDR : begin if (s_addr2s_data) begin s_state_n = S_DATA; end else if(s_addr2s_delay) begin s_state_n = S_DELAY; end else begin s_state_n = s_state_c; end end S_DATA : begin if (s_data2s_idle) begin s_state_n = S_IDLE; end else if(s_data2s_delay)begin s_state_n = S_DELAY; end else begin s_state_n = s_state_c; end end S_DELAY : begin if(s_delay2s_idle)begin s_state_n = S_IDLE; end else begin s_state_n = s_state_c; end end default: s_state_n = s_state_c; endcase end //主状态机转换条件 assign m_idle2m_wren = m_state_c == M_IDLE && key_in[2]; assign m_wren2m_rdsr = m_state_c == M_WREN && s_delay2s_idle && flag == 2'b00; assign m_rdsr2m_wren = m_state_c == M_RDSR && s_data2s_idle; assign m_wren2m_se = m_state_c == M_WREN && s_delay2s_idle && flag == 2'b01; assign m_wren2m_pp = m_state_c == M_WREN && s_delay2s_idle && flag == 2'b10; assign m_se2m_wren = m_state_c == M_SE && s_delay2s_idle; assign m_pp2m_idle = m_state_c == M_PP && s_delay2s_idle; //从状态机转换条件 assign s_idle2s_cmd = s_state_c == S_IDLE && (!(m_state_c == M_IDLE) ); assign s_cmd2s_addr = s_state_c == S_CMD && end_cnt_byte && (m_state_c == M_SE | m_state_c == M_PP); assign s_cmd2s_data = s_state_c == S_CMD && end_cnt_byte && m_state_c == M_RDSR; assign s_addr2s_data = s_state_c == S_ADDR && end_cnt_byte && m_state_c == M_PP; assign s_addr2s_delay = s_state_c == S_ADDR && end_cnt_byte && m_state_c == M_SE ; assign s_data2s_idle = s_state_c == S_DATA && end_cnt_byte && m_state_c == M_RDSR; assign s_data2s_delay = s_state_c == S_DATA && end_cnt_byte && (m_state_c == M_PP); assign s_cmd2s_delay = s_state_c == S_CMD && end_cnt_byte && m_state_c == M_WREN; assign s_delay2s_idle = s_state_c == S_DELAY && ((( (m_state_c == M_SE)?end_cnt_se_r : end_cnt_pp_r) && (m_state_c == M_SE || m_state_c == M_PP)) || (end_cnt_100ns && m_state_c == M_WREN)); //计数器 always @(posedge clk or negedge rst_n)begin if(!rst_n)begin cnt_100ns <= 0; end else if(add_cnt_100ns)begin if(end_cnt_100ns)begin cnt_100ns <= 0; end else begin cnt_100ns <= cnt_100ns + 1; end end else begin cnt_100ns <= cnt_100ns; end end assign add_cnt_100ns = s_state_c == S_DELAY && m_state_c == M_WREN; assign end_cnt_100ns = add_cnt_100ns && cnt_100ns == 5; always @(posedge clk or negedge rst_n)begin if(!rst_n)begin cnt_byte <= 0; end else if(add_cnt_byte)begin if(end_cnt_byte)begin cnt_byte <= 0; end else begin cnt_byte <= cnt_byte + 1; end end else begin cnt_byte <= cnt_byte; end end assign add_cnt_byte = done_m && (s_state_c == S_CMD | s_state_c == S_ADDR | s_state_c == S_DATA ); assign end_cnt_byte = add_cnt_byte && cnt_byte == byte_num-1; always @(posedge clk or negedge rst_n)begin if(!rst_n)begin cnt_pp <= 0; end else if(add_cnt_pp)begin if(end_cnt_pp | s_delay2s_idle)begin cnt_pp <= 0; end else begin cnt_pp <= cnt_pp + 1; end end else begin cnt_pp <= cnt_pp; end end assign add_cnt_pp = s_state_c == S_DELAY && (m_state_c == M_PP || m_state_c == M_SE); assign end_cnt_pp = add_cnt_pp && cnt_pp == `DELAY_5MS-1; always @(posedge clk or negedge rst_n)begin if(!rst_n)begin cnt_se <= 0; end else if(add_cnt_se)begin if(end_cnt_se)begin cnt_se <= 0; end else begin cnt_se <= cnt_se + 1; end end else begin cnt_se <= cnt_se; end end assign add_cnt_se= s_state_c == S_DELAY && end_cnt_pp && m_state_c == M_SE; assign end_cnt_se = add_cnt_se && cnt_se == 600-1; //flag always @(posedge clk or negedge rst_n)begin if(!rst_n)begin flag <= 2'b00; end else if(m_state_c == M_RDSR)begin flag <=2'b01 ; end else if(m_state_c == M_SE)begin flag <= 2'b10; end else if(m_state_c == M_PP)begin flag <= 2'b00; end end always @(posedge clk or negedge rst_n)begin if(!rst_n)begin end_cnt_pp_r <= 0; end_cnt_se_r <= 0; end else begin end_cnt_pp_r <= end_cnt_pp; end_cnt_se_r <= end_cnt_se; end end //byte_num always @(posedge clk or negedge rst_n)begin if(!rst_n)begin byte_num <= 0; end else if(s_state_c == S_CMD)begin byte_num <= `CMD_BYTE; end else if(s_state_c == S_ADDR)begin byte_num <= `ADDR_BYTE; end else if(s_state_c == S_DATA)begin byte_num <= `DATA_BYTE; end else begin byte_num <= byte_num; end end //addr_wr always @(posedge clk or negedge rst_n)begin if(!rst_n)begin addr_wr <= 24'h100; end // else if(m_pp2m_idle)begin // addr_wr <= addr_wr +1; // end else begin addr_wr <= addr_wr; end end // always @(posedge clk or negedge rst_n)begin // if(!rst_n)begin // req_r <= 0; // end // else begin // req_r <= done_m; // end // end //输出 //dout always @(posedge clk or negedge rst_n)begin if(!rst_n)begin dout <= 0; end else if(s_state_c == S_CMD)begin if(m_state_c == M_WREN)begin dout <= `CMD_WREN; end else if(m_state_c == M_SE ) begin dout <= `CMD_SE; end else if(m_state_c == M_RDSR)begin dout <= `CMD_RDSR; end else if (m_state_c == M_PP ) begin dout <= `CMD_PP; end else begin dout <= dout; end end else if(s_state_c == S_ADDR)begin dout <=addr_wr[23-cnt_byte*8 -:8]; end else if (s_state_c == S_DATA && m_state_c == M_PP) begin dout <=din; end end //data_req en done data_m_vld busy assign data_req = m_state_c == M_PP && done_m && s_state_c == S_DATA; assign en =(key_in[2] & m_state_c == M_IDLE) | (s_delay2s_idle && m_state_c == M_SE) | (s_delay2s_idle && m_state_c == M_WREN); assign done = (s_data2s_delay && m_state_c == M_PP) | s_addr2s_delay | s_cmd2s_delay; assign data_m_vld = done_m && s_state_c == S_DATA && m_state_c == M_RDSR; assign busy= !(m_state_c==M_IDLE); endmodule
https://blog.csdn.net/li_lys/article/details/121849916
https://blog.csdn.net/li_lys/article/details/122887251?spm=1001.2014.3001.5502
读ID时需
读时序
写时序,写没截完
读ID
单字节读数据
写数据,读数据
工程链接:
https://blog.csdn.net/li_lys/article/details/124870664?utm_source=app&app_version=5.4.0&code=app_1562916241&uLinkId=usr1mkqgl919blen
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。