spi flash通用读写软IP

来源:互联网 发布:json用什么解析 编辑:程序博客网 时间:2024/06/05 10:55
spi flash通用读写模块,有两个模块,分别为spiflash控制模块和spi控制模块
spiflash控制模块RTL代码如下:
//功能描述//这是一个spiflash的控制程序//写选择(wr)和读选择(rd)一样时为空操作//写选择(wr)为1并且读选择(rd)为0时使用写模式,写模式下有数据命令的选择//写选择(wr)为0并且读选择(rd)为1时使用读模式//命令和数据的输入都是使用data_in//地址的输入是使用addr//目前能使用的只有写入8位的命令(通过data_in),写入数据(通过addr和data_in),读出8位数据(通过addr和data_out),时钟上升沿//使用时不用检测忙位,模块会自动进行检测//当完成读或者写时信号spifl_over会出现上升沿 //DO、Dio、cs、spi_clk_out对应spiflash的端口module spiflash_common(flash_clk,sys_rst,DO,wr,rs,rd,addr,data_in,data_out,cs,Dio,spiflash_over,spi_clk_out);input  flash_clk;//flash的时钟input  sys_rst;//复位input  DO;//flash数据的串行输出口input  wr;//写选择,为1时有效,为0时无效input  rs;//读选择,为1时有效,为0时无效input  rd;//数据命令选择,为1时为数据,为0时为命令input   [23:0]  addr;input   [7:0]   data_in;output  [7:0]   data_out;outputcs;output Dio;output spiflash_over;//操作完成信号(上升沿)output spi_clk_out;reg [7:0] data_out_r;reg   cs_r;reg  spiflash_over_r;   assign data_out = data_out_r;parameter disenable= 8'b00000001;//状态机编码,使用独热玛,这是不使能状态parameter open_wel  = 8'b00000010;//打开写使能状态parameter write_com  = 8'b00000100;//写命令状态parameter chip_program= 8'b00001000;//芯片编程状态,就是写数据parameter done       = 8'b00010000;//完成状态parameter close_wel  = 8'b00100000;//关闭写使能状态parameter read_data= 8'b01000000;//读数据状态parameter busy_check= 8'b10000000;//检测忙位状态reg [7:0] current_state/*synthesis noprune*/;reg [7:0] next_state;reg [1:0] check_busy_flag;wire   busy;initial begincurrent_state = 8'd0;next_state = 8'd0;check_busy_flag = 2'd0;endwire input_check;assign input_check = wr ^ rd;//检测是否会读写冲突always@(posedge flash_clk or negedge sys_rst)//状态转移beginif(~sys_rst)current_state <= disenable;else if(input_check)current_state <= next_state;elsecurrent_state <= disenable;endreg [39:0] spi_data_out_r;reg [1:0]  mode_r;always@(negedge flash_clk)//状态机begincase(current_state)disenable:begincs_r <= 1; //关闭片选spiflash_over_r <= 0;if(input_check)//检测是否读写冲突beginif(wr)beginnext_state <= busy_check;check_busy_flag <= 2'b00;//传到忙检测状态的标识码,以便检测到不忙时跳转到相应的状态endelsenext_state <= read_data;endelsenext_state <= disenable;endopen_wel:beginmode_r <= 2'b01;//传到spi控制器的模式选择,具体看spi控制器模块spi_data_out_r <= 40'h0000000006;//传到spi控制器的数据if(spi_over)//如果spi返回操作已经完成begincs_r <= 1;if(rs)next_state <= chip_program;elsenext_state <= write_com;endelsebegincs_r <= 0;next_state <= open_wel;endendwrite_com: beginmode_r <= 2'b01;spi_data_out_r <= {32'd0,data_in};check_busy_flag <= 2'b01;//传到忙检测状态的标识码,以便检测到不忙时跳转到相应的状态if(spi_over)begincs_r <= 1;next_state <= busy_check;endelsebegincs_r <= 0;next_state <= write_com;endendchip_program:beginmode_r <= 2'b11;spi_data_out_r <= {2'h02,addr,data_in};check_busy_flag <= 2'b10;if(spi_over)begincs_r <= 1;next_state <= busy_check;endelsebegincs_r <= 0;next_state <= chip_program;endendclose_wel:beginspi_data_out_r <= 40'h0000000004;mode_r <= 2'b01;if(spi_over)begincs_r <= 1;next_state <= done;spiflash_over_r <= 1;//操作已经完成,将spiflash_over拉高endelsebegincs_r <= 0;next_state <= close_wel;endendread_data:beginspi_data_out_r <= {8'h03,addr,8'h00};mode_r <= 2'b00;if(spi_over)begincs_r <= 1;data_out_r <= state_reg;next_state <= done;spiflash_over_r <= 1;//操作已经完成,将spiflash_over拉高endelsebegincs_r <= 0;next_state <= read_data;endendbusy_check:beginif(spi_over)begincs_r <= 1;if(busy)next_state <= busy_check;else beginif(check_busy_flag == 2'b00)//根据不同的标识码跳转的不同的状态next_state <= open_wel;else if(check_busy_flag == 2'b10)//根据不同的标识码跳转的不同的状态next_state <= close_wel;else beginnext_state <= done;spiflash_over_r <= 1;//操作已经完成,将spiflash_over拉高endendendelsebegincs_r <= 0;mode_r <= 2'b10; spi_data_out_r <= 40'h0000000500; next_state <= busy_check;endenddone:next_state <= disenable;//跳转到非使能状态,在这个状态中保持spiflash_over的高电平,否则如果直接跳转到非使能状态会立刻拉低spiflash_over,造成错误default: next_state <= disenable;endcaseendwire [1:0] mode;wire [39:0] spi_data_out;wire spi_over;wire [7:0]state_reg;spi_controller u1(.spi_clk_in(flash_clk),.mode  (mode),.data(spi_data_out),.cs(cs),.miso(DO),.state_reg(state_reg),.mosi(mosi),.spi_over(spi_over),.spi_clk_out (spi_clk_out));assign Dio = mosi;assign cs   = cs_r;assign spi_data_out = spi_data_out_r;assign mode = mode_r; assign spiflash_over= spiflash_over_r;assign busy = state_reg[0];endmodule
spi控制模块代码如下:
<pre name="code" class="plain">module spi_controller(spi_clk_in,mode,data,cs,miso,state_reg,mosi,spi_over,spi_clk_out);input spi_clk_in;//spi时钟的输入input [1:0] mode;//模式选择,有四个模式,00位读数据模式{8位读指令,24位地址,8位数据输出},01为输入8位命令,10为{8位读寄存器命令,8位寄存器数据输出},11为写数据模式{8位写命令,24位地址,8位数据输入}}input [39:0] data;//由上面的模式选择可以的到输入最多为40位的数据,输入数据用40位的位宽,如果用不到40位则只需用低位,如16位只用到40位的低16位input cs;//输入的片选端input  miso;//flash的数据串行输出口output [7:0] state_reg;//状态寄存器的值output  mosi;//flash的数据串行输入端output spi_over;//执行完成时标识信号,为0时为完成为1 时表示已经完成output  spi_clk_out;//经过处理的spi时钟输出reg [5:0] spi_bit_num;reg       spi_clk_out_flag;reg [5:0] spi_bit_counter;reg spi_over_r;always@(posedge spi_clk_in)begin case(mode)//对spi_bit_counter进行判断,如果已经操作完成,则给一个信号用于控制spi_clk_out,2'b00:begin spi_bit_num <= 41; spi_clk_out_flag <= (spi_bit_counter >= 40)?1:0; end//00模式,在40位的基础上加上一个周期给cs拉低到开始操作,和一个周期给停止操作到cs拉高2'b01:begin spi_bit_num <= 9;  spi_clk_out_flag <= (spi_bit_counter >= 8)?1:0; end//01模式,同上2'b10:begin spi_bit_num <= 17; spi_clk_out_flag <= (spi_bit_counter >= 16)?1:0; end//10模式,同上2'b11:begin spi_bit_num <= 41; spi_clk_out_flag <= (spi_bit_counter >= 40)?1:0; end//11模式,同上default:begin spi_bit_num <= 0; spi_clk_out_flag <= 0; endendcaseendalways@(posedge spi_clk_in)beginif(cs) begin//如果没有被选中则清零spi_bit_counter <= 0;spi_over_r <= 0;endelse if(spi_over)//如果操作结束对进度计数器清零beginspi_bit_counter <= 0;endelse if(spi_bit_counter == spi_bit_num)//用于判断操作是否结束beginspi_bit_counter <= spi_bit_num;spi_over_r <= 1;endelsebeginspi_bit_counter <= spi_bit_counter + 1;//操作未结束时进度计数器自加spi_over_r <= 0;endendassign spi_clk_out = ((spi_bit_counter == 0) || (spi_clk_out_flag == 1)) ? 1 : spi_clk_in;//如果进度计数器是在0或者最大值,就是最小值和最大值,则时钟一直为1,否则就是spi时钟reg [39:0] data_r;reg mosi_r;always@(negedge spi_clk_out)//数据串行输出beginif(spi_over)mosi_r <= 0;elsecase(mode)//不同模式只取40位数据相应的位宽2'b00:mosi_r <= data_r[39];2'b01:mosi_r <= data_r[7];2'b10:mosi_r <= data_r[15];2'b11:mosi_r <= data_r[39];default:mosi_r <= 0;endcaseendalways@(posedge spi_clk_in)beginif(spi_bit_counter == 0)data_r <= data;//在进度为0时置数,将数据锁存进来else data_r <= data_r << 1;//随后开始右移,以满足总是取最高位给flash(上头的数据串行输出),简化设计endreg [7:0] state_reg_r;always@(posedge spi_clk_out)beginif((mode == 2'b10 && spi_bit_counter >= 9 && ~spi_over)||(mode == 2'b00 && spi_bit_counter >=33 && ~spi_over))//如果进度到了数据输出时开始更新寄存器数据state_reg_r <= {state_reg_r[6:0],miso};endassign state_reg = (spi_over)?state_reg_r:0;//操作完成时将数据输出assign mosi = mosi_r;assign spi_over = spi_over_r;endmodule



0 0
原创粉丝点击