发一个我写的DDS芯片AD9833,请大家指正交流
AD9833的控制可以分为以下几步:1、写控制寄存器。复位等。
2、写频率寄存器低位。
3、写频率寄存器高位。
4、写相位寄存器。
5、写输出使能。
6、延时后输出有效。
百度了以下,控制字可以分别写入:0X2100,0X4A7C,0X4000,0XC000,0X0000。可以使芯片输出100HZ正弦波。如果需要调整频率,调整第二个和第三个控制字即可。
所以,在编写verilog程序时候,考虑分:IDLE,START,WR_CTR,WR_F_L,WR_F_M,WR_PHASE,WR_EN,DEALY,OVER,这几个状态,依次为“空闲、开始、写控制寄存器、写频率低位、写频率高位、写相位、写输出是能控制字、延时、结束”。然后再用一个计数器,在每个状态开始的时候,由0计数到17,对应的在0-15,或者1-16的时候写数据。特别要注意每次状态转换时候要清零。
程序如下:
module dds_ad9833(clk,rst_n,start_config,fsync,spi_data,spi_clk,out_cnt2,out_state,out_cnt1,state_flag,fsync_reg_r);
input clk,
rst_n,
start_config;
output fsync,
spi_data,
spi_clk;
output wire out_cnt2;
output wire out_state;
output wire out_cnt1;
assign out_state = cstate;///////////////
assign out_cnt1 = cnt1;
parameter IDLE = 10'b00_0000_0001,//--1
START = 10'b00_0000_0010,//2
WR_CTR = 10'b00_0000_0100,//4
WR_F_L = 10'b00_0000_1000,//8
WR_F_M = 10'b00_0001_0000,//16
WR_PHASE = 10'b00_0010_0000,//32
WR_EN = 10'b00_0100_0000,//64
DELAY = 10'b00_1000_0000,//128
OVER = 10'b01_0000_0000;//
//------------------产生分频信号------------------------
regcnt1;
reg spi_clk_r;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
cnt1 <= 5'd0;
else if(fsync_reg_r==1)///////////++
cnt1 <= 5'd0;
else
cnt1 <= cnt1 + 1'b1;
end
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
spi_clk_r <= 1'b0;
else if(cstate==OVER)
spi_clk_r <= 1'bz;
else if(((cnt2==5'd16)||(cnt2==5'd17))&&(cstate!=WR_CTR))
spi_clk_r <= 1'b0;
/*else if((cnt2==5'd15)&&(cnt1==5'd16))
spi_clk_r <= 1'b0;*/
else
begin
case(cnt1)
5'd0,5'd1,5'd2,5'd3,
5'd4,5'd5,5'd6,5'd7,
5'd8,5'd9,5'd10,5'd11,
5'd12,5'd13,5'd14,5'd15: spi_clk_r <= 1'b0;
5'd16,5'd17,5'd18,5'd19,
5'd20,5'd21,5'd22,5'd23,
5'd24,5'd25,5'd26,5'd27,
5'd28,5'd29,5'd30,5'd31: spi_clk_r <= 1'b1;
default: spi_clk_r <= 1'b0;
endcase
end
end
assign spi_clk = spi_clk_r;
//----------------------------------------------
regctr_reg;
regfsl_reg;
regfsm_reg;
regphase_reg;
regen_reg;
regcstate,
nstate;
regcnt2;
reg spi_data_reg;
reg fsync_reg;
reg state_finish;
//----------------------------------
output wire fsync_reg_r;
reg fsync_reg_n;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
fsync_reg_n <= 1'b1;
else
fsync_reg_n <= fsync_reg;
end
assign fsync_reg_r = ((~fsync_reg_n)&&(fsync_reg));//
//-----------------------------------
output wire state_flag;
assign state_flag = state_finish;
always@(posedge clk or negedge rst_n)//对分频的时钟上升沿计数,计满17次清零
begin
if(!rst_n)
cnt2 <= 5'd0;
else if((fsync_reg_r==1'b1)&&(cnt1==5'd16))//
cnt2 <= 5'd0;
else if((cnt2==5'd17)&&(cnt1==5'd16))//++
cnt2 <= 5'd0;//
else if(cnt1==5'd16)
cnt2 <= cnt2 + 1'b1;
end
assign out_cnt2 = cnt2;
always@(posedge clk or negedge rst_n)//操作状态机
begin
if(!rst_n)
cstate <= IDLE;
else
cstate <= nstate;
end
always@(cstate or start_config or cnt2)
begin
case(cstate)
IDLE:
begin
//state_finish = 1'b0
fsync_reg = 1'b1;
if(start_config==1'b1)
begin
nstate = START;
end
else
begin
nstate = IDLE;
end
end
START:
begin
/*if(start_config==1'b1)//
begin
nstate = WR_CTR;
end
else
nstate = IDLE;*/
nstate = WR_CTR;
end
WR_CTR:
begin
case(cnt2)
5'd0:
begin
if(cnt1==5'd16)
begin
//state_finish = 1'b0;
fsync_reg = 1'b0;
spi_data_reg = 1'b0;
end
else
begin
fsync_reg = 1'b1;
spi_data_reg = 1'b0;
end
end/*
begin
//state_finish = 1'b0;
fsync_reg = 1'b0;
spi_data_reg = 1'b0;
end*/
5'd1:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
end
5'd2:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
end
5'd3:
begin
fsync_reg = 0;
spi_data_reg = 1'b1;
end
5'd4:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
end
5'd5:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
end
5'd6:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
end
5'd7:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
end
5'd8:
begin
fsync_reg = 0;
spi_data_reg = 1'b1;
end
5'd9:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
end
5'd10:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
end
5'd11:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
end
5'd12:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
end
5'd13:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
end
5'd14:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
end
5'd15:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
end
5'd16:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
end
5'd17:
begin
if(cnt1==5'd16)
begin
nstate = WR_F_L;
fsync_reg = 1'b1;
//state_finish = 1'b1;
spi_data_reg = 1'bz;
end
else
begin
nstate = WR_CTR;
fsync_reg = 1'b1;
spi_data_reg = 1'bz;
end
end
default:
begin
spi_data_reg = 1'bz;
nstate = WR_CTR;
end
endcase
end
WR_F_L: ////8state
begin
case(cnt2)
5'd0:
/*begin
if(cnt1==5'd16)
begin
//state_finish = 1'b0;
fsync_reg = 1'b0;
spi_data_reg = 1'b0;
end
else
begin
fsync_reg = 1'b1;
spi_data_reg = 1'b0;
end
end*/
begin
//state_finish = 1'b0;
fsync_reg = 0;
spi_data_reg = 1'b0;
nstate = WR_F_L;
end
5'd1:
begin
fsync_reg = 0;
spi_data_reg = 1'b1;
nstate = WR_F_L;
end
5'd2:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
nstate = WR_F_L;
end
5'd3:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
nstate = WR_F_L;
end
5'd4:
begin
fsync_reg = 0;
spi_data_reg = 1'b1;
nstate = WR_F_L;
end
5'd5:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
nstate = WR_F_L;
end
5'd6:
begin
fsync_reg = 0;
spi_data_reg = 1'b1;
nstate = WR_F_L;
end
5'd7:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
nstate = WR_F_L;
end
5'd8:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
nstate = WR_F_L;
end
5'd9:
begin
fsync_reg = 0;
spi_data_reg = 1'b1;
nstate = WR_F_L;
end
5'd10:
begin
fsync_reg = 0;
spi_data_reg = 1'b1;
nstate = WR_F_L;
end
5'd11:
begin
fsync_reg = 0;
spi_data_reg = 1'b1;
nstate = WR_F_L;
end
5'd12:
begin
fsync_reg = 0;
spi_data_reg = 1'b1;
nstate = WR_F_L;
end
5'd13:
begin
fsync_reg = 0;
spi_data_reg = 1'b1;
nstate = WR_F_L;
end
5'd14:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
nstate = WR_F_L;
end
5'd15:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
nstate = WR_F_L;
end
5'd16:
begin
if(cnt1==5'd16)
begin
nstate = WR_F_M;
fsync_reg = 1'b1;
spi_data_reg = 1'bz;
//state_finish = 1'b1;
end
else
begin//+
nstate = WR_F_L;
fsync_reg = 1'b1;
spi_data_reg = 1'bz;
end
end
default:
begin
spi_data_reg = 1'bz;
nstate = WR_F_L;
fsync_reg = 1'b1;//++
end
endcase
end
WR_F_M:
begin
case(cnt2)
5'd0:
/*begin
if(cnt1==5'd16)
begin
//state_finish = 1'b0;
fsync_reg = 1'b0;
spi_data_reg = 1'b0;
end
else
begin
fsync_reg = 1'b1;
spi_data_reg = 1'b0;
end
end*/
begin
//state_finish = 1'b0;
fsync_reg = 0;
spi_data_reg = 1'b0;
end
5'd1:
begin
fsync_reg = 0;
spi_data_reg = 1'b1;
end
5'd2:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
end
5'd3:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
end
5'd4:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
end
5'd5:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
end
5'd6:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
end
5'd7:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
end
5'd8:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
end
5'd9:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
end
5'd10:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
end
5'd11:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
end
5'd12:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
end
5'd13:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
end
5'd14:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
end
5'd15:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
end
5'd16:
begin
if(cnt1==5'd16)
begin
nstate = WR_PHASE;
fsync_reg = 1'b1;
spi_data_reg = 1'bz;
//state_finish = 1'b1;
end
else
begin
nstate = WR_F_M;
fsync_reg = 1'b1;
spi_data_reg = 1'bz;
end
end
default:
begin
spi_data_reg = 1'bz;
nstate = WR_F_M;
fsync_reg = 1'b1;//++
end
endcase
end
WR_PHASE:
begin
case(cnt2)
5'd0:
/*begin
if(cnt1==5'd16)
begin
//state_finish = 1'b0;
fsync_reg = 1'b0;
spi_data_reg = 1'b1;
end
else
begin
fsync_reg = 1'b1;
spi_data_reg = 1'b1;
end
end*/
begin
//state_finish = 1'b0;
fsync_reg = 0;
spi_data_reg = 1'b1;
end
5'd1:
begin
fsync_reg = 0;
spi_data_reg = 1'b1;
end
5'd2:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
end
5'd3:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
end
5'd4:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
end
5'd5:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
end
5'd6:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
end
5'd7:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
end
5'd8:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
end
5'd9:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
end
5'd10:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
end
5'd11:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
end
5'd12:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
end
5'd13:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
end
5'd14:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
end
5'd15:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
end
5'd16:
begin
if(cnt1==5'd16)
begin
nstate = WR_EN;
fsync_reg = 1'b1;
spi_data_reg = 1'bz;
//state_finish = 1'b1;
end
else
begin
nstate = WR_PHASE;
fsync_reg = 1'b1;
spi_data_reg = 1'bz;
end
end
default:
begin
spi_data_reg = 1'bz;
nstate = WR_PHASE;
fsync_reg = 1'b1;//++
end
endcase
end
WR_EN:
begin
case(cnt2)
5'd0:
/*begin
if(cnt1==5'd16)
begin
//state_finish = 1'b0;
fsync_reg = 1'b0;
spi_data_reg = 1'b0;
end
else
begin
fsync_reg = 1'b1;
spi_data_reg = 1'b0;
end
end*/
begin
//state_finish = 1'b0;
fsync_reg = 0;
spi_data_reg = 1'b0;
end
5'd1:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
end
5'd2:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
end
5'd3:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
end
5'd4:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
end
5'd5:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
end
5'd6:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
end
5'd7:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
end
5'd8:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
end
5'd9:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
end
5'd10:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
end
5'd11:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
end
5'd12:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
end
5'd13:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
end
5'd14:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
end
5'd15:
begin
fsync_reg = 0;
spi_data_reg = 1'b0;
end
5'd16:
begin
if(cnt1==5'd16)
begin
nstate = DELAY;
fsync_reg = 1'b1;
spi_data_reg = 1'bz;
//state_finish = 1'b1;
end
else
begin
nstate = WR_EN;
fsync_reg = 1'b1;
spi_data_reg = 1'bz;
end
end
default:
begin
spi_data_reg = 1'bz;
nstate = WR_EN;
fsync_reg = 1'b1;//++
end
endcase
end
DELAY:
begin
fsync_reg = 1'b1;
spi_data_reg = 1'bz;
if(cnt2==5'd16)
nstate = OVER;
else
nstate = DELAY;
end
OVER:
begin
spi_data_reg = 1'bz;
fsync_reg = 1'b1;
nstate = OVER;
end
default: nstate = IDLE;//
endcase
end
assign spi_data = spi_data_reg;
assign fsync = fsync_reg;
endmodule
注意的几个问题:
1、状态的划分要清晰
2、控制标志何时清零、清零信号的选择要注意
3、CASE语句中,每个case中对变量赋的值不会保持,综合出来是一个触发器,下一个case就会丢失,如果想让改变量保持住,在 每个case中都需要赋值。
4、时序仿真时,不知道为什么WR_F_L状态不稳定,故在每个case中加上了赋为本身状态的语句,再次仿真则稳定了。
5、控制信号都是相互关联的,牵一发而动全身,修改的时候要注意。往往改着改着自己都忘记这个是什么功能了。
6、检测信号上升沿可以用该信号下一个状态值与上当前状态值的非,检测信号下降沿,可以用该信号下一个状态值的非与上当前值。检测出来的信号可作为触发信号控制其他变量。
7、组合逻辑,只有触发变量发生变化时,下面的程序才会执行,时序逻辑在每个时钟内都执行一次,在编写控制电路的时候要注意 服了,这么简单一个芯片,写这么长的代码 干吗不用个D/A直接出,还用9833 贴出来的程序太长了要是打包一份就好了 是cpld控制dds?
我今天用dspbuilder弄了个类似dds的东西 回复【1楼】p.nicholas
-----------------------------------------------------------------------
头一次用这个芯片啊,请指正,能不能说下你的建议啊? 回复【2楼】ibmx311
-----------------------------------------------------------------------
D/A输出??能具体说下吗? 回复【6楼】mcsky 豆子
回复【2楼】ibmx311
-----------------------------------------------------------------------
d/a输出??能具体说下吗?
-----------------------------------------------------------------------
您找一个速度高点的d/a,然后把sin或其他的什么三角的,方的等波形存在另一个并口rom里,然后不就是dds了吗 回复【7楼】ibmx311
-----------------------------------------------------------------------
恩,这个很好啊,呵呵。回去试一试,谢谢了 回复【6楼】mcsky豆子
-----------------------------------------------------------------------
D/A都用不上,直接并行输出外接电阻接个加法器,注意运放用带宽较宽的,就是DA了 楼上些个,果真都是牛人啊,把做硬件电路都说的跟做软件似的。。。有集成芯片不用,居然要自己搭电路。
自己用DA做DDS,各种软件,硬件带宽、速率、稳定性等问题等意想不到问题会一个个的把你难道。。。如果你真的很牛逼,做出来了,好我服,但是试问成本几何?? 回复【10楼】RedYang211
-----------------------------------------------------------------------
嘿嘿,做大系统的,当然不能像楼上几位说的,不过自己玩玩的话还是可以 ll mark 楼主的程序用来学习状态机挺好的。
页:
[1]