当前位置:   article > 正文

三大通信协议(3)SPI——flash擦除实验_扇区擦除

扇区擦除

目录

一、知识储备

二、M25P16时序手册

三、实例

     1.全擦除实验

    2.扇区擦除实验

    3.上板验证

总结


、知识储备

       在编写完Verilog程序后,需要将程序下载到硬件FPGA中进行上板验证,通常有两种下载方式:1.直接生成.sof文件,通过JTAG接口下载到FPGA中,这种方式下载速度较快,操作简单,但是由于它是将程序直接烧录到FPGA内部的SRAM中,因此,断电后程序自动丢失。2.通过转换,将生成的.sof文件转换为.jic文件,同样通过JTAG接口下载到FPGA中,这种方式虽然下载速度较慢,但是它是将编写的程序固化到FPGA的外部flash中,断电后程序不丢失,重新上电后,FPGA从外部的flash中读取烧录的程序到内部的SRAM中,重新执行。

      如果要对flash中的程序进行擦除,通常有两种方式,一种是直接在程序下载的页面设置,如下图所示;另一种是通过编写擦除程序,对flash内部程序进行擦除。

      flash擦除有两种:全擦除和扇区擦除。全擦除是对flash内部所有扇区进行擦除,扇区擦除是对某个扇区内存放的程序进行擦除,最大只能擦除一个扇区。

     以黑金的开发板EP4CE6F17C8为例,外部的flash芯片为M25P16,存储大小为16Mbite,内部共有32个扇区,每个扇区为512K,而每个扇区内部又有256页,每页为256个字节。即16Mbite=(256*8)*256*32 = 16Mbite


二、M25P16时序手册

       首先给出M25P16对应的指令,本实验只关注WREN、SE、BE三个指令,如下图所示,WREN是写使能指令、SE是扇区擦除指令、BE是全擦除指令。

      下边是写使能指令WREN对应的时序逻辑图,CS片选信号拉低后,SCLK输出时钟信号,SDI对应输出指令信息,分别对应8个bite位0000_0110。

     下边是全擦除指令SE对应的时序图,同样,在输出写使能指令后,紧跟着输出全擦除指令,SDIO对应输出指令信息,分别对应8个bite位1100_0111。

        下边是扇区擦除BE对应的时序图。如果是扇区擦除,同样也是先输出写使能指令,随后输出扇区擦除指令,如下图,SDI首先输出扇区擦除的指令信息,然后紧跟着输出三个字节的地址信息,分别对应扇区地址、页地址、字节地址。

三、实例

     1.全擦除实验

           外界输入一个全擦除的按键信号,FPGA检测到该标志信号对flash中的数据进行全擦除操作。下边给系统框图。

              

               

       下边是编写全擦除模块程序的时序图,检测到按键信号后,先等待一段时间(等待32个时钟周期),再发送写使能指令,发送完写使能指令后同样等待32个系统时钟周期后,再发送全擦除指令。

       根据上述时序图,可以写出下列Verilog代码

  1. module flash_all(
  2. input sclk,
  3. input rst_n,
  4. input key_flag,
  5. output reg cs_n,
  6. output reg sck,
  7. output reg sdi
  8. );
  9. //定义状态机的四个状态
  10. parameter IDLE = 4'b0001;
  11. parameter WREN = 4'b0010;
  12. parameter DELAT= 4'b0100;
  13. parameter BE = 4'b1000;
  14. parameter WREN_ORDER = 8'h06;//写允许的命令字
  15. parameter BE_ORDER = 8'hc7;//扇区擦除的命令字
  16. //parameter SE_ADDR = 24'h00_01_02;//擦除扇区的地址
  17. reg [ 3:0] state;//状态机的状态
  18. reg [ 4:0] cnt_32;//对系统时钟计数,两次命令字之间的延迟时间
  19. reg [ 2:0] cnt_state;//WREN计数三次,中间一次进行数据传输,SE状态计数6次,中间4次进行数据传输
  20. reg [ 1:0] cnt_4;//生成sck的时钟计数器,sck=12.5M
  21. reg [ 4:0] bit_cnt;
  22. always @(posedge sclk or negedge rst_n)
  23. if(rst_n == 1'b0)
  24. cs_n <= 1'b1;
  25. else if(key_flag == 1'b1)
  26. cs_n <= 1'b0;
  27. else if(state == WREN && cnt_32 == 'd31 && cnt_state == 'd2)
  28. cs_n <= 1'b1;
  29. else if(state == DELAT && cnt_32 == 'd31)
  30. cs_n <= 1'b0;
  31. else if(state == BE && cnt_32 == 'd31 && cnt_state == 'd2)
  32. cs_n <= 1'b1;
  33. else
  34. cs_n <= cs_n;
  35. always @(posedge sclk or negedge rst_n)
  36. if(rst_n == 1'b0)
  37. state <= IDLE;
  38. else case(state)
  39. IDLE:if(key_flag == 1'b1)
  40. state <= WREN;
  41. else
  42. state <= state;
  43. WREN:if(cnt_32 == 'd31 && cnt_state == 'd2)
  44. state <= DELAT;
  45. else
  46. state <= state;
  47. DELAT:if(cnt_32 == 'd31)
  48. state <= BE;
  49. else
  50. state <= state;
  51. BE :if(cnt_32 == 'd31 && cnt_state == 'd2)
  52. state <= IDLE;
  53. else
  54. state <= state;
  55. default :state <= IDLE;
  56. endcase
  57. always @(posedge sclk or negedge rst_n)
  58. if(rst_n == 1'b0)
  59. cnt_32 <= 5'd0;
  60. else if(cnt_32 == 'd31)
  61. cnt_32 <= 5'd0;
  62. else if(state != IDLE)
  63. cnt_32 <= cnt_32 + 1'b1;
  64. else
  65. cnt_32 <= 5'd0;
  66. always @(posedge sclk or negedge rst_n)
  67. if(rst_n == 1'b0)
  68. cnt_state <= 3'd0;
  69. else if(state == IDLE)
  70. cnt_state <= 3'd0;
  71. else if(state == WREN && cnt_32 == 'd31 && cnt_state == 'd2)
  72. cnt_state <= 3'd0;
  73. else if(state == DELAT && cnt_32 == 'd31)
  74. cnt_state <= 3'd0;
  75. else if(state == BE && cnt_32 == 'd31 && cnt_state == 'd2)
  76. cnt_state <= 3'd0;
  77. else if(cnt_32 == 'd31)
  78. cnt_state <= cnt_state + 1'b1;
  79. else
  80. cnt_state <= cnt_state;
  81. always @(posedge sclk or negedge rst_n)
  82. if(rst_n == 1'b0)
  83. cnt_4 <= 'd0;
  84. else if(state == WREN && cnt_state == 'd1)
  85. cnt_4 <= cnt_4 + 1'b1;
  86. else if(state == BE && cnt_state == 'd1)
  87. cnt_4 <= cnt_4 + 1'b1;
  88. always @(posedge sclk or negedge rst_n)
  89. if(rst_n == 1'b0)
  90. sck <= 1'b0;
  91. else if(cnt_4 == 'd0)
  92. sck <= 1'b0;
  93. else if(cnt_4 == 'd2)
  94. sck <= 1'b1;
  95. else
  96. sck <= sck;
  97. always @(posedge sclk or negedge rst_n)
  98. if(rst_n == 1'b0)
  99. sdi <= 1'b0;
  100. else if(state == WREN && cnt_state == 'd1 && cnt_4 == 'd0)
  101. sdi <= WREN_ORDER[7-bit_cnt];
  102. else if(state == BE && cnt_state == 'd1 && cnt_4 == 'd0)
  103. sdi <= BE_ORDER[7-bit_cnt];
  104. else if(state == BE && cnt_32 == 'd31 && cnt_state == 'd1)
  105. sdi <= 1'b0;
  106. else
  107. sdi <= sdi;
  108. always @(posedge sclk or negedge rst_n)
  109. if(rst_n == 1'b0)
  110. bit_cnt <= 5'd0;
  111. else if(state == WREN && bit_cnt == 'd7 && cnt_4 == 'd2)
  112. bit_cnt <= 5'd0;
  113. else if(state == BE && bit_cnt == 'd7 && cnt_4 == 'd2)
  114. bit_cnt <= 5'd0;
  115. else if(cnt_4 == 'd2)
  116. bit_cnt <= bit_cnt + 1'b1;
  117. else
  118. bit_cnt <= bit_cnt;
  119. endmodule

      下面给出仿真测试的tb_flash_all.v代码

  1. `timescale 1ns/1ns
  2. module tb_flash_all();
  3. reg sys_clk ;
  4. reg sys_res ;
  5. reg key ;
  6. wire cs_n ;
  7. wire sck ;
  8. wire sdi ;
  9. //时钟、复位信号、模拟按键信号
  10. initial
  11. begin
  12. sys_clk <= 1'b1;
  13. sys_res <= 1'b0;
  14. key <= 1'b0;
  15. #100
  16. sys_res <= 1'b1;
  17. #1000
  18. key <= 1'b1;
  19. #20
  20. key <= 1'b0;
  21. end
  22. always #10 sys_clk <= ~sys_clk;
  23. flash_all tb_flash_all
  24. (
  25. .sclk (sys_clk ),
  26. .rst_n (sys_res ),
  27. .key_flag (key ),
  28. .sck (sck ),
  29. .cs_n (cs_n ),
  30. .sdi (sdi )
  31. );
  32. endmodule

下面给出Modelsim仿真结果

 该仿真结果与上述编写的时序图基本吻合,验证了程序的准确性。

   2.扇区擦除实验

       扇区擦除与全擦除基本类似,唯一不同的地方在于,扇区擦除在发送完擦除指令后,需要继续发送三个相应的地址(扇区地址、页地址、字节地址)。本实验选择擦除的地址是24‘h00_01_02,分别对应扇区地址8‘h00,页地址8‘h01,字节地址8‘h02。

       系统框图和扇区擦除模块的时序图与上述的全擦除实验基本相同,这里不再赘述。下边直接给出扇区擦除模块的Verilog代码:

  1. module flash_earse(
  2. input sclk,
  3. input rst_n,
  4. input key_flag,
  5. output reg cs_n,
  6. output reg sck,
  7. output reg sdi
  8. );
  9. //定义状态机的四个状态
  10. parameter IDLE = 4'b0001;
  11. parameter WREN = 4'b0010;
  12. parameter DELAT= 4'b0100;
  13. parameter SE = 4'b1000;
  14. parameter WREN_ORDER = 8'h06;//写允许的命令字
  15. parameter SE_ORDER = 8'hd8;//扇区擦除的命令字
  16. parameter SE_ADDR = 24'h00_01_02;//擦除扇区的地址
  17. reg [ 3:0] state;//状态机的状态
  18. reg [ 4:0] cnt_32;//对系统时钟计数,两次命令字之间的延迟时间
  19. reg [ 2:0] cnt_state;//WREN计数三次,中间一次进行数据传输,SE状态计数6次,中间4次进行数据传输
  20. reg [ 1:0] cnt_4;//生成sck的时钟计数器,sck=12.5M
  21. reg [ 4:0] bit_cnt;
  22. always @(posedge sclk or negedge rst_n)
  23. if(rst_n == 1'b0)
  24. cs_n <= 1'b1;
  25. else if(key_flag == 1'b1)
  26. cs_n <= 1'b0;
  27. else if(state == WREN && cnt_32 == 'd31 && cnt_state == 'd2)
  28. cs_n <= 1'b1;
  29. else if(state == DELAT && cnt_32 == 'd31)
  30. cs_n <= 1'b0;
  31. else if(state == SE && cnt_32 == 'd31 && cnt_state == 'd5)
  32. cs_n <= 1'b1;
  33. else
  34. cs_n <= cs_n;
  35. always @(posedge sclk or negedge rst_n)
  36. if(rst_n == 1'b0)
  37. state <= IDLE;
  38. else case(state)
  39. IDLE:if(key_flag == 1'b1)
  40. state <= WREN;
  41. else
  42. state <= state;
  43. WREN:if(cnt_32 == 'd31 && cnt_state == 'd2)
  44. state <= DELAT;
  45. else
  46. state <= state;
  47. DELAT:if(cnt_32 == 'd31)
  48. state <= SE;
  49. else
  50. state <= state;
  51. SE :if(cnt_32 == 'd31 && cnt_state == 'd5)
  52. state <= IDLE;
  53. else
  54. state <= state;
  55. default :state <= IDLE;
  56. endcase
  57. always @(posedge sclk or negedge rst_n)
  58. if(rst_n == 1'b0)
  59. cnt_32 <= 5'd0;
  60. else if(cnt_32 == 'd31)
  61. cnt_32 <= 5'd0;
  62. else if(state != IDLE)
  63. cnt_32 <= cnt_32 + 1'b1;
  64. else
  65. cnt_32 <= 5'd0;
  66. always @(posedge sclk or negedge rst_n)
  67. if(rst_n == 1'b0)
  68. cnt_state <= 3'd0;
  69. else if(state == IDLE)
  70. cnt_state <= 3'd0;
  71. else if(state == WREN && cnt_32 == 'd31 && cnt_state == 'd2)
  72. cnt_state <= 3'd0;
  73. else if(state == DELAT && cnt_32 == 'd31)
  74. cnt_state <= 3'd0;
  75. else if(state == SE && cnt_32 == 'd31 && cnt_state == 'd5)
  76. cnt_state <= 3'd0;
  77. else if(cnt_32 == 'd31)
  78. cnt_state <= cnt_state + 1'b1;
  79. else
  80. cnt_state <= cnt_state;
  81. always @(posedge sclk or negedge rst_n)
  82. if(rst_n == 1'b0)
  83. cnt_4 <= 'd0;
  84. else if(state == WREN && cnt_state == 'd1)
  85. cnt_4 <= cnt_4 + 1'b1;
  86. else if(state == SE && cnt_state >= 'd1 && cnt_state <= 'd4)
  87. cnt_4 <= cnt_4 + 1'b1;
  88. always @(posedge sclk or negedge rst_n)
  89. if(rst_n == 1'b0)
  90. sck <= 1'b0;
  91. else if(cnt_4 == 'd0)
  92. sck <= 1'b0;
  93. else if(cnt_4 == 'd2)
  94. sck <= 1'b1;
  95. else
  96. sck <= sck;
  97. always @(posedge sclk or negedge rst_n)
  98. if(rst_n == 1'b0)
  99. sdi <= 1'b0;
  100. else if(state == WREN && cnt_state == 'd1 && cnt_4 == 'd0)
  101. sdi <= WREN_ORDER[7-bit_cnt];
  102. else if(state == SE && cnt_state == 'd1 && cnt_4 == 'd0)
  103. sdi <= SE_ORDER[7-bit_cnt];
  104. else if(state == SE && cnt_4 == 'd0 && cnt_state > 'd1 && cnt_state <= 'd4)
  105. sdi <= SE_ADDR[31-bit_cnt];
  106. else if(state == SE && cnt_32 == 'd31 && cnt_state == 'd4)
  107. sdi <= 1'b0;
  108. else
  109. sdi <= sdi;
  110. always @(posedge sclk or negedge rst_n)
  111. if(rst_n == 1'b0)
  112. bit_cnt <= 5'd0;
  113. else if(state == WREN && bit_cnt == 'd7 && cnt_4 == 'd2)
  114. bit_cnt <= 5'd0;
  115. else if(state == SE && bit_cnt == 'd31 && cnt_4 == 'd2)
  116. bit_cnt <= 5'd0;
  117. else if(cnt_4 == 'd2)
  118. bit_cnt <= bit_cnt + 1'b1;
  119. else
  120. bit_cnt <= bit_cnt;
  121. endmodule

        由于tb文件与上述全擦除实验的tb文件基本类似,因此这里直接给出仿真后的波形图,结果如下。检测到KEY按键信号后,同样等待一段时间,然后发送写使能指令,再等待一段时间,然后发送扇区擦除指令接着继续发送三个字节的地址。

    3.上板验证

      开发板选用的是黑金的FPGA,型号是EP4CE6F17C8,将一个事先写好的数码管显示实验的程序编译好后转换成.jic文件,然后将该程序固化到FPGA中,重新上电后再将上述的全擦除实验的程序编译后下载到FPGA中,观察如下图所示:

  可以明显的观察到,数码管不再显示,说明Flash中的程序已经被擦除。


总结

初次创作,难免文章中存在错误,希望读者能够及时纠正并给予私信,望大家共同进步!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/429292
推荐阅读
相关标签
  

闽ICP备14008679号