FPGA 实现SPI 主机双工通信 CS前后肩可调 操作时钟频率可调 ,SPI模式可调,传输位宽可调(最大32位)
1 //testbench 2 `timescale 1ns/1ns 3 module lcd_spi_m_tb(); 4 reg rst_n_i; 5 reg spi_clkx_i; 6 reg [31:0] spi_data_i; 7 reg spi_start; 8 reg spi_miso_r1,spi_miso_r2; 9 wire spi_miso_i; 10 wire [0:0] spi_done; 11 wire [0:0] spi_busy; 12 wire [0:0] spi_cs_o; 13 wire [0:0] spi_scl_o; 14 wire [0:0] spi_mosi_o; 15 wire [31:0] spi_data_o; 16 17 localparam CPOL=1'B0 ; 18 localparam CPHA=1'B1 ; 19 20 21 22 always #50 spi_clkx_i<=~spi_clkx_i; 23 initial begin 24 rst_n_i=0; 25 spi_clkx_i=0; 26 #200; 27 spi_start=0; 28 rst_n_i=1; 29 @(posedge spi_clkx_i) 30 spi_data_i=16'h8121; 31 spi_start=1; 32 @(posedge spi_clkx_i) 33 spi_start=0; 34 @(posedge spi_done) 35 #200; 36 @(posedge spi_clkx_i) 37 spi_data_i=16'h0003; 38 spi_start=1; 39 @(posedge spi_clkx_i) 40 spi_start=0; 41 @(posedge spi_done) 42 #200; 43 @(posedge spi_clkx_i) 44 spi_data_i=16'hF227; 45 spi_start=1; 46 @(posedge spi_clkx_i) 47 spi_start=0; 48 @(posedge spi_done) 49 #200; 50 @(posedge spi_clkx_i) 51 spi_data_i=16'hA31B; 52 spi_start=1; 53 @(posedge spi_clkx_i) 54 spi_start=0; 55 @(posedge spi_done) 56 $stop; 57 end 58 59 always @(negedge spi_scl_o or negedge rst_n_i )//要根据CPOL CPHA配置 spi_scl_o采样极性 60 begin 61 if(rst_n_i==1'b0) 62 spi_miso_r1<=1'b1; 63 else if (spi_cs_o==1'b0 ) 64 spi_miso_r1<=~spi_miso_r1; 65 else 66 spi_miso_r1<=1'b0; 67 end 68 69 always @(posedge spi_scl_o or negedge rst_n_i )//要根据CPOL CPHA配置 spi_scl_o采样极性 70 begin 71 if(rst_n_i==1'b0) 72 spi_miso_r2<=1'b1; 73 else if (spi_cs_o==1'b0 ) 74 spi_miso_r2<=~spi_miso_r2; 75 else 76 spi_miso_r2<=1'b0; 77 end 78 assign spi_miso_i =(CPOL==1'B0 && CPHA==1'B0 || CPOL==1'B1 && CPHA==1'B1)? spi_miso_r1 :spi_miso_r2; 79 80 lcd_spi_m 81 #( 82 .SPI_IN_WIDTH(6'd16),//spi 输入位数 83 .SPI_OUT_WIDTH(6'd16),//SPI 输出位数 84 .SPI_CPOL(CPOL), 85 .SPI_CPHA(CPHA), 86 .CLK_DIV(6'D5), 87 .CS_F_DELAY(6'd3), 88 .CS_B_DELAY(6'd3) 89 90 91 92 ) 93 lcd_spi_m_inst 94 ( 95 .rst_n_i (rst_n_i ) , 96 .spi_clkx_i (spi_clkx_i ) , 97 .spi_data_i (spi_data_i ) , 98 .spi_start (spi_start ) , 99 .spi_miso_i (spi_miso_i ) , 100 .spi_done (spi_done ) , 101 .spi_busy (spi_busy ) , 102 .spi_cs_o (spi_cs_o ) , 103 .spi_scl_o (spi_scl_o ) , 104 .spi_mosi_o (spi_mosi_o ) , 105 .spi_data_o (spi_data_o ) 106 107 ); 108 109 endmodule
1 //SPI主程序 2 //功能:完成32位以内SPI接口的数据双向通信 3 module lcd_spi_m 4 #( 5 parameter [5:0]SPI_IN_WIDTH =6'd16,//spi 输入位数 6 parameter [5:0]SPI_OUT_WIDTH =6'd16,//SPI 输出位数 7 parameter [0:0]SPI_CPOL=1'b0,//空闲状态SCL电平 0:SCL=0 1:SCL=1 8 parameter [0:0]SPI_CPHA=1'b0, //SPI数据在哪个SCL边沿有效 0:数据在SCL第一个边沿有效,1:数据在SCL第二个边沿有效, 9 parameter [5:0]CLK_DIV =6'D3, //设定SPI_SCL半个周期所占的spi_clkx_i时钟个数 10 parameter [5:0]CS_F_DELAY=6'D1, //CS前延时,相对于spi_scl_o时钟个数 11 parameter [5:0]CS_B_DELAY=6'D1 //CS后延时,相对于spi_scl_o时钟个数 12 13 14 ) 15 ( 16 input wire [0:0] rst_n_i, //复位输入,低电平复位 17 input wire [0:0] spi_clkx_i,//SPI系统时钟 为SCL输出时钟的倍数 spi_clkx_i=spi_scl_o*2(高电平+低电平)*CLK_DIV 18 input wire [31:0] spi_data_i,//输入32位要从MOSI发送出去的数据 19 input wire [0:0] spi_start, //单次发送开始,把数据送到spi_data_i 并把spi_start维技一个周期的高电平 20 input wire [0:0] spi_miso_i,//主机接收从机输出引脚 21 output reg [0:0] spi_done,//SPI完成一次传输并从spi_data_o输出读到的数??? 22 output reg [0:0] spi_busy,//SPI忙信号输出,在忙状态时不接收外部数据,高表示忙 23 output reg [0:0] spi_cs_o,//SPI片选信号输出低有效 24 output wire [0:0] spi_scl_o,//SPI 时钟信号输出,请结合CPOL CPHA分析有效??? 25 output reg [0:0] spi_mosi_o,//SPI主机输出从机输入接口 26 output reg [31:0] spi_data_o//从从机读到的数据在SPI_DONE为高时为有效数据 27 28 29 ); 30 localparam [5:0]CS_F_CNT=CS_F_DELAY-6'D1; //CS前面延时 31 localparam [5:0]CS_B_CNT=CS_B_DELAY-6'D1; //CS前面延时 32 localparam [5:0] WIDTH_MAX=(SPI_IN_WIDTH>SPI_OUT_WIDTH)? SPI_IN_WIDTH :SPI_OUT_WIDTH;//16 33 localparam [7:0] SPI_MAX =WIDTH_MAX+CS_F_DELAY+CS_B_DELAY-1'D1;//17 34 35 36 reg [7:0] spi_scl_cnt; 37 reg [7:0 ] clk_cnt; 38 reg [1:0] pol_cnt; 39 reg [0:0] spi_sclk_r; 40 wire [0:0] spi_flag; 41 wire [0:0] pol_flag; 42 //产生时钟计数 43 always @(posedge spi_clkx_i or negedge rst_n_i) 44 begin 45 if(rst_n_i==1'b0) 46 clk_cnt<=8'd0; 47 else if(spi_busy==1'b1 ) 48 begin 49 if(clk_cnt>=CLK_DIV-1'd1) 50 clk_cnt<=8'd0; 51 else 52 clk_cnt<=clk_cnt+1'd1; 53 end 54 else 55 clk_cnt<=8'd0; 56 end 57 58 59 60 //产生SPI_SCL极性计数 61 always @(posedge spi_clkx_i or negedge rst_n_i) 62 begin 63 if(rst_n_i==1'b0) 64 pol_cnt<=2'd0; 65 else if(pol_cnt>=2'd1 && clk_cnt>=CLK_DIV-1'd1) 66 pol_cnt<=2'd0; 67 else if(clk_cnt>=CLK_DIV-1'd1) 68 pol_cnt<=pol_cnt+1'd1; 69 else 70 pol_cnt<=pol_cnt; 71 end 72 73 assign pol_flag= (clk_cnt>=CLK_DIV-1'd1)? 1'b1:1'b0; 74 75 //产生spi_scl时钟计数 76 always @(posedge spi_clkx_i or negedge rst_n_i) 77 begin 78 if(rst_n_i==1'b0) 79 spi_scl_cnt<=15'd0; 80 else if((spi_scl_cnt>=SPI_MAX) &&(spi_flag==1'b1)) 81 spi_scl_cnt<=8'd0; 82 else if(spi_flag==1'b1) 83 spi_scl_cnt<=spi_scl_cnt+1'd1; 84 else 85 86 spi_scl_cnt<=spi_scl_cnt; 87 88 end 89 assign spi_flag=(clk_cnt>=CLK_DIV-1'd1 && pol_cnt>=1'd1)? 1'b1:1'b0; 90 91 //输出SPI_CS信号 92 always @(posedge spi_clkx_i or negedge rst_n_i) 93 begin 94 if(rst_n_i==1'b0) 95 spi_cs_o<=1'b1; 96 else if(spi_start==1'b1 && spi_busy==1'b0) 97 spi_cs_o<=1'b0; 98 else if((spi_scl_cnt>=SPI_MAX) &&(spi_flag==1'b1)) 99 spi_cs_o<=1'b1; 100 else 101 spi_cs_o<=spi_cs_o; 102 end 103 104 //输出SPI_DONE信号 105 always @(posedge spi_clkx_i or negedge rst_n_i) 106 begin 107 if(rst_n_i==1'b0) 108 spi_done<=1'b0; 109 else if((spi_scl_cnt>=SPI_MAX) &&(spi_flag==1'b1)) 110 spi_done<=1'b1; 111 else 112 spi_done<=1'b0; 113 end 114 115 116 //输出spi_scl信号 117 always @(posedge spi_clkx_i or negedge rst_n_i) 118 begin 119 if(rst_n_i==1'b0) 120 begin 121 spi_sclk_r<=1'b0; 122 end 123 else if(pol_flag==1'b1) 124 spi_sclk_r<=~spi_sclk_r; 125 else 126 begin 127 spi_sclk_r<=spi_sclk_r; 128 end 129 end 130 assign spi_scl_o =((spi_scl_cnt>CS_F_CNT) && (spi_scl_cnt<(SPI_MAX-CS_B_CNT)))?((SPI_CPOL)? ~spi_sclk_r:spi_sclk_r):((SPI_CPOL==1'B1)? 1'B1:1'B0); 131 132 133 //在spi_start???时捕获数??? 134 reg [31:0] temp_data_i; 135 //输出SPI_MOSI信号 136 always @(posedge spi_clkx_i or negedge rst_n_i) 137 begin 138 if(rst_n_i==1'b0) 139 begin 140 spi_mosi_o<=1'b0; 141 spi_busy<=1'b0; 142 temp_data_i<=32'b0; 143 end 144 else if(spi_start==1'b1 && spi_busy==1'b0) //在spi_start???时捕获数??? 145 begin 146 temp_data_i<=spi_data_i; 147 spi_busy<=1'b1; 148 end 149 else if(spi_done==1'b1) 150 spi_busy<=1'b0; 151 else if(SPI_CPHA==1'b0) 152 begin 153 if((spi_scl_cnt>=CS_F_CNT) && (spi_scl_cnt<(SPI_MAX-CS_B_CNT)) &&(spi_flag==1'b1) && (pol_flag==1'b1) ) 154 begin 155 spi_mosi_o<=temp_data_i[SPI_OUT_WIDTH-1'd1]; 156 temp_data_i<={temp_data_i[(SPI_OUT_WIDTH-2'd2):0],temp_data_i[SPI_OUT_WIDTH-1'd1]}; 157 end 158 else 159 begin 160 spi_mosi_o<=spi_mosi_o; 161 end 162 163 end 164 else 165 begin 166 if((spi_scl_cnt>CS_F_CNT) && (spi_scl_cnt<(SPI_MAX-CS_B_CNT))&& (spi_flag==1'b0) && (pol_flag==1'b1))//CPOL=0 CPHA=1->NG 167 begin 168 spi_mosi_o<=temp_data_i[SPI_OUT_WIDTH-1'd1]; 169 temp_data_i<={temp_data_i[SPI_OUT_WIDTH-2'd2:0],temp_data_i[SPI_OUT_WIDTH-1'd0]}; 170 end 171 else 172 begin 173 spi_mosi_o<=spi_mosi_o; 174 end 175 end 176 177 178 179 end 180 181 //接收SPI_MISO信号 182 always @(posedge spi_clkx_i or negedge rst_n_i) 183 begin 184 if(rst_n_i==1'b0) 185 spi_data_o<=32'b0; 186 else if(SPI_CPHA==1'b0) 187 begin 188 if((spi_scl_cnt>CS_F_CNT) && (spi_scl_cnt<(SPI_MAX-CS_B_CNT)) &&(pol_flag==1'b1)&& (spi_flag==1'b0) ) 189 begin 190 spi_data_o<={spi_data_o[30:0],spi_miso_i}; 191 end 192 else 193 begin 194 spi_data_o<=spi_data_o; 195 end 196 end 197 else if(SPI_CPHA==1'b1) 198 begin 199 if((spi_scl_cnt>CS_F_CNT) && (spi_scl_cnt<(SPI_MAX-CS_B_CNT)) &&(pol_flag==1'b1)&& (spi_flag==1'b1) ) 200 begin 201 spi_data_o<={spi_data_o[30:0],spi_miso_i}; 202 end 203 else 204 begin 205 spi_data_o<=spi_data_o; 206 end 207 end 208 else 209 begin 210 spi_data_o<=spi_data_o; 211 end 212 213 end 214 215 216 endmodule