赞
踩
一.M25P16flash芯片介绍
本设计使用了M25P16flash芯片,它拥有16Mbit的空间。M25P16flash芯片有32个扇区,每个扇区有256页,每页有256个位空间。32*256*256=2097152=16M。因此它的地址有24位。它的各扇区地址如下表。
二.扇区擦除原理
扇区擦除(SE)指令可以按照扇区擦除 Flash。和块擦除不同的是,扇区擦除是要指定扇区地址,扇区擦除前也需要发送写使能指令。时序图如下:
同全擦除一样,首先得发送写允许指令,然后发送扇区擦除指令。和全擦除不同的是它的扇区擦除指令后面得加一个24位的地址。例如我们现在要把第一扇区擦除,地址的高八位就得是01h,另外24位可以为0000h-ffffh中的任意值。
三.代码
此代码没有像野火那样使用状态机,具体如下:
- // -----------------------------------------------------------------------------
- // Create : 2023-12-21
- // Note : spi flash扇区擦除实验
- // 实验开发板:黑金ax301,flash芯片:M25P16
- // 需要用到的命令:
- // WREN(Write Enable): 06h
- // SE(Sector Erase): D8h
- // 扇区擦除前要先写入WREN,然后cs拉高需要至少100ns才能开始下一次传输,本代码将擦除第0扇区
- // Revise : 2023-12-2
- // -----------------------------------------------------------------------------
-
- module spi_se (
- clk,
- reset,
- spi_miso,
- spi_mosi,
- spi_cs,
- spi_sck
- );
- input clk;
- input reset;
- input spi_miso;
- output spi_mosi;
- output spi_sck;
- output spi_cs;
-
- reg [11:0] cnt;
-
- //设置扇区擦除程序运行一次的周期位4095*20ns,当cnt为12'hfff时,cnt将保持不变。
- always @(posedge clk, negedge reset) begin
- if(!reset)
- cnt <= 0;
- else if(cnt < 12'hfff)
- cnt <= cnt + 12'd1;
- end
- //设置指令的产生和指令标准位脉冲的产生,cnt为2000时,指令为写允许指令“00000110”,产生一个时钟周期的指令标准为脉冲,
- //cnt为2050时,指令为扇区擦除指令“d8001213h”,产生一个时钟周期的指令标准为脉冲。
- wire data_flag_1 = cnt == 12'd2000;
- wire data_flag_2 = cnt == 12'd2050;
- wire [31:0]data = (cnt == 12'd2000) ? 32'h00000006 : ((cnt == 12'd2050) ? 32'hd8001213 : 8'd0);
-
-
- spi_driver spi_driver(
- .clk(clk),
- .reset(reset),
- .data(data),
- .spi_miso(spi_miso),
- .data_flag_1(data_flag_1),
- .data_flag_2(data_flag_2),
- .spi_cs(spi_cs),
- .spi_sck(spi_sck),
- .spi_mosi(spi_mosi)
- );
- endmodule
- // -----------------------------------------------------------------------------
- // Create : 2023-11-31
- // Revise : 2023-12-2
- // Note : spi驱动,模式0,时钟默认低电平,上升沿数据有效,主机模式,目前只有单字节发送功能
- // 该flash快速命令最高支持50M时钟,常规命令最高支持20M时钟,所以SPI时钟使用主时钟四分频12.5M
- // -----------------------------------------------------------------------------
-
- module spi_driver (
- clk,
- reset,
- data,
- spi_miso,
- data_flag_1,//写允许指令标准位
- data_flag_2,//扇区擦除指令标准位
- spi_cs,
- spi_sck,
- spi_mosi
- );
- input clk;
- input reset;
- input[31:0]data; //指令数据
- input data_flag_1; //写允许指令标准位
- input data_flag_2; //扇区擦除指令标志位
- input spi_miso;
- output reg spi_cs;
- output wire spi_sck;
- output reg spi_mosi;
-
-
- reg[1:0]cnt ; //用于四分频
- reg[4:0]cnt_data; //用于计数当前发送的数据位
- reg[31:0]data_r;
- reg[1:0]data_flag_r;//01表示发写允许指令,10表示发扇区擦除指令
-
- //当写允许指令来的时候,data_flag_r为2‘b01,扇区擦除指令来的时候为2'b10
- always @(posedge clk or negedge reset) begin
- if(!reset)
- data_flag_r <= 0;
- else if(data_flag_1)
- data_flag_r <= 2'b01;
- else if(data_flag_2)
- data_flag_r <= 2'b10;
- end
- //data_r,由于写允许指令只有8位,因此把写允许指令给data_r的低8位,剩下的24位补0
- always @(posedge clk or negedge reset) begin
- if(!reset)
- data_r <= 0;
- else if(data_flag_1)
- data_r <= {24'h00,data[7:0]};
- else if(data_flag_2)
- data_r <= data;
- end
- //cnt
- always @(posedge clk or negedge reset) begin
- if(!reset)
- cnt <= 0;
- else if(!spi_cs)
- cnt <= cnt+1'b1;
- end
- //产生12.5mhz的sck
- assign spi_sck = cnt[1];
- //8位数据的计数
- always @(posedge clk or negedge reset) begin
- if(!reset)
- cnt_data <= 0;
- else if(cnt == 2'b11)
- if(data_flag_r == 2'b01 && cnt_data == 5'd7)
- cnt_data <= 0;
- else
- cnt_data <= cnt_data+1'b1;
- end
-
- //片选信号,低电平有效
- always @(posedge clk or negedge reset) begin
- if(!reset)
- spi_cs <= 1;
- else if(data_flag_1 || data_flag_2)
- spi_cs <= 0;
- else if(data_flag_r == 2'b01 && cnt_data == 5'b00111 && cnt == 2'b11)
- spi_cs <= 1;
- else if(data_flag_r == 2'b10 && cnt_data == 5'b11111 && cnt == 2'b11)
- spi_cs <= 1;
- end
- //spi协议规定先发高位,因此将cnt_data取反。
- always @(*) begin
- if(!reset)
- spi_mosi <= 0;
- else if(data_flag_r == 2'b01)
- spi_mosi <= spi_cs? 0 : data_r[~cnt_data[2:0]];//此时数据有效位为7:0位
- else if(data_flag_r == 2'b10)
- spi_mosi <= spi_cs? 0 : data_r[~cnt_data];
- end
-
- endmodule
- `timescale 1ns/1ns
- module spi_tb;
- reg clk;
- reg reset;
- reg spi_miso;
- wire spi_cs;
- wire spi_sck;
- wire spi_mosi;
-
- spi_se spi_se(
- .clk(clk),
- .reset(reset),
- .spi_miso(spi_miso),
- .spi_cs(spi_cs),
- .spi_sck(spi_sck),
- .spi_mosi(spi_mosi)
-
- );
-
- initial clk=0;
- always#10 clk=!clk;
-
- initial begin
- reset=0;
- spi_miso=0;
- #201;
- reset=1;
- #100000
- $stop;
- end
- endmodule
四.仿真波形
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。