AD7303 DAC SPI 控制 Verilog Vivado

名称:AD7303 DAC SPI 控制 Verilog Vivado

软件:Vivado

语言:Verilog

功能介绍

本设计使用 Verilog 实现 AD7303 DAC 的串行接口控制器,通过 FPGA 产生 SCLK、nCS 和 MOSI 信号,将 8 位控制字节与 8 位数据字节组合成 16 位串行帧发送至 DAC。外部系统只需提供 FPGA 时钟、低有效复位、待转换数据和 start 启动信号,即可发起一次完整传输。 模块提供 done 完成指示,适合接入上层采样控制、波形发生或数据更新逻辑。代码包含状态机、时钟分频、移位寄存器和位计数器,接口信号清晰,既可使用固定控制字节快速验证,也可按注释恢复 control 输入以适配实际应用。

运行环境

Verilog HDL,Vivado 开发环境。工程包含可综合 RTL、测试平台文件以及 pins.xdc 管脚约束,顶层模块为 AD7303。

设计思路

设计采用有限状态机组织一次完整的 DAC 串行写入过程。空闲状态等待 start 启动,随后进入片选拉低阶段,将 8 位控制字节与 8 位数据字节拼接到 16 位移位寄存器中;SHIFT 状态按最高位优先方式逐位输出到 MOSI,并用 bitcount 记录已发送位数,最后进入结束状态产生 done 指示。 SCLK 不使用自由运行方式,而是由 FPGA 时钟计数器按 PRESCALER 分频并在状态机工作期间翻转,从而只在传输需要时产生串行时钟。当前代码以 25MHz FPGA 时钟和 PRESCALER=4 为参数,形成约 5MHz 的 SCLK 配置。两套工程目录同时提供单路控制与双 DAC 控制相关模块,便于根据系统接口选择复用。

模块结构

顶层功能模块为 AD7303,负责 SPI 时序生成、16 位数据装载与串行移位;AD7303_tb 用于配套测试。工程的 AD7303_2DAC 目录还包含 AD7303_ctrl、AD7303 及 tb_AD7303_ctrl,可用于扩展双 DAC 控制场景。pins.xdc 用于完成顶层端口的管脚约束与接口分配。

开发板验证

工程提供了 pins.xdc 管脚约束文件,可据此完成 FPGA 顶层时钟、复位及 DAC SPI 信号的管脚分配,并用于开发板级连接验证。设计接口包含 sclk、nCS、mosi 和 done,便于将串行控制时序直接连接到 AD7303 外部器件。

演示视频

工程配套演示视频用于展示 AD7303 控制逻辑的运行过程,可结合 Vivado 工程与外部 DAC 连接方式观察启动、串行移位及完成指示信号的时序变化。

仿真图/仿真说明/设计文档图片

设计文档配套整理了工程文件、程序文件、程序编译、Testbench 和仿真图等内容,可用于按照 Vivado 流程完成编译检查、测试平台运行和波形查看,并辅助理解单路及双 DAC 目录中的模块关系。

AD7303 DAC SPI 控制 Verilog Vivado 设计文档图片 image1.png

AD7303 DAC SPI 控制 Verilog Vivado 设计文档图片 image2.png

AD7303 DAC SPI 控制 Verilog Vivado 设计文档图片 image3.png

AD7303 DAC SPI 控制 Verilog Vivado 设计文档图片 image4.png

AD7303 DAC SPI 控制 Verilog Vivado 设计文档图片 image5.png

AD7303 DAC SPI 控制 Verilog Vivado 设计文档图片 image6.png

AD7303 DAC SPI 控制 Verilog Vivado 设计文档图片 image1.png

AD7303 DAC SPI 控制 Verilog Vivado 设计文档图片 image2.png

AD7303 DAC SPI 控制 Verilog Vivado 设计文档图片 image3.png

AD7303 DAC SPI 控制 Verilog Vivado 设计文档图片 image4.png

AD7303 DAC SPI 控制 Verilog Vivado 设计文档图片 image5.png

AD7303 DAC SPI 控制 Verilog Vivado 设计文档图片 image6.png

部分代码

以下展示顶层模块 AD7303 的部分代码,完整源码请下载压缩包查看。

module AD7303(
	input clk,					// FPGA 时钟,频率 25MHz
	input nreset,				// 低电平复位信号
	//input [7:0] control,		// 8 位控制字节
	input [7:0] data,			// 8 位数据字节,外部输入 DAC 信号
	input start,				// 启动命令,可以一直保持高电平以启动传输
	output reg sclk,			// 生成的 SPI 时钟
	output reg nCS,				// 信号 SYNC
	output reg mosi,			// 串行数据输出 MOSI(连接到 DAC DIN)
	output reg done             // 转换完成指示信号
	);

    parameter IDLE    = 2'b00;
    parameter CS_LOW  = 2'b01;
    parameter SHIFT   = 2'b10;
    parameter CS_HIGH = 2'b11;
	/* 输入字节 control 和 data 在这里被注释掉,并作为参数形式给出,仅用于测试
	   用户可以在实际应用中取消对 input 端口的注释,并删除这些参数定义,将其与自己系统的信号相连
	*/
	parameter control = 8'h00; // 8 位控制字节,控制寄存器取为 0x00,使能两个 DAC
	//parameter data = 8'h7F;   // 8 位数据字节

    reg [1:0] state_cur, state_nxt;
    reg [15:0] shift_reg;	// 16 位移位寄存器,用于通过 MOSI 依次发送 16 位数据
    reg [4:0] bitcount;		// 位计数器,从 15 计到 0,用于统计已发送的位数
    localparam BITSTOSHIFT = 4'b1111; // 需要移出的总位数为 16 位(8 位控制 + 8 位数据)
    localparam PRESCALER = 8'd4;	// 分频系数,对 25MHz 时钟分频得到约 5MHz 的 SCLK
    reg [6:0] clk_counter; 		// 时钟分频计数器

    wire sclk_rise = (clk_counter == PRESCALER);        // 计数结束时产生一个时钟上升沿“单脉冲”标志
    wire sclk_fall = (clk_counter == (PRESCALER>>1));   // 计数到一半时产生一个时钟下降沿“单脉冲”标志


    // 不采用自由运行的时钟方式
    // 让状态机根据需要来产生每一个 SCLK 的边沿
    always @(posedge clk) begin
        if(!nreset) clk_counter <= 7'd0;
        else if(state_cur == IDLE) clk_counter <= 7'd0;
        else if (clk_counter == PRESCALER) clk_counter <= 7'd0;
        else clk_counter <= clk_counter + 1'b1;
    end
    // 根据时钟计数器的计数结果来产生 SCLK
    always @(posedge clk) begin
        if (!nreset) sclk <= 1'b0;
        else if (state_cur != IDLE && (clk_counter == PRESCALER)) sclk <= ~sclk; //toggle clock at the end of the count and only in the states other than IDLE
        else if (state_cur == IDLE) sclk <= 1'b0; //keep SCLK low in IDLE state
        else sclk <= sclk; //expliciting- hold SCLK state
    end

    // 两段式状态机
    // 时序部分:状态寄存器
    always @(posedge clk) begin
        if (!nreset) state_cur <= IDLE;
        else state_cur <= state_nxt;
    end

    // 组合逻辑部分:根据当前状态和输入决定下一状态和输出
    always @(*) begin
        // 默认赋值部分
        state_nxt = state_cur; // 默认保持当前状态
        nCS = 1'b1; // 默认片选拉高(不选中)
        mosi = shift_reg[15]; // 默认输出移位寄存器最高位
        done = 1'b0; // 默认转换未完成

        case(state_cur)
        IDLE:   begin
            nCS = 1'b1; // 片选保持高电平
            if (start) begin
                state_nxt = CS_LOW; // 接收到启动信号后转到 CS_LOW 状态
                shift_reg = {control, data}; // 将控制字节和数据字节装载到移位寄存器中
                bitcount = BITSTOSHIFT; // 位计数器设为 15(共 16 位需要发送)
            end
        end
        CS_LOW: begin
            nCS = 1'b0; // 片选拉低,选中 DAC
            if (sclk_fall && (sclk != 1'b1)) begin  // 仅在 SCLK 为低电平且检测到下降沿时准备数据,供下一个上升沿采样
                mosi = shift_reg[BITSTOSHIFT]; // 将移位寄存器最高位输出到 MOSI
                //shift_reg = {shift_reg[BITSTOSHIFT-1:0], 1'b0}; //shift left
                state_nxt = SHIFT; // 完成片选后进入 SHIFT 状态开始移位发送
            end
        end
        SHIFT: begin
            nCS = 1'b0; // 片选保持拉低
            if (sclk_fall && (sclk != 1'b1)) begin
                mosi = shift_reg[BITSTOSHIFT]; // 将移位寄存器最高位输出到 MOSI
                shift_reg = {shift_reg[BITSTOSHIFT-1:0], 1'b0}; // 左移一位,准备下一位数据
                bitcount = bitcount - 1'b1;
                if (bitcount == 0) state_nxt = CS_HIGH; // 所有位发送完毕后转到 CS_HIGH 状态
            end
        end
        CS_HIGH: begin
            nCS = 1'b0; // 片选继续保持拉低(准备结束本次传输)
            if (sclk_fall && (sclk != 1'b1)) begin
                state_nxt = IDLE; // 在检测到时钟边沿后回到 IDLE 空闲状态
                //nCS = 1'b1; // 片选拉高,结束本次传输
                done = 1'b1; // 置位完成信号,表示一次传输结束
            end
        end
        default: begin
            state_nxt = IDLE; // 默认回到 IDLE 状态
            nCS = 1'b1; // 默认片选高电平
            mosi = 1'b0; // 默认 MOSI 输出低电平
            done = 1'b0; // 默认完成信号为低
        end
    endcase

    end
    endmodule

代码文件(付费下载)

📥 付费后此处显示完整工程压缩包下载链接。
1、代码文件需要付费后才可见。
2、支付问题请联系微信公众号客服。
3、优质Verilog/VHDL代码资源,所见即所得。
Verilog/VHDL资源下载 » AD7303 DAC SPI 控制 Verilog Vivado

注册为本站会员,充值100得150,详情咨询客服

目前为止共有 *** 位优秀的会员加入! 立刻加入会员