SPI协议实现

  1. SPI是全双工,串行,同步的协议。
    在这里插入图片描述
    SPI先发高位再发低位。

  2. 有四种模式,通常采用0和3,因为支持flash读写。
    其中0模式实现如下
    在这里插入图片描述
    将MOSI和MISO连接一起形成回环测试。发送1010 10 10
    在这里插入图片描述

采用第一种模式,空闲状态为低电平

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           ,//o是主??
    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   
);

/***************function**************/

/***************parameter*************/

/***************port******************/             

/***************mechine***************/

/***************reg*******************/
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       ;

/***************component*************/

/***************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)   //写了多少数???的计数??  spi的长?? spi数据的长度
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;                  //主机发???,从机接收主句output 从机input
    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 if()
    else
        ro_user_read_data <= {ro_user_read_data[P_DATA_WIDTH - 2 : 0],i_spi_miso};//从机发???的数据
    // else if()

    // else 
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

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基于Nios的C编程可以实现SPI协议。在这个实验中,可以使用Nios软核作为主机部分,并使用IDE为Nios软核编写一个自动收发激励数据的C程序。同时,将上一次实验编译的myspi作为从机部分,构建SPI通信环路。这样,就可以在Nios处理器中生成激励数据并发送,然后通过Nios处理器读取结果数据并接收。每次发送一个数据同时接收一个数据,并使用软件进行验证读写是否正确。\[1\] 在这个实验中,需要注意一些主要问题。首先,要考虑Nios软核和DE0开发板之间建立SPI通信自环的时钟相位差。这是由于硬件布线造成的不可忽视的时延问题。不同的从机硬件设置不同的PLL,这直接影响Nios的发送和接收数据寻址是否正确。同时,还需要确定Nios中的SPI使用何种输入时钟。可以参考alter友晶提供的SDRAM DEMO,其中给出了DE0开发板SDRAM与CPU的时钟相位差。在本次实验中,可以使用CPU时钟而不是SDRAM时钟作为Nios中SPI的输入时钟。\[3\] 通过以上步骤,基于Nios的C编程可以实现SPI协议的功能。 #### 引用[.reference_title] - *1* *2* *3* [nios-spi进阶实验:SPI环路用NIOS处理器生成激励数据发送、接收并验证](https://blog.csdn.net/weixin_41033536/article/details/80242194)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值