Spartan-3AN Starter
Kitを知る その1 SPI通信 1. Spartan-3AN Starter
KitのDACを作動させるには countは、counterでして、これが、各ステージの指標になります。 myDCM instance_name ( myDDS YourInstanceName
(
SerialのSPI通信を行う、LTC2624 DACが付いています。
このDACを動かしてみたくなりました。
ここには、LTC2624は、
「12ビットの符号なしレゾリューソン付きのクワッドDACです。」と、書いてあります。
しかし、実際に作動させてみました所、
符号付のsin波形でないと、うまく表示されませんでしたわ.....
DDS Compilerの出力は、符号付sin波で、DACは、やはり、符号無しだったようです、
(-_-;;
出力は 12bits。
符号付 10KHz sine波形データを使って、LTC2624にて出力した。(無負荷)
2.SPI通信、どうする?
そんなんで、先ず
1. DAC_CSをLOWにする
2. LTC2624は、DAC_CSがLOWになってから、SPI_SCKのposedgeで、データを捕らえる
これを24回繰り返すのですが、問題は
SPI_SCKのクロックのposedgeで、FPGA側が、データをセットして、
同時に、LTC2624が、データを読み出すというのは、苦しい。
で、結論として
FPGAで、データをセットするのは、SPI_SCKのnegedgeで、行う事にしました。
DAC(LTC2624)は、SPI_SCKのposedgeで、SPI_MOSIを、勝手に読んでくれますから。
3. DAC_CSをHIGHにする
DAC_SCをHIGHにするのも、FPGA側では、SPI_CLKのnegedgeで行いました。
こんなHLD記述になります。
assign DAC_CS=DAC_enable;
assign SPI_SCK=CLK0_OUT;
assign SPI_MOSI=serial_data;
assign DAC_CLR=dac_clr; //don't
forget DAC_CLR :non active=high
assign
sin_signed=sin_unsigned-12'h7ff; //sin_signedのデータをDACに送る
always
@(negedge CLK0_OUT ) begin
//for
SPI
count=count-1;
case(count)
23: begin
DAC_enable=0;
serial_data=SPI_data[count];
end
31: begin
count=24;
DAC_enable=1'b1;
SPI_data=
{4'b0011,4'b0000,sin_signed,4'b1111};//last 4bits : don't care
bits
end
default: serial_data=SPI_data[count];
endcase
end
で、タイミング関係を調べたのが、最初の図です。
FPGA側(送り手)は、全て、SPI_CLKのnegaedgeで設定して、
直後のposedgeで、DAC(受け手)が、データを受け取ると言う訳です。
再掲
3.SPI通信で、困った事
DAC_CLRは、HIGHでないと、いけません。
これを忘れて、DAC_CLRを省略してしまいましたら、
DAC出力が、全くありませんでした....当然ですね。
信号のやり取りをするには、DAC_CLRがHIGHでないと、いけませんから
忘れず、DAC_CLRを設定しましょう。
3日も、悩んでしまいますた
(^_^;;
それから、もう一点
Serial通信ですから、
SPI_SCKが、50MHzのクロックだとすると
25回、DACがデータを受け取る間に(SPI_MOSIと、DAC_CSも含める)
データは、その間、動かせません。
つまり
データは、SPI_CLK 50MHzの1/25のクロックで、samplingしたものである必要があります。
例
50MHz SPI_SCK
10KHzのsin波形を、NCOで作成し、DACに10KHzのsin波形を得る場合
----------------------------------------------------------------------
NCOのsampling周波数は
50MHz / 25 = 2MHz
2MHzを得る為に
DCMにて 50MHzの4/25分周を行う。
次に、HDL記述にて、更に 1/4に分周する。
50MHz x 4/25 x 1/4 =2MHz
1/4分周するHDL記述は
always
@(posedge CLKFX_OUT) begin //D-FlipFlop
//for
devide_count
devide_count=devide_count+1;
if(devide_count==0)begin
devide_clk=~devide_clk;
end
end
1/2、1/4、1/8,、1/16、1/32分周もできるように、devide_countと言う、counterを用いた。
CLKFX_OUTは、DCMにて、50MHzを 4/25 分周したものです。
注意点は、devide_clkは、2回の反転で、1周期になりますから。(私なんか、よく間違えます)
1/4分周するには、devide_countは 1bitでよいと言うことに、なります
いや、違った。
devide_countが 1bitならば、やっぱり、2分割ですよね。
でも、こうしないと、
DACの出力周波数が、半分の5KHzになってしまうんです、不思議。
Serial通信って、便利やけど、面倒ですね (^_^;;
今回の HDL記述です。
`timescale 1ns /
1ps
//////////////////////////////////////////////////////////////////////////////////
module
myADC (clk,SPI_SCK,SPI_MOSI,DAC_CS,DAC_CLR);
input
clk;
output DAC_CLR;
output SPI_SCK;
output SPI_MOSI;
output DAC_CS;
/// DCM //////////////////////////////////
wire
RST_IN;
wire CLKFX_OUT;
wire
CLKIN_IBUFG_OUT;
wire CLK0_OUT;
wire
LOCKED_OUT;
//////////////////////////////////////////
wire [11:0]sin_unsigned;
wire signed[11:0]sin_signed;
//////////////////////////////////////////
reg [23:0]SPI_data=0;
reg DAC_enable=0;
reg serial_data=0;
reg [4:0]count=5'h18;//=24
reg devide_count=0;
reg devide_clk=0;
reg dac_clr=0;
//////////////////////////////////////////
assign DAC_CS=DAC_enable;
assign SPI_SCK=CLK0_OUT;
assign SPI_MOSI=serial_data;
assign DAC_CLR=dac_clr; //don't
forget DAC_CLR :non active=high
assign
sin_signed=sin_unsigned-12'h7ff;
always
@(LOCKED_OUT)begin
dac_clr=1;
end
always
@(negedge CLK0_OUT ) begin
//for
SPI
count=count-1;
case(count)
23: begin
DAC_enable=0;
serial_data=SPI_data[count];
end
31: begin
count=24;
DAC_enable=1'b1;
SPI_data=
{4'b0011,4'b0000,sin_signed,4'b1111};//last 4bits : don't care
bits
end
default: serial_data=SPI_data[count];
endcase
end
always
@(posedge CLKFX_OUT) begin //D-FlipFlop
//for
devide_count
devide_count=devide_count+1;
if(devide_count==0)begin
devide_clk=~devide_clk;
end
end
.CLKIN_IN(clk),
.RST_IN(RST_IN),
.CLKFX_OUT(CLKFX_OUT),
.CLKIN_IBUFG_OUT(CLKIN_IBUFG_OUT),
.CLK0_OUT(CLK0_OUT),
.LOCKED_OUT(LOCKED_OUT)
);
.clk(devide_clk),
.sine(sin_unsigned)); //
Bus [11 : 0]
H.22.12.8