2014年4月1日火曜日

CPLDで光デジタル出力してみる

最後の投稿が半年前とは時が経つのは早いもので、(ry
とりあえず、作業ログとしていろいろ書いてきたい。ということで、こんなの作った!

これを

こうして

こうじゃ!


単純に興味本位でCPLD(Altera MAX II)で光デジタル出力をしてみました。
一応出力出来たけど、なぜか波形が汚め。たぶん光デジタルのDACが500円くらいの安物だからかな?
VHDL初心者が勢いで作って3日くらいで出来たから、そんなに難しい事でもないんだろうな。

とりあえず完成したときは131ロジックエレメント(LE)で、その後ガリガリ削ったら88LEまで減らせた。ここらへんで満足。

さて、次はなに作ろうか

ソースコード

(あとから見たら恥ずかしくなるんだろうなぁ…)

spdif_top.vhd

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;

entity SPDIF_TOP is
 port (
  CLK : in std_logic;
  SPDIF : out std_logic);
end entity;

architecture RTL of SPDIF_TOP is
 component SPDIF_ENC is
  port (
   CLK : in std_logic;
   SPDIF : out std_logic;
   DATA : in std_logic_vector(15 downto 0));
 end component;

 subtype DELAY is std_logic_vector(4 downto 0);
 type DELAY_TABLE is array (0 to 191) of DELAY;
 constant delay_tbl : DELAY_TABLE := (
  "01111","10000","01111","01111","10000","01111","01111","01111","10000","01111",
  "01111","10000","01111","01111","01111","10000","01111","01111","01111","10000",
  "01111","01111","10000","01111","01111","01111","10000","01111","01111","10000",
  "01111","01111","01111","10000","01111","01111","01111","10000","01111","01111",
  "10000","01111","01111","01111","10000","01111","01111","01111","10000","01111",
  "01111","10000","01111","01111","01111","10000","01111","01111","10000","01111",
  "01111","01111","10000","01111","01111","01111","10000","01111","01111","10000",
  "01111","01111","01111","10000","01111","01111","01111","10000","01111","01111",
  "10000","01111","01111","01111","10000","01111","01111","10000","01111","01111",
  "01111","10000","01111","01111","01111","10000","01111","01111","10000","01111",
  "01111","01111","10000","01111","01111","01111","10000","01111","01111","10000",
  "01111","01111","01111","10000","01111","01111","10000","01111","01111","01111",
  "10000","01111","01111","01111","10000","01111","01111","10000","01111","01111",
  "01111","10000","01111","01111","01111","10000","01111","01111","10000","01111",
  "01111","01111","10000","01111","01111","10000","01111","01111","01111","10000",
  "01111","01111","01111","10000","01111","01111","10000","01111","01111","01111",
  "10000","01111","01111","01111","10000","01111","01111","10000","01111","01111",
  "01111","10000","01111","01111","10000","01111","01111","01111","10000","01111",
  "01111","01111","10000","01111","01111","10000","01111","01111","01111","10000",
  "01111","01111");

 signal delay_phase : std_logic_vector(7 downto 0);
 signal delay_cnt : std_logic_vector(4 downto 0);

 signal spdif_clk : std_logic;
 signal spdif_data : std_logic_vector(15 downto 0);

 signal cnt : std_logic_vector(12 downto 0);
begin
 encoder : SPDIF_ENC port map (spdif_clk, SPDIF, spdif_data);

 process (CLK)
 begin
  if (CLK'event and CLK = '1') then
   if (delay_cnt < delay_tbl(conv_integer(delay_phase))) then
    delay_cnt <= delay_cnt + 1;
    spdif_clk <= '0';
   else
    delay_cnt <= (others => '0');
    if (delay_phase < 192 - 1) then
     delay_phase <= delay_phase + 1;
    else
     delay_phase <= (others => '0');
    end if;
    spdif_clk <= '1';

    cnt <= cnt + 1;
    spdif_data <= (15 downto 13 => (cnt(11) xor cnt(6)), 12 => '1' , others => '0');
   end if;
  end if;
 end process;
end architecture;

spdif_enc.vhd

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;

entity SPDIF_ENC is
 port (
  CLK : in std_logic;
  SPDIF : out std_logic;
  DATA : in std_logic_vector(15 downto 0));
end entity;

architecture RTL of SPDIF_ENC is
 signal reset : std_logic := '0';

 signal frame : std_logic_vector(7 downto 0) := (others => '0');
 signal channel : std_logic := '0';
 signal cnt : std_logic_vector(5 downto 0) := (others => '0');

 signal preamble : std_logic_vector(7 downto 0);
 signal parity : std_logic := '0';

 signal cell : std_logic := '0';

 constant preamble_b : std_logic_vector(7 downto 0) := "11101000";
 constant preamble_m : std_logic_vector(7 downto 0) := "11100010";
 constant preamble_w : std_logic_vector(7 downto 0) := "11100100";
begin
 process (CLK)
  variable v_logic : std_logic;
  variable v_cell : std_logic;
 begin
  if (CLK'event and CLK = '1') then
   if (reset = '0') then
    preamble <= preamble_b;
    reset <= '1';
   else
    cnt <= cnt + 1;

    if (cnt(5 downto 3) = 0) then -- Preamble
     parity <= '0';
     SPDIF <= preamble(7 - conv_integer(cnt(2 downto 0))) xor cell;
    else
     if (cnt(0) = '1') then
      if (cnt(5 downto 1) >= 12 and cnt(5 downto 1) <= 27) then -- Sample
       v_logic := DATA(conv_integer(cnt(5 downto 1)) - 12);
      elsif (cnt(5 downto 1) = 31) then -- Parity
       v_logic := parity;
      else -- AUX,Validity,Subcode,Channel info
       v_logic := '0';
      end if;
      parity <= parity xor v_logic;

      v_cell := cell xor v_logic;

      if (cnt(5 downto 1) = 31) then
       if (frame < 191) then
        frame <= frame + 1;
       else
        frame <= (others => '0');
       end if;

       channel <= not channel;

       if (channel = '0') then
        preamble <= preamble_w;
       else
        if (frame /= 191) then
         preamble <= preamble_m;
        else
         preamble <= preamble_b;
        end if;
       end if;
      end if;
     else
      v_cell := not cell;
     end if;

     cell <= v_cell;
     SPDIF <= v_cell;
    end if;
   end if;
  end if;
 end process;
end architecture;

参考サイト
ePanorama.net (http://www.epanorama.net/documents/audio/spdif.html)
minidisc.org (http://www.minidisc.org/spdif_c_channel.html)
ボクにもわかる地上デジタル (http://www.geocities.jp/bokunimowakaru/std-spdif.html)

0 件のコメント:

コメントを投稿