FPGA模块——SPI接口设计

博客围绕SPI基础代码模版展开,介绍了其输入输出情况。还阐述了SPI协议与芯片交互接口,即加入芯片命令和寄存器地址的数据,读写位数由控制器控制;以及SPI协议的控制器(状态机),可连续读出FIFO中的数据。

SPI基础代码模版

user输入: valid信号 , 要输出的值
输出 :一个周期读valid , 读到的值
在这里插入图片描述

module spi_drive#(
    parameter                           P_DATA_WIDTH        = 8 ,
                                        P_READ_DATA_WIDTH   = 8 , 
                                        P_CPOL              = 0 ,
                                        P_CPHL              = 0 
)(                  
    input                               i_clk               ,
    input                               i_rst               ,

    output                              o_spi_clk           ,
    output                              o_spi_cs            ,
    output                              o_spi_mosi          ,
    input                               i_spi_miso          ,

    input   [P_DATA_WIDTH - 1 :0]       i_user_data         ,
    input                               i_user_valid        ,
    output                              o_user_ready        ,

    output  [P_READ_DATA_WIDTH - 1:0]   o_user_read_data    ,
    output                              o_user_read_valid   
);

reg                                 ro_spi_clk          ;
reg                                 ro_spi_cs           ;
reg                                 ro_spi_mosi         ;
reg                                 ro_user_ready       ;
reg  [P_DATA_WIDTH - 1:0]           r_user_data         ;
reg                                 r_run               ;
reg  [15:0]                         r_cnt               ;
reg                                 r_spi_cnt           ;
reg  [P_READ_DATA_WIDTH - 1:0]      ro_user_read_data   ;
reg                                 ro_user_read_valid  ;
reg                                 r_run_1d            ;
/***************wire******************/
wire                                w_user_active       ;
wire                                w_run_negedge       ;



/***************assign****************/
assign o_spi_clk            = ro_spi_clk            ;
assign o_spi_cs             = ro_spi_cs             ;
assign o_spi_mosi           = ro_spi_mosi           ;
assign o_user_ready         = ro_user_ready         ;
assign o_user_read_data     = ro_user_read_data     ;
assign o_user_read_valid    = ro_user_read_valid    ;
assign w_run_negedge        = !r_run & r_run_1d     ;

/***************always****************/
assign w_user_active = i_user_valid & o_user_ready;

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ro_user_ready <='d1;
    else if(w_user_active)
        ro_user_ready <= 'd0;
    else if(w_run_negedge)
        ro_user_ready <= 'd1;
    else 
        ro_user_ready <= ro_user_ready;
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_user_data <= 'd0;
    else if(w_user_active)
        r_user_data <= i_user_data;
    else if(r_spi_cnt)
        r_user_data <= r_user_data << 1;
    else 
        r_user_data <= r_user_data;    
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_run <= 'd0;
    else if(r_spi_cnt && r_cnt == 7)
        r_run <= 'd0;
    else if(w_user_active)
        r_run <= 'd1;
    else 
        r_run <= r_run;
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_run_1d <= 'd0;
    else
        r_run_1d <= r_run;
end
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_cnt <= 'd0;
    else if(r_spi_cnt && r_cnt == 7)
        r_cnt <= 'd0;
    else if(r_spi_cnt)
        r_cnt <= r_cnt + 1;
    else 
        r_cnt <= r_cnt;
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_spi_cnt <= 'd0;
    else if(r_run)
        r_spi_cnt <= r_spi_cnt + 1;
    else 
        r_spi_cnt <= 'd0;
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ro_spi_clk <= P_CPOL;
    else if(r_run)
        ro_spi_clk <= ~ro_spi_clk;
    else 
        ro_spi_clk <= P_CPOL; 
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ro_spi_cs <= 'd1;
    else if(w_user_active)
        ro_spi_cs <= 'd0;
    else if(!r_run)
        ro_spi_cs <= 'd1;
    else 
        ro_spi_cs <= ro_spi_cs;
end


always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ro_spi_mosi <= 'd0;
    else if(w_user_active)
        ro_spi_mosi <= i_user_data[P_DATA_WIDTH - 1];
    else if(r_spi_cnt)
        ro_spi_mosi <= r_user_data[P_DATA_WIDTH - 2];
    else 
        ro_spi_mosi <= ro_spi_mosi;
end     

always@(posedge ro_spi_clk,posedge i_rst)
begin
    if(i_rst)
        ro_user_read_data <= 'd0;
    
    else
        ro_user_read_data <= {
   
   ro_user_read_data[P_DATA_WIDTH - 2 : 0],i_spi_miso};
    
end

always@(posedge i_clk,posedge i_rst) 
begin
    if(i_rst)
        ro_user_read_valid <= 'd0;
    else if(r_spi_cnt && r_cnt == 7)
        ro_user_read_valid <= 'd1;
    else 
        ro_user_read_valid <= 'd0;
end

endmodule

1. SPI协议与芯片交互接口

实际上就是加入了(芯片命令cmd + 寄存器地址) 的数据。读写操作的位数可以由spi控制器来控制,用于完成各种spi协议芯片的读写任务。

读数据
在这里插入图片描述

写数据
在这里插入图片描述

module spi_drive#(
    parameter                           P_DATA_WIDTH        = 8 ,
                                        P_OP_LEN            = 32,
                                        P_READ_DATA_WIDTH   = 8 , 
                                        P_CPOL              = 0 ,
                                        P_CPHL              = 0 
)(                  
    input                               i_clk               ,//系统时钟
    input                               i_rst               ,//复位
    
    //spi驱动
    output                              o_spi_clk           ,//spi的clk
    output                              o_spi_cs            ,//spi的片选
    output                              o_spi_mosi          ,//spi的主机输出
    input                               i_spi_miso          ,//spi的从机输入
    
    //操作通道
    input   [P_OP_LEN - 1 :0]           i_user_op_data      ,//操作数据(命令8bit+地址24bit)
    input   [1 :0]                      i_user_op_type      ,//操作类型(读、写、指令)
    input   
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

湖南恒力电子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值