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 的部分代码,完整源码请下载压缩包查看。
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
2、支付问题请联系微信公众号客服。
3、优质Verilog/VHDL代码资源,所见即所得。
Verilog/VHDL资源下载 » AD7303 DAC SPI 控制 Verilog Vivado