Verilog DDS 数字信号发生器:DAC 输出模拟波形与 ADC 回采观测
文章目录
- [Verilog DDS 数字信号发生器:DAC 输出模拟波形与 ADC 回采观测](#Verilog DDS 数字信号发生器:DAC 输出模拟波形与 ADC 回采观测)
一、项目概述
DDS 模块输出的是数字波形数据,而传统示波器只能观测模拟电压信号。因此需要 DAC 数模转换器,把数字波形转换成模拟波形,才可以使用示波器进行观测。
本工程使用 SPI 接口 DAC 芯片:MAX5383 / MAX5384 / MAX5385,为 8 bit 数模转换器,输出位宽与 DDS 模块输出的 8 bit 数字波形完全匹配。
MAX5383 系列为三线式 SPI 接口 DAC,只需要主机输出 MOSI 发送配置与波形数据;MISO 引脚无功能,芯片直接输出模拟电压,不会回传数字数据。
除硬件示波器观测模拟波形之外,本工程还实现数字波形回传 PC 上位机 的方案:
通过 ADC 模数转换器,把 DAC 输出的模拟波形重新采样变回数字信号,经由 UART-TX 发送到电脑,使用上位机波形软件查看数字波形。
器件选用 MAX1115 / MAX1116 ADC 芯片;ADC 接收到模拟输入后,内部需要一定转换等待时间,转换完成后通过 SPI 的 MISO 信号线,把采样得到的数字数据回传给 FPGA 主机。
本项目可以实现双重观测:
- 硬件示波器:直接观测 DAC 输出原始模拟波形;
- PC 上位机:ADC 回采,串口接收数字波形,上位机软件观测波形。
拓展:基于这套 DDS+ADC 采集链路,还可以进一步实现 FPGA 片上简易示波器综合系统。
整体数据流框图
上位机下发串口指令 → rx 接收解析并行数据 → ctrl_rx 解析指令参数 → DDS (ctrl_rom1) 生成调制数字波形 → DAC (MAX5383) 数模转换输出模拟波形 → ADC (MAX1115) 模拟信号回采转换数字信号 → tx 串口上传至上位机 PC:
- 模块分工说明
ctrl_rom1:DDS 波形发生模块;完成正弦波选择、调相、调频、调幅,输出调制后的 8 bit 数字波形以及数据有效信号。ctrl_dac:DAC 专用 SPI 主机模块;驱动 MAX5383 系列,发送波形数字量,完成数模转换。ctrl_adc:ADC 专用 SPI 主机模块;驱动 MAX1115/MAX1116,启动采样转换,读取 ADC 采样得到的数字值。- rx、ctrl_rx:串口接收、帧解析,解析波形选择、相位、频率、幅度配置参数。
- tx:UART 发送模块,把 ADC 采样数据回传给 PC 上位机。
- top 顶层:完成所有子模块例化,区分两套独立 SPI 接口,分别供给 DAC、ADC 使用。
二、关键器件要点
- MAX5383(8 bit SPI‑DAC)
- 三线 SPI,只需要主机发送 MOSI,无 MISO 回传;
- 输入数字位宽 8 bit,和 DDS 输出数据位宽对齐;
- 在 SPI 通信完成之后,输出对应的模拟电压波形,供示波器探头测量。
- 下面是数据输入格式:

- MAX1115 / MAX1116(ADC)
- 模拟输入来自 DAC 输出波形;
- 启动转换之后需要等待芯片内部转换时间(7500 ns);
- 转换结束,通过 MISO 向 FPGA 主机回传采样数字结果;
- 采样得到数字量经由 TX 串口发送到 PC,实现软件示波器效果。
三、模块代码实现
ctrl_rom1 DDS 波形发生模块
verilog
//完成正弦波(01)的波形选择、调相、调频、调幅
module ctrl_rom1 (
input wire clk ,
input wire rst_n ,
input wire [7:0] wave ,//波形选择
input wire [7:0] phal ,//初始相位
input wire [7:0] ferq ,//频率参数
input wire [7:0] ampl ,//调幅参数
input wire done_cmd ,//指令更新信号
input wire done_tx ,//tx单字节发送完成信号
output wire [7:0] data_wave1 ,//调制后信号
output wire wave1_vld //数据有效信号
);
//状态
localparam IDLE = 1,
REG = 2,
WAVE = 3,
PHAL = 4,
FERQ = 5,
AMPL = 6,
DATA = 7,
WAIT = 8;
reg [3:0] state_c,state_n;
//内部信号
//信号寄存
reg [7:0] wave_reg;
reg [7:0] phal_reg;
reg [7:0] ferq_reg;
reg [7:0] ampl_reg;
reg [7:0] data_reg;//输出信号寄存
reg [3:0] cnt_freq;//频率计数
//rom
reg [8:0] address;
wire [7:0] q ;
//状态机第一段
always @(posedge clk or negedge rst_n) begin
if (rst_n == 0) begin
state_c <= IDLE;
end
else begin
state_c <= state_n;
end
end
//状态机第二段
always @(*) begin
if (rst_n == 0) begin
state_n = IDLE;
end
else begin
case (state_c)
IDLE:begin
if (done_cmd) begin
state_n = REG;
end
else begin
state_n = state_c;
end
end
REG :state_n = WAVE;//一个周期用来进行参数寄存
WAVE:begin//一个周期进行波形选择
if (done_cmd) begin
state_n = REG;
end
else if (wave_reg != 8'h01) begin
state_n = IDLE;
end
else begin
state_n = PHAL;
end
end
PHAL:begin//数据没有更新的情况下直接跳,进行rom地址的初始化(相位初始化)
if (done_cmd) begin
state_n = REG;
end
else begin
state_n = FERQ;
end
end
FERQ:begin//频率计数到最大值进行采样完成频率调制
if (done_cmd) begin
state_n = REG;
end
else if ((ferq_reg[4] == 0 && cnt_freq == ferq_reg[3:0] - 1 ) || ferq_reg[4] == 1)begin
state_n = AMPL;
end
else begin
state_n = state_c;
end
end
AMPL:begin//一个周期完成调幅
if (done_cmd) begin
state_n = REG;
end
else begin
state_n = DATA;
end
end
DATA:begin//一个周期完成信号赋值
if (done_cmd) begin
state_n = REG;
end
else begin
state_n = WAIT;
end
end
WAIT:begin//一个周期的过渡
if (done_cmd) begin
state_n = REG;
end
else if(done_tx)begin
state_n = FERQ;
end
else begin
state_n = WAIT;
end
end
default:state_n = IDLE;
endcase
end
end
//状态机第三段
always @(posedge clk or negedge rst_n) begin
if (rst_n == 0) begin
wave_reg <= 0;
phal_reg <= 0;
ferq_reg <= 0;
ampl_reg <= 0;
data_reg <= 0;
cnt_freq <= 0;
address <= 0;
end
else begin
case (state_c)
IDLE: begin//等done_cmd,指令有效信号
wave_reg <= 0;
phal_reg <= 0;
ferq_reg <= 0;
ampl_reg <= 0;
data_reg <= 0;
cnt_freq <= 0;
address <= 0;
end
REG :begin//进行指令寄存
wave_reg <= wave;
phal_reg <= phal;
ferq_reg <= ferq;
ampl_reg <= ampl;
end
WAVE:;//进行波形选择,只做了一个判断
PHAL:begin//调相
address <= phal_reg;
end
FERQ:begin//调频,调大(周期缩小)、调小(周期展宽)
//频率计数
if (cnt_freq == ferq_reg[3:0] - 1) begin
cnt_freq <= 0;
end
else begin
cnt_freq <= cnt_freq + 1;
end
//地址
if ((ferq_reg[4] == 1 && cnt_freq == ferq_reg[3:0] - 1 ) || ferq_reg[4] == 0) begin
address <= address + 1;
end
end
AMPL:begin//根据上一个状态选中的地址,由于读使能一直打开,q为开放状态可以直接读取
data_reg <= q/ampl_reg;
end
DATA:;//产生所谓的数据有效信号
WAIT:;//过渡状态
default:begin
wave_reg <= 0;
phal_reg <= 0;
ferq_reg <= 0;
ampl_reg <= 0;
data_reg <= 0;
cnt_freq <= 0;
address <= 0;
end
endcase
end
end
//输出信号
assign data_wave1 = data_reg;
assign wave1_vld = (state_c == DATA);
rom1 rom1_inst (
.aclr (~rst_n ),
.address (address ),
.clock (clk ),
.q (q )
);
endmodule
ctrl_adc ADC SPI 驱动模块
verilog
//ADC 的专用 SPI,用于接收 ADC 转换成功的数字信号
//1. 接口分析:协议开始信号,目前只回传数据,以字节为单位,因此长度设为 1?
//并未写数据,MOSI 处于闲置状态
module ctrl_adc(
input wire clk ,
input wire rst_n ,
input wire start_spi ,//上层给到 SPI 接口的开始信号
input wire [7:0] data_len ,//上层给到 SPI 接口的总传输长度
input wire [7:0] wr_lenth ,//上层给到spi接口的要写(发送给从机的长度)
output wire [7:0] data_o_spi ,//输出的数据
output wire done_w ,//握手信号
output wire done_r ,//握手信号
output wire done_spi ,//握手信号
output wire ADC_SCK ,//四线
output wire ADC_CNVST ,//四线
output wire ADC_MOSI ,//四线
input wire ADC_MISO //四线
);
//参数
parameter CPOL = 0 ,//时钟极性
CPHA = 0 ,//时钟相位
delay = 6 ,//分频系数
TIME = 375;
//状态定义
localparam IDLE = 4'b0001,
START = 4'b0010,
DATA = 4'b0100,
STOP = 4'b1000;
reg [3:0] state_c,state_n;
//状态转移
wire IDLE_START,
START_DATA,
DATA_STOP ,
STOP_IDLE ;
//内部信号
reg [8:0] cnt_clk;//分频时钟计数
reg [7:0] cnt_bit;//比特计数
reg [1:0] start_reg ;//输入寄存信号
reg [7:0] data_reg ;//输入寄存信号
reg [7:0] data_len_r ;//输入寄存信号
reg [7:0] wr_lenth_r ;//输入寄存信号
reg SCK_R ;//时钟寄存
reg [7:0] data_temp ;//输出数据的暂存信号
reg MOSI_R ;//主机输出寄存
reg CS_N_R ;//片选信号寄存
//开始信号的寄存
always @(posedge clk or negedge rst_n) begin
if (rst_n == 0) begin
start_reg <= 2'b00;
end
else begin
start_reg <= {start_reg[0],start_spi};
end
end
//状态机第一段
always @(posedge clk or negedge rst_n) begin
if (rst_n == 0) begin
state_c <= IDLE;
end
else begin
state_c <= state_n;
end
end
//状态机第二段
always @(*) begin
if (rst_n == 0) begin
state_n = IDLE;
end
else begin
case (state_c)
IDLE :state_n = (IDLE_START) ? START : state_c ;
START :state_n = (START_DATA) ? DATA : state_c ;
DATA :state_n = (DATA_STOP ) ? STOP : state_c ;
STOP :state_n = (STOP_IDLE ) ? IDLE : state_c ;
default:state_n = IDLE;
endcase
end
end
//状态转移条件
assign IDLE_START = (state_c == IDLE ) && start_reg == 2'b01;
assign START_DATA = (state_c == START) && cnt_clk == TIME - 1;
assign DATA_STOP = (state_c == DATA ) && ((CPHA == 0 &&cnt_bit == data_len_r*8 - 1 && cnt_clk == delay - 1) || (CPHA == 1 &&cnt_bit == data_len_r*8 && cnt_clk == 0));
assign STOP_IDLE = (state_c == STOP ) && cnt_clk == delay - 1;
//状态机第三段
always @(posedge clk or negedge rst_n) begin
if (rst_n == 0) begin
cnt_clk <= 0 ;//分频时钟计数
cnt_bit <= 0 ;//比特计数
CS_N_R <= 1 ;//片选信号
SCK_R <= CPOL;//分频时钟信号
data_reg <= 0 ;//输入寄存信号
data_len_r <= 0 ;//输入寄存信号
wr_lenth_r <= 0 ;//输入寄存信号
data_temp <= 0 ;//输出数据的暂存信号
end
else begin
case (state_c)
IDLE :begin//寄存、等待开始信号
cnt_clk <= 0;//分频时钟计数
cnt_bit <= 0;//比特计数
CS_N_R <= 1;//片选信号
SCK_R <= CPOL;
data_reg <= 0;
data_len_r <= data_len;//输入寄存信号
wr_lenth_r <= wr_lenth;//输入寄存信号
data_temp <= 0;//输出数据的暂存信号
end
START :begin//拉低片选信号,并等待7.5us
if (cnt_clk == TIME) begin//分频时钟计数,也是一个bit计数器,多给一周期
cnt_clk <= 0;
CS_N_R <= 1;
end
else begin
cnt_clk <= cnt_clk + 1;
CS_N_R <= 0;//片选信号拉低
end
end
DATA :begin//数据的更新,接收,发送
if (cnt_clk == delay - 1) begin//分频时钟计数,也是一个bit计数器
cnt_clk <= 0;
end
else begin
cnt_clk <= cnt_clk + 1;
end
if (cnt_clk == delay - 1) begin//比特计数
if (cnt_bit == data_len_r*8) begin
cnt_bit <= 0;
end
else begin
cnt_bit <= cnt_bit + 1;
end
end
//时钟
if (cnt_clk == delay/2 || (cnt_clk == 0 && cnt_bit > 0 )) begin
SCK_R <= ~SCK_R;
end
//根据极性来进行采样和寄存
case (CPHA)
0:begin//第一个沿进行采集
//数据发送
if (cnt_clk == 0) begin//数据已经在上一个字节末尾进行更新
MOSI_R <= data_reg[7 - cnt_bit];//高位优先
end
//数据接收/采集
if (cnt_clk == delay/2) begin
data_temp <= {data_temp[6:0],ADC_MISO};
end
end
default:begin//第二个沿进行采集
//数据发送
if (cnt_clk == delay/2 ) begin
MOSI_R <= data_reg[7 - cnt_bit%8];//高位优先
end
//数据接收/采集
if (cnt_clk == 0) begin
data_temp <= {data_temp[6:0],ADC_MISO};
end
end
endcase
end
STOP :begin//持续一个周期后拉高片选产生done_spi结束本次通信
if (cnt_clk == delay - 1) begin
cnt_clk <= 0;
CS_N_R <= 1;
end
else begin
cnt_clk <= cnt_clk + 1;
end
cnt_bit <= 0;
SCK_R <= CPOL;
end
default:begin
cnt_clk <= 0 ;//分频时钟计数
cnt_bit <= 0 ;//比特计数
CS_N_R <= 1 ;//片选信号
SCK_R <= CPOL;//分频时钟信号
data_reg <= 0 ;//输入寄存信号
data_len_r <= 0 ;//输入寄存信号
wr_lenth_r <= 0 ;//输入寄存信号
data_temp <= 0 ;//输出数据的暂存信号
end
endcase
end
end
//输出信号
// assign data_o_spi = ((CPHA == 0 && cnt_clk == delay/2 && cnt_bit%8 == 7) || (CPHA == 1 && cnt_clk == delay - 1 && cnt_bit%8 == 7)) ? data_temp : data_o_spi ;
assign data_o_spi = data_temp ;//只在done_r信号来的时候才采样
assign done_r = (CPHA == 0 && cnt_clk == delay/2 + 1 && cnt_bit%8 == 7 && cnt_bit > wr_lenth*8) || (CPHA == 1 && cnt_clk == 1 && cnt_bit%8 == 0 && cnt_bit > wr_lenth*8 && data_len > wr_lenth);
assign done_w = (CPHA == 0 && cnt_clk == 1 && cnt_bit%8 == 7 && cnt_bit <= wr_lenth*8) || (CPHA == 1 && cnt_clk == delay/2 + 1 && cnt_bit%8 == 7 && cnt_bit <= wr_lenth*8) ;
// assign done_spi = STOP_IDLE ;
assign done_spi = (state_c == STOP) && (cnt_clk == delay - 1);
assign ADC_SCK = SCK_R ;
assign ADC_CNVST = CS_N_R ;
assign ADC_MOSI = MOSI_R ;
endmodule
ctrl_dac DAC SPI 驱动模块
verilog
//dac的专用spi
//1.接口分析:时钟、复位、上层给到spi接口的开始信号、数据、定义的总传输长度、要写(发送给从机的长度)、接口之间的四线结构
//输出的数据、以及读写、一次通信完成的握手信号
//2.四个时序图转换为代码
//之前是依托flash进行的帧解析,现在要使用dac,原理比flash更简单,只需要两字节的输出就可以了。
//由于之前是以单字节为基础写的,所以在赋值的时候有点问题
//如果完善一下,写一个针对dac的控制模块也可以,顺便省去额外不必要的信号。
module ctrl_dac(
input wire clk ,
input wire rst_n ,
input wire start_spi ,//上层给到spi接口的开始信号
input wire [15:0] data_i_spi ,//上层给到spi接口的(指令、地址、数据)
input wire [15:0] data_len ,//上层给到spi接口的总传输长度
input wire [15:0] wr_lenth ,//上层给到spi接口的要写(发送给从机的长度)
output wire [15:0] data_o_spi ,//输出的数据
output wire done_w ,//握手信号
output wire done_r ,//握手信号
output wire done_spi ,//握手信号
output wire DAC_SCK ,//四线
output wire DAC_CS_N ,//四线
output wire DAC_MOSI ,//四线
input wire DAC_MISO //四线
);
//参数
parameter CPOL = 0 ,//时钟极性
CPHA = 0 ,//时钟相位
delay = 6 ;//分频系数
//状态定义
localparam IDLE = 4'b0001,
START = 4'b0010,
DATA = 4'b0100,
STOP = 4'b1000;
reg [3:0] state_c,state_n;
//状态转移
wire IDLE_START,
START_DATA,
DATA_STOP ,
STOP_IDLE ;
//内部信号
reg [2:0] cnt_clk;//分频时钟计数
reg [15:0] cnt_bit;//比特计数
reg [1:0] start_reg ;//输入寄存信号
reg [15:0] data_reg ;//输入寄存信号
reg [15:0] data_len_r ;//输入寄存信号
reg [15:0] wr_lenth_r ;//输入寄存信号
reg SCK_R ;//时钟寄存
reg [15:0] data_temp ;//输出数据的暂存信号
reg MOSI_R ;//主机输出寄存
reg CS_N_R ;//片选信号寄存
//开始信号的寄存
always @(posedge clk or negedge rst_n) begin
if (rst_n == 0) begin
start_reg <= 2'b00;
end
else begin
start_reg <= {start_reg[0],start_spi};
end
end
//状态机第一段
always @(posedge clk or negedge rst_n) begin
if (rst_n == 0) begin
state_c <= IDLE;
end
else begin
state_c <= state_n;
end
end
//状态机第二段
always @(*) begin
if (rst_n == 0) begin
state_n = IDLE;
end
else begin
case (state_c)
IDLE :state_n = (IDLE_START) ? START : state_c ;
START :state_n = (START_DATA) ? DATA : state_c ;
DATA :state_n = (DATA_STOP ) ? STOP : state_c ;
STOP :state_n = (STOP_IDLE ) ? IDLE : state_c ;
default:state_n = IDLE;
endcase
end
end
//状态转移条件
assign IDLE_START = (state_c == IDLE ) && start_reg == 2'b01;
assign START_DATA = (state_c == START) ;
assign DATA_STOP = (state_c == DATA ) && ((CPHA == 0 && cnt_bit == data_len_r*8 - 1 && cnt_clk == delay - 1) || (CPHA == 1 && cnt_bit == data_len_r*8 && cnt_clk == 0));
assign STOP_IDLE = (state_c == STOP ) && cnt_clk == delay - 1;
//状态机第三段
always @(posedge clk or negedge rst_n) begin
if (rst_n == 0) begin
cnt_clk <= 0 ;//分频时钟计数
cnt_bit <= 0 ;//比特计数
CS_N_R <= 1 ;//片选信号
SCK_R <= CPOL;//分频时钟信号
data_reg <= 0 ;//输入寄存信号
data_len_r <= 0 ;//输入寄存信号
wr_lenth_r <= 0 ;//输入寄存信号
data_temp <= 0 ;//输出数据的暂存信号
end
else begin
case (state_c)
IDLE :begin//寄存、等待开始信号
cnt_clk <= 0;//分频时钟计数
cnt_bit <= 0;//比特计数
CS_N_R <= 1;//片选信号
SCK_R <= CPOL;
data_reg <= data_i_spi;//输入寄存信号
data_len_r <= data_len;//输入寄存信号
wr_lenth_r <= wr_lenth;//输入寄存信号
data_temp <= 0;//输出数据的暂存信号
end
START :begin//拉低片选信号
CS_N_R <= 0;//片选信号拉低
end
DATA :begin//数据的更新,接收,发送
if (cnt_clk == delay - 1) begin//分频时钟计数,也是一个bit计数器
cnt_clk <= 0;
end
else begin
cnt_clk <= cnt_clk + 1;
end
if (cnt_clk == delay - 1) begin//比特计数
if (cnt_bit == data_len_r*8) begin
cnt_bit <= 0;
end
else begin
cnt_bit <= cnt_bit + 1;
end
end
//时钟
if (cnt_clk == delay/2 || (cnt_clk == 0 && cnt_bit > 0 )) begin
SCK_R <= ~SCK_R;
end
//根据极性来进行采样和寄存
case (CPHA)
0:begin//第一个沿进行采集
//数据发送
if (cnt_clk == 0) begin//数据已经在上一个字节末尾进行更新
MOSI_R <= data_reg[15 - cnt_bit];//高位优先
end
//数据接收/采集
if (cnt_clk == delay/2) begin
data_temp <= {data_temp[6:0],DAC_MISO};
end
end
default:begin//第二个沿进行采集
//数据发送
if (cnt_clk == delay/2 ) begin
MOSI_R <= data_reg[15 - cnt_bit%16];//高位优先
end
//数据接收/采集
if (cnt_clk == 0) begin
data_temp <= {data_temp[6:0],DAC_MISO};
end
end
endcase
end
STOP :begin//持续一个周期后拉高片选产生done_spi结束本次通信
if (cnt_clk == delay - 1) begin
cnt_clk <= 0;
CS_N_R <= 1;
end
else begin
cnt_clk <= cnt_clk + 1;
end
cnt_bit <= 0;
SCK_R <= CPOL;
end
default:begin
cnt_clk <= 0 ;//分频时钟计数
cnt_bit <= 0 ;//比特计数
CS_N_R <= 1 ;//片选信号
SCK_R <= CPOL;//分频时钟信号
data_reg <= 0 ;//输入寄存信号
data_len_r <= 0 ;//输入寄存信号
wr_lenth_r <= 0 ;//输入寄存信号
data_temp <= 0 ;//输出数据的暂存信号
end
endcase
end
end
//输出信号
// assign data_o_spi = ((CPHA == 0 && cnt_clk == delay/2 && cnt_bit%16 == 15) || (CPHA == 1 && cnt_clk == delay - 1 && cnt_bit%16 == 15)) ? data_temp : data_o_spi ;
assign data_o_spi = data_temp ;//只在done_r信号来的时候才采样
assign done_r = (CPHA == 0 && cnt_clk == delay/2 + 1 && cnt_bit%16 == 15 && cnt_bit > wr_lenth*8) || (CPHA == 1 && cnt_clk == 1 && cnt_bit%16 == 0 && cnt_bit > wr_lenth*8 && data_len > wr_lenth);
assign done_w = (CPHA == 0 && cnt_clk == 1 && cnt_bit%16 == 15 && cnt_bit <= wr_lenth*8) || (CPHA == 1 && cnt_clk == delay/2 + 1 && cnt_bit%16 == 15 && cnt_bit <= wr_lenth*8) ;
// assign done_spi = STOP_IDLE ;
assign done_spi = (state_c == STOP) && (cnt_clk == delay - 1);
assign DAC_SCK = SCK_R ;
assign DAC_CS_N = CS_N_R ;
assign DAC_MOSI = MOSI_R ;
endmodule
top 顶层模块
verilog
//一个主机芯片可以有多个 SPI 接口,所以这里的 SCK 是分开的。
module top (
input wire clk ,
input wire rst_n ,
input wire rx ,//接收端:串行数据线
//dac
output wire DAC_SCK ,
output wire DAC_CS_N ,
output wire DAC_MOSI ,
//adc
output wire ADC_SCK ,
output wire ADC_CNVST,
input wire ADC_MISO ,
output wire tx //输出的串行数据
);
//rx
wire [7:0] data_rx;
wire done_rx;
//ctrl_rx
wire [7:0] wave ;
wire [7:0] phal ;
wire [7:0] ferq ;
wire [7:0] ampl ;
wire done_cmd;
//ctrl_rom1
wire [7:0] data_wave1;
wire wave1_vld ;
//ctrl_rom2
wire [7:0] data_wave2;
wire wave2_vld ;
//ctrl_rom3
wire [7:0] data_wave3;
wire wave3_vld ;
//ctrl_rom4
wire [7:0] data_wave4;
wire wave4_vld ;
//tx
wire done_tx;
wire done_rom;
//ctrl_dac
wire [7:0] dac_data_len ;
wire [7:0] dac_wr_lenth ;
wire [7:0] dac_data_o_spi;
wire dac_done_w ;
wire dac_done_r ;
wire dac_done_spi ;
wire DAC_MISO ;
//ctrl_adc
wire [7:0] adc_data_len ;
wire [7:0] adc_wr_lenth ;
wire [7:0] adc_data_o_spi;
wire adc_done_w ;
wire adc_done_r ;
wire adc_done_spi ;
wire ADC_MOSI;
//
// wire [7:0] data_out ;
// wire rd_done ;
//中间信号
reg [7:0] data_wave;
reg wave_vld ;
always @(*) begin
if (rst_n == 0) begin
data_wave = 0;
wave_vld = 0;
end
else begin case (wave)
8'h01:begin
data_wave = data_wave1;
wave_vld = wave1_vld ;
end
8'h02:begin
data_wave = data_wave2;
wave_vld = wave2_vld ;
end
8'h03:begin
data_wave = data_wave3;
wave_vld = wave3_vld ;
end
default:begin
data_wave = data_wave4;
wave_vld = wave4_vld ;
end
endcase
end
end
rx rx_inst(
.clk (clk ),
.rst_n (rst_n ),
.rx (rx ),//接收端:串行数据线
.data_rx (data_rx),//并行数据
.done_rx (done_rx) //数据有效信号
);
ctrl_rx ctrl_rx_inst(
.clk (clk ),
.rst_n (rst_n ),
.data_rx (data_rx ),//rx发送过来的单个指令
.done_rx (done_rx ),//数据有效信号
.wave (wave ),//波形选择
.phal (phal ),//初始相位
.ferq (ferq ),//频率参数
.ampl (ampl ),//调幅参数
.done_cmd (done_cmd)
);
ctrl_rom1 ctrl_rom1_inst(
.clk (clk ),
.rst_n (rst_n ),
.wave (wave ),//波形选择
.phal (phal ),//初始相位
.ferq (ferq ),//频率参数
.ampl (ampl ),//调幅参数
.done_cmd (done_cmd ),//指令更新信号
.done_tx (done_rom ),//tx发送,提前更新数据
.data_wave1 (data_wave1),//调制后信号
.wave1_vld (wave1_vld ) //数据有效信号
);
ctrl_rom2 ctrl_rom2_inst(
.clk (clk ),
.rst_n (rst_n ),
.wave (wave ),//波形选择
.phal (phal ),//初始相位
.ferq (ferq ),//频率参数
.ampl (ampl ),//调幅参数
.done_cmd (done_cmd ),//指令更新信号
.done_tx (done_rom ),//tx发送,提前更新数据
.data_wave2 (data_wave2),//调制后信号
.wave2_vld (wave2_vld ) //数据有效信号
);
ctrl_rom3 ctrl_rom3_inst(
.clk (clk ),
.rst_n (rst_n ),
.wave (wave ),//波形选择
.phal (phal ),//初始相位
.ferq (ferq ),//频率参数
.ampl (ampl ),//调幅参数
.done_cmd (done_cmd ),//指令更新信号
.done_tx (done_rom ),//tx发送,提前更新数据
.data_wave3 (data_wave3),//调制后信号
.wave3_vld (wave3_vld ) //数据有效信号
);
ctrl_rom4 ctrl_rom4_inst(
.clk (clk ),
.rst_n (rst_n ),
.wave (wave ),//波形选择
.phal (phal ),//初始相位
.ferq (ferq ),//频率参数
.ampl (ampl ),//调幅参数
.done_cmd (done_cmd ),//指令更新信号
.done_tx (done_rom ),//tx发送,提前更新数据
.data_wave4 (data_wave4),//调制后信号
.wave4_vld (wave4_vld ) //数据有效信号
);
ctrl_dac ctrl_dac_inst(
.clk (clk ),
.rst_n (rst_n ),
.start_spi (wave_vld ),//上层给到spi接口的开始信号
.data_i_spi ({4'b0000,data_wave,4'b0000}),
.data_len (8'd2 ),//上层给到spi接口的总传输长度
.wr_lenth (8'd2 ),//上层给到spi接口的要写(发送给从机的长度)
.data_o_spi (dac_data_o_spi ),//输出的数据
.done_w (dac_done_w ),//握手信号
.done_r (dac_done_r ),//握手信号
.done_spi (dac_done_spi ),//握手信号
.DAC_SCK (DAC_SCK ),//四线
.DAC_CS_N (DAC_CS_N ),//四线
.DAC_MOSI (DAC_MOSI ),//四线
.DAC_MISO (DAC_MISO ) //四线
);
ctrl_adc ctrl_adc_inst(
.clk (clk ),
.rst_n (rst_n ),
.start_spi (dac_done_spi ),//上层给到spi接口的开始信号
.data_len (8'd1 ),//上层给到spi接口的总传输长度
.wr_lenth (8'd0 ),//上层给到spi接口的要写(发送给从机的长度)
.data_o_spi (adc_data_o_spi ),//输出的数据
.done_w (adc_done_w ),//握手信号
.done_r (adc_done_r ),//握手信号
.done_spi (adc_done_spi ),//握手信号
.ADC_SCK (ADC_SCK ),//四线
.ADC_CNVST (ADC_CNVST ),//四线
.ADC_MOSI (ADC_MOSI ),//四线
.ADC_MISO (ADC_MISO ) //四线
);
//ctrl_tx ctrl_tx_inst(
// .clk (clk ),
// .rst_n (rst_n ),
// .data_o_spi (adc_data_o_spi),//spi的输出数据,也就是读出的
// .done_r (adc_done_r ),//完成一次读数据的握手信号
// .done_tx (done_tx ),//读数据控制读使能的信号
// .done_spi (adc_done_spi ),//数据寄存fifo结束
// .data_out (data_out),//tx的输入
// .rd_done (rd_done ) //tx的开始
//);
tx tx_inst(
.clk (clk ),
.rst_n (rst_n ),
.data (adc_data_o_spi),//并行数据
.data_done (adc_done_r ),//数据有效信号,和数据同时到来
.tx (tx ),//输出的串行数据
.done_rom (done_rom ),
.done_tx (done_tx ) //表示这组数据发送完毕等待下一个数据到来
);
endmodule
四、上板测试
- 观测的时候,示波器的探头没稳定接触,存在少量毛刺。

- 上位机观测现象。
