当前位置:   article > 正文

利用FPGA(verilog)实现SPI-FLASH芯片扇区擦除_verilog flash擦除

verilog flash擦除

一.M25P16flash芯片介绍

本设计使用了M25P16flash芯片,它拥有16Mbit的空间。M25P16flash芯片有32个扇区,每个扇区有256页,每页有256个位空间。32*256*256=2097152=16M。因此它的地址有24位。它的各扇区地址如下表。

  

二.扇区擦除原理

扇区擦除(SE)指令可以按照扇区擦除 Flash。和块擦除不同的是,扇区擦除是要指定扇区地址,扇区擦除前也需要发送写使能指令。时序图如下:

              

同全擦除一样,首先得发送写允许指令,然后发送扇区擦除指令。和全擦除不同的是它的扇区擦除指令后面得加一个24位的地址。例如我们现在要把第一扇区擦除,地址的高八位就得是01h,另外24位可以为0000h-ffffh中的任意值。

三.代码

此代码没有像野火那样使用状态机,具体如下:

  1. // -----------------------------------------------------------------------------
  2. // Create : 2023-12-21
  3. // Note : spi flash扇区擦除实验
  4. // 实验开发板:黑金ax301,flash芯片:M25P16
  5. // 需要用到的命令:
  6. // WREN(Write Enable): 06h
  7. // SE(Sector Erase): D8h
  8. // 扇区擦除前要先写入WREN,然后cs拉高需要至少100ns才能开始下一次传输,本代码将擦除第0扇区
  9. // Revise : 2023-12-2
  10. // -----------------------------------------------------------------------------
  11. module spi_se (
  12. clk,
  13. reset,
  14. spi_miso,
  15. spi_mosi,
  16. spi_cs,
  17. spi_sck
  18. );
  19. input clk;
  20. input reset;
  21. input spi_miso;
  22. output spi_mosi;
  23. output spi_sck;
  24. output spi_cs;
  25. reg [11:0] cnt;
  26. //设置扇区擦除程序运行一次的周期位4095*20ns,当cnt为12'hfff时,cnt将保持不变。
  27. always @(posedge clk, negedge reset) begin
  28. if(!reset)
  29. cnt <= 0;
  30. else if(cnt < 12'hfff)
  31. cnt <= cnt + 12'd1;
  32. end
  33. //设置指令的产生和指令标准位脉冲的产生,cnt为2000时,指令为写允许指令“00000110”,产生一个时钟周期的指令标准为脉冲,
  34. //cnt为2050时,指令为扇区擦除指令“d8001213h”,产生一个时钟周期的指令标准为脉冲。
  35. wire data_flag_1 = cnt == 12'd2000;
  36. wire data_flag_2 = cnt == 12'd2050;
  37. wire [31:0]data = (cnt == 12'd2000) ? 32'h00000006 : ((cnt == 12'd2050) ? 32'hd8001213 : 8'd0);
  38. spi_driver spi_driver(
  39. .clk(clk),
  40. .reset(reset),
  41. .data(data),
  42. .spi_miso(spi_miso),
  43. .data_flag_1(data_flag_1),
  44. .data_flag_2(data_flag_2),
  45. .spi_cs(spi_cs),
  46. .spi_sck(spi_sck),
  47. .spi_mosi(spi_mosi)
  48. );
  49. endmodule
  1. // -----------------------------------------------------------------------------
  2. // Create : 2023-11-31
  3. // Revise : 2023-12-2
  4. // Note : spi驱动,模式0,时钟默认低电平,上升沿数据有效,主机模式,目前只有单字节发送功能
  5. // 该flash快速命令最高支持50M时钟,常规命令最高支持20M时钟,所以SPI时钟使用主时钟四分频12.5M
  6. // -----------------------------------------------------------------------------
  7. module spi_driver (
  8. clk,
  9. reset,
  10. data,
  11. spi_miso,
  12. data_flag_1,//写允许指令标准位
  13. data_flag_2,//扇区擦除指令标准位
  14. spi_cs,
  15. spi_sck,
  16. spi_mosi
  17. );
  18. input clk;
  19. input reset;
  20. input[31:0]data; //指令数据
  21. input data_flag_1; //写允许指令标准位
  22. input data_flag_2; //扇区擦除指令标志位
  23. input spi_miso;
  24. output reg spi_cs;
  25. output wire spi_sck;
  26. output reg spi_mosi;
  27. reg[1:0]cnt ; //用于四分频
  28. reg[4:0]cnt_data; //用于计数当前发送的数据位
  29. reg[31:0]data_r;
  30. reg[1:0]data_flag_r;//01表示发写允许指令,10表示发扇区擦除指令
  31. //当写允许指令来的时候,data_flag_r为2‘b01,扇区擦除指令来的时候为2'b10
  32. always @(posedge clk or negedge reset) begin
  33. if(!reset)
  34. data_flag_r <= 0;
  35. else if(data_flag_1)
  36. data_flag_r <= 2'b01;
  37. else if(data_flag_2)
  38. data_flag_r <= 2'b10;
  39. end
  40. //data_r,由于写允许指令只有8位,因此把写允许指令给data_r的低8位,剩下的24位补0
  41. always @(posedge clk or negedge reset) begin
  42. if(!reset)
  43. data_r <= 0;
  44. else if(data_flag_1)
  45. data_r <= {24'h00,data[7:0]};
  46. else if(data_flag_2)
  47. data_r <= data;
  48. end
  49. //cnt
  50. always @(posedge clk or negedge reset) begin
  51. if(!reset)
  52. cnt <= 0;
  53. else if(!spi_cs)
  54. cnt <= cnt+1'b1;
  55. end
  56. //产生12.5mhz的sck
  57. assign spi_sck = cnt[1];
  58. //8位数据的计数
  59. always @(posedge clk or negedge reset) begin
  60. if(!reset)
  61. cnt_data <= 0;
  62. else if(cnt == 2'b11)
  63. if(data_flag_r == 2'b01 && cnt_data == 5'd7)
  64. cnt_data <= 0;
  65. else
  66. cnt_data <= cnt_data+1'b1;
  67. end
  68. //片选信号,低电平有效
  69. always @(posedge clk or negedge reset) begin
  70. if(!reset)
  71. spi_cs <= 1;
  72. else if(data_flag_1 || data_flag_2)
  73. spi_cs <= 0;
  74. else if(data_flag_r == 2'b01 && cnt_data == 5'b00111 && cnt == 2'b11)
  75. spi_cs <= 1;
  76. else if(data_flag_r == 2'b10 && cnt_data == 5'b11111 && cnt == 2'b11)
  77. spi_cs <= 1;
  78. end
  79. //spi协议规定先发高位,因此将cnt_data取反。
  80. always @(*) begin
  81. if(!reset)
  82. spi_mosi <= 0;
  83. else if(data_flag_r == 2'b01)
  84. spi_mosi <= spi_cs? 0 : data_r[~cnt_data[2:0]];//此时数据有效位为70
  85. else if(data_flag_r == 2'b10)
  86. spi_mosi <= spi_cs? 0 : data_r[~cnt_data];
  87. end
  88. endmodule
  1. `timescale 1ns/1ns
  2. module spi_tb;
  3. reg clk;
  4. reg reset;
  5. reg spi_miso;
  6. wire spi_cs;
  7. wire spi_sck;
  8. wire spi_mosi;
  9. spi_se spi_se(
  10. .clk(clk),
  11. .reset(reset),
  12. .spi_miso(spi_miso),
  13. .spi_cs(spi_cs),
  14. .spi_sck(spi_sck),
  15. .spi_mosi(spi_mosi)
  16. );
  17. initial clk=0;
  18. always#10 clk=!clk;
  19. initial begin
  20. reset=0;
  21. spi_miso=0;
  22. #201;
  23. reset=1;
  24. #100000
  25. $stop;
  26. end
  27. endmodule

四.仿真波形

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

闽ICP备14008679号