SPI协议的verilog实现(spi master slave联合实现)

这篇具有很好参考价值的文章主要介绍了SPI协议的verilog实现(spi master slave联合实现)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

SPI协议介绍

spi是serial peripheral interface的缩写,即串行扩展总线。SPI是单主设备通信,总线中只有一个主设备发起通信,能发起通信的设备称为主设备。当SPI主设备想读写从设备时,首先拉低对应从设备的ss线(低电平有效)。然后发送工作麦种到时钟线上,在相应的脉冲时间上,主设备把信号发送到MOSI实现读写,同时又可以对MISO采样实现读。一般SPI通信涉及到一下术语:

SCLK serial clock (来自主设备)
MOSI Master Output Slave Input(来自主设备)
MISO Master Input Slave Output(来自从设备)
SS Slave Select(低电平有效,来自主设备)

主设备和从设备的两种链接方式

一主一从

一主一从模式表明有一个主机和一个从机,如下所示:(其中还有SCK信号,由主机到从机)
spi slave verilog,verilog实战,fpga开发,单片机,网络

一主多从

一主多从表示有一个主机和一个从机,唯一不同的点是要为每个从机配备一个选择信号。
spi slave verilog,verilog实战,fpga开发,单片机,网络

SPI协议的工作模式

SPI有四种工作模式,主要由时钟极性CPOL(Clock Polarity),时钟相位CPHA(Clock Phase)的组合决定。

  • CPOL为0,表示SCK在空闲状态为0,为1,则表示SCK在空闲状态为1
  • CPHA为0,表示在SCK的第一个边沿时输出输出数据有效,CPHA为1时,表示在SCK的第二个边沿输入输出数据有效

CPOL = 0, CPHA = 0

spi slave verilog,verilog实战,fpga开发,单片机,网络

CPOL = 0, CPHA = 1

spi slave verilog,verilog实战,fpga开发,单片机,网络

CPOL = 1. CPHA = 0

spi slave verilog,verilog实战,fpga开发,单片机,网络

CPOL = 1, CPHA = 1

spi slave verilog,verilog实战,fpga开发,单片机,网络

SPI MASTER 的verilog设计思路

设计的引脚说明:

信号名 方向 +解释
clk 输入,时钟信号
rst_n 输入,复位信号
miso 输入,从机输入到主机
data_i 输入,主机发送从机的数据(一定比特位宽)
start 输入,开始的使能信号
mosi 输出,主机到从机
sclk 输出,时钟信号
ss_n 输出,从机的选择信号
finish 一次传输完成信号

首先将需要的宏定义收录在一个文件defines.v中,其中的代码如下所示:

`define CPOL 0      //clock polarity
`define CPHA 0      //clock phase
`define CLK_FREQ 50_000_000  // input clk frequency
`define SCLK_FREQ  5_000_000  // sclk frequency
`define DATA_WIDTH 8            // a word width
`define CLK_CYCLE 20

其次时SPI MASTER的设计思路,总体思路时采用一个状态机,首先状态机是在IDLE状态,然后接收开始信号后,会将寄存器data_I中数据一个一个的发送出去,当指定宽距的比特位发送完成后。此时有两种选择,一种是跳转到FINISH状态,另一种是跳转到EXTRA状态,在跳转到FINISH状态。主要是由于当数据发送完成之后要判断此时的SCLK状态是不是空闲下的默认状态,如果不是,则需要跳转到EXTRA状态。结束状态下一个状态回到IDLE状态,得到start命令。

IDLE 空闲状态
DATA 发送数据状态
EXTRA 额外状态
FINISH 结束状态

verilog的代码如下:

`include "defines.v"

module SPI_MASTER(
    input   wire                        clk     ,
    input   wire                        rst_n   ,
    input   wire                        miso    ,
    input   wire    [`DATA_WIDTH-1:0]   data_i  ,
    input   wire                        start   ,

    output  wire                        mosi    ,
    output  reg                         sclk    ,
    output  reg                         ss_n    ,
    output  wire                        finish    
);
    parameter       IDLE    =   5'b00001  ,
                    //CHOOSE  =   5'b00010  ,
                    DATA    =   5'b00100  ,
                    EXTRA   =   5'b01000  ,
                    FINISH  =   5'b10000  ;
    
    parameter       CNT_MAX =   `CLK_FREQ / `SCLK_FREQ - 1;
    
    reg     [31:0]      cnt                     ;   //sclk的时钟周期的计数器
    reg     [4:0]       state                   ;   
    reg     [4:0]       nx_state                ;
    wire    [3:0]       cnt_data                ;   //输出的数据计数器
    reg                 sclk_dly                ;   //sclk的打一拍信号
    reg     [3:0]       cnt_sclk_pos            ;   //sclk的上升沿计数器信号
    reg     [3:0]       cnt_sclk_neg            ;   //sclk的下降沿计数器信号
    reg                 start_dly               ;   //start的打一拍信号
    reg     [3:0]       cnt_data_dly            ;

    wire                cnt_max_flag            ;   //计数器cnt达到最大值的信号
    wire                dec_pos_or_neg_sample   ;   //1 posedge sample, 0 negedge sample
    wire                sclk_posedge            ;   //sclk的上升沿
    wire                sclk_negedge            ;   //sclk的下降沿


    assign  dec_pos_or_neg_sample = (`CPOL == `CPHA) ? 1'b1 : 1'b0;

    assign cnt_max_flag = (cnt == CNT_MAX ) ? 1'b1 : 1'b0;
    assign sclk_posedge = ((sclk == 1'b1) && (sclk_dly == 1'b0)) ? 1'b1 : 1'b0;
    assign sclk_negedge = ((sclk == 1'b0) && (sclk_dly == 1'b1)) ? 1'b1 : 1'b0;
    assign cnt_data = dec_pos_or_neg_sample ? cnt_sclk_pos : cnt_sclk_neg;

    always @(posedge clk or negedge rst_n) begin
        sclk_dly <= sclk;
        start_dly <= start;
    end

    always @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            cnt_sclk_pos <= 4'd0;
        end
        else if(state == FINISH) begin
            cnt_sclk_pos <= 4'd0;
        end
        //else if((sclk_posedge) && (cnt_sclk_pos == `DATA_WIDTH - 1)) begin
        //    cnt_sclk_pos <= `DATA_WIDTH - 1;
        //end
        else if(sclk_posedge) begin
            cnt_sclk_pos <= cnt_sclk_pos + 1'b1;
        end
        else begin
            cnt_sclk_pos <= cnt_sclk_pos;
        end
    end

    always @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            cnt_sclk_neg <= 4'd0;
        end
        else if(state == FINISH) begin
            cnt_sclk_neg <= 4'd0;
        end
        //else if((sclk_negedge) && (cnt_sclk_neg == `DATA_WIDTH - 1)) begin
        //    cnt_sclk_neg <= `DATA_WIDTH - 1;
        //end
        else if(sclk_negedge) begin
            cnt_sclk_neg <= cnt_sclk_neg + 1'b1;
        end
        else begin
            cnt_sclk_neg <= cnt_sclk_neg;
        end
    end
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            state <= IDLE;
        end
        else begin
            state <= nx_state;
        end
    end

    always @(*) begin
        nx_state <= IDLE;
        case(state)
            IDLE:   nx_state <= start_dly ? DATA : IDLE;
            DATA:   nx_state <= (cnt_data == `DATA_WIDTH) ? (`CPHA == 0) ? EXTRA : FINISH : DATA;
            EXTRA:  nx_state <= cnt_max_flag ? FINISH : EXTRA ;
            FINISH: nx_state <= IDLE;
            default:nx_state <= IDLE;
        endcase
    end

    always @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            cnt <= 'd0;
        end
        else if((state == DATA) && (nx_state == FINISH) && (cnt == CNT_MAX)) begin
            cnt <= 'd0;
        end
        else if((state == DATA) && (nx_state == EXTRA) && (cnt == CNT_MAX)) begin
            cnt <= 'd0;
        end
        else if((state == DATA) && (cnt == CNT_MAX)) begin
            cnt <= 'd0;
        end
        else if((state == EXTRA) && (cnt == CNT_MAX)) begin
            cnt <= 'd0;
        end
        else if(state == DATA) begin
            cnt <= cnt + 1'b1;
        end
        else if(state == EXTRA) begin
            cnt <= cnt + 1'b1;
        end
        else begin
            cnt <= 'd0;
        end
    end 

    always @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            sclk <= (`CPOL) ? 1'b1 : 1'b0;
        end
        else if(start_dly) begin
            sclk <= ~sclk;
        end
        else if((state == DATA) && (cnt_max_flag) && (cnt_data < `DATA_WIDTH) ) begin
            sclk <= ~sclk;
        end
        else if((state == DATA) && (cnt_max_flag) && (cnt_data == `DATA_WIDTH) && (nx_state == EXTRA)) begin
            sclk <= ~sclk;
        end
        else if((state == EXTRA) && (cnt_max_flag) && (nx_state == FINISH)) begin
            sclk <= ~sclk;
        end
        else begin
            sclk <= sclk;
        end
    end

    always @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            ss_n <= 1'b1;
        end
        else if(start) begin
            ss_n <= 1'b0;
        end
        else if(state == FINISH) begin
            ss_n <= 1'b1;
        end
        else begin
            ss_n <= ss_n;
        end
    end

    always @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            cnt_data_dly <= 'd0;
        end
        else begin
            cnt_data_dly <= cnt_data;
        end
    end

    assign finish = (state == FINISH) ? 1'b1 : 1'b0;

    assign mosi  = (state == DATA) ? ((cnt_data_dly < `DATA_WIDTH) ? data_i[cnt_data_dly] : data_i[`DATA_WIDTH-1]) : data_i[0]; 
endmodule


仿真的testbench如下:

`timescale  1ns/1ns
`include "defines.v"

module tb_master_slave();

    reg                         clk         ;
    reg                         rst_n       ;
    //reg                         mosi        ;
    reg     [`DATA_WIDTH-1:0]   data_i      ;
    reg                         start       ;
    reg                         miso        ;

    wire                        mosi        ;
    wire                        sclk        ;
    wire                        finish      ;
    wire                        ss_n        ;
    wire    [`DATA_WIDTH-1:0]   data_o      ;
    wire                        r_finish    ;

    SPI_MASTER u_spi_master (
        .clk    (clk)       ,
        .rst_n  (rst_n)     ,
        .miso   (miso)      ,
        .data_i (data_i)    ,
        .start  (start)     ,

        .mosi   (mosi)      ,
        .sclk   (sclk)      ,
        .finish (finish)    ,
        .ss_n   (ss_n)
    );

    SPI_SLAVE u_spi_slave(
        .clk    (clk)       ,
        .rst_n  (rst_n)     ,
        .mosi   (mosi)      ,
        .sclk   (sclk)      ,
        .tx_finish(finish),
        .start  (start)     ,
        .ss_n   (ss_n)      ,

        .data_o (data_o)    ,
        .r_finish(r_finish)
    );

    initial begin
         clk = 1'b0;
         rst_n = 1'b0;
         start = 1'b0;
         data_i = 8'h35;
         miso = 1'b0;
         #30
         rst_n = 1'b1;
         #10;
         @(posedge clk);
         start <= 1'b1;
         @(posedge clk);
         start <= 1'b0;
         @(negedge finish);
         data_i = 8'h44;
         repeat(2) @(posedge clk);
         start = 1'b1;
         @(posedge clk);
         start = 1'b0;
    end

    always #(`CLK_CYCLE / 2) clk = ~clk;

endmodule

仿真波形如下,可以通过mosi成功发出了数据。
spi slave verilog,verilog实战,fpga开发,单片机,网络

SPI SLAVE设计思路

SPI SPLAVE的设计思路大体如master类似,端口说明如下:

信号名 方向 +解释
clk 输入,时钟信号
rst_n 输入,复位信号
miso 输入,从机输入到主机
data_i 输入,主机发送从机的数据(一定比特位宽)
start 输入,开始的使能信号
mosi 输出,主机到从机
sclk 输入,时钟信号
ss_n 输入,从机的选择信号
r_finish 一次传输完成信号
data_o 输出,收集到的数据

依然采用的是状态机思路,首先在IDLE状态,当开始信号使能之后,会跳转到RV_DATA接收到数据状态。RV_DATA数据接收完成,之后回跳转到FINISH状态,表明此次读取完成。

IDLE 空闲状态
RV_ DATA 接收数据状态
FINISH 结束状态
spi slave的代码如下所示:
`include "defines.v"
module SPI_SLAVE(
    input   wire                        clk         ,
    input   wire                        rst_n       ,
    input   wire                        mosi        ,
    input   wire                        sclk        ,
    input   wire                        tx_finish   ,
    input   wire                        start       ,
    input   wire                        ss_n        ,

    output  wire    [`DATA_WIDTH-1:0]   data_o      ,
    //output  wire                        miso        ,
    output  wire                        r_finish
);
    parameter       IDLE    =   4'b0001     ,
                    RV_DATA =   4'b0010     ,
                    FINISH  =   4'b0100     ;

    wire                        sclk_posedge        ;
    wire                        sclk_negedge        ;
    wire                        dec_pos_or_neg_sample;
    //wire                        sclk_posedge        ;
    //wire                        sclk_negedge        ;


    reg                         sclk_dly            ;
    reg     [`DATA_WIDTH-1:0]   data_shift_pos      ;
    reg     [`DATA_WIDTH-1:0]   data_shift_neg      ;
    reg     [3:0]               state               ;
    reg     [3:0]               nx_state            ;
    reg     [3:0]               cnt_sclk_pos        ;
    reg     [3:0]               cnt_sclk_neg        ;
    wire    [3:0]               num_sample_data     ;

    assign  sclk_posedge = ((sclk == 1'b1) && (sclk_dly == 1'b0)) ? 1'b1 : 1'b0;
    assign  sclk_negedge = ((sclk == 1'b0) && (sclk_dly == 1'b1)) ? 1'b1 : 1'b0;
    assign  dec_pos_or_neg_sample = (`CPOL == `CPHA) ? 1'b1 : 1'b0;
    //assign  sclk_posedge = ((sclk == 1'b1) && (sclk_dly == 1'b0)) ? 1'b1 : 1'b0;
    //assign  sclk_negedge = ((sclk == 1'b0) && (sclk_dly == 1'b1)) ? 1'b1 : 1'b0;
    assign  num_sample_data = (dec_pos_or_neg_sample) ? cnt_sclk_pos : cnt_sclk_neg;
    
    always @(posedge clk or negedge rst_n) begin
        sclk_dly <= sclk;
    end

    always @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            state <= IDLE;
        end
        else begin
            state <= nx_state;
        end
    end

    always @(*) begin
        nx_state <= IDLE;
        case(state)
            IDLE: nx_state <= start ? RV_DATA :IDLE;
            RV_DATA: begin
                if((num_sample_data == 7) && (dec_pos_or_neg_sample) && (sclk_posedge) && (!ss_n)) begin
                    nx_state <= FINISH;
                end
                else if((num_sample_data == 7) && (~dec_pos_or_neg_sample) && (sclk_negedge) && (!ss_n)) begin
                    nx_state <= FINISH;
                end
                else begin
                    nx_state <= RV_DATA;
                end
            end
            FINISH: nx_state <= IDLE;
        endcase
    end


    always @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            cnt_sclk_pos <= 4'd0;
        end
        else if((state == FINISH)) begin
            cnt_sclk_pos <= 4'd0;
        end
        else if(sclk_posedge) begin
            cnt_sclk_pos <= cnt_sclk_pos + 1'b1;
        end
        else begin
            cnt_sclk_pos <= cnt_sclk_pos;
        end
    end

    always @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            cnt_sclk_neg <= 4'd0;
        end
        else if (state == FINISH) begin
            cnt_sclk_neg <= 4'd0;
        end
        else if (sclk_negedge) begin
            cnt_sclk_neg <= cnt_sclk_neg + 1'b1;
        end
        else begin
            cnt_sclk_neg <= cnt_sclk_neg;
        end
    end

    always @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            data_shift_pos <= {`DATA_WIDTH{1'b0}};
        end
        else if((state == RV_DATA) && (sclk_posedge)) begin
            data_shift_pos <= {mosi, data_shift_pos[`DATA_WIDTH-1:1]};
        end
        else if (state == FINISH) begin
            data_shift_pos <= {`DATA_WIDTH{1'b0}};
        end
        else begin
            data_shift_pos <= data_shift_pos;
        end
    end

    always @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            data_shift_neg <= {`DATA_WIDTH{1'b0}};
        end
        else if((state == RV_DATA) && (sclk_negedge)) begin
            data_shift_neg <= {mosi, data_shift_neg[`DATA_WIDTH-1:1]};
        end
        else if(state == FINISH) begin
            data_shift_neg <= {`DATA_WIDTH{1'b0}};
        end
        else begin
            data_shift_neg <= data_shift_neg;
        end
    end

    //assign data_o = dec_pos_or_neg_sample ? data_shift_pos : data_shift_neg;

    assign  data_o = (state == FINISH) ? (dec_pos_or_neg_sample ? data_shift_pos : data_shift_neg): {`DATA_WIDTH{1'b0}};
    assign  r_finish = (state == FINISH); 




endmodule

SPI MASTRT 和 SLAVE联合仿真

testbench如下所示:

`timescale  1ns/1ns
`include "defines.v"

module tb_master_slave();

    reg                         clk         ;
    reg                         rst_n       ;
    //reg                         mosi        ;
    reg     [`DATA_WIDTH-1:0]   data_i      ;
    reg                         start       ;
    reg                         miso        ;

    wire                        mosi        ;
    wire                        sclk        ;
    wire                        finish      ;
    wire                        ss_n        ;
    wire    [`DATA_WIDTH-1:0]   data_o      ;
    wire                        r_finish    ;

    SPI_MASTER u_spi_master (
        .clk    (clk)       ,
        .rst_n  (rst_n)     ,
        .miso   (miso)      ,
        .data_i (data_i)    ,
        .start  (start)     ,

        .mosi   (mosi)      ,
        .sclk   (sclk)      ,
        .finish (finish)    ,
        .ss_n   (ss_n)
    );

    SPI_SLAVE u_spi_slave(
        .clk    (clk)       ,
        .rst_n  (rst_n)     ,
        .mosi   (mosi)      ,
        .sclk   (sclk)      ,
        .tx_finish(finish),
        .start  (start)     ,
        .ss_n   (ss_n)      ,

        .data_o (data_o)    ,
        .r_finish(r_finish)
    );

    initial begin
         clk = 1'b0;
         rst_n = 1'b0;
         start = 1'b0;
         data_i = 8'h35;
         miso = 1'b0;
         #30
         rst_n = 1'b1;
         #10;
         @(posedge clk);
         start <= 1'b1;
         @(posedge clk);
         start <= 1'b0;
         @(negedge finish);
         data_i = 8'h44;
         repeat(2) @(posedge clk);
         start = 1'b1;
         @(posedge clk);
         start = 1'b0;
    end

    always #(`CLK_CYCLE / 2) clk = ~clk;

endmodule

仿真的波形如下,可知成功的读取到了8’h35和8’h44。验证成功。
spi slave verilog,verilog实战,fpga开发,单片机,网络
spi slave verilog,verilog实战,fpga开发,单片机,网络

总结

通过这次spi的协议的编写,感觉自己对于状态机的掌握,以及脑子里可以浮现波形。加油加油!!!文章来源地址https://www.toymoban.com/news/detail-787304.html

到了这里,关于SPI协议的verilog实现(spi master slave联合实现)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【LabVIEW FPGA入门】LabVIEW FPGA 实现SPI通信协议

            该实现由两个组件组成:在 LabVIEW FPGA 中实现的 SPI 协议以及用于从主机 PC 或实时控制器与 FPGA 进行通信的 LabVIEW 主机接口。该架构允许从单个主机程序控制多个 SPI 端口,同时仍然允许定制 FPGA VI 以进行其他数据采集和处理。该实现不使用任何DMA(直接内存访问

    2024年01月17日
    浏览(58)
  • 【接口协议】FPGA实现SPI协议基于ADC128S022进行模拟信号采集

    使用vivado联合modelsim实现SPI协议基于ADC128S022进行模拟信号连续采集。 SPI是串行外设接口,是一种同步/全双工/主从式接口。通常由四根信号线构成: CS_N :片选信号,主从式接口,可以有多个从机,用片选信号进行从机选择; SCLK :串行时钟线,由主机提供给从机; MISO :主机

    2024年02月07日
    浏览(53)
  • FPGA实现SPI协议基于ADC128S022进行模拟信号采集

    使用vivado联合modelsim实现SPI协议基于ADC128S022进行模拟信号连续采集。 SPI是串行外设接口,是一种同步/全双工/主从式接口。通常由四根信号线构成: CS_N :片选信号,主从式接口,可以有多个从机,用片选信号进行从机选择; SCLK :串行时钟线,由主机提供给从机; MISO :主机

    2024年02月14日
    浏览(46)
  • SPI协议详解(Standard SPI、Dual SPI和Queued SPI)

    (1)SCLK:时钟线; (2)MOSI(master output slave input):主设备输出,从设备输入,单向传输; (3)MISO(master input slave output):主设备输入,从设备输出,单向传输; (4)CS(chip select):片选信号,用于主片选中从片; (1)SPI(serial peripheral interface)是串行外设接口的缩写; (2)SPI是一种高速的、全

    2024年01月21日
    浏览(33)
  • SPI通信协议&SPI通信外设

    目录 SPI 介绍 硬件电路 移位示意图  软件SPI SPI时序基本单元  SPI时序​编辑 W25Q64  硬件电路 W25Q64框图 Flash操作注意事项 指令集  硬件SPI SPI框图  主模式全双工连续传输 非连续传输  推挽输出 ,高低电平都有很强的驱动能力,使得上升沿和下降沿都很迅速。   当ss为高电

    2024年02月10日
    浏览(51)
  • uboot下UCLASS框架详解---结合项目工作中spi master和flash驱动开发

    本文通过如何通过编写特定板子的spi master驱动从而识别到spi norflash设备,完成norflash设备的读写。 2.1 uclass uclass可以理解为一些具有相同属性的udevice对外操作的接口,uclass的驱动是uclass_driver,主要为上层提供接口。 udevice的是指具体设备的抽象,对应驱动是driver,driver主要负

    2024年02月07日
    浏览(43)
  • FPGA实现基于SPI协议的Flash驱动控制(全擦除、页擦除、读数据、页写、连续写—地址写)

    本论文使用Verilog HDL硬件描述语言,结合野火可以FPGA征途Pro开发板,实现了SPI通信协议的全擦除,扇区擦除,读数据,页写,连续写的驱动设计。在 Altera Cyclone Ⅳ 芯片上采用“自顶向下”的模块化设计思想及 Verilog HDL 硬件描述语言,设计并实现串行外设接口(SPI)。在 Qu

    2024年02月12日
    浏览(50)
  • 【STM32 CubeMX】SPI层次结构SPI协议与SPI控制器结构

    随着嵌入式系统的迅猛发展,STM32系列微控制器在各种应用中得到广泛应用。在嵌入式系统设计中,串行外设接口(SPI)是一种常见且重要的通信协议。为了更便捷地配置和使用SPI,STMicroelectronics提供了一款强大的工具——STM32 CubeMX。本文将着重介绍STM32 CubeMX中SPI的层次结构

    2024年02月20日
    浏览(46)
  • FPGA:三大协议(UART、IIC、SPI)之SPI

    摘要:1、本文介绍SPI物理层面连接(通过哪几条线通信),2、本文介绍SPI时序(通过哪种方式进行器件之间交流)。3、提供主机和从机verilog代码。4、仅供自己参考 一、SPI物理层连接 (1)有四根线连接:CS_N(片选信号--主机发出)、miso(从机发出,主机接收)、mosi(主机发

    2024年02月14日
    浏览(48)
  • 通信协议(二)——SPI协议

    1.1 概念 SPI(Serial Peripheral Interface,串行外围设备接口),是Motorola公司提出的一种同步串行接口技术,是一种高速、全双工、同步通信总线,在芯片中只占用四根管脚用来控制及数据传输,广泛用于EEPROM、Flash、RTC(实时时钟)、ADC(数模转换器)、DSP(数字信号处理器)以

    2023年04月08日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包