SPI协议主机verilog

对SPI协议的理解


        最近刚做了一个项目,现在还没做完,但是我发现官方的ip写得很全面,但是很复杂,许多东西对于速度要求不是很高的就用不着,比如一个crc,crc本身计算并不复杂,软件的速度一般都可以计算,何况是一个数据只有8bits的spi,所以我决定做一个简单的spi。
        spi协议本身并不难,理解起来也很容易。spi主要就是由主机发送指令对从机进行操作,一般所有操作都是由主机发起的,现在我会以我的理解用verilog对主机进行描述,不规范和有错误的地方欢迎指正。

spi协议

  你以为我就直接将spi协议呢? 嘿嘿,百度吧,一搜一大堆,我就不赘诉了。

  总的来说就是四根线,mosi,miso,sck和cs,三线模式下为半双工通信(同一时刻只能输入或者输出),四线模式下为全双工通信(同一时刻既能输入,又能输出),连接方式如下图所示:
在这里插入图片描述
   这是一个一主多从的连接方式,每个设备都会收到时钟和数据,但是决定哪一个从机去响应就由片选信号(cs)决定;
sck : 主机时钟输出
mosi:主机输出,从机输入,与从机的mosi或者单向的sdi连接;
miso:主机输入,从机输出,与从机的miso或者单向的sdo连接;
cs :chip select (片选信号)

      spi一共有四种模式:mode0, mode1,mode2, mode3,一般由CPOL,CPHA 控制它的初始时钟电平,相位;需要注意的是mode0和mode2是第一个时钟沿是采样沿,数据在第一个时钟沿到来之前需要准备好mosi的数据。

      1.CPOL = 0,CPHA = 0(mode0):此时空闲态时,SCLK处于低电平,数据采样是在第1个边沿,也就是SCLK由低电平到高电平的跳变,所以数据采样是在上升沿,数据发送是在下降沿,时序如下:
在这里插入图片描述

      2.CPOL = 0,CPHA = 1(mode1):此时空闲态时,SCLK处于低电平,数据发送是在第1个边沿,也就是SCLK由低电平到高电平的跳变,所以数据采样是在下降沿,数据发送是在上升沿,时序如下:
在这里插入图片描述

ps:粘贴一半发现原版文档值写了前两种模式,崩溃,重新找图

      3.CPOL = 1,CPHA = 0(mode2):此时空闲态时,SCLK处于高电平,数据采集是在第1个边沿,也就是SCLK由高电平到低电平的跳变,所以数据采集是在下降沿,数据发送是在上升沿,时序如下:
在这里插入图片描述

      4.CPOL = 1,CPHA = 1(mode3):此时空闲态时,SCLK处于高电平,数据发送是在第1个边沿,也就是SCLK由高电平到低电平的跳变,所以数据采集是在上升沿,数据发送是在下降沿,时序如下:
在这里插入图片描述
ps:不好意思,盗图有点东拼西凑,实在是懒得画图

      关于三线和四线模式,我看到官方文档里面是mosi和miso都是作为一个双向io口使用的。作为四线模式使用时,是一个全双工模式通信,输入和输出都是单向数据;而作为三线模式时,spi时一个半双工通信,也就是说用的同一根数据线进行输入输出,分时复用,所以我的代码里面用的是将mosi作为一个双向io;而另外一根miso线则是在三线模式中没有使用,我没太懂为啥文档里会把miso也作为一个双向的io。

      下面是飞思卡尔的一个spi协议的模块框图:
在这里插入图片描述
      这个spi模块就划分为了几个大的部分,有控制寄存器,状态寄存器,时钟分频和移位寄存器。

verilog

      先说一下代码,有很多不规范的地方,不同时钟最好放在不同module里面,等等,欢迎大家指正。
此为spi主设备,可挂外部设备进行通讯,以下为此模块特点:
1、传输帧数据位宽8、16、32位选择
2、对于外部从设备时钟SCLK频率,以PCLK为基础分频,可写入预分频系数进行分频;
3、cs为片选信号
4、支持三线半双工或四线全双工工作模式,二线的情况下通讯MOSI作为双向数据线;
5、可编数据发送顺序,MSB优先或LSB优先
6、SPI通讯忙标志
7、SPI频率计算公式(最小8分频)
8、SPI频率 = PCLK/(DIV * 2);
使用方式就是:先配置好时钟分频和spi模式,然后开启cs,最后开启start;(cs和start的间隔时间具体看从机器件规格书)
这是一个基于apb总线的模块,寄存器本想做一个表格,但是这上面表格里面换行不知道怎么弄就截图了。
在这里插入图片描述在这里插入图片描述
这一段是时钟分频,sel0,sel1,sel2,sel3是四种模式,sclk的初始的电平不同:

//clk divide counter
always @(posedge clk or negedge rst_n)
    if(!rst_n)
        div_cnt <= 0;
    else if(div_cnt == div)
        div_cnt <= 0;
    else if(start_r2)
        div_cnt <= div_cnt + 31'b1;
    else 
        div_cnt <= 0;

//spi clk generate
always @(posedge clk or negedge rst_n)
    if(!rst_n)
        sclk <= 0;
    else if(start) begin
        if(div_cnt == div)
            sclk <= ~sclk;
        else ;
    end 
    else begin 
        if(sel0 || sel1)
            sclk <= 0;
        else if(sel2 || sel3)
            sclk <= 1;
    end

这一段是数据的移位,在每一个采样沿移位,给下一次数据做准备;其中ctrl【4:3】就是mode的选择,2‘b00代表sel0,2‘b01代表sel1,2’b10代表sel2,2’b11代表sel3;start_r2是延迟两拍的开始信号,ctrl【0】是开始信号的命令,lsb_en为1表示低位先出,否则为msb(高位先出)。

//shift data
always @(posedge clk or negedge rst_n)
    if(!rst_n)
        wr_data <= 0;
    else if(ctrl[0])    
        wr_data <= wr_r;
    else if(start_r2) begin
        if(lsb_en) begin
            case (ctrl[4:3])
                2'b00:begin
                    if(sclk_pos || start_pos) 
                        tx_lsb_shift;
                    else ;
                end

                2'b01:begin
                    if(sclk_neg)
                        tx_lsb_shift;
                    else ;
                end

                2'b10:begin
                    if(sclk_neg || start_pos) 
                        tx_lsb_shift;
                    else ;
                end

                2'b11:begin
                    if(sclk_pos)
                        tx_lsb_shift;
                    else ;
                end
            endcase
        end
        else begin
            case (ctrl[4:3])
                2'b00:begin
                    if(sclk_pos || start_pos) 
                        tx_msb_shift;
                    else ;
                end

                2'b01:begin
                    if(sclk_neg)
                        tx_msb_shift;
                    else ;
                end

                2'b10:begin
       
  • 2
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值