• FPGA——SPI总线控制flash(2)(含代码)


    强烈建议先看完下面两篇再看这一篇: 
    FPGA——SPI总线详解(概念)_居安士的博客-CSDN博客_fpga芯片
    FPGA——SPI总线控制flash(1)(含代码)_居安士的博客-CSDN博客

    在(1)中详细介绍了写使能,读状态,擦除三种操作,接下来介绍如何使用SPI总线对flash进行读写

    目录

    flash页写

    flash页读


    flash页写

    页写指令允许在先前擦除(FFh)的存储器位置编程一个字节到 256个字节(一页)的数据。 在器件接受页写指令(状态寄存器位 WEL=1)之前,必须执行写使能指令。 该指令通过将 /CS 引脚驱动为低电平,然后将指令代码“02h”后跟一个 24 位地址 (A23-A0) 和至少一个数据字节移入 DI 引脚来启动。 当数据被发送到设备时,/CS 引脚必须在指令的整个长度内保持低电平。

    页写模块框图如下:

    先向fifo写入数据,fifo写完了之后,再从fifo里面读数据(start_write),启动页写操作

    首先发送02H的指令,后面是24位数据首地址,后面至多可以跟256个字节(256*8位)的数据

    ps:页写需要时间,需要设置定时器,保证页写时间结束之后(3ms)停止页写

    输入输出信号:

    名称

    输入输出

    位宽

    解释

    start_write

    input

    1

    启动页写

    brust_length

    input

    9(256个字节)

    突发长度:写入数据的长度

    write_addr

    input

    24

    页写数据24位首地址

    clk_wr

    input

    1

    fifo写入时钟

    wr_en

    input

    1

    fifo写使能信号

    din

    input

    8

    fifo输入数据

    wr_fifo_empty

    output

    1

    fifo空

    wr_fifo_full

    ouput

    1

    fifo满

    spi_cs

    output

    1

    spi片选线

    spi_clk

    output

    1

    spi时钟线

    spi_dout

    output

    1

    spi输出

    mux_write

    output

    1

    写总线请求

    mux_write_done

    input

    1

    写总线应答

    write_en

    output

    1

    启动计时器

    time_done

    input

    1

    计时器完成

    write_done

    output

    1

    页写操作完成

    flash页写流程图如下:

     页写过程:

    0(初始状态):把页写突发长度和页写地址寄存

    1(指令解析):把02h给指令寄存器

    2(请求总线):请求打开总线

    3(发送指令1):把指令最高位给spi_dout,移完8位把地址最高位给spi_dout

    4(发送指令2):移位8位指令

    5(发送地址1):把地址最高位给spi_dout,移完24位把数据最高位给spi_dout

    6(发送地址2):移位24位地址

    7(发送数据1):把数据最高位给spi_dout,移完8位把cnt_byte加一;

                                  如果cnt_byte小于突发长度-1,启动fifo读使能

                                  否则,关闭读使能,把下一个字节的数据给spi_dout

    8(发送数据2):移位8位数据

    9(计数发送数据):判断cnt_byte是否等于突发长度

    10(停止):请求总线停止

    11(等待总线应答2):等待总线同意停止

    12(等待页写时间到):3ms的延时

    13(页写完成)

    页写代码如下:

    1. module write_top(
    2. input clk ,
    3. input clk_wr ,//fifo时钟
    4. input reset ,
    5. input start_write ,//启动页写
    6. //fifo部分驱动接口
    7. input [8:0]brust_length,//突发长度
    8. input [23:0]write_addr ,//初始地址
    9. input wr_fifo_en ,//写使能
    10. input [7:0]din ,//写数据
    11. output wr_fifo_empty ,//fifo空
    12. output wr_fifo_full ,//fifo满
    13. //总线接口
    14. output reg spi_cs ,//spi片选
    15. output reg spi_clk ,//spi时钟
    16. output reg spi_dout ,//spi输出
    17. output reg mux_write ,//请求总线
    18. input mux_write_done ,//总线应答
    19. output reg write_done ,//页写完成
    20. //计时器
    21. input time_done ,//计时完成
    22. output reg write_en //启动计时
    23. );
    24. //例化页写延时
    25. erase_time inst_erase_time(
    26. .clk (clk),
    27. .reset (reset),
    28. .write_en (write_en),//页写计时
    29. .erase_en (),//擦除计时
    30. .erase_cmd(),//擦除模式选择
    31. .time_done(time_done)
    32. );
    33. //例化FIFO
    34. reg rd_en ;//fifo读使能
    35. wire[7:0] dout ;//fifo输出
    36. FIFO_wr inst_FIFO_wr (
    37. .rst(reset), // input wire rst
    38. .wr_clk(clk_wr), // input wire wr_clk
    39. .rd_clk(clk), // input wire rd_clk
    40. .din(din), // input wire [7 : 0] din
    41. .wr_en(wr_fifo_en), // input wire wr_en
    42. .rd_en(rd_en), // input wire rd_en
    43. .dout(dout), // output wire [7 : 0] dout
    44. .full(wr_fifo_full), // output wire full
    45. .empty(wr_fifo_empty), // output wire empty
    46. .wr_rst_busy(wr_rst_busy), // output wire wr_rst_busy
    47. .rd_rst_busy(rd_rst_busy) // output wire rd_rst_busy
    48. );
    49. reg [7:0] vaild_cmd ;//指令寄存器
    50. reg [23:0]write_addr_reg ;//地址寄存器
    51. reg [7:0] write_data ;//数据寄存器
    52. reg [8:0] brust_length_reg;//突发长度寄存器
    53. reg [4:0] cnt_bit ;//位计数器
    54. reg [8:0] cnt_byte ;//字节计数器
    55. reg [3:0]state;//定义状态机
    56. always@(posedge clk)begin
    57. if(reset)begin
    58. spi_cs <=1'd1;
    59. spi_clk <=1'd0;
    60. spi_dout <=1'd1;
    61. write_done <=1'd0;
    62. write_en <=1'd0;
    63. vaild_cmd <=8'd0;
    64. write_addr_reg <=24'd0;
    65. write_data <=8'd0;
    66. brust_length_reg<=9'd0;
    67. cnt_bit <=5'd0;
    68. cnt_byte <=9'd0;
    69. mux_write <=1'd0;
    70. state<=4'd0;
    71. end
    72. else begin
    73. case(state)
    74. 4'd0:begin
    75. if(start_write)begin
    76. state<=4'd1;
    77. write_addr_reg<=write_addr;
    78. brust_length_reg<=brust_length;
    79. end
    80. else begin
    81. state<=4'd0;
    82. end
    83. end
    84. 4'd1:begin
    85. vaild_cmd<=8'h02;
    86. state<=4'd2;
    87. end
    88. 4'd2:begin
    89. mux_write<=1'd1;
    90. if(mux_write_done)begin
    91. state<=4'd3;
    92. write_en<=1'd1;//启动延时计时
    93. end
    94. else begin
    95. state<=4'd2;
    96. end
    97. end
    98. 4'd3:begin
    99. if(cnt_bit==5'd8)begin
    100. cnt_bit<=5'd0;
    101. spi_cs<=1'd0;
    102. spi_clk<=1'd0;
    103. spi_dout<=write_addr_reg[23];//提前准备好地址
    104. state<= 4'd6;
    105. end
    106. else begin
    107. cnt_bit<=cnt_bit+5'd1;
    108. spi_cs<=1'd0;
    109. spi_clk<=1'd0;
    110. spi_dout<=vaild_cmd[7];
    111. state<= 4'd4;
    112. end
    113. end
    114. 4'd4:begin
    115. state<= 4'd3;
    116. spi_cs<=1'd0;
    117. spi_clk<=1'd1;
    118. vaild_cmd<={vaild_cmd[6:0],vaild_cmd[7]};
    119. end
    120. 4'd5:begin
    121. if(cnt_bit==5'd23)begin
    122. cnt_bit<=5'd0;
    123. spi_cs<=1'd0;
    124. spi_clk<=1'd0;
    125. spi_dout<=write_data[7];//提前准备好数据
    126. state<= 4'd7;
    127. end
    128. else begin
    129. cnt_bit<=cnt_bit+5'd1;
    130. spi_cs<=1'd0;
    131. spi_clk<=1'd0;
    132. spi_dout<=write_addr_reg[23];
    133. state<= 4'd6;
    134. end
    135. end
    136. 4'd6:begin
    137. state<= 4'd5;
    138. spi_cs<=1'd0;
    139. spi_clk<=1'd1;
    140. write_addr_reg<={write_addr_reg[22:0],write_addr_reg[23]};
    141. end
    142. 4'd7:begin
    143. if(cnt_bit==5'd7)begin
    144. cnt_bit<=5'd0;
    145. cnt_byte<=cnt_byte+9'd1;//字节计数器++
    146. spi_cs<=1'd0;
    147. spi_clk<=1'd0;
    148. spi_dout<=dout[7];//提前准备fifo输出字节最高位
    149. state<=4'd9 ;
    150. if(cnt_byte1)begin//是否达到突发长度
    151. rd_en<=1'd1;
    152. write_data<=dout;//更新fifo输出的字节
    153. end
    154. else begin
    155. rd_en<=1'd0;
    156. end
    157. end
    158. else begin
    159. cnt_bit<=cnt_bit+5'd1;
    160. spi_cs<=1'd0;
    161. spi_clk<=1'd0;
    162. spi_dout<=write_data[7];
    163. state<=4'd8;
    164. end
    165. end
    166. 4'd8:begin
    167. spi_cs<=1'd0;
    168. spi_clk<=1'd1;
    169. write_data<={write_data[6:0],write_data[7]};
    170. state<=4'd7;
    171. end
    172. 4'd9:begin
    173. if(cnt_byte==brust_length_reg)begin
    174. cnt_bit<=5'd0;
    175. cnt_byte<=9'd0;
    176. spi_cs<=1'd1;
    177. spi_clk<=1'd0;
    178. spi_dout<=1'd1;
    179. rd_en<=1'd0;
    180. state<=4'd10;
    181. end
    182. else begin
    183. state<=4'd7;
    184. spi_cs<=1'd0;
    185. spi_clk<=1'd1;//clk连续
    186. write_data<={write_data[6:0],write_data[7]};//最高位已经发送,因此需要移位
    187. end
    188. end
    189. 4'd10:begin
    190. mux_write<=1'd0;
    191. state<=4'd11;
    192. end
    193. 4'd11:begin
    194. if(mux_write_done)begin
    195. state<=4'd12;
    196. write_en<=1'd0;
    197. end
    198. else begin
    199. state<=4'd11;
    200. end
    201. end
    202. 4'd12:begin
    203. if(time_done)begin//延时结束
    204. state<=4'd13;
    205. end
    206. else begin
    207. state<=4'd12;
    208. end
    209. end
    210. 4'd13:begin
    211. write_done<=1'd1;
    212. state<=4'd0;
    213. end
    214. endcase
    215. end
    216. end
    217. endmodule

    关于FIFO的操作方法可以看这篇(1条消息) FPGA存储器(FIFO+RAM+ROM)存储实战_居安士的博客-CSDN博客_fpga的存储器资源

    TB文件里面完成fifo的写,仿真代码如下:

    1. module TB_write_top(
    2. );
    3. reg clk ;
    4. reg reset ;
    5. reg start_write ;//启动页写
    6. reg [8:0]brust_length;//突发长度
    7. reg [23:0]write_addr ;//初始地址
    8. //fifo部分驱动接口
    9. reg clk_wr ;//fifo时钟
    10. reg wr_fifo_en ;//写使能
    11. reg [7:0]din ;//写数据
    12. wire wr_fifo_empty ;//fifo空
    13. wire wr_fifo_full ;//fifo满
    14. //总线接口
    15. wire spi_cs ;//spi片选
    16. wire spi_clk ;//spi时钟
    17. wire spi_dout ;//spi输出
    18. wire mux_write ;//请求总线
    19. reg mux_write_done ;//总线应答
    20. wire write_done ;//页写完成
    21. //计时器
    22. wire time_done ;//计时完成
    23. wire write_en ;//启动计时
    24. write_top inst_write_top(
    25. .clk (clk) ,
    26. .reset (reset) ,
    27. .start_write (start_write) ,//启动页写
    28. //fifo部分驱动接口
    29. .brust_length (brust_length) ,//突发长度
    30. .write_addr (write_addr) ,//初始地址
    31. .clk_wr (clk_wr) ,//fifo时钟
    32. .wr_fifo_en (wr_fifo_en) ,//写使能
    33. .din (din) ,//写数据
    34. .wr_fifo_empty (wr_fifo_empty) ,//fifo空
    35. .wr_fifo_full (wr_fifo_full) ,//fifo满
    36. //总线接口
    37. .spi_cs (spi_cs) ,//spi片选
    38. .spi_clk (spi_clk) ,//spi时钟
    39. .spi_dout (spi_dout) ,//spi输出
    40. .mux_write (mux_write) ,//请求总线
    41. .mux_write_done (mux_write_done) ,//总线应答
    42. .write_done (write_done) ,//页写完成
    43. //计时器
    44. .time_done (time_done) ,//计时完成
    45. .write_en (write_en) //启动计时
    46. );
    47. initial begin
    48. clk=0;
    49. clk_wr=0;
    50. reset=1;
    51. start_write <= 1'b0;
    52. brust_length<= 9'd0;
    53. write_addr <= 24'd0;
    54. #1000;
    55. reset=0; //复位信号
    56. #20000;
    57. start_write <= 1'b1;
    58. brust_length<= 9'd255;
    59. write_addr <= 24'h010203;
    60. #40;
    61. start_write <= 1'b0;
    62. brust_length<= 9'd0;
    63. write_addr <= 24'd0;
    64. end
    65. always #20 clk=~clk;
    66. always #20 clk_wr=~clk_wr;
    67. //写FIFO
    68. reg [7:0]count_wait;//FIFO复位需要时间
    69. reg [8:0]count_wren;
    70. always @(posedge clk_wr)begin
    71. if(reset)begin
    72. count_wait<=8'd0;
    73. count_wren<=9'd0;
    74. wr_fifo_en<=1'b0;
    75. din<=8'd0;
    76. end
    77. else if(count_wait <= 8'd20) begin//fifo复位时间到了再进行下面程序
    78. count_wait<=count_wait+8'd1;
    79. end
    80. else if(count_wren>=9'd255)begin
    81. count_wren<=count_wren;
    82. wr_fifo_en<=1'b0; //fifo写使能=0
    83. din<=8'd0;//数据清零
    84. end
    85. else begin
    86. count_wren<=count_wren+9'b1;//计数器++
    87. wr_fifo_en<=1'b1; //fifo写使能=1
    88. din<=din+8'b1; //数据++
    89. end
    90. end
    91. reg [2:0] state;
    92. always @(posedge clk)begin
    93. if(reset)begin
    94. state <= 3'd0;
    95. mux_write_done<=1'b0;
    96. end
    97. else begin
    98. case (state)
    99. 3'd0:begin
    100. if(mux_write)begin
    101. state <= 3'd1;
    102. mux_write_done<=1'b1;
    103. end
    104. else begin
    105. state <= 3'd0;
    106. mux_write_done<=1'b0;
    107. end
    108. end
    109. 3'd1:begin
    110. if(!mux_write)begin
    111. state <= 3'd2;
    112. mux_write_done<=1'b1;
    113. end
    114. else begin
    115. state <= 3'd1;
    116. mux_write_done<=1'b0;
    117. end
    118. end
    119. 3'd2:begin
    120. mux_write_done<=1'b0;
    121. state <= 3'd0;
    122. end
    123. default :state <= 3'd0;
    124. endcase
    125. end
    126. end

    仿真结果如下:

     首先向FIFO的din写入1~255数据

    在start_write=1时把突发长度,地址寄存

    把页写指令移位输出

    指令输出完成后,把页写地址移位输出

    地址输出完成后,把dout移位输出

    flash页读

    页读指令(03h)允许从存储器中顺序读取一个或多个数据字节。 该指令通过将 /CS 引脚驱动为低电平,然后将指令代码“03h”后跟一个 24 位地址(A23-A0)移入 DI 引脚来启动。时序如下:

    发送完地址之后,总线会输出spi_din数据,高位先发,把总线输出的spi_din缓存到FIFO里

    页读模块框图如下:

    输入输出信号: 

    名称

    输入/输出

    位宽

    解释

    start_read

    input

    1

    开始页读

    read_addr

    input

    24

    读地址

    brust_length

    input

    9

    突发长度

    rd_fifo_en

    input

    1

    fifo读使能

    rd_fifo_data

    output

    8

    fifo读出的数据

    rd_fifo_empty

    output

    1

    fifo空

    rd_fifo_full

    output

    1

    fifo满

    spi_cs

    output

    1

    片选线

    spi_clk

    output

    1

    时钟线

    spi_dout

    output

    1

    spi输出

    spi_din

    input

    1

    spi输入

    mux_read

    output

    1

    请求总线

    mux_read_done

    input

    1

    总线应答

    read_done

    output

    1

    页读完成

     流程图如下:

    0(初始状态):页写启动信号=1时,把读地址和突发长度寄存

    1(指令解析):把指令03h输入

    2(请求开放总线):请求总线开放,当总线应答后跳转

    3(发送指令1):把指令最高位给spi_dout,cnt_bit+1,跳转发送指令2;当cnt_bit==8时,把地址最高位给spi_dout,跳转发送地址2

    4(发送指令2):8位指令进行移位,跳转发送指令1

    5(发送地址1):把地址最高位给spi_dout,cnt_bit+1,跳转发送地址2;当cnt_bit==8时,跳转接收2

    6(发送指令2):把24位地址进行移位,跳转发送地址1

    7(接收1):cnt_bit+1,跳转接收2;当cnt_bit==8,cnt_byte+1,fifo写使能打开,跳转计算模块

    8(接收2):把读数据使能打开,跳转接收1

    9(计算):判断cnt_byte是否等于突发长度

    10(停止页读):请求总线停止

    11(请求总线停止):等待总线应答后跳转

    12(页读完成):read_done=1

    编写代码如下:

    1. module read_top(
    2. input clk ,
    3. input reset ,
    4. input rd_clk ,
    5. input start_read ,//开始页读
    6. input [23:0] read_addr , //页读地址
    7. input [8:0] brust_length ,//突发长度
    8. input rd_fifo_en ,//fifo读使能
    9. output [7:0] rd_fifo_data ,//从fifo读出的数据
    10. output rd_fifo_empty ,
    11. output rd_fifo_full ,
    12. output reg spi_cs ,
    13. output reg spi_clk ,
    14. output reg spi_dout ,
    15. input spi_din ,
    16. output reg mux_read ,
    17. input mux_read_done ,
    18. output reg read_done
    19. );
    20. //例化fifo
    21. reg wr_en;
    22. reg [7:0] valid_data ;//读出的8位数据
    23. fifo_rd fifo_rd (
    24. .wr_clk(clk), // input wire wr_clk
    25. .rd_clk(rd_clk), // input wire rd_clk
    26. .din(valid_data), // input wire [7 : 0] din
    27. .wr_en(wr_en), // input wire wr_en
    28. .rd_en(rd_fifo_en), // input wire rd_en
    29. .dout(rd_fifo_data), // output wire [7 : 0] dout
    30. .full(rd_fifo_full), // output wire full
    31. .empty(rd_fifo_empty) // output wire empty
    32. );
    33. reg [7:0] cnt_bit ;
    34. reg [7:0] cnt_byte ;
    35. reg [7:0] valid_cmd ;//页读指令03h
    36. reg [23:0] read_addr_reg ;//页读地址
    37. reg [8:0] brust_length_reg ;//突发长度
    38. //状态机
    39. reg [4:0] state;
    40. always@(posedge clk)begin
    41. if(reset)begin
    42. spi_cs <=1'd1;
    43. spi_clk <=1'd0;
    44. spi_dout <=1'd1;
    45. cnt_bit <=8'd0;
    46. cnt_byte <=8'd0;
    47. read_done <=1'd0;
    48. valid_cmd <=8'd0 ;
    49. read_addr_reg <=24'd0 ;
    50. brust_length_reg<= 9'd0 ;
    51. mux_read<=1'd0;
    52. wr_en<=1'd0;
    53. valid_data<=8'd0;
    54. state<=4'd0;
    55. end
    56. else begin
    57. case(state)
    58. 4'd0:begin
    59. if(start_read)begin
    60. state<=4'd1;
    61. read_addr_reg<=read_addr;
    62. brust_length_reg<=brust_length;
    63. end
    64. else begin
    65. state<=4'd0;
    66. end
    67. end
    68. 4'd1:begin
    69. valid_cmd<=8'h03;
    70. state<=4'd2;
    71. end
    72. 4'd2:begin
    73. mux_read<=1'd1;
    74. if(mux_read_done)begin
    75. state<=4'd3;
    76. end
    77. else begin
    78. state<=4'd2;
    79. end
    80. end
    81. 4'd3:begin
    82. if(cnt_bit==8'd8)begin
    83. cnt_bit<=8'd0;
    84. spi_cs <=1'd0;
    85. spi_clk <=1'd0;
    86. spi_dout <=read_addr_reg[23];
    87. state<=4'd6;
    88. end
    89. else begin
    90. cnt_bit<=cnt_bit+8'd1;
    91. spi_cs <=1'd0;
    92. spi_clk <=1'd0;
    93. spi_dout <=valid_cmd[7];
    94. state<=4'd4;
    95. end
    96. end
    97. 4'd4:begin
    98. spi_cs <=1'd0;
    99. spi_clk <=1'd1;
    100. valid_cmd <={valid_cmd[6:0],valid_cmd[7]};
    101. state<=4'd3;
    102. end
    103. 4'd5:begin
    104. if(cnt_bit==8'd23)begin
    105. cnt_bit<=8'd0;
    106. spi_cs <=1'd0;
    107. spi_clk <=1'd0;
    108. spi_dout <=1'd1;
    109. state<=4'd7;
    110. end
    111. else begin
    112. cnt_bit<=cnt_bit+8'd1;
    113. spi_cs <=1'd0;
    114. spi_clk <=1'd0;
    115. spi_dout <=read_addr_reg[23];
    116. state<=4'd6;
    117. end
    118. end
    119. 4'd6:begin
    120. spi_cs <=1'd0;
    121. spi_clk <=1'd1;
    122. read_addr_reg <={read_addr_reg[22:0],read_addr_reg[23]};
    123. state<=4'd5;
    124. end
    125. 4'd7:begin
    126. if(cnt_bit==8'd7)begin
    127. cnt_byte<=cnt_byte+8'd1;
    128. spi_cs<=1'd0;
    129. spi_clk<=1'd0;
    130. cnt_bit<=8'd0;
    131. wr_en <=1'd1;//开启写使能,valid_data给fifo的din
    132. state<=4'd9;
    133. end
    134. else begin
    135. cnt_bit<=cnt_bit+8'd1;
    136. spi_cs <=1'd0;
    137. spi_clk <=1'd0;
    138. state<=4'd8;
    139. end
    140. end
    141. 4'd8:begin
    142. spi_cs <=1'd0;
    143. spi_clk <=1'd1;
    144. valid_data<={valid_data[6:0],spi_din};//把总线输出的数据移位进valid_data
    145. state<=4'd7;
    146. end
    147. 4'd9:begin
    148. if(cnt_byte==brust_length_reg)begin
    149. cnt_byte<=8'd0;
    150. spi_cs<=1'd1;
    151. spi_clk<=1'd0;
    152. cnt_bit<=8'd0;
    153. wr_en <=1'd0;
    154. state<=4'd10;
    155. end
    156. else begin
    157. spi_cs<=1'd0;
    158. spi_clk<=1'd1;
    159. valid_data<={valid_data[6:0],spi_din};//把总线输出的数据移位进valid_data
    160. state<=4'd7;
    161. end
    162. end
    163. 4'd10:begin
    164. mux_read<=1'd0;
    165. state<=4'd11;
    166. end
    167. 4'd11:begin
    168. if(mux_read_done)begin
    169. state<=4'd12;
    170. end
    171. else begin
    172. state<=4'd11;
    173. end
    174. end
    175. 4'd12:begin
    176. read_done <=1'd0;
    177. state<=4'd0;
    178. end
    179. endcase
    180. end
    181. end
    182. endmodule

    编写TB代码:

    1. module TB_read_top(
    2. );
    3. reg clk ;
    4. reg reset ;
    5. reg rd_clk ;
    6. reg start_read ;//开始页读
    7. reg [23:0] read_addr ; //页读地址
    8. reg [8:0] brust_length ;//突发长度
    9. reg rd_fifo_en ;//fifo读使能
    10. wire [7:0] rd_fifo_data ;//从fifo读出的数据
    11. wire rd_fifo_empty ;
    12. wire rd_fifo_full ;
    13. wire spi_cs ;
    14. wire spi_clk ;
    15. wire spi_dout ;
    16. reg spi_din ;
    17. wire mux_read ;
    18. reg mux_read_done ;
    19. wire read_done ;
    20. read_top inst_read_top(
    21. .clk (clk) ,
    22. .reset (reset) ,
    23. .rd_clk (rd_clk) ,
    24. .start_read (start_read) ,//开始页读
    25. .read_addr (read_addr) , //页读地址
    26. .brust_length (brust_length) ,//突发长度
    27. .rd_fifo_en (rd_fifo_en) ,//fifo读使能
    28. .rd_fifo_data (rd_fifo_data) ,//从fifo读出的数据
    29. .rd_fifo_empty (rd_fifo_empty) ,
    30. .rd_fifo_full (rd_fifo_full) ,
    31. .spi_cs (spi_cs) ,
    32. .spi_clk (spi_clk) ,
    33. .spi_dout (spi_dout) ,
    34. .spi_din (spi_din) ,
    35. .mux_read (mux_read) ,
    36. .mux_read_done (mux_read_done) ,
    37. .read_done (read_done)
    38. );
    39. initial begin
    40. clk=0;
    41. rd_clk=0;
    42. reset=1;
    43. start_read<=1'd0;
    44. #100
    45. reset=0;
    46. start_read<=1'd1;
    47. #40
    48. start_read<=1'd0;
    49. end
    50. always #20 clk=~clk;
    51. always #20 rd_clk=~rd_clk;
    52. //状态机
    53. reg [1:0]state;
    54. always@(posedge clk)begin
    55. if(reset)begin
    56. start_read<=1'd0;
    57. read_addr<=24'd0;
    58. brust_length<=9'd0;
    59. spi_din<=1'd0;
    60. state<=2'd0;
    61. end
    62. else begin
    63. spi_din<=~spi_din;
    64. case(state)
    65. 2'd0:begin
    66. read_addr<=24'h123456;
    67. brust_length<=9'd10;
    68. if(mux_read)begin
    69. mux_read_done<=1'd1;
    70. state<=2'd1;
    71. end
    72. end
    73. 2'd1:begin
    74. if(!mux_read)begin
    75. mux_read_done<=1'd1;
    76. state<=2'd2;
    77. end
    78. end
    79. 2'd2:begin
    80. start_read<=1'd0;
    81. read_addr<=24'h0;
    82. brust_length<=9'd0;
    83. state<=2'd3;
    84. end
    85. endcase
    86. end
    87. end
    88. endmodule

    仿真结果如下:

    打拍+寄存

    发送指令

    发送地址

     

  • 相关阅读:
    JavaScript基础与变量
    分布式机器学习:逻辑回归的并行化实现(PySpark)
    使用singularity本地部署wandb
    【excel技巧】Excel表格里的图片如何批量调整大小?
    QT日志类SimpleQtLogger的简单记录
    <Rust><iced>基于rust使用iced库构建GUI实例:图片的格式转换程序
    Seata的四种模式
    C# GetMethod 方法应用实例
    记录一次某MFC软件算法逆向之旅
    Elasticsearch与Kibana安装
  • 原文地址:https://blog.csdn.net/weixin_46188211/article/details/125926506