本实验重点学习了:
flash的页编程指令pp。
在写之前要先进行擦除(全擦除和页擦除);
本实验:先传写指令,然后进入写锁存周期,然后传页编程指令,+3个地址;
然后传数据,奇数传55,偶数传aa。
在之前扇区擦除的代码上改改就行了。加一个功能就是传入数据大于256个时候,mosi一直拉高。
模块框图:
状态机:
代码:
只放spi模块的。因为其他代码和扇区擦除指令是一样的。
module spi (input wire sys_clk ,input wire sys_rst_n , input wire key_start ,output wire miso ,output reg mosi ,output reg cs_n ,output reg sck
);// parameter parameter COMD_W = 8'h06 , // 写指令, 先发送写指令,进入写锁存周期COMD_P = 8'h02 , // 页写指令MAX_NUM = 32'd270 ; // 要发送指令+地址+数据的字节数。 2 + 3 + 100parameter ADR_SE = 8'h00 , // 扇区地址 adress secterADR_PA = 8'h04 , // 页地址 adress pageADR_BY = 8'h00 ; // 字节地址 adress byteparameter DATA_ODD = 8'h55 , // odd 奇数DATA_EVE = 8'haa ; // even 偶数parameter IDLE = 5'b00001 ,WREN = 5'b00010 ,WEL = 5'b00100 ,INST = 5'b01000 , // instruct 传送pp指令和addrDATA = 5'b10000 ; // instruct 传送要写入的数据。// wire signal deginewire IDLEtoWREN; wire WRENtoWEL ; wire WRENtoINST; wire INSTtoDATA; wire DATAtoIDLE; // reg signal definereg [19:0] data_num ; // 记录传递的数据,如果超过256个,那么mosi将会一直拉高(传1).reg [4:0] state_c ;reg [4:0] state_n ;reg [3:0] cnt_20ns ;reg [3:0] cnt_bit ;reg [31:0] cnt_byte ;reg flag_bit ;reg f_b_reg ; // flag_bit_reg的缩写
/****************************************************************************/// 三段式状态机// 现态与次态描述// state_calways @(posedge sys_clk or negedge sys_rst_n) beginif(~sys_rst_n) state_c <= IDLE ;elsestate_c <= state_n ;end// state_nalways @(*) begincase (state_c)IDLE :if(IDLEtoWREN)state_n <= WREN ;else state_n <= IDLE ;WREN :if(WRENtoWEL)state_n <= WEL ;else state_n <= WREN ;WEL :if(WRENtoINST)state_n <= INST ;else state_n <= WEL ;INST :if(INSTtoDATA)state_n <= DATA ;else state_n <= INST ;DATA :if(DATAtoIDLE)state_n <= IDLE ;else state_n <= DATA ;default: state_n <= IDLE ;endcaseend// 状态转移描述assign IDLEtoWREN = ( state_c == IDLE) && ( key_start ) ;assign WRENtoWEL = ( state_c == WREN) && ( f_b_reg ) ;assign WRENtoINST = ( state_c == WEL ) && ( cnt_20ns == 6 ) ;assign INSTtoDATA = ( state_c == INST) && ( f_b_reg ) ;assign DATAtoIDLE = ( state_c == DATA) && ( f_b_reg && cnt_byte != 5) ; // 至少传递一个数据。否则会卡死在这个状态。// 相关信号描述// reg [3:0] cnt_20ns ;always @(posedge sys_clk or negedge sys_rst_n) beginif(~sys_rst_n) cnt_20ns <= 4'd0 ;else case (state_c)IDLE : cnt_20ns <= 4'd0 ;WREN : if(cnt_20ns || f_b_reg)cnt_20ns <= 4'd0 ;else cnt_20ns <= cnt_20ns + 1'b1 ;WEL : if(cnt_20ns == 6) // 60x20ns==120nscnt_20ns <= 4'd0 ;elsecnt_20ns <= cnt_20ns + 1'b1 ;INST : if(cnt_20ns) // 由于下一个状态是发送数据,sck和cnt_20_ns的变换规律与INST相同。所以不需要f_b_reg。cnt_20ns <= 4'd0 ;else cnt_20ns <= cnt_20ns + 1'b1 ;DATA : if(cnt_20ns || (f_b_reg && cnt_byte != 5))cnt_20ns <= 4'd0 ;else cnt_20ns <= cnt_20ns + 1'b1 ;default: cnt_20ns <= 4'd0 ;endcaseend// reg [3:0] cnt_bit ;always @(posedge sys_clk or negedge sys_rst_n) beginif(~sys_rst_n)cnt_bit <= 4'd0 ;else case (state_c)IDLE : cnt_bit <= 4'd0 ;WREN : if(!cnt_20ns && sck && cnt_bit == 7)cnt_bit <= 4'd0 ;else if(!cnt_20ns && sck)cnt_bit <= cnt_bit + 1'b1 ;WEL : cnt_bit <= 4'd0 ;INST : if(!cnt_20ns && sck && cnt_bit == 7)cnt_bit <= 4'd0 ;else if(!cnt_20ns && sck)cnt_bit <= cnt_bit + 1'b1 ;DATA : if(!cnt_20ns && sck && cnt_bit == 7)cnt_bit <= 4'd0 ;else if(!cnt_20ns && sck)cnt_bit <= cnt_bit + 1'b1 ;default: cnt_bit <= 4'd0 ;endcaseend// reg [31:0] cnt_bytealways @(posedge sys_clk or negedge sys_rst_n) beginif(~sys_rst_n) cnt_byte <= 32'd0 ;else if(cnt_bit == 7 && !cnt_20ns && sck && cnt_byte == MAX_NUM - 1) // 计数到传送字节的最大值。cnt_byte <= 32'd0 ;else if(cnt_bit == 7 && !cnt_20ns && sck)cnt_byte <= cnt_byte + 1'b1 ;else cnt_byte <= cnt_byte ;end// reg flag_bit ;always @(posedge sys_clk or negedge sys_rst_n) beginif(~sys_rst_n) flag_bit <= 1'b0 ;elsecase (state_c)IDLE : flag_bit <= 1'b0 ;WREN : if(cnt_bit == 7 && sck && !cnt_20ns)flag_bit <= 1'b1 ;else flag_bit <= flag_bit ;WEL : flag_bit <= 1'b0 ;INST : if(cnt_bit == 7 && sck && !cnt_20ns && cnt_byte == 4)flag_bit <= 1'b1 ;else flag_bit <= flag_bit ;DATA : if(cnt_bit == 0 && cnt_byte == 5)flag_bit <= 1'b0 ;else if(cnt_bit == 7 && sck && !cnt_20ns && cnt_byte == MAX_NUM - 1)flag_bit <= 1'b1 ;else flag_bit <= flag_bit ;default: flag_bit <= 1'b0 ;endcaseend// reg f_b_reg ;always @(posedge sys_clk or negedge sys_rst_n) beginif(~sys_rst_n) beginf_b_reg <= 1'b0 ;end else beginf_b_reg <= flag_bit ;endend// reg [19:0] data_numalways @(posedge sys_clk or negedge sys_rst_n) beginif(~sys_rst_n)data_num <= 20'd0 ;else if(state_c == DATA && cnt_bit == 7 && !cnt_20ns && sck)data_num <= data_num + 1'b1 ;else if(state_c != DATA)data_num <= 20'd0 ;else data_num <= data_num ;end// output signal// wire miso ,assign miso = 1'bz ;// mosialways @(posedge sys_clk or negedge sys_rst_n) beginif(~sys_rst_n)mosi <= 1'b0 ;elsecase (state_c)IDLE : mosi <= 1'b0 ;WREN : if(!cnt_bit) // (cnt_bit == 0)mosi <= COMD_W[7] ;else if(cnt_20ns && sck)mosi <= COMD_W[7 - cnt_bit] ;else mosi <= mosi ;WEL : mosi <= 1'b0 ;INST : case (cnt_byte)1: beginif(!cnt_bit)mosi <= COMD_P[7] ;else if(cnt_20ns && sck)mosi <= COMD_P[7 - cnt_bit] ;else mosi <= mosi ; end2: beginif(!cnt_bit)mosi <= ADR_SE[7] ;else if(cnt_20ns && sck)mosi <= ADR_SE[7 - cnt_bit] ;else mosi <= mosi ; end3: beginif(!cnt_bit)mosi <= ADR_PA[7] ;else if(cnt_20ns && sck)mosi <= ADR_PA[7 - cnt_bit] ;else mosi <= mosi ; end4: beginif(!cnt_bit)mosi <= ADR_BY[7] ;else if(cnt_20ns && sck)mosi <= ADR_BY[7 - cnt_bit] ;else mosi <= mosi ; end5: beginif(!cnt_bit) // 由于当cnt_byte == 5 时,有一段state_c没有立即跳转到data状态。mosi <= DATA_ODD[7] ;else if(cnt_20ns && sck)mosi <= DATA_ODD[7 - cnt_bit] ;else mosi <= mosi ; enddefault: mosi <= 1'b0 ;endcaseDATA : if(data_num <= 255) beginif(cnt_byte[0]) begin // 二进制最低为奇偶标志位,1表示奇位,发送数据5。if(!cnt_bit)mosi <= DATA_ODD[7] ;else if(cnt_20ns && sck)mosi <= DATA_ODD[7 - cnt_bit] ;else mosi <= mosi ; end else begin // cnt_byte[0] == 0 偶数。发送数据aif(!cnt_bit)mosi <= DATA_EVE[7] ;else if(cnt_20ns && sck)mosi <= DATA_EVE[7 - cnt_bit] ;else mosi <= mosi ; endend else beginmosi <= 1'b1 ; // 大于256个数据之后,mosi就一直传递1.enddefault: mosi <= 1'b0 ;endcaseend// reg cs_n ,always @(posedge sys_clk or negedge sys_rst_n) beginif(~sys_rst_n) begincs_n <= 1'b1 ;end else begincase (state_c)IDLE : if(key_start)cs_n <= 1'b0 ;else cs_n <= 1'b1 ;WREN : if(f_b_reg)cs_n <= 1'b1 ;else cs_n <= cs_n ;WEL : if(cnt_20ns == 6) cs_n <= 1'b0 ;else cs_n <= cs_n ;INST : cs_n <= 1'b0 ;DATA : if(f_b_reg && cnt_byte != 5 )cs_n <= 1'b1 ;else cs_n <= cs_n ;default: cs_n <= 1'b1 ;endcaseendend// reg sck always @(posedge sys_clk or negedge sys_rst_n) beginif(~sys_rst_n)sck <= 1'b0 ;else case (state_c)IDLE : sck <= 1'b0 ;WREN : if(cnt_20ns)sck <= ~sck ;else sck <= sck ;WEL : sck <= 1'b0 ;INST : if(cnt_20ns)sck <= ~sck ;else sck <= sck ;DATA : if(cnt_20ns)sck <= ~sck ;else sck <= sck ;default: sck <= 1'b0 ;endcaseendendmodule
仿真波形: