赞
踩
SPI(Serial Peripheral Interface)是一种同步串行通信协议,通常用于在嵌入式系统中连接微控制器和外部设备。它允许微控制器与多个外设同时进行全双工通信,实现高速数据传输。SPI协议通常用于连接存储器芯片、传感器、显示屏、通信模块和其他外设。
SPI协议的基本工作原理如下:微控制器通过主设备选择(SS)引脚选择要与之通信的外设,并通过时钟信号(SCLK)同步数据传输。它还使用主输出主输入(MOSI)和主输入主输出(MISO)引脚进行双向数据传输。在传输过程中,主设备将数据位传输到外设的输入引脚,同时从外设的输出引脚读取数据位。
SPI协议具有以下特点:
简单灵活:SPI协议使用少量的引脚和简单的硬件电路,易于实现和调试。
高速通信:由于采用同步传输方式,SPI协议可以实现高速数据传输,适用于实时应用。
可靠性好:SPI协议具有错误检测和纠正机制,可以提供可靠的数据传输。
多设备支持:SPI协议使用主从结构,一个主设备可以连接多个从设备,使得系统具备良好的扩展性。
SPI协议的配置通常由以下参数确定:
时钟极性(CPOL):确定时钟信号的空闲状态和活动状态。
时钟相位(CPHA):确定数据采样的时机。
数据位顺序:确定数据位的传输顺序,可以是最高位先传输(MSB-first)或最低位先传输(LSB-first)。
在实际应用中,SPI协议根据不同的硬件平台和设备需求进行配置。通过正确配置参数,微控制器可以与外设进行可靠的通信和数据交换。
ADC128S022器件是一种低功耗、8通道CMOS 12位模数转换器,其转换吞吐量为50 ksps到200 ksps。该转换器是基于一个逐次逼近寄存器结构与一个内部跟踪和保持电路。它可以配置为在输入IN0到IN7接受多达8个输入信号。串行数据的输出是直接二进制,并兼容多种标准,如SPI, QSPI, MICROWIRE和许多常见的DSP串行接口。 ADC128S022可使用独立的模拟和数字电源。模拟电源(VA)的电压范围是2.7 V到5.25 V,数字电源(VD)的电压范围是2.7 V到VA。使用3v或5v电源的正常功耗分别为1.2 mW和7.5 mW。当使用3v电源时,功耗为0.06µW;当使用5v电源时,功耗为0.25µW确保在-40°C至+105°C的扩展工业温度范围内运行。
CS:片选信号,低电平表示选中。
SCLK:输入时钟。
DIN:串行输入,SCLK的上升沿进行采集。
DOUT:转换输出,SCLK的下降沿进行数据输出。
- module SPI(
- input clk,
- input rst_n,
- input start,
- input [2:0]channel,
-
- //========ADC128S022===========//
- output reg SCLK,
- output reg DIN,
- output reg CS_N,
- input DOUT,
-
- output reg done,
- output reg [11:0]data
- );
-
- reg en;
- reg [2:0]r_channel;
- reg [4:0]cnt;
- reg cnt_flag;
- reg [5:0]SCLK_CNT;
- reg [11:0]r_data;
-
- //==============写入通道===================//
- always@(posedge clk or negedge rst_n)begin
- if(!rst_n)
- r_channel <= 'd0;
- else if(start)
- r_channel <= channel;
- else
- r_channel <= r_channel;
- end
-
- //============转换使能信号==================//
- always@(posedge clk or negedge rst_n)begin
- if(!rst_n)
- en <= 1'b0;
- else if(start)
- en <= 1'b1;
- else if(done)
- en <= 1'b0;
- else
- en <= en;
- end
-
- //==================cnt=====================//
- always@(posedge clk or negedge rst_n)begin
- if(!rst_n)
- cnt <= 'd0;
- else if(en)begin
- if(cnt == 'd10)
- cnt <= 'd0;
- else
- cnt <= cnt + 1'b1;
- end
- else
- cnt <= 'd0;
- end
-
- //===================cnt_flag===============//
- always@(posedge clk or negedge rst_n)begin
- if(!rst_n)
- cnt_flag <= 1'b0;
- else if(cnt == 'd10)
- cnt_flag <= 1'b1;
- else
- cnt_flag <= 1'b0;
- end
- //===============SCLK_CNT===================//
- always@(posedge clk or negedge rst_n)begin
- if(!rst_n)
- SCLK_CNT <= 'd0;
- else if(en)begin
- if(cnt_flag && (SCLK_CNT == 'd33))
- SCLK_CNT <= 'd0;
- else if(cnt_flag)
- SCLK_CNT <= SCLK_CNT + 1'b1;
- else
- SCLK_CNT <= SCLK_CNT;
- end
- else
- SCLK_CNT <= 'd0;
- end
-
- //===========================================//
- always@(posedge clk or negedge rst_n)begin
- if(!rst_n)begin
- SCLK <= 1'b1;
- CS_N <= 1'b1;
- DIN <= 1'b1;
- end
- else if(en)begin
- if(cnt_flag)begin
- case(SCLK_CNT)
- 6'd0:begin CS_N <= 1'b0;end
- 6'd1:begin SCLK <= 1'b0;DIN <= 1'b0;end
- 6'd2:begin SCLK <= 1'b1;end
- 6'd3:begin SCLK <= 1'b0;end
- 6'd4:begin SCLK <= 1'b1;end
- //写入通道
- 6'd5:begin SCLK <= 1'b0;DIN <= r_channel[2];end
- 6'd6:begin SCLK <= 1'b1;end
- 6'd7:begin SCLK <= 1'b0;DIN <= r_channel[1];end
- 6'd8:begin SCLK <= 1'b1;end
- 6'd9:begin SCLK <= 1'b0;DIN <= r_channel[0];end
- //写入数据,在上升沿使数据逐次左移 6'd10,6'd12,6'd14,6'd16,6'd18,6'd20,6'd22,6'd24,6'd26,6'd28,6'd30,6'd32:
- begin SCLK <= 1'b1;r_data <= {r_data[10:0],DOUT};end
- 6'd11,6'd13,6'd15,6'd17,6'd19,6'd21,6'd23,6'd25,6'd27,6'd29,6'd31:
- begin SCLK <= 1'b0;end
- //传输结束,结束选中
- 6'd33:begin CS_N <= 1'b1;end
- default:begin CS_N <= 1'b1;end
- endcase
- end
- else ;
- end
- else begin
- SCLK <= 1'b1;
- CS_N <= 1'b1;
- DIN <= 1'b1;
- end
- end
-
- //================done=================//
- always@(posedge clk or negedge rst_n)begin
- if(!rst_n)
- done <= 1'b0;
- else if(cnt_flag && (SCLK_CNT == 'd33))
- done <= 1'b1;
- else
- done <= 1'b0;
- end
-
- //================data=================//
- always@(posedge clk or negedge rst_n)begin
- if(!rst_n)
- data <= 'd0;
- else if(cnt_flag && (SCLK_CNT == 'd33))
- data <= r_data;
- else
- data <= data;
- end
- endmodule
注:这部分代码参考自b站FPGA小学生。
- `timescale 1ns/1ns
-
- module SPI_tb;
-
- reg clk;
- reg rst_n;
- reg start;
- reg [2:0]channel;
-
- wire SCLK;
- wire DIN;
- wire CS_N;
- reg DOUT;
-
- wire done;
- wire [11:0]data;
-
- reg i = 0;
-
- initial clk = 1'b1;
- always#10 clk = ~clk;
-
- SPI SPI_inst(
- .clk(clk),
- .rst_n(rst_n),
- .start(start),
- .channel(channel),
-
- //========ADC128S022===========//
- .SCLK(SCLK),
- .DIN(DIN),
- .CS_N(CS_N),
- .DOUT(DOUT),
-
- .done(done),
- .data(data)
- );
-
- initial begin
- rst_n = 1'b0;
- channel = 'd0;
- start = 1'b0;
- DOUT = 1'b0;
- #100;
- rst_n = 1'b1;
- #100;
- channel = 3;
- for(i=0;i<3;i=i+1)begin
- start = 1;
- #20;
- start = 0;
- gene_DOUT(12'b0101_1100_1010); //依次将存储器中存储的波形读出,按照ADC的转换结果输出方式送到DOUT信号线上
- @(posedge done); //等待转换完成信号
- #200;
- end
- #20000;
- $stop;
- end
-
-
-
- //将并行数据按照ADC的数据输出格式,送到DOUT信号线上,供控制模块采集读取
- task gene_DOUT;
- input [15:0]vdata;
- reg [4:0]cnt;
- begin
- cnt = 0;
- wait(!CS_N);
- while(cnt<16)begin
- @(negedge SCLK) DOUT = vdata[15-cnt];
- cnt = cnt + 1'b1;
- end
- end
- endtask
-
- endmodule
FLASH闪存是一种非易失性存储器,常用于存储数据并替代传统的磁盘驱动器。它具有许多优点,例如速度快、耐用性高和体积小。其具有内部时钟,可确保数据在正确的时间段写入和读取,同时提供更高的数据传输速度和准确性,还有助于协调闪存与其他设备之间的数据传输。对其主要操作包括擦除、写入和读取。因为闪存内部的存储单元被分为多个块,每个块都可以独立操作,使得闪存在处理大量数据时表现出色。
图 FLASH的连接方式
注:其他有关SPI和FLASH的基础内容请移步至前章的STM32通信总结。
值得注意的是这里需要区分delay_cnt、bit_cnt和clk_cnt,具体如下图所示。
delay_cnt和clk_cnt均为1位,delay_cnt更多是作为延时开始的标志,而bit_clk会在clk_cnt高电平时加一,进而切换输出的位号。根据FLASH定义的时序,上电后会需要一段时间的延时等待,接着是8位的命令、24位的地址以及后续的数据,这也说明了在32位后才真正开始进行数据的传输。
- module spi_drive(
-
- input clk_100m ,
- input sys_rst_n ,
-
- //user interface
- input spi_start ,//spi开启使能。
- input [7:0 ] spi_cmd ,//FLAH操作指令
- input [23:0] spi_addr ,//FLASH地址
- input [7:0 ] spi_data ,//FLASH写入的数据
- input [3:0 ] cmd_cnt ,
-
- output idel_flag_r ,//空闲状态标志的上升沿
- output reg w_data_req ,//FLASH写数据请求
- output reg [7:0] r_data ,//FLASH读出的数据
- output reg erro_flag ,//读出的数据错误标志
-
- //spi interface
- output reg spi_cs ,//SPI从机的片选信号,低电平有效。
- output reg spi_clk ,//主从机之间的数据同步时钟。
- output reg spi_mosi ,//数据引脚,主机输出,从机输入。
- input spi_miso //数据引脚,主机输入,从机输出。
-
- );
-
- //状态机
- parameter IDLE =4'd0;//空闲状态
- parameter WEL =4'd1;//写使能状态
- parameter S_ERA =4'd2;//扇区擦除状态
- parameter C_ERA =4'd3;//全局擦除
- parameter READ =4'd4;//读状态
- parameter WRITE =4'd5;//写状态
- parameter R_STA_REG =4'd6;
- //指令集
- parameter WEL_CMD =8'h06;
- parameter S_ERA_CMD =8'h20;
- parameter C_ERA_CMD =8'hc7;
- parameter READ_CMD =8'h03;
- parameter WRITE_CMD =8'h02;
- parameter R_STA_REG_CMD=8'h05;
- //wire define
- wire idel_flag;
- //reg define
- reg[3:0] current_state ;
- reg[3:0] next_state ;
- reg[7:0 ] data_buffer ;
- reg[7:0 ] cmd_buffer ;
- reg[7:0 ] sta_reg ;
- reg[23:0] addr_buffer ;
- reg[31:0] bit_cnt ;
- reg clk_cnt ;
- reg dely_cnt ;
- reg[31:0] dely_state_cnt ;
- reg[7:0 ] rd_data_buffer ;
- reg spi_clk0 ;
- reg stdone ;
- reg[7:0 ] data_check ;
- reg idel_flag0 ;
- reg idel_flag1 ;
- //*****************************************************
- //** main code
- //*****************************************************
- assign idel_flag=(current_state==IDLE)?1:0;//空闲状态标志
- assign idel_flag_r=idel_flag0&&(~idel_flag1);//空闲状态标志的上升沿
- always @(posedge clk_100m or negedge sys_rst_n )begin
- if(!sys_rst_n)begin
- idel_flag0<=1'b1;
- idel_flag1<=1'b1;
- end
- else begin
- idel_flag0<=idel_flag;
- idel_flag1<=idel_flag0;
- end
- end
- always @(posedge clk_100m or negedge sys_rst_n )begin
- if(!sys_rst_n)
- w_data_req<=1'b0;
- else if((bit_cnt+2)%8==0&&bit_cnt>=30&&clk_cnt==0&¤t_state==WRITE)
- w_data_req<=1'b1;
- else
- w_data_req<=1'b0;
- end
-
- always @(posedge clk_100m or negedge sys_rst_n )begin//读出的数据移位寄存
- if(!sys_rst_n)
- rd_data_buffer<=8'd0;
- else if(bit_cnt>=32&&bit_cnt<=2080&&clk_cnt==0&¤t_state==READ)
- rd_data_buffer<={rd_data_buffer[6:0],spi_miso};
- else
- rd_data_buffer<=rd_data_buffer;
- end
- always @(posedge clk_100m or negedge sys_rst_n )begin//检查读出的数据是否正确
- if(!sys_rst_n)
- data_check<=8'd0;
- else if(bit_cnt%8==0&&bit_cnt>=40&&clk_cnt==1&¤t_state==READ)
- data_check<=data_check+1'd1;
- else
- data_check<=data_check;
- end
- always @(posedge clk_100m or negedge sys_rst_n )begin//读出的数据
- if(!sys_rst_n)
- r_data<=8'd0;
- else if(bit_cnt%8==0&&bit_cnt>38&&clk_cnt==1&¤t_state==READ)
- r_data<=rd_data_buffer;
- else
- r_data<=r_data;
- end
-
- always @(posedge clk_100m or negedge sys_rst_n )begin//读出的数据错误标志
- if(!sys_rst_n)
- erro_flag<=1'd0;
- else if(bit_cnt>32&&bit_cnt<=2080&¤t_state==READ&&cmd_cnt==6)begin
- if(data_check!=r_data)
- erro_flag<=1'd1;
- else
- erro_flag<=erro_flag;
- end
- else
- erro_flag<=erro_flag;
- end
-
- always @(posedge clk_100m or negedge sys_rst_n )begin
- if(!sys_rst_n)
- data_buffer<=8'd0;
- else if((bit_cnt+1)%8==0&&bit_cnt>30&&clk_cnt==1)
- data_buffer<=spi_data;
- else if(clk_cnt==1&¤t_state==WRITE&&bit_cnt>=32)
- data_buffer<={data_buffer[6:0],data_buffer[7]};
- else
- data_buffer<=data_buffer;
- end
- always @(posedge clk_100m or negedge sys_rst_n )begin
- if(!sys_rst_n)
- cmd_buffer<=8'd0;
- else if(spi_cs==0&&dely_cnt==0)
- cmd_buffer<=spi_cmd;
- else if(clk_cnt==1&&(current_state==WEL||current_state==S_ERA||current_state==C_ERA
- ||current_state==READ||current_state==WRITE||current_state==R_STA_REG)&&bit_cnt<8)
- cmd_buffer<={cmd_buffer[6:0],1'b1};
- else
- cmd_buffer<=cmd_buffer;
- end
- always @(posedge clk_100m or negedge sys_rst_n )begin
- if(!sys_rst_n)
- addr_buffer<=8'd0;
- else if(spi_cs==0&&dely_cnt==0)
- addr_buffer<=spi_addr;
- else if(clk_cnt==1&&(current_state==READ||current_state==WRITE)&&bit_cnt>=8&&bit_cnt<32)
- addr_buffer<={addr_buffer[22:0],addr_buffer[23]};
- else
- addr_buffer<=addr_buffer;
- end
-
- always @(posedge clk_100m or negedge sys_rst_n )begin
- if(!sys_rst_n)
- clk_cnt<=1'd0;
- else if(dely_cnt==1)
- clk_cnt<=clk_cnt+1'd1;
- else
- clk_cnt<=1'd0;
- end
- always @(posedge clk_100m or negedge sys_rst_n )begin
- if(!sys_rst_n)
- dely_cnt<=1'd0;
- else if(spi_cs==0)begin
- if(dely_cnt<1)
- dely_cnt<=dely_cnt+1'd1;
- else
- dely_cnt<=dely_cnt;
- end
- else
- dely_cnt<=1'd0;
- end
-
- always @(posedge clk_100m or negedge sys_rst_n )begin
- if(!sys_rst_n)
- dely_state_cnt<=1'd0;
- else if(spi_cs)begin
- if(dely_state_cnt<400000000)
- dely_state_cnt<=dely_state_cnt+1'd1;
- else
- dely_state_cnt<=dely_state_cnt;
- end
- else
- dely_state_cnt<=1'd0;
- end
- always @(posedge clk_100m or negedge sys_rst_n )begin
- if(!sys_rst_n)
- bit_cnt<=11'd0;
- else if(dely_cnt==1)begin
- if(clk_cnt==1'b1)
- bit_cnt<=bit_cnt+1'd1;
- else
- bit_cnt<=bit_cnt;
- end
- else
- bit_cnt<=11'd0;
- end
-
- //三段式状态机
- always @(posedge clk_100m or negedge sys_rst_n )begin
- if(!sys_rst_n)
- current_state<=IDLE;
- else
- current_state<=next_state;
- end
- always @(*)begin
- case(current_state)
-
- IDLE: begin
- if(spi_start&&spi_cmd==WEL_CMD)
- next_state=WEL;
- else if(spi_start&&spi_cmd==C_ERA_CMD)
- next_state=C_ERA;
- else if(spi_start&&spi_cmd==S_ERA_CMD)
- next_state=S_ERA;
- else if(spi_start&&spi_cmd==READ_CMD)
- next_state=READ;
- else if(spi_start&&spi_cmd==WRITE_CMD)
- next_state=WRITE;
- else if(spi_start&&spi_cmd==R_STA_REG_CMD)
- next_state=R_STA_REG;
- else
- next_state=IDLE;
- end
-
- WEL: begin
- if(stdone&&bit_cnt>=8)
- next_state=IDLE;
- else
- next_state=WEL;
- end
-
- S_ERA: begin
- if(stdone)
- next_state=IDLE;
- else
- next_state=S_ERA;
- end
- C_ERA: begin
- if(stdone)
- next_state=IDLE;
- else
- next_state=C_ERA;
- end
- READ: begin
- if(stdone&&bit_cnt>=8)
- next_state=IDLE;
- else
- next_state=READ;
- end
- WRITE: begin
- if(stdone&&bit_cnt>=8)
- next_state=IDLE;
- else
- next_state=WRITE;
- end
- R_STA_REG: begin
- if(stdone)
- next_state=IDLE;
- else
- next_state=R_STA_REG;
- end
-
- default: next_state=IDLE;
- endcase
- end
-
- always @(posedge clk_100m or negedge sys_rst_n )begin
- if(!sys_rst_n) begin
- spi_cs<=1'b1;
- spi_clk<=1'b0;
- spi_clk0<=1'b0;
- spi_mosi<=1'b0;
- stdone<=1'b0;
- end
- else begin
- case(current_state)
- IDLE: begin
- spi_cs<=1'b1;
- spi_clk<=1'b0;
- spi_mosi<=1'b0;
- end
-
- WEL: begin
- stdone<=1'b0;
- spi_cs<=1'b0;
- if(dely_cnt==1&&bit_cnt<8) begin
- spi_clk0<=~spi_clk0;
- spi_clk<=spi_clk0;
- spi_mosi<=cmd_buffer[7];
- end
- else if(bit_cnt==8&&clk_cnt==0)begin
- stdone<=1'b1;
- spi_clk<=1'b0;
- spi_mosi<=1'b0;
- end
- else if(bit_cnt==8&&clk_cnt==1)begin
- spi_cs<=1'b1;
- end
- end
- C_ERA: begin
- stdone<=1'b0;
- if(dely_state_cnt==10)
- spi_cs<=1'b0;
- else if(dely_cnt==1&&bit_cnt<8) begin
- spi_clk0<=~spi_clk0;
- spi_clk<=spi_clk0;
- spi_mosi<=cmd_buffer[7];
- end
- else if(bit_cnt==8&&clk_cnt==0)begin
- stdone<=1'b1;
- spi_clk<=1'b0;
- spi_mosi<=1'b0;
- end
- else if(bit_cnt==8&&clk_cnt==1)begin
- spi_cs<=1'b1;
- end
- end
- S_ERA: begin
- stdone<=1'b0;
- if(dely_state_cnt==10)
- spi_cs<=1'b0;
- else if(dely_cnt==1&&bit_cnt<8) begin
- spi_clk0<=~spi_clk0;
- spi_clk<=spi_clk0;
- spi_mosi<=cmd_buffer[7];
- end
- else if(bit_cnt>=8&&bit_cnt<32&&spi_cs==0)begin
- spi_cs<=1'b0;
- spi_clk0<=~spi_clk0;
- spi_clk<=spi_clk0;
- spi_mosi<=addr_buffer[23];
- end
- else if(bit_cnt==32&&clk_cnt==0) begin
- spi_cs<=1'b1;
- spi_clk<=1'b0;
- spi_mosi<=1'b0;
- stdone<=1'b1;
- end
- end
- READ: begin
- stdone<=1'b0;
- if(dely_state_cnt==10)
- spi_cs<=1'b0;
- else if(dely_cnt==1&&bit_cnt<8) begin
- spi_clk0<=~spi_clk0;
- spi_clk<=spi_clk0;
- spi_mosi<=cmd_buffer[7];
- end
- else if(bit_cnt>=8&&bit_cnt<32&&spi_cs==0)begin
- spi_clk0<=~spi_clk0;
- spi_clk<=spi_clk0;
- spi_mosi<=addr_buffer[23];
- end
- else if(bit_cnt>=32&&bit_cnt<2080)begin
- spi_clk0<=~spi_clk0;
- spi_clk<=spi_clk0;
- spi_mosi<=1'b0;
- end
- else if(bit_cnt==2080&&clk_cnt==0) begin
- spi_clk<=1'b0;
- spi_mosi<=1'b0;
- stdone<=1'b1;
- end
- else if(bit_cnt==2080&&clk_cnt==1) begin
- spi_cs<=1'b1;
- end
- end
- WRITE: begin
- stdone<=1'b0;
- if(dely_state_cnt==10)
- spi_cs<=1'b0;
- else if(dely_cnt==1&&bit_cnt<8) begin
- spi_clk0<=~spi_clk0;
- spi_clk<=spi_clk0;
- spi_mosi<=cmd_buffer[7];
- end
- else if(bit_cnt>=8&&bit_cnt<32&&spi_cs==0)begin
- spi_clk0<=~spi_clk0;
- spi_clk<=spi_clk0;
- spi_mosi<=addr_buffer[23];
- end
- else if(bit_cnt>=32&&bit_cnt<2080)begin
- spi_clk0<=~spi_clk0;
- spi_clk<=spi_clk0;
- spi_mosi<=data_buffer[7];
- end
- else if(bit_cnt==2080&&clk_cnt==0) begin
-
- spi_clk<=1'b0;
- spi_mosi<=1'b0;
- stdone<=1'b1;
- end
- else if(bit_cnt==2080&&clk_cnt==1) begin
- spi_cs<=1'b1;
- end
- end
- R_STA_REG:begin
- stdone<=1'b0;
- if(dely_state_cnt==10)
- spi_cs<=1'b0;
- else if(dely_cnt==1&&bit_cnt<8)begin
- spi_clk0<=~spi_clk0;
- spi_clk<=spi_clk0;
- spi_mosi<=cmd_buffer[7];
- end
- else if(bit_cnt==8)begin
- spi_clk0<=~spi_clk0;
- spi_clk<=spi_clk0;
- spi_mosi<=1'b0;
- end
- else if(~spi_miso&&bit_cnt%8==0)begin
- spi_clk<=1'b0;
- spi_cs<=1'b1;
- stdone<=1'b1;
- end
- else if(~spi_cs&&dely_cnt==1)begin
- spi_clk0<=~spi_clk0;
- spi_clk<=spi_clk0;
- end
- end
- default: begin
- stdone<=1'b0;
- spi_cs<=1'b1;
- spi_clk<=1'b0;
- spi_clk0<=1'b0;
- spi_mosi<=1'b0;
- end
- endcase
- end
- end
-
- endmodule
- module flash_rw(
-
- input sys_clk ,
- input sys_rst_n ,
-
- input idel_flag_r ,//抓取空闲状态上升沿
- input w_data_req ,//写请求
- output reg[3:0 ] cmd_cnt ,//计数器
- output reg spi_start ,//spi开启使能
- output reg[7:0 ] spi_cmd ,//spi命令号
- output reg[7:0 ] spi_data
-
- );
-
- //指令集
- parameter WEL_CMD =16'h06;//允许写
- parameter S_ERA_CMD =16'h20;//扇擦除
- parameter C_ERA_CMD =16'hc7;//块擦除
- parameter READ_CMD =16'h03;//读数据
- parameter WRITE_CMD =16'h02;//写数据
- parameter R_STA_REG_CMD=8'h05 ;//读状态寄存器
-
- //reg define
- reg[3:0] flash_start;
-
- //*****************************************************
- //** main code
- //*****************************************************
-
- always @(posedge sys_clk or negedge sys_rst_n )begin //延时
- if(!sys_rst_n)
- flash_start<=0;
- else if(flash_start<=10)
- flash_start<=flash_start+1;
- else
- flash_start<=flash_start;
- end
-
- always @(posedge sys_clk or negedge sys_rst_n )begin
- if(!sys_rst_n)
- cmd_cnt<=0;
- else if(flash_start==9) //生成第一次flash_start
- spi_start<=1'b1;
- else if(idel_flag_r&&cmd_cnt<10)begin //状态抓取idel_flag_r状态
- cmd_cnt<=cmd_cnt+1; //切换下一次指令
- spi_start<=1'b1;
- end
- else begin
- cmd_cnt<=cmd_cnt;
- spi_start<=1'b0;
- end
- end
- always @(posedge sys_clk or negedge sys_rst_n )begin //数据逐次加一
- if(!sys_rst_n)
- spi_data<=8'd0;
- else if(w_data_req)
- spi_data<=spi_data+1'b1;
- else
- spi_data<=spi_data;
- end
- always @(*)begin //赋值命令
- case(cmd_cnt)
- 0:spi_cmd=WEL_CMD;
- 1:spi_cmd=C_ERA_CMD;
- 2:spi_cmd=R_STA_REG_CMD;
- 3:spi_cmd=WEL_CMD;
- 4:spi_cmd=WRITE_CMD;
- 5:spi_cmd=R_STA_REG_CMD;
- 6:spi_cmd=READ_CMD;
- 7:spi_cmd=WEL_CMD;
- 8:spi_cmd=S_ERA_CMD;
- 9:spi_cmd=R_STA_REG_CMD;
- 10:spi_cmd=READ_CMD;
-
- default:;
- endcase
- end
- endmodule
免责声明:本文所引用的各种资料均用于自己学习使用,这里感谢黑金和正点原子官方的资料以及各位优秀的创作者。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。