这个是多年前初学verilog的时候写的DAC7731的控制程序,当时是做DDS的输出频率控制的,中间涉及到一些DDS的东西,可以参考一下。
有几个地方要注意:
1. 同时用了时钟的正沿和负沿做触发,这个不是好习惯,在设计中尽量避免。
2.只是针对DAC7731的控制时序,采用计数器计数的方式来生成各种控制逻辑,通用性比较差,可以改用状态机。
3. 当时做功率信号发生器的,输出频率比较低,所以整个系统的控制随便写就都满足要求了。如果想要运行在比较高的频率下,代码要做进一步的优化。
module fre_da_ptos(
sout_permission_0,clk,rst,fr_da_clk,flash_data,
dds_foot_length,flash_ce,flash_oe,flash_add,
fr_da_cs,fr_da_sclk,fr_da_data,fr_da_ldac,fr_da_rst
);
input sout_permission_0; //数据输出允许信号,高电平有效,系统初始化时为低电平
input clk; //FPGA系统时钟20MHz
input rst; //复位信号
input fr_da_clk; //频率DA输出刷新频率控制时钟
input [15:0] flash_data; //FLASH存储器数据输入接口
input [21:0] dds_foot_length; //DDS步长控制输入
output flash_ce; //FLASH存储器控制,片选信号,低电平有效
output flash_oe; //FLASH存储器控制,读允许信号,低电平有效
output [19:0] flash_add; //FLASH存储器地址输出接口
output fr_da_cs; //频率DA控制,片选信号,低电平有效
output fr_da_sclk; //频率DA控制,时钟信号,有效时频率等于FPGA系统时钟,20MHz
output fr_da_data; //频率DA控制,数据信号
output fr_da_ldac; //频率DA控制,DA输出允许信号,上升沿有效
output fr_da_rst; //频率DA控制,复位信号
reg flash_ce;
reg flash_oe;
reg fr_da_cs;
reg fr_da_data;
reg fr_da_ldac;
reg fr_da_rst;
wire fr_da_sclk;
reg [19:0] flash_add;
reg [21:0] flash_add_temp; //地址寄存器1,存储真实地址
reg [19:0] flash_add_temp2; //地址寄存器2,存储经处理后的地址
reg [15:0] flash_data_temp; //FLASH输入数据寄存器,先从FLASH读取数据存入该寄存器,然后转换为串行数据
reg [5:0] s_clk_counter; //时钟周期计数器,控制FLASH数据读取和数据转换
wire da_clk_mark; //时钟标记
reg da_clk_mark_temp1; //DA时钟标记1,当系统复位后,其值为1,在da_clk_fre的上升沿,变为相反的值
reg da_clk_mark_temp2; //DA时钟标记2
assign fr_da_sclk = (s_clk_counter >= 6'd10 && s_clk_counter <=25) ? clk : 1'b0 ;
assign da_clk_mark = da_clk_mark_temp1 ^ da_clk_mark_temp2; //标记1与标记2异或运算,得到时钟标记
always @ (posedge fr_da_clk or negedge rst)
begin
if(!rst)
da_clk_mark_temp1 <=1'b0;
else
da_clk_mark_temp1 <= ~da_clk_mark_temp1;
end
always @(posedge clk or negedge rst)
begin
if(!rst)
begin
flash_oe <= 1'b0;
fr_da_rst <= 1'b0;
fr_da_ldac <= 1'b1;
da_clk_mark_temp2 <= 1'b0;
s_clk_counter <= 6'b00_0000;
flash_add <= 20'b0000_0000_0000_0000_0000;
flash_add_temp <= 22'b00_0000_0000_0000_0000_0000;
flash_add_temp2 <= 20'b0000_0000_0000_0000_0000;
end
else
if(da_clk_mark === 1'b0 && sout_permission_0 === 1'b1)
case(s_clk_counter)
6'd0:
begin
//判断是否是直流信号输出,如果是直流信号的话,将基地址
//初始化为262144,即频率生成DA保持10V输出。
if(dds_foot_length === 22'b00_0000_0000_0000_0000_0000)
flash_add_temp2 <= 20'd262144;
s_clk_counter <= s_clk_counter + 1'b1;
if(fr_da_rst != 1'b1)
fr_da_rst <= 1'b1;
end
6'd1:
s_clk_counter <= s_clk_counter + 1'b1;
6'd2:
begin
flash_add <= flash_add_temp2;
s_clk_counter <= s_clk_counter + 1'b1;
end
6'd3:
begin
s_clk_counter <= s_clk_counter + 1'b1;
end
6'd4:
begin
flash_data_temp <= flash_data;
s_clk_counter <= s_clk_counter + 1'b1;
end
6'd5:
begin
s_clk_counter <= s_clk_counter + 1'b1;
end
6'd6:
begin
flash_add <= 20'bzzzz_zzzz_zzzz_zzzz_zzzz;
s_clk_counter <= s_clk_counter + 1'b1;
end
6'd7:
begin
s_clk_counter <= s_clk_counter + 1'b1;
end
6'd8:
begin
s_clk_counter <= s_clk_counter + 1'b1;
end
6'd9,6'd10,6'd11,6'd12,6'd13,6'd14,6'd15,6'd16,6'd17,6'd18,6'd19,6'd20,6'd21,
6'd22,6'd23 :
s_clk_counter <= s_clk_counter + 1'b1;
6'd24:
begin
s_clk_counter <= s_clk_counter + 1'b1;
fr_da_ldac <= 1'b0;
end
6'd25:
begin
s_clk_counter <= s_clk_counter + 1'b1;
fr_da_ldac <= 1'b1;
end
6'd26:
s_clk_counter <= s_clk_counter + 1'b1;
6'd27:
s_clk_counter <= s_clk_counter + 1'b1;
6'd28:
begin
s_clk_counter <= s_clk_counter + 1'b1;
flash_add_temp <= flash_add_temp + dds_foot_length;
end
6'd29:
s_clk_counter <= s_clk_counter + 1'b1;
6'd30:
begin
flash_add_temp2 <= flash_add_temp[19:0];
s_clk_counter <= 6'b00_0000;
da_clk_mark_temp2 <= ~da_clk_mark_temp2;
end
endcase
end
always @(negedge clk or negedge rst)
begin
if(!rst)
begin
fr_da_cs <= 1'b0;
flash_ce <= 1'b0;
end
else
begin
if(s_clk_counter === 6'd8)
begin
fr_da_data <= flash_data_temp[15];
end
else if (s_clk_counter >6'd9 && s_clk_counter <6'd24)
fr_da_data <= flash_data_temp[6'd24 - s_clk_counter];
end
end
endmodule |