📄 spi_controller.v
字号:
module spi_controller(clk,reset,sck_int,sck_int_re,sck_int_fe, sck_re,sck_fe,start,done,rec_load,ss_mask_reg, /*ss_in_int,*/tx_empty,tx_empty_reset,rec_full, rec_full_reset,cpha,cpol,ss_n,/*ss_in_n,*/ss_n_int, tx_shift,tx_load,clk0_mask,clk1_mask); //mcu interface input start; //start transfer output done; //byte transfer is complete input rec_load; //load control signal to spi receive register input [7:0]ss_mask_reg; //uc slave select register //inout ss_in_int; //internal sampled version of ss_in_n needed by //mcu to generate an interrupt inout tx_empty; //flag indicating that spitr is empty input tx_empty_reset; //tx_empty flag reset when spitr is written output rec_full; //flag indicating that spirr has new data input rec_full_reset; //rec_full flag reset when spirr is read input cpha; //clock phase from mcu input cpol; //clock polarity from mcu //spi interface output [7:0]ss_n; //slave select signals //input ss_in_n; //input slave select indicating master bus contention inout ss_n_int; //slave select register //internal interface input sck_int; //internal version of sck with cpha=1 input sck_int_re; //indicates rising edge on internal sck input sck_int_fe; //indicates falling edge on internal sck input sck_re; //indicates rising edge on external sck input sck_fe; //indicates falling edge on external sck output tx_shift; //shift control signal to spi xmit shift register inout tx_load; //load control signal to the spi xmit shift register output clk0_mask; //masks cpha=0 version of sck output clk1_mask; //masks cpha=1 version of sck input clk,reset; reg done,rec_full,tx_shift,clk0_mask, clk1_mask; reg /*ss_in_int_reg,*/tx_empty_reg,tx_load_reg; //reg ss_in_neg; //SS_IN_N sampled with negative edge of clk //reg ss_in_pos; //SS_IN_N sampled with rising edge of clk //reg [7:0]ss_n_out; //output SS_N that are 3-stated if SS_IN_INT reg cnt_en; //count enable for counter reg cnt_reset; //reset for counter from SPI wire [3:0]cnt; //counter output reg cnt_rst; //reset to counter that includes SS_IN_INT parameter idle=0,assert_ssn1=1,assert_ssn2=2,unmask_sck=3, xfer_bit=4,assert_done=5,chk_start=6,mask_sck=7, hold_ssn1=8,hold_ssn2=9,negate_ssn=10; reg [3:0]state,next_state; counter_4bit cnt_4(.clk(sck_int),.clr(cnt_reset),.cnt_en(cnt_en), .q(cnt)); //assign ss_in_int=ss_in_int_reg; assign tx_empty=tx_empty_reg; assign tx_load=tx_load_reg; //assign cnt_reset=(cnt_rst==0)?0:1; assign ss_n_int=((state==idle)||(state==negate_ssn))?1:0; assign ss_n=~ss_mask_reg; //sample ss_in_n signal at posedge /*always @(posedge clk or negedge reset) begin if (!reset) ss_in_pos<=1; else ss_in_pos<=ss_in_n; end */ //sample ss_in_n signal at negedge /*always @(negedge clk or negedge reset) begin if (!reset) ss_in_neg<=1; else ss_in_neg<=ss_in_n; end */ //generate ss_in_int /*always @(posedge clk or negedge reset) begin if (!reset) ss_in_int_reg<=1; else if ((ss_in_pos==0)&&(ss_in_neg==0)) ss_in_int_reg<=0; else ss_in_int_reg<=1; end */ //spi_sm always @(posedge clk or negedge reset) begin if (!reset) state<=idle; else state<=next_state; end always @(state,start,cnt,sck_int_re,sck_int_fe,sck_re, sck_fe,tx_empty,cpha,cpol) begin clk0_mask<=0; clk1_mask<=0; cnt_en<=0; cnt_rst<=0; done<=0; tx_shift<=0; tx_load_reg<=0; case (state) idle: begin if ((start==1)&&(tx_empty==0)) next_state<=assert_ssn1; else next_state<=idle; end //this state asserts SS_N and waits for first edge of SCK_INT //SS_N must be asserted ~1 SCK before SCK is output from chip assert_ssn1: begin if (sck_int_re==1) next_state<=assert_ssn2; else next_state<=assert_ssn1; end //this state asserts SS_N and waits for next edge of SCK_INT //SS_N must be asserted ~1 SCK before SCK is output from chip assert_ssn2: begin if (sck_int_fe==1) next_state<=unmask_sck; else next_state<=assert_ssn2; end //UNMASK_SCK State unmask_sck: begin cnt_rst<=1; //release counter from reset cnt_en<=1; //enable counter clk1_mask<=1; //unmask sck_1 tx_load_reg<=1; //load SPI shift register if (sck_int_re==1) next_state<=xfer_bit; else next_state<=unmask_sck; end //XFER_BIT State xfer_bit: begin cnt_rst<=1; //release counter from reset cnt_en<=1; //enable counter clk0_mask<=1; //unmask sck_0 clk1_mask<=1; //unmask sck_1 tx_shift<=1; //enable shifting of SPI shift registers if (cnt==8) next_state<=assert_done; else next_state<=xfer_bit; end //this state asserts done to the uC so that new data //can be written into the transmit register or data //can be read from the receive register assert_done: begin done<=1; clk0_mask<=1; clk1_mask<=1; tx_shift<=1; if (sck_int_fe==1) next_state<=chk_start; else next_state<=assert_done; end //CHK_START State chk_start: begin cnt_en<=1; cnt_rst<=1; clk0_mask<=1; clk1_mask<=1; done<=1; if (cpha==0) //when CPHA = 0, have to negate slave select and then //re-assert it. Need to wait for last SCK pulse to complete //and mask SCK before negating SS_N. if (((sck_re==1)&&(cpol==1))|| ((sck_fe==0)&&(cpol==0))) begin clk0_mask<=0; clk1_mask<=0; next_state<=mask_sck; end //else // begin // clk0_mask<=clk0_mask; // clk1_mask<=clk1_mask; // end //CPHA=1 and have more data to transfer, go back to //UNMASK_CK state else if ((start==1)&&(tx_empty==0)) begin clk1_mask<=1; tx_load_reg<=1; next_state<=unmask_sck; end else //CPHA=1 and no more data to transfer //wait for last SCKs and then mask SCK begin if (((sck_re==1)&&(cpol==1))|| ((sck_fe==0)&&(cpol==0))) begin clk0_mask<=0; clk1_mask<=0; next_state<=mask_sck; end //else // begin // clk0_mask<=clk0_mask; // clk1_mask<=clk1_mask; // end //else next_state<=chk_start; clk0_mask<=0; clk1_mask<=1; end end //MASK_SCK State //wait for next internal SCK edge to help provide SS_N hold time mask_sck: begin if (sck_int_fe==1) next_state<=hold_ssn1; else next_state<=mask_sck; end //HOLD_SSN1 State //This state waits for another SCK edge to provide SS_N hold time hold_ssn1: begin if (sck_int_fe==1) next_state<=hold_ssn2; else next_state<=hold_ssn1; end //HOLD_SSN2 State //This state waits for another SCK edge to provide SS_N hold time hold_ssn2: begin if (sck_int_fe==1) next_state<=negate_ssn; else next_state<=hold_ssn2; end //NEGATE_SSN State //SS_N should negate for an entire SCK This state waits for an SCK edge negate_ssn: begin if (sck_int_fe==1) next_state<=idle; else next_state<=negate_ssn; end default: next_state<=idle; endcase end //generate tx_empty always @(posedge sck_int or negedge reset) begin if (!reset) tx_empty_reg<=0; else if (!tx_empty_reset) tx_empty_reg<=0; else if (tx_load) tx_empty_reg<=1; //else tx_empty_reg<=tx_empty_reg; end //generate rec_full always @(posedge clk or negedge reset) begin if (!reset) rec_full<=0; else if (!rec_full_reset) rec_full<=0; else if (rec_load) rec_full<=1; //else rec_full<=rec_full; end //generate ss_n_out /*always @(posedge clk or negedge reset) begin if (!reset) ss_n_out<=8'b11111111; else if (ss_n_int==0) ss_n_out<=~ss_mask_reg; else ss_n_out<=8'b11111111; end */ always @(cnt_rst,reset) begin if (cnt_rst==!reset) cnt_reset<=0; else cnt_reset<=1; end endmodule
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -