Spartan-3AN Starter Kitを知る その1 SPI通信



1. Spartan-3AN Starter KitのDACを作動させるには

     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

    countは、counterでして、これが、各ステージの指標になります。

    で、タイミング関係を調べたのが、最初の図です。

    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
 

 myDCM instance_name (
  .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)
    );

 myDDS YourInstanceName (
  .clk(devide_clk),
  .sine(sin_unsigned)); // Bus [11 : 0]  


H.22.12.8