FPGA DAC模块 SPI通信

这篇具有很好参考价值的文章主要介绍了FPGA DAC模块 SPI通信。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一 SPI通信       

1.串行外设接口(SPI)是微控制器和外围IC(如传感器、ADC、DAC、移位寄存器、SRAM等)之间使用最广泛的接口之一。

2.SPI是一种同步、全双工、主从式接口。来自主机或从机的数据在时钟上升沿或下降沿同步。主机和从机可以同时传输数据。SPI接口可以是3线式或4线式。

 fpga spi通信,fpga开发

 SPI总线传输只需要4根线就能完成,这四根线的作用分别如下:

  • SCK (Serial Clock):时钟信号线,用于同步通讯数据。由通讯主机产生,决定了通讯的速率,不同的设备支持的最高时钟频率不同
     
  • MOSI (Master Output, Slave Input):主设备输出/从设备输入引脚。主机的数据从这条信号线输出,从机由这条信号线读入主机发送的数据,数据方向由主机到从机
  • MISO (Master Input,Slave Output):主设备输入/从设备输出引脚。主机从这条信号线读入数据,从机的数据由这条信号线输出到主机,数据方向由从机到主机
  • CS (Chip Select):片选信号线。当有多个 SPI 从 设备与 SPI 主机相连时,设备的其它信号线 SCK、MOSI 及 MISO 同时并联到相同的 SPI 总线上,即无论有多少个从设备,都共同使用这 3 条总线;而每个从设备都有独立的片选信号线,即有多少个从设备,就有多少条片选信号线。相当于由SPI构成的通信系统中,通过CS片选信号来决定通信的从机设备是哪一台。通信期间低电平有效,表示对应从机被选中

二 DAC8830

        DAC8830是TI的TI一款DAC芯片,他支持16bit数据输入,同时建立时间为1us,支持标准的3线SPI接口,最快可支持50Mhz。

 fpga spi通信,fpga开发fpga spi通信,fpga开发

以下是接口定义

fpga spi通信,fpga开发

        时序图

fpga spi通信,fpga开发

  1. 总线主设备将芯片选择信号CS拉低,表示要访问DAC模块。

  2. 在CS处于低电平状态时,总线主设备生成同步时钟信号SCLK,并将串行输入数据SDI按照时钟的下降沿进行传输。数据从总线主设备经由SDI线逐位地传输到DAC模块。

  3. DAC模块在SCLK的下降沿时,将串行输入数据SDI的每一位依次存储到输入移位寄存器中。通常情况下,最高有效位(MSB)先传输,并在SCLK的上升沿锁存到输入移位寄存器中。

  4. 当CS由低电平变为高电平时,表示数据传输完成,并且同时更新输出。为了传输一个完整的数据,CS必须在16个SCLK后立即变为高电平。

  5. CS信号从DAC更新到下一次传输开启的时间间隔不能小于30ns

三 程序设计

        模块设计

fpga spi通信,fpga开发

  • 输入信号:

    • clk:时钟信号,模块在时钟上升沿执行。
    • rst_n:复位信号,低电平有效,当复位信号为低电平时,模块会清零输出数据,并将使能信号、DAC8830 时钟、数据和片选信号都输出为高电平。
    • start:开始信号,高电平有效,当开始信号为高电平时,模块会将输入数据赋值给输出数据,并将使能信号设置为高电平。
    • data_in:16位的输入数据信号,用于传输到 DAC8830 芯片。
  • 输出信号:

    • SCLK:DAC8830 时钟信号,用于控制数据传输时序。
    • DIN:DAC8830 数据输入信号,传输到 DAC8830 芯片的串行数据。
    • CS:DAC8830 片选信号,用于选择 DAC8830 芯片。
    • done:传输完成信号,用于指示数据传输完成。

时序图

fpga spi通信,fpga开发

  • en是使能信号,由外部输入开始信号时,en为高电平,数据开始传输;数据传输完成后done信号拉高,en变为低电平,停止传输。
  • SCLK_CNT是输出时钟计数器,用于计数时钟周期的数量。它在数据传输过程中递增,用于控制时钟信号的生成和数据的传输时机。
  • cnt是分频计数器,用于计数SCLK的时钟周期。当计数器的值达到一定数量(这里是10)时,cnt_flag置1。
  • cnt_flag是计数标志,用于指示分频计数器的状态。当cnt_flag为高电平时,表示已经传输了一位数据并且需要进行下一位数据的传输。

代码示例

module SPI_drive(
    input clk,          // 输入时钟
    input rst_n,        // 复位信号
    input start,        // 启动信号
    input [15:0] data_in,  // 输入数据

    // DAC8830输入
    output reg SCLK,    // 时钟信号
    output reg DIN,     // 输入数据信号
    output reg CS,      // 芯片选择信号

    output reg done     // 完成信号
    );

    reg en;              // 使能信号
    reg [3:0] cnt;       // 分频计数
    reg [6:0] SCLK_CNT;  // 输出时钟计数
    reg cnt_flag;        // 计数标志
    reg [15:0] data_out; // 输出数据

    parameter cnt_threshold  = 5;//时钟分频阈值,
                                //输出时钟频率为输入时钟频率的1/(cnt_threshold+1)

    // 接收数据
    always @(posedge clk or negedge rst_n)
    begin
        if (!rst_n)
            data_out <= 16'b0;     
        else if (en)
            data_out <= data_in;   // 在启动时加载输入数据
        else
            data_out <= data_out;  
    end

    // 使能信号
    always @(posedge clk or negedge rst_n)
    begin
        if (!rst_n)
            en <= 1'b0;            
        else if (start)
            en <= 1'b1;            // 在启动时使能信号为高电平
        else if (done)
            en <= 1'b0;            // 在传输完成后禁用使能信号
        else
            en <= en;              
    end

    // 分频计数
    always @(posedge clk or negedge rst_n)
    begin
        if (!rst_n)
        begin
            cnt <= 4'b0;           
            cnt_flag <= 1'b0;      
        end
        else if (en)
        begin
            if (cnt == cnt_threshold)
            begin
                cnt <= 4'b0;       // 达到分频阈值时清零分频计数
                cnt_flag <= 1'b1;  // 设置计数标志
            end
            else
            begin
                cnt <= cnt + 4'b1;  // 增加分频计数
                cnt_flag <= 1'b0;  // 清零计数标志
            end
        end
        else
            cnt <= 0;              // 禁用时清零分频计数
    end

    // 输出时钟计数
    always @(posedge clk or negedge rst_n)
    begin
        if (!rst_n)
            SCLK_CNT <= 7'b0;      
        else if (en)
        begin
            if (cnt_flag && (SCLK_CNT == 7'd32))
                SCLK_CNT <= 7'b0;     // 达到输出时钟计数阈值时清零计数
            else if (cnt_flag)
                SCLK_CNT <= SCLK_CNT + 1'b1;  // 增加输出时钟计数
            else
                SCLK_CNT <= SCLK_CNT;  // 其他情况下保持输出时钟计数不变
        end
        else
            SCLK_CNT <= 0;           // 禁用时清零输出时钟计数
    end

    // 开启数据传输,线性序列机,每个时钟周期按照固定的步骤依次执行
    always @(posedge clk or negedge rst_n)
    begin
        if (!rst_n)
        begin
            SCLK <= 1'b1;            
            DIN <= 1'b1;             
            CS <= 1'b1;             
        end
        else if (en)
        begin
            if (cnt_flag)
            begin
                case (SCLK_CNT)
                    7'd0: begin SCLK <= 1'b0; DIN <= data_out[15]; CS <= 1'b0; end
                    7'd2: begin SCLK <= 1'b0; DIN <= data_out[14]; end
                    7'd4: begin SCLK <= 1'b0; DIN <= data_out[13]; end
                    7'd6: begin SCLK <= 1'b0; DIN <= data_out[12]; end
                    7'd8: begin SCLK <= 1'b0; DIN <= data_out[11]; end
                    7'd10: begin SCLK <= 1'b0; DIN <= data_out[10]; end
                    7'd12: begin SCLK <= 1'b0; DIN <= data_out[9]; end
                    7'd14: begin SCLK <= 1'b0; DIN <= data_out[8]; end
                    7'd16: begin SCLK <= 1'b0; DIN <= data_out[7]; end
                    7'd18: begin SCLK <= 1'b0; DIN <= data_out[6]; end
                    7'd20: begin SCLK <= 1'b0; DIN <= data_out[5]; end
                    7'd22: begin SCLK <= 1'b0; DIN <= data_out[4]; end
                    7'd24: begin SCLK <= 1'b0; DIN <= data_out[3]; end
                    7'd26: begin SCLK <= 1'b0; DIN <= data_out[2]; end
                    7'd28: begin SCLK <= 1'b0; DIN <= data_out[1]; end
                    7'd30: begin SCLK <= 1'b0; DIN <= data_out[0]; end
                    7'd1,7'd3,7'd5,7'd7,7'd9,7'd11,7'd13,7'd15,7'd17,
                    7'd19,7'd21,7'd23,7'd25,7'd27,7'd29,7'd31: begin SCLK <= 1'b1; end
                    7'd32: begin SCLK <= 1'b0;
                            CS <= 1'b1; end // 全部数据输出后,cs信号马上拉高
                endcase
            end
            else ;
        end
        else
        begin
            SCLK <= 1'b1;  
            DIN <= 1'b1;   
            CS <= 1'b1;   
        end
    end

    // 传输完成
    always @(posedge clk or negedge rst_n)
    begin
        if (!rst_n)
            done <= 1'b0;  
        else if (cnt_flag && (SCLK_CNT == 7'd32))
            done <= 1'b1;  // 达到输出时钟计数阈值时设置完成信号为高电平
        else
            done <= 1'b0;  
    end
       
endmodule

仿真图像

fpga spi通信,fpga开发 en信号一直为高是因为外部一直在给start信号文章来源地址https://www.toymoban.com/news/detail-676319.html

到了这里,关于FPGA DAC模块 SPI通信的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • 基于SPI实现stm32与fpga通信(一)

    SPI通信协议有以下4种模式: 模式0:时钟极性为0,时钟相位为0,数据在时钟下降沿捕获,数据在时钟上升沿改变。 模式1:时钟极性为0,时钟相位为1,数据在时钟上升沿捕获,数据在时钟下降沿改变。 模式2:时钟极性为1,时钟相位为0,数据在时钟上升沿捕获,数据在时钟

    2024年04月16日
    浏览(34)
  • FPGA主SPI与STM32从机通信

    目录 概述 FPGA的SPI主机代码 STM32从机 SPI模式配置 SPI参数设置  SPI的DMA传输配置 STM32从机SPI接收代码         不说一些SPI原理之类的废话,浪费空间。我使用的硬件环境为STM32F407VET6和DE0-nano,长什么样子如下图。  使用cubemx配置工程,FPGA使用Quartus软件,时序仿真图如下    

    2024年02月02日
    浏览(28)
  • 【LabVIEW FPGA入门】使用CompactRIO进行SPI和I2C通信

            NI提供了 SPI and I2C Driver API:下载SPI and I2C Driver API - NI         该API使用FPGA数字I / O线与SPI或I2C设备进行通信。         选择数字硬件时,要考虑三个选项: NI Single-Board RIO硬件可同时使用SPI和I2C驱动程序。 NI 9401 C系列模块与SPI驱动程序配合使用效果最佳。

    2024年02月02日
    浏览(44)
  • 基于SPI的FPGA-MCU通用通信界面设计与技术详解

    FPGA与MCU之间的通信想必是很多异构人极为头疼的难题。如果每次写一个工程都要大费周章重写通信逻辑、通信协议之类的东西,不仅耗费心神,而且浪费时间。本文基于安陆PH1A90SBG484,提出一个已经通过门级仿真验证的通用通信界面解决方案。详细代码见以下链接: Github代

    2024年02月04日
    浏览(33)
  • FPGA实现SPI接口(1)--什么是SPI接口?

    目录 1、什么是SPI协议 2、SPI协议详述 2.1、SPI协议物理层 2.2、SPI 协议层 2.3、SPI协议通信过程 2.4、SPI协议的特性 2.5、SPI协议的优势、劣势 3、驱动代码的设计实现 3.1、接口定义与整体设计 3.2、Verilog代码 4、Testbench及仿真结果 4.1、单个BYTE的仿真 4.2、多个BYTE的仿真 5、其他  

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

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

    2024年02月14日
    浏览(30)
  • 【FPGA】SPI协议

    SPI(Serial Perripheral Interface, 串行外围设备接口)是 Motorola 公司推出的一种同步串行接口技术。SPI 总线在物理上是通过接在外围设备微控制器(PICmicro) 上面的微处理控制单元 (MCU) 上叫作同步串行端口(Synchronous Serial Port) 的模块(Module)来实现的, 它允许 MCU 以全双工的同步串行方式

    2024年02月09日
    浏览(25)
  • FPGA——spi代码篇

            为了避免每次SPI驱动重写,直接参数化,尽量一劳永逸。SPI master有啥用呢,你发现各种外围芯片的配置一般都是通过SPI配置的,只不过有三线和四线。SPI slave有什么用呢,当外部主机(cpu)要读取FPGA内部寄存器值,那就很有用了,FPGA寄存器就相当于RAM,cpu通过

    2024年03月14日
    浏览(27)
  • FPGA SPI 驱动程序

    此驱动程序已经完成很久了,花了2个星期的时间,主要是提升程序运行的效率。最近整理文件的时候又看到了,记录一下。 (1)状态控制程序 其主要是以空状态,写状态,读状态三个状态顺序执行的。 (2)写命令程序部分 (3)读数据程序部分

    2024年02月10日
    浏览(32)
  • 【FPGA】SPI读写flash

    SPI是同步全双工通信,通信原理以主从方式工作,通常有一个主设备和一个或多个从设备,需要4根线连接:MISO(主设备数据输入)、MOSI(主设备输出)、SCLK(时钟)、CS(片选)。通常拉低对应从机的片选来收发数据。 MISO:主设备输入,从设备输出 MOSI:主设备输出,从设备输入 SCLK:时

    2024年02月05日
    浏览(28)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包