flash的普通读指令,在指定地址开始读。可以更改地址与读的数据个数。
先发送读指令+扇区地址+页地址+字节地址。
然后读数据。再把读到的串行数据转化为8bit的数据,存入fifo。
然后读出FIFO中数据,通过uart_tx模块发送给上位机。
接收数据:比如接收8bit的串行数据,通过miso传递。
1,先接收高位。
reg [7:0] data ;
那么通过data保存miso传递的数据,把串行数据,转换为并行数据。
有两种常用写法:
data <= {data[6:0],miso};
或者
data <= data << 1 + miso ;
或者:写一个cnt_bit,记录保存到第几bit。
data[cnt_bit] <= miso ;
2,先接收低位
data <= {miso,data[7:1]};
data[cnt_bit] <= miso ;
画时序图时不一定要先画内部信号,再画输出端口信号。
按照自己的设计思路,该到那个信号就画那个信号,画完也不要改,
写代码时,按照这个思路,这个画时序图的顺序,编写代码。
相当于再次检查一遍,即容易排错,有容易编写代码。



- module spi (
- input wire sys_clk ,
- input wire sys_rst_n ,
- input wire key_flag ,
-
- input wire miso ,
-
- output reg cs_n ,
- output reg sck ,
- output reg mosi ,
- output reg po_flag ,
- output wire [7:0] po_data
- );
- // localparam define 一般状态机的状态定义用局部参数就可以。
- localparam IDLE = 4'b0001 ,
- INSTRUCT = 4'b0010 ,
- READ = 4'b0100 ,
- SEND = 4'b1000 ;
- // parameter define 指令,计数器最大值,用全局参数定义。
- parameter COMD_REA = 8'h03 , // comd_read
- ADDR_SEC = 8'h00 , // address_secter 扇区地址
- ADDR_PAG = 8'h00 , // address_page 页地址(行地址)
- ADDR_BYT = 8'h00 , // assress_byte 字节地址
- NUM_COMD = 4'd4 ; // 用来记录在指令状态传递指令和地址byte数量
- parameter CNT_MAX_BYTE = 11'd300 , // 4 + 要读出的数据。例如: 4 + 256
- CNT_MAX_SEND = 20'd53000 ;
- // reg signal define
- reg [3:0] state_c ;
- reg [3:0] state_n ;
- reg cnt_20_ns ;
- reg [2:0] cnt_bit ;
- reg [10:0] cnt_byte ;
- reg flag_b ; // flag_byte
- reg flagBreg ;
- reg flag_R_S ; // flag_byte
- reg flag_RSr ;
- reg [7:0] datInFifo ; // data_in_fifo
- reg flag_data ; // flag_data 采样标志信号
- reg flaInFifo ; // flag_in_fifo
- reg [19:0] cnt_send ; // uart_tx模块发送1byte数据的等待时间。
- reg flaSenEnd ; // 计数器cnt_send计数到CNT_MAX_SEND - 2 拉高一个时钟周期,
- reg flag_out_fifo_reg ;
- // wire signal define
- wire empty ;
- wire full ;
- wire flaOutFif ; // flag_out_fifo
- wire [9:0] usedw ; // fifo中存储的数据量
- wire IDLEtoINSTRUCT ;
- wire INSTRUCTto_READ ;
- wire READtoSEND ;
- wire SENDtoIDLE ;
- /**********************************************************************/
- // // reg signal describe
- /*******状态机采用三段式描述*******/
- // reg [3:0] state_c ;
- // reg [3:0] state_n ;
- always @(posedge sys_clk or negedge sys_rst_n) begin
- if(~sys_rst_n)
- state_c <= IDLE ;
- else
- state_c <= state_n ;
- end
- always @(*) begin
- case (state_c)
- IDLE : if(IDLEtoINSTRUCT)
- state_n <= INSTRUCT ;
- else
- state_n <= IDLE ;
- INSTRUCT : if(INSTRUCTto_READ)
- state_n <= READ ;
- else
- state_n <= INSTRUCT ;
- READ : if(READtoSEND)
- state_n <= SEND ;
- else
- state_n <= READ ;
- SEND : if(SENDtoIDLE)
- state_n <= IDLE ;
- else
- state_n <= SEND ;
- default: state_n <= IDLE ;
- endcase
- end
- assign IDLEtoINSTRUCT = (state_c == IDLE ) && (key_flag) ;
- assign INSTRUCTto_READ = (state_c == INSTRUCT) && (flagBreg) ; // 指令的的最后1byte发送完毕
- assign READtoSEND = (state_c == READ ) && (flag_RSr) ; // 读完想要的最后1byte
- assign SENDtoIDLE = (state_c == SEND ) && (flaSenEnd && empty) ;
- // reg cnt_20_ns ;
- always @(posedge sys_clk or negedge sys_rst_n) begin
- if(~sys_rst_n)
- cnt_20_ns <= 1'b0 ;
- else if(state_c == INSTRUCT || state_c == READ)
- cnt_20_ns <= cnt_20_ns + 1'b1 ;
- else if(state_c != INSTRUCT || state_c != READ)
- cnt_20_ns <= 1'b0 ;
- else
- cnt_20_ns <= 1'b0 ;
- end
- // reg [2:0] cnt_bit ;
- always @(posedge sys_clk or negedge sys_rst_n) begin
- if(~sys_rst_n)
- cnt_bit <=3'd0 ;
- else
- case (state_c)
- IDLE : cnt_bit <=3'd0 ;
- INSTRUCT: if(!cnt_20_ns && sck && cnt_bit == 7)
- cnt_bit <= 3'd0 ;
- else if(!cnt_20_ns && sck)
- cnt_bit <= cnt_bit + 1'b1 ;
- READ : if(!cnt_20_ns && sck && cnt_bit == 7)
- cnt_bit <= 3'd0 ;
- else if(!cnt_20_ns && sck)
- cnt_bit <= cnt_bit + 1'b1 ;
- SEND : cnt_bit <=3'd0 ;
- default : cnt_bit <=3'd0 ;
- endcase
- end
- // reg [10:0] cnt_byte ;
- always @(posedge sys_clk or negedge sys_rst_n) begin
- if(~sys_rst_n)
- cnt_byte <= 4'd0 ;
- else if(cnt_bit == 7 && cnt_byte == CNT_MAX_BYTE - 1 && !cnt_20_ns && sck)
- cnt_byte <= 4'd0 ;
- else if(cnt_bit == 7 && !cnt_20_ns && sck)
- cnt_byte <= cnt_byte + 1'b1 ;
- else
- cnt_byte <= cnt_byte ;
- end
- // reg flag_R_S ;
- // reg flag_b ;
- always @(posedge sys_clk or negedge sys_rst_n) begin
- if(~sys_rst_n) begin
- flag_b <= 1'b0 ;
- flag_R_S <= 1'b0 ;
- end
- else
- case (state_c)
- IDLE : begin
- flag_b <= 1'b0 ;
- flag_R_S <= 1'b0 ;
- end
- INSTRUCT: begin
- if((cnt_byte == NUM_COMD - 1) && (cnt_bit == 7) && !cnt_20_ns && sck)
- flag_b <= 1'b1 ;
- else
- flag_b <= flag_b ;
- flag_R_S <= 1'b0 ;
- end
- READ : begin
- if(cnt_byte == NUM_COMD)
- flag_R_S <= 1'b0 ;
- else if((cnt_byte == CNT_MAX_BYTE - 1) && (cnt_bit == 7) && !cnt_20_ns && sck)
- flag_R_S <= 1'b1 ;
-
- flag_b <= 1'b0 ;
- end
- SEND : begin
- flag_b <= 1'b0 ;
- flag_R_S <= 1'b0 ;
- end
- default : begin
- flag_b <= 1'b0 ;
- flag_R_S <= 1'b0 ;
- end
- endcase
- end
- // reg flagBreg ;
- // reg flag_RSr ;
- always @(posedge sys_clk or negedge sys_rst_n) begin
- if(~sys_rst_n)
- flagBreg <= 1'b0 ;
- else
- flagBreg <= flag_b ;
- end
- always @(posedge sys_clk or negedge sys_rst_n) begin
- if(~sys_rst_n)
- flag_RSr <= 1'b0 ;
- else
- flag_RSr <= flag_R_S ;
- end
- // reg [7:0] datInFifo ; // data_in_fifo
- always @(posedge sys_clk or negedge sys_rst_n) begin
- if(~sys_rst_n)
- datInFifo <= 1'b0 ;
- else if(flag_data)
- datInFifo <= {miso,datInFifo[7:1]}; // 读flash中数据,先传的低位。
- else
- datInFifo <= datInFifo ;
- end
- // reg flag_data ; // flag_data 采样标志信号
- always @(posedge sys_clk or negedge sys_rst_n) begin
- if(~sys_rst_n)
- flag_data <= 1'b0 ;
- else if(state_c == READ) begin
- if(cnt_20_ns && !sck)
- flag_data <= 1'b1 ;
- else
- flag_data <= 1'b0 ;
- end else begin
- flag_data <= 1'b0 ;
- end
- end
- // reg flaInFifo ; // flag_in_fifo
- always @(posedge sys_clk or negedge sys_rst_n) begin
- if(~sys_rst_n)
- flaInFifo <= 1'b0 ;
- else if(state_c == READ && cnt_bit == 7 && flag_data)
- flaInFifo <= 1'b1 ;
- else
- flaInFifo <= 1'b0 ;
- end
- // reg [19:0] cnt_send ; // uart_tx模块发送1byte数据的等待时间。
- always @(posedge sys_clk or negedge sys_rst_n) begin
- if(~sys_rst_n)
- cnt_send <= 20'd0 ;
- else
- if(state_c == SEND) begin
- if(cnt_send == CNT_MAX_SEND - 1)
- cnt_send <= 20'd0 ;
- else
- cnt_send <= cnt_send + 1'b1 ;
- end
- else
- cnt_send <= 20'd0 ;
- end
- // reg flag_out_fifo_reg ;
- always @(posedge sys_clk or negedge sys_rst_n) begin
- if(~sys_rst_n)
- flag_out_fifo_reg <= 1'b0 ;
- else if(flaSenEnd && !empty)
- flag_out_fifo_reg <= 1'b1 ;
- else
- flag_out_fifo_reg <= 1'b0 ;
- end
- // reg flaSenEnd ;
- always @(posedge sys_clk or negedge sys_rst_n) begin
- if(~sys_rst_n)
- flaSenEnd <= 1'b0 ;
- else if(cnt_send == CNT_MAX_SEND - 2)
- flaSenEnd <= 1'b1 ;
- else
- flaSenEnd <= 1'b0 ;
- end
- // output signal describe
- // cs_n ,
- always @(posedge sys_clk or negedge sys_rst_n) begin
- if(~sys_rst_n)
- cs_n <= 1'b1 ;
- else
- case (state_c)
- IDLE : if(key_flag)
- cs_n <= 1'b0 ;
- else
- cs_n <= cs_n ;
- INSTRUCT: cs_n <= cs_n ;
- READ : cs_n <= cs_n ;
- SEND : cs_n <= 1'b1 ;
- default : cs_n <= 1'b1 ;
- endcase
- end
- // sck ,
- always @(posedge sys_clk or negedge sys_rst_n) begin
- if(~sys_rst_n)
- sck <= 1'b0 ;
- else
- case (state_c)
- IDLE : sck <= 1'b0 ;
- INSTRUCT: if(cnt_20_ns)
- sck <= ~sck ;
- else
- sck <= sck ;
- READ : if(cnt_20_ns)
- sck <= ~sck ;
- else
- sck <= sck ;
- SEND : sck <= 1'b0 ;
- default : sck <= 1'b0 ;
- endcase
- end
- // mosi ,
- always @(posedge sys_clk or negedge sys_rst_n) begin
- if(~sys_rst_n) begin
- mosi <= 1'b0 ;
- end else begin
- case (state_c)
- IDLE : mosi <= 1'b0 ;
- INSTRUCT: case (cnt_byte)
- 0 : if(cnt_bit == 0)
- mosi <= COMD_REA[7] ;
- else if(cnt_20_ns && sck)
- mosi <= COMD_REA[7 - cnt_bit] ;
- else
- mosi <= mosi ;
- 1 : if(cnt_bit == 0)
- mosi <= ADDR_SEC[7] ;
- else if(cnt_20_ns && sck)
- mosi <= ADDR_SEC[7 - cnt_bit] ;
- else
- mosi <= mosi ;
- 2 : if(cnt_bit == 0)
- mosi <= ADDR_PAG[7] ;
- else if(cnt_20_ns && sck)
- mosi <= ADDR_PAG[7 - cnt_bit] ;
- else
- mosi <= mosi ;
- 3 : if(cnt_bit == 0)
- mosi <= ADDR_BYT[7] ;
- else if(cnt_20_ns && sck)
- mosi <= ADDR_BYT[7 - cnt_bit] ;
- else
- mosi <= mosi ;
- default : mosi <= 1'b0 ;
- endcase
- READ : mosi <= 1'b0 ;
- SEND : mosi <= 1'b0 ;
- default : mosi <= 1'b0 ;
- endcase
- end
- end
- // po_flag ,
- always @(posedge sys_clk or negedge sys_rst_n) begin
- if(~sys_rst_n)
- po_flag <= 1'b0 ;
- else
- po_flag <= flag_out_fifo_reg ;
- end
- // wire [7:0] po_data ;// 直接连接到fifo的输出端口。
- // */
- /***********************例化FIFO***************************************/
- assign flaOutFif = flag_out_fifo_reg ;
- fifo_1024x8 fifo_1024x8_inst(
- .clock ( sys_clk ) ,
- .data ( datInFifo ) ,
- .rdreq ( flaOutFif ) ,
- .wrreq ( flaInFifo ) ,
- .empty ( empty ) ,
- .full ( full ) ,
- .q ( po_data ) ,
- .usedw ( usedw )
- );
-
- endmodule
- module top (
- input wire sys_clk ,
- input wire sys_rst_n ,
- input wire key_in ,
-
- input wire miso ,
-
- output wire cs_n ,
- output wire sck ,
- output wire mosi ,
- output wire tx
- );
- // 例化间连线
- wire key_flag ;
- wire po_flag ;
- wire [7:0] po_data ;
-
- key_filter key_filter_isnt(
- .sys_clk ( sys_clk ) ,
- .sys_rst_n ( sys_rst_n ) ,
- .key_in ( key_in ) ,
-
- .key_out ( key_flag )
- );
-
- spi spi_inst(
- .sys_clk ( sys_clk ) ,
- .sys_rst_n ( sys_rst_n ) ,
- .key_flag ( key_flag ) ,
-
- .miso ( miso ) ,
-
- .cs_n ( cs_n ) ,
- .sck ( sck ) ,
- .mosi ( mosi ) ,
- .po_flag ( po_flag ) ,
- .po_data ( po_data )
- );
-
- uart_tx uart_tx_isnt(
- .sys_clk ( sys_clk ) ,
- .sys_rst_n ( sys_rst_n ) ,
- .pi_flag ( po_flag ) ,
- .pi_data ( po_data ) ,
-
- .tx ( tx )
- );
-
- endmodule
- module key_filter
- #(
- parameter MAX_CNT_20MS = 20'd100_0000
- )(
- input wire sys_clk ,
- input wire sys_rst_n ,
- input wire key_in ,
- output wire key_out
- );
- reg key_r_0 ;
- reg key_r_1 ;
- wire nege ;
- wire pose ;
- reg [19:00] cnt_20ms ;
- wire add_cnt_20ms ;
- wire end_cnt_20ms ;
- reg add_cnt_flag ;
- // key_r_0 key_r_1
- always @(posedge sys_clk or negedge sys_rst_n) begin
- if(~sys_rst_n) begin
- key_r_0 <= 1'b1 ;
- end else begin
- key_r_0 <= key_in ;
- end
- end
- always @(posedge sys_clk or negedge sys_rst_n) begin
- if(~sys_rst_n) begin
- key_r_1 <= 1'b1 ;
- end else begin
- key_r_1 <= key_r_0 ;
- end
- end
- // nege pose
- assign nege = ~key_r_0 && key_r_1 ;
- assign pose = key_r_0 && ~key_r_1 ;
- // add_cnt_flag
- always @(posedge sys_clk or negedge sys_rst_n) begin
- if(~sys_rst_n) begin
- add_cnt_flag <= 1'b0 ;
- end else begin
- if(nege) begin
- add_cnt_flag <= 1'b1 ;
- end else begin
- if( pose || end_cnt_20ms ) begin
- add_cnt_flag <= 1'b0 ;
- end else begin
- add_cnt_flag <= add_cnt_flag ;
- end
- end
- end
- end
-
- // cnt_20ms add_cnt_20ms end_cnt_20ms
- always @(posedge sys_clk or negedge sys_rst_n) begin
- if(~sys_rst_n) begin
- cnt_20ms <= 20'd0 ;
- end else begin
- if(add_cnt_20ms) begin
- if(end_cnt_20ms) begin
- cnt_20ms <= 20'd0 ;
- end else begin
- cnt_20ms <= cnt_20ms + 20'd1 ;
- end
- end else begin
- cnt_20ms <= 20'd0 ;
- end
- end
- end
- assign add_cnt_20ms = add_cnt_flag ;
- assign end_cnt_20ms = add_cnt_20ms && cnt_20ms == ( MAX_CNT_20MS - 1'b1 ) ;
- // key_out
- // always @(posedge sys_clk or negedge sys_rst_n) begin
- // // always @(*) begin // 这样的话 会综合成 数据选择器
- // if(~sys_rst_n) begin
- // key_out <= 1'b0 ;
- // end else begin
- // if(end_cnt_20ms) begin
- // key_out <= 1'b1 ;
- // end else begin
- // key_out <= 1'b0 ;
- // end
- // end
- // end
- assign key_out = end_cnt_20ms ;
- endmodule
- module uart_tx (
- input wire sys_clk ,
- input wire sys_rst_n ,
- input wire pi_flag ,
- input wire [7:0] pi_data ,
-
- output reg tx
- );
- // parameter
- parameter SUB_1K = 1000 , // 缩减第十位,空闲位的时间。
- CLK_UART = 50_000_000 ,
- BPS = 9600 ;
- localparam MAX_BPS = CLK_UART / BPS ;
-
- // reg signal define
- reg pi_flag_reg1 ;
- reg [ 7:0] pi_data_reg1 ;
- reg work_en ;
- reg [12:0] cnt_bps ;
- reg [ 3:0] cnt_bit ;
- reg bit_flag ;
-
- /**********************************************/
- // reg pi_flag_reg1 ;
- always @(posedge sys_clk or negedge sys_rst_n) begin
- if(~sys_rst_n)
- pi_flag_reg1 <= 1'b0 ;
- else
- pi_flag_reg1 <= pi_flag ;
- end
- // reg pi_data_reg1 ;
- always @(posedge sys_clk or negedge sys_rst_n) begin
- if(~sys_rst_n)
- pi_data_reg1 <= 8'd0 ;
- else
- pi_data_reg1 <= pi_data ;
- end
- // reg work_en ;
- always @(posedge sys_clk or negedge sys_rst_n) begin
- if(~sys_rst_n)
- work_en <= 1'b0 ;
- else if(((cnt_bit == 4'd0) && pi_flag_reg1) || (cnt_bit == 4'd9) && (bit_flag))
- work_en <= ~work_en ;
- else
- work_en <= work_en ;
- end
- // reg [12:0] cnt_bps ;
- always @(posedge sys_clk or negedge sys_rst_n) begin
- if(~sys_rst_n)
- cnt_bps <= 13'd0 ;
- else if(work_en && cnt_bps == MAX_BPS - 1) // 波特率计数器计数到最大值。
- cnt_bps <= 13'd0 ;
- else if(work_en)
- cnt_bps <= cnt_bps + 1'b1 ;
- else
- cnt_bps <= 13'd0 ;
- end
- // reg bit_flag ;
- always @(posedge sys_clk or negedge sys_rst_n) begin
- if(~sys_rst_n)
- bit_flag <= 1'b0 ;
- else if((work_en && cnt_bps == MAX_BPS - 1) || (work_en && cnt_bps == MAX_BPS - SUB_1K && cnt_bit == 9))
- bit_flag <= 1'b1 ;
- else
- bit_flag <= 1'b0 ;
- end
- // reg [ 3:0] cnt_bit ;
- always @(posedge sys_clk or negedge sys_rst_n) begin
- if(~sys_rst_n)
- cnt_bit <= 4'd0 ;
- else if(work_en && bit_flag && cnt_bit == 4'd9) // 传递完第十位,位计数器要归零。
- cnt_bit <= 4'd0 ;
- else if(work_en && bit_flag)
- cnt_bit <= cnt_bit + 1'b1 ;
- else if(work_en)
- cnt_bit <= cnt_bit ;
- else
- cnt_bit <= 4'd0 ;
- end
- /****************************************/
- // output signal
- // tx
- always @(posedge sys_clk or negedge sys_rst_n) begin
- if(~sys_rst_n)
- tx <= 1'b1 ;
- else if(work_en) begin
- case (cnt_bit)
- 0 : tx <= 1'b0 ;
- 1 : tx <= pi_data_reg1[0] ; // 先发最低位。
- 2 : tx <= pi_data_reg1[1] ;
- 3 : tx <= pi_data_reg1[2] ;
- 4 : tx <= pi_data_reg1[3] ;
- 5 : tx <= pi_data_reg1[4] ;
- 6 : tx <= pi_data_reg1[5] ;
- 7 : tx <= pi_data_reg1[6] ;
- 8 : tx <= pi_data_reg1[7] ;
- 9 : tx <= 1'b1 ;
- default: tx <= 1'b1 ;
- endcase
- end else begin
- tx <= 1'b1 ;
- end
- end
- endmodule
- `timescale 1ns/1ns
-
- module test_spi();
- reg sys_clk ;
- reg sys_rst_n ;
- reg key_flag ;
- wire miso ;
- wire cs_n ;
- wire sck ;
- wire mosi ;
- wire po_flag ;
- wire [7:0] po_data ;
-
- defparam memory.mem_access.initfile = "initmemory.txt";
- defparam spi_inst.CNT_MAX_SEND = 100 ;
- m25p16 memory (
- .c ( sck ) ,
- .data_in ( mosi ) ,
- .s ( cs_n ) ,
- .w ( 1'b1 ) ,
- .hold ( 1'b1 ) ,
- .data_out ( miso )
- );
- spi spi_inst(
- .sys_clk ( sys_clk ) ,
- .sys_rst_n ( sys_rst_n ) ,
- .key_flag ( key_flag ) ,
-
- .miso ( miso ) ,
-
- .cs_n ( cs_n ) ,
- .sck ( sck ) ,
- .mosi ( mosi ) ,
- .po_flag ( po_flag ) ,
- .po_data ( po_data )
- );
-
- parameter CYCLE = 20 ;
-
- initial begin
- sys_clk = 1'b1 ;
- sys_rst_n <= 1'b0 ;
- key_flag <= 1'b0 ;
- #(CYCLE) ;
- sys_rst_n <= 1'b1 ;
- #(CYCLE*10) ;
- #(CYCLE * 100) ;
- key_flag <= 1'b1 ;
- #(CYCLE) ;
- key_flag <= 1'b0 ;
- end
- always #(CYCLE/2) sys_clk = ~sys_clk ;
-
- endmodule

上版验证通过。