首页 > 其他分享 >SPI主机 双工

SPI主机 双工

时间:2023-09-26 19:44:24浏览次数:48  
标签:CNT 双工 SPI 主机 spi wire CS reg

//主程序
//功能:完成32位以内SPI接口的数据双向通信
module  lcd_spi_m
#(
    parameter [5:0]spi_in_width  =6'd9,//spi  输入位数
    parameter [5:0]spi_out_width =6'd9,//SPI  输出位数
    parameter [0:0]spi_cpol=1'b0,//空闲状态SCL电平 0:SCL=0  1:SCL=1
    parameter [0:0]spi_cpha=1'b1 //SPI数据在哪个SCL边沿有效 0:数据在SCL第一个边沿有效,1:数据在SCL第二个边沿有效,


)
(
     input  wire  [0:0]  rst_n_i, //复位输入,低电平复位 
     input  wire  [0:0]  spi_x2clk_i,//SPI系统时钟 为SCL输出时钟的两倍
     input  wire  [31:0] spi_data_i,//输入32位要从MOSI发送出去的数据
     input  wire  [0:0]  spi_start, //单次发送开始,把数据送到spi_data_i 并把spi_start维技一个周期的高电平   
     input  wire  [0:0]  spi_miso_i,//主机接收从机输出引脚
     output reg   [0:0]  spi_done,//SPI完成一次传输并从spi_data_o输出读到的数据
     output reg   [0:0]  spi_busy,//SPI忙信号输出,在忙状态时不接收外部数据,高表示忙
     output reg   [0:0]  spi_cs_o,//SPI片选信号输出低有效
     output reg   [0:0]  spi_scl_o,//SPI 时钟信号输出,请结合CPOL CPHA分析有效性
     output reg   [0:0]  spi_mosi_o,//SPI主机输出从机输入接口
     output reg   [31:0] spi_data_o//从从机读到的数据在SPI_DONE为高时为有效数据
     
             
);

localparam [7:0] CS_F_DELAY=8'D1; //CS前面延时
localparam [7:0] CS_B_DELAY=8'D1; //CS后面延时
localparam [7:0] CS_F_CNT=CS_F_DELAY+CS_F_DELAY; //CS前面延时
localparam [7:0] CS_B_CNT=CS_B_DELAY+CS_B_DELAY; //CS后面延时
localparam [7:0] WIDTH_MAX=(spi_in_width>spi_in_width)? (spi_in_width*2'D2+CS_F_CNT+CS_B_CNT) :(spi_out_width*2'D2+CS_F_CNT+CS_B_CNT);

//在spi_start为1时捕获数据
reg [31:0] temp_data_i;
always @(posedge spi_x2clk_i  or negedge rst_n_i)
     begin
         if(rst_n_i==1'b0)
             begin
                 temp_data_i<=32'b0;
                 spi_busy<=1'b0;
             end
         else if(spi_start==1'b1 && spi_busy==1'b0)  
                 begin
                     temp_data_i<=spi_data_i;
                     spi_busy<=1'b1;
                 end               
                 
         else if(spi_done==1'b1)
                 spi_busy<=1'b0;         
         else
                  begin
                      temp_data_i<=temp_data_i;
                      spi_busy<=spi_busy;
                  end     
     end

      
//产生spi_x2clk_i时钟计数 
reg [6:0] clk_cnt;
always @(posedge spi_x2clk_i  or negedge rst_n_i)
     begin
         if(rst_n_i==1'b0)
             clk_cnt<=6'd0;
         else if(spi_busy==1'b1 )  
                 if(clk_cnt<WIDTH_MAX)                             
                       clk_cnt<=clk_cnt+1'd1;    
                   else 
                    clk_cnt<=7'd0;                
        else
                clk_cnt<=7'd0;   
     end       
     
//输出SPI_CS信号 
always @(posedge spi_x2clk_i  or negedge rst_n_i)
     begin
         if(rst_n_i==1'b0)
             spi_cs_o<=1'b1;       
         else if(spi_start==1'b1 && spi_busy==1'b0)                                 
             spi_cs_o<=1'b0;                         
         else if(clk_cnt<(WIDTH_MAX-1'd1))
             spi_cs_o<=spi_cs_o; 
         else
            spi_cs_o<=1'b1;   
     end  

    

     
//输出spi_scl信号
always @(posedge spi_x2clk_i  or negedge rst_n_i)
     begin
         if(rst_n_i==1'b0)
             begin
                 if(spi_cpol==1'b0)
                     spi_scl_o<=1'b0;
                 else 
                    spi_scl_o<=1'b1;
                spi_done<=1'b0;            
             end             
         else if(clk_cnt>CS_F_CNT-1'd1 && clk_cnt<(WIDTH_MAX-CS_B_CNT-1'd1))  
                 begin
                    spi_scl_o<=~spi_scl_o;
                end
        else if(clk_cnt==WIDTH_MAX-1'd1)
                begin    
                     spi_done<=1'b1;

                 end
         else 
            begin
                 if(spi_cpol==1'b0)
                     spi_scl_o<=1'b0;
                 else 
                    spi_scl_o<=1'b1;
                spi_done<=1'b0;
    
             end  
     end   
                
//输出SPI_MOSI信号
always @(posedge spi_x2clk_i  or negedge rst_n_i)
     begin
         if(rst_n_i==1'b0)
             spi_mosi_o<=1'b0;
         else if(spi_cpha==1'b0) 
                 begin
                     if((clk_cnt>=(CS_F_CNT-8'd1)) && (clk_cnt<(WIDTH_MAX-CS_B_CNT-CS_F_CNT-8'd2)) && (clk_cnt%2==1)  )
                         begin
                             spi_mosi_o<=temp_data_i[spi_out_width-1'd1];
                             temp_data_i<={temp_data_i[(spi_out_width-2'd2):0],temp_data_i[spi_out_width-1'd1]};                             
                         end
                     else 
                         begin                            
                             spi_mosi_o<=spi_mosi_o;                         
                         end

                 end    
        else  if(spi_cpha==1'b1) 
                 begin
                     if((clk_cnt>=CS_F_CNT) && clk_cnt<(WIDTH_MAX-CS_B_CNT-CS_F_CNT) && (clk_cnt%2==0) )
                         begin
                             spi_mosi_o<=temp_data_i[spi_out_width-1'd1];
                             temp_data_i<={temp_data_i[spi_out_width-2'd2:0],temp_data_i[spi_out_width-1'd0]};                             
                         end
                     else 
                         begin                            
                             spi_mosi_o<=spi_mosi_o;                         
                         end
                 end    
         else 
             begin 
                             spi_mosi_o<=1'b1;  
             end
                  
     end 
     
//接收SPI_MISO信号
always @(posedge spi_x2clk_i or negedge rst_n_i)
     begin
         if(rst_n_i==1'b0)
             spi_data_o<=32'b0;
         else if(spi_cpha==1'b0) 
                 begin
                     if((clk_cnt>=CS_F_CNT-8'D1) && (clk_cnt<(WIDTH_MAX-CS_B_CNT)) && (clk_cnt%2==1)  )
                         begin         
                             spi_data_o<={spi_data_o[30:0],spi_miso_i};                             
                         end
                     else 
                         begin
                             spi_data_o<=spi_data_o;                                                   
                         end
                 end    
        else  if(spi_cpha==1'b1) 
                 begin
                     if((clk_cnt>=CS_F_CNT) && (clk_cnt<(WIDTH_MAX-CS_B_CNT)) && (clk_cnt%2==1) )
                         begin
                             spi_data_o<={spi_data_o[30:0],spi_miso_i};                             
                         end
                     else 
                         begin
                             spi_data_o<=spi_data_o;                                                   
                         end
                 end    
         else 
             begin
                    spi_data_o<=spi_data_o;     
             end
                  
     end 

endmodule


//testbench
`timescale 1ns/1ns
module  lcd_spi_m_tb();
 reg rst_n_i;    
 reg spi_x2clk_i; 
 reg [31:0] spi_data_i;
 reg spi_start;     
 reg spi_miso_i;
 wire [0:0]  spi_done;
 wire [0:0]  spi_busy;
 wire [0:0]  spi_cs_o;
 wire [0:0]  spi_scl_o;
 wire [0:0]  spi_mosi_o;
 wire [31:0] spi_data_o;



always #50 spi_x2clk_i<=~spi_x2clk_i;
initial begin
         rst_n_i=0;
         spi_x2clk_i=0;
         #200; 
         spi_start=0;        
         rst_n_i=1;
         @(posedge spi_x2clk_i)
         spi_data_i=9'h1B0;
         spi_start=1;
         @(posedge spi_x2clk_i)
         spi_start=0;
         @(negedge spi_done)
         #200; 
         $stop;
        end
        
always @(posedge spi_scl_o or negedge rst_n_i )//要根据CPOL CPHA配置 spi_scl_o采样极性
     begin
         if(rst_n_i==1'b0)
             spi_miso_i<=1'b0;
         else if (spi_cs_o==1'b0 )
             spi_miso_i<=~spi_miso_i;                         
         else
             spi_miso_i<=1'b0;    
     end        

lcd_spi_m
#(
    .spi_in_width(6'd9),//spi  输入位数
    .spi_out_width (6'd9),//SPI  输出位数
    .spi_cpol(1'b0),
    .spi_cpha(1'b1)


)
lcd_spi_m_inst
(
     .rst_n_i            (rst_n_i     )       ,    
     .spi_x2clk_i        (spi_x2clk_i )       ,
     .spi_data_i         (spi_data_i  )       ,
     .spi_start          (spi_start   )       ,     
     .spi_miso_i         (spi_miso_i  )       ,
     .spi_done           (spi_done    )       ,
     .spi_busy           (spi_busy    )       ,
     .spi_cs_o           (spi_cs_o    )       ,
     .spi_scl_o          (spi_scl_o   )       ,
     .spi_mosi_o         (spi_mosi_o  )       ,
     .spi_data_o         (spi_data_o  )    
             
);

endmodule


 

 

 

 

 

 

 

 

标签:CNT,双工,SPI,主机,spi,wire,CS,reg
From: https://www.cnblogs.com/xgj-0817/p/17731001.html

相关文章

  • 利用SPI实现全自动化——LCD屏与RGB灯
     如果你开启了广告屏蔽,请将博客园加入白名单,帮助博客园渡过难关,谢谢! 前言在21年做物理实验和23年客串电赛之后,我带着STM32重回电子DIY界。这次的项目是一个电池供电的补光灯,由于用途更偏向艺术创作而非严肃照明,选用了WS2812RGB灯带;控制灯带的参数需要呈现给用户,通过LCD屏的......
  • CH573 CH582 CH579蓝牙从机(Peripheral)/主机(Central)例程讲解一(蓝牙主从机收发数据
    原文链接:https://www.cnblogs.com/risc5-ble/p/15994545.html前言:蓝牙从机,顾名思义,就是一个蓝牙从设备,可以不断发送广播等待与主机建立连接进行通信,建立连接后,可以通知主机,也可以收到主机发的信息,一般使用BLE调试助手(安卓应用市场可下载),ios可使用Lightblue来进行调试通信等......
  • 免费云服务器云虚拟主机
    3丰云致力于为大众提供优质的互联网基础服务和物联网服务,包括:域名注册、虚拟主机、云服务器、主机托管租用、CDN网站加速、物联网应用等服务。以帮助客户轻松、高速、高效的应用互联网/物联网,提高企业竞争能力。起步定价:46元/每月免费试用:有公司名称:北京太极3丰云计算有限......
  • 问题处理 --- 阿里云虚拟主机存在iis短文件泄露漏洞修复
    问题原因win为了兼容dos系统默认启用了长文件名称缩写为短文件名称的功能解决方法关闭设置。这里有两种解决办法:1.如果是云服务器或硬件设备fsutilbehaviorsetdisable8dot312.如果是虚拟主机修改注册列表HKLM\SYSTEM\CurrentControlSet\Control\FileSystem\NtfsDisable......
  • 服务器主机:复杂理论的视角与SEO策略
    本文分享自天翼云开发者社区《服务器主机:复杂理论的视角与SEO策略》,作者:不知不觉在数字世界的演变中,服务器主机在信息存储和数据处理方面发挥着核心作用。本文将带你重新认识服务器主机的价值,并通过复杂理论解释其重要性和必要性,同时结合SEO关键字布局来指导你如何优化内容。......
  • 关于wake on lan远程唤醒主机的问题,长时间关机无法远程唤醒
    英特尔在年初发布了几款低功耗的CPU,国内厂商在迷你主机领域纷纷搭载新款CPU,卖的火爆。之前关注过迷你主机这块,于是,我也入手一个迷你主机玩玩,买的是板载N100的迷你主机。使用过程中会涉及到如何远程开启主机服务,从网上查了一些方法,无碍乎就是智能插座、开机棒、开机盒子等。如何在......
  • 【刷题笔记】59. Spiral Matrix II
    题目Givenapositiveinteger n,generateasquarematrixfilledwithelementsfrom1to n2 inspiralorder.Example:Input:3Output:[[1,2,3],[8,9,4],[7,6,5]]题目大意给定一个正整数n,生成一个包含1到n^2所有元素,且元素按顺时针顺序螺......
  • Ansible专栏文章之十五:Ansible管理Windows主机
    回到:Ansible系列文章各位读者,请您:由于Ansible使用Jinja2模板,它的模板语法{%raw%}{{}}{%endraw%}和{%raw%}{%%}{%endraw%}和博客系统的模板使用的符号一样,在渲染时会产生冲突,尽管我尽我努力地花了大量时间做了调整,但无法保证已经全部都调整。因此,如果各位阅读时发......
  • 单工、半双工、全双工
    单工:1一路连线,一端只能同时单纯接听或发送,另一端相反;办双工:1x1一路连线,复用,两端都可收发,但是时分差分进行发送、接收,也就是说一端发的时候,另一端只能收,反之然也!全双工:2x2两路连线,对端双方都可以同时进行发送和接收,如打电话等 其他解释:半双工(HalfDuplex)一种传送制式。使用......
  • 服务器与主机的区别
    服务器与主机的区别1、主机和服务器是相对而言的。主机一般是指个人使用的电脑PC机。而在专业术语中,主机仅是电脑的一部分。而常说的主机却往往代表整个电脑。服务器一般是指用于专业用的电脑PC机,在实质上,服务器和主机没有什么意义上的区别。主机如果做为服务器也是可以的,服务器也......