R = 1.000Y + 1.402(V-128)
G = 1.000Y - 0.344(U-128) -0.714(V-128)
B = 1.000Y + 1.772(U-128)
R = (Y<<8 + 359*V)>>8
G = (Y<<8 - 183*V - 88*U)>>8
B = (Y<<8 + 454*U)>>8
R = (Y<<8 + 359*(V-128))>>8
G = (Y<<8 - 183*(V-128) - 88*(U-128))>>8
B = (Y<<8 + 454*(U-128))>>8
0.402 X 2 = 0.804 なので2進数の小数の最初の桁は0
0.804 X 2 = 1.608 なので2進数の小数のこの桁は 1、次は桁上がりの1は除く。
0.608 X 2 = 1.216 なので2進数の小数のこの桁は 1、次は桁上がりの1は除く。
0.216 X 2 = 0.432 なので2進数の小数のこの桁は 0
0.432 X 2 = 0.864 なので2進数の小数のこの桁は 0
0.864 X 2 = 1.728 なので2進数の小数のこの桁は 1、次は桁上がりの1は除く。
0.728 X 2 = 1.456 なので2進数の小数のこの桁は 1、次は桁上がりの1は除く。
0.456 X 2 = 0.912 なので2進数の小数のこの桁は 0
R = (Y<<8 + 359*V - 45,952)>>8
G = (Y<<8 - 183*V - 88*U + 34,688)>>8
B = (Y<<8 + 454*V - 58,112)>>8
R = (Y<<8 + X"167"*V - X"B380")>>8
G = (Y<<8 - X"58"*U - X"B7"*V + X"8780")>>8
B = (Y<<8 + X"1C6"*U - X"E300")>>8
R = (Y<<8 + X"167"*(V-128))>>8
G = (Y<<8 - X"B7"*(V-128) - X"58"*(U-128))>>8
B = (Y<<8 + X"1C6"*(U-128))>>8
R = (Y<<8 + "1_0110_0111"*(V-128))>>8
G = (Y<<8 - "1011_0111"*(V-128) - "0101_1000"*(U-128))>>8
B = (Y<<8 + "1_1100_0110"*(U-128))>>8
R = (Y<<8 + "1_0110_0111"*V - X"B380")>>8
G = (Y<<8 - "1011_0111"*V - "0101_1000"*U + X"8780")>>8
B = (Y<<8 + "1_1100_0110"*U - X"E300")>>8
n_mem_data_oe <= not mem_data_oe;
MEM_DATA_GEN : for i in 15 downto 0 generate
IOBUF_inst : IOBUF port map(
O => input_mem_data(i),
IO => mem_data(i),
I => mem_data_out(i),
T => n_mem_data_oe
);
end generate MEM_DATA_GEN;
-- n_mem_we, mem_data_oe を生成する。48MHzのステートマシンで出力
process(clk48) begin
if clk48'event and clk48='1' then
if reset='1' then
cs_we <= idle_we;
else
cs_we <= ns_we;
end if;
end if;
end process;
process(cs_we, r_w, cam_href_3d) begin
case cs_we is
when idle_we =>
n_mem_we_node <= '1';
mem_data_oe <= '0';
if r_w='0' and cam_href_3d='1' then -- hrefの間だけSRAMにWriteする
ns_we <= we_active;
else
ns_we <= idle_we;
end if;
when we_active => -- r_w が1時48MHzクロック1クロック間だけ n_mem_we を0にする
n_mem_we_node <= '0';
mem_data_oe <= '1';
ns_we <= we_holdoff;
when we_holdoff => -- この時はまだr_wが0
n_mem_we_node <= '1';
mem_data_oe <= '0';
ns_we <= idle_we;
end case;
end process;
n_mem_we <= n_mem_we_node;
signal mem_data_node : std_logic_vector(15 downto 0);
signal next_mem_data_oe : std_logic;
attribute iob : string;
attribute iob of n_mem_data_oe : signal is "TRUE";
attribute keep : string;
attribute keep of n_mem_data_oe : signal is "TRUE";
attribute keep of next_mem_data_oe : signal is "TRUE";
begin
.....
-- n_mem_we, mem_data_oe を生成する。48MHzのステートマシンで出力
process(clk48) begin
if clk48'event and clk48='1' then
if reset='1' then
cs_we <= idle_we;
else
cs_we <= ns_we;
end if;
end if;
end process;
process(cs_we, r_w, cam_href_3d) begin
case cs_we is
when idle_we =>
n_mem_we_node <= '1';
if r_w='0' and cam_href_3d='1' then -- hrefの間だけSRAMにWriteする
ns_we <= we_active;
next_mem_data_oe <= '1';
else
ns_we <= idle_we;
next_mem_data_oe <= '0';
end if;
when we_active => -- r_w が1時48MHzクロック1クロック間だけ n_mem_we を0にする
n_mem_we_node <= '0';
ns_we <= we_holdoff;
next_mem_data_oe <= '0';
when we_holdoff => -- この時はまだr_wが0
n_mem_we_node <= '1';
ns_we <= idle_we;
next_mem_data_oe <= '0';
when others =>
n_mem_we_node <= '1';
ns_we <= idle_we;
next_mem_data_oe <= '0';
end case;
end process;
n_mem_we <= n_mem_we_node;
-- mem_data_oeの出力
process(clk48) begin
if clk48'event and clk48='1' then
if reset='1' then
n_mem_data_oe <= (others => '1');
else
for i in 15 downto 0 loop
n_mem_data_oe(i) <= not next_mem_data_oe;
end loop;
end if;
end if;
end process;
MEM_DATA_GEN : for i in 15 downto 0 generate
IOBUF_inst : IOBUF port map(
O => input_mem_data(i),
IO => mem_data(i),
I => mem_data_out(i),
T => n_mem_data_oe(i)
);
end generate MEM_DATA_GEN;
-- 設定できる係数は-16 to 15
-- ラプラシアン・フィルタ
constant Xnm1Ynm1VaL1 : integer := -1;
constant XnYnm1VaL1 : integer := -1;
constant Xnp1Ynm1VaL1 : integer := -1;
constant Xnm1YnVaL1 : integer := -1;
constant XnYnVaL1 : integer := 8;
constant Xnp1YnVaL1 : integer := -1;
constant Xnm1Ynp1VaL1 : integer := -1;
constant XnYnp1VaL1 : integer := -1;
constant Xnp1Ynp1VaL1 : integer := -1;
constant Xnm1Ynm1VaL2 : integer := 0;
constant XnYnm1VaL2 : integer := 0;
constant Xnp1Ynm1VaL2 : integer := 0;
constant Xnm1YnVaL2 : integer := 0;
constant XnYnVaL2 : integer := 0;
constant Xnp1YnVaL2 : integer := 0;
constant Xnm1Ynp1VaL2 : integer := 0;
constant XnYnp1VaL2 : integer := 0;
constant Xnp1Ynp1VaL2 : integer := 0;
-- Sobelフィルタ,X方向, Y方向
-- constant Xnm1Ynm1VaL1 : integer := -1;
-- constant XnYnm1VaL1 : integer := 0;
-- constant Xnp1Ynm1VaL1 : integer := 1;
-- constant Xnm1YnVaL1 : integer := -2;
-- constant XnYnVaL1 : integer := 0;
-- constant Xnp1YnVaL1 : integer := 2;
-- constant Xnm1Ynp1VaL1 : integer := -1;
-- constant XnYnp1VaL1 : integer := 0;
-- constant Xnp1Ynp1VaL1 : integer := 1;
-- constant Xnm1Ynm1VaL2 : integer := -1;
-- constant XnYnm1VaL2 : integer := -2;
-- constant Xnp1Ynm1VaL2 : integer := -1;
-- constant Xnm1YnVaL2 : integer := 0;
-- constant XnYnVaL2 : integer := 0;
-- constant Xnp1YnVaL2 : integer := 0;
-- constant Xnm1Ynp1VaL2 : integer := 1;
-- constant XnYnp1VaL2 : integer := 2;
-- constant Xnp1Ynp1VaL2 : integer := 1;
-- Prewittフィルタ, X方向, Y方向
-- constant Xnm1Ynm1VaL1 : integer := -1;
-- constant XnYnm1VaL1 : integer := 0;
-- constant Xnp1Ynm1VaL1 : integer := 1;
-- constant Xnm1YnVaL1 : integer := -1;
-- constant XnYnVaL1 : integer := 0;
-- constant Xnp1YnVaL1 : integer := 1;
-- constant Xnm1Ynp1VaL1 : integer := -1;
-- constant XnYnp1VaL1 : integer := 0;
-- constant Xnp1Ynp1VaL1 : integer := 1;
-- constant Xnm1Ynm1VaL2 : integer := -1;
-- constant XnYnm1VaL2 : integer := -1;
-- constant Xnp1Ynm1VaL2 : integer := -1;
-- constant Xnm1YnVaL2 : integer := 0;
-- constant XnYnVaL2 : integer := 0;
-- constant Xnp1YnVaL2 : integer := 0;
-- constant Xnm1Ynp1VaL2 : integer := 1;
-- constant XnYnp1VaL2 : integer := 1;
-- constant Xnp1Ynp1VaL2 : integer := 1;
op_int_vaL1 <= Xnm1Ynm1VaL1*CONV_INTEGER(Xnm1Ynm1) + XnYnm1VaL1*CONV_INTEGER(XnYnm1) + Xnp1Ynm1VaL1*CONV_INTEGER(Xnp1Ynm1)
+ Xnm1YnVaL1*CONV_INTEGER(Xnm1Yn) + XnYnVaL1*CONV_INTEGER(XnYn) + Xnp1YnVaL1*CONV_INTEGER(Xnp1Yn)
+ Xnm1Ynp1VaL1*CONV_INTEGER(Xnm1Ynp1) + XnYnp1VaL1*CONV_INTEGER(XnYnp1) + Xnp1Ynp1VaL1*CONV_INTEGER(Xnp1Ynp1);
op_int_vaL2 <= Xnm1Ynm1VaL2*CONV_INTEGER(Xnm1Ynm1) + XnYnm1VaL2*CONV_INTEGER(XnYnm1) + Xnp1Ynm1VaL2*CONV_INTEGER(Xnp1Ynm1)
+ Xnm1YnVaL2*CONV_INTEGER(Xnm1Yn) + XnYnVaL2*CONV_INTEGER(XnYn) + Xnp1YnVaL2*CONV_INTEGER(Xnp1Yn)
+ Xnm1Ynp1VaL2*CONV_INTEGER(Xnm1Ynp1) + XnYnp1VaL2*CONV_INTEGER(XnYnp1) + Xnp1Ynp1VaL2*CONV_INTEGER(Xnp1Ynp1);
op_vaL1 <= CONV_STD_LOGIC_VECTOR(op_int_vaL1, op_vaL1'length);
op_vaL2 <= CONV_STD_LOGIC_VECTOR(op_int_vaL2, op_vaL2'length);
process(op_vaL1) begin
if op_vaL1(op_vaL1'left)='1' then -- 負の値
abs_op_cal_vaL1 <= not(op_vaL1 -1);
else -- 正の数
abs_op_cal_vaL1 <= op_vaL1;
end if;
end process;
process(op_vaL2) begin
if op_vaL2(op_vaL2'left)='1' then -- 負の値
abs_op_cal_vaL2 <= not(op_vaL2 -1);
else -- 正の数
abs_op_cal_vaL2 <= op_vaL2;
end if;
end process;
abs_op_cal_val <= abs_op_cal_vaL1 + abs_op_cal_vaL2;
ydata_out <= x"00" when h_valid_flag='0' or v_valid_flag='0' else
x"FF" when (abs_op_cal_val(12) or abs_op_cal_val(11) or abs_op_cal_val(10) or abs_op_cal_val(9) or abs_op_cal_val(8))='1'
else abs_op_cal_val(7 downto 0); -- 飽和演算
diff_cal_val <= "011"*(cam_ydata_2d) - ("000"&bram_data_1d) - ("000"&bram_data) - ("000"&y_data_1d);
Laplacian_cal_val <= "01000"*(XnYn) - ("00000"&Xnm1Ynm1) - ("00000"&XnYnm1) - ("00000"&Xnp1Ynm1) - ("00000"&Xnm1Yn) - ("00000"&Xnp1Yn) - ("00000"&Xnm1Ynp1) - ("00000"&XnYnp1) - ("00000"&Xnp1Ynp1) ;
-- マトリクスの絶対値
Xnp1Ynm1 <= bram_data2;
Xnp1Yn <= bram_data;
Xnp1Ynp1 <= cam_ydata_2d;
-- 1クロック前のBRAMの出力と現在の値の1クロック前の値を保持
process(clk) begin
if clk'event and clk='1' then
if reset='1' then
Xnm1Ynm1 <= (others => '0');
XnYnm1 <= (others => '0');
Xnm1Yn <= (others => '0');
XnYn <= (others => '0');
Xnm1Ynp1 <= (others => '0');
XnYnp1 <= (others => '0');
else
if r_w='1' then
Xnm1Ynm1 <= XnYnm1;
XnYnm1 <= Xnp1Ynm1;
Xnm1Yn <= XnYn;
XnYn <= Xnp1Yn;
Xnm1Ynp1 <= XnYnp1;
XnYnp1 <= Xnp1Ynp1;
end if;
end if;
end if;
end process;
Laplacian_cal_val <= "01000"*(XnYn) - ("00000"&Xnm1Ynm1) - ("00000"&XnYnm1) - ("00000"&Xnp1Ynm1) - ("00000"&Xnm1Yn) - ("00000"&Xnp1Yn) - ("00000"&Xnm1Ynp1) - ("00000"&XnYnp1) - ("00000"&Xnp1Ynp1) ;
-- マトリクスの絶対値
process(Laplacian_cal_val) begin
if Laplacian_cal_val(12)='1' then -- 負の値
abs_Laplacian_cal_val <= not(Laplacian_cal_val-1);
else -- 正の数
abs_Laplacian_cal_val <= Laplacian_cal_val;
end if;
end process;
ydata_out <= x"00" when h_valid_flag='0' or v_valid_flag='0' else
x"FF" when (abs_Laplacian_cal_val(12) or abs_Laplacian_cal_val(11) or abs_Laplacian_cal_val(10) or abs_Laplacian_cal_val(9) or abs_Laplacian_cal_val(8))='1'
else abs_Laplacian_cal_val(7 downto 0); -- 飽和演算
Xn-1Yn-1 = 01
XnYn-1 = 02
Xn+1Y-1 = 04
Xn-1Yn = 02
XnYn = 03
Xn+1Yn = 04
Xn-1Yn+1 = 82
XnYn+1 = 04
Xn+1Yn+1 = 08
-------------
| -1| -1| -1|
-------------
| -1| 8| -1|
-------------
| -1| -1| -1|
-------------
-------------
| -1| -1| -1|
-------------
| -1| 8| -1|
-------------
| -1| -1| -1|
-------------
------------ -------------
| -1| 0| 1| | -1| -2| -1|
------------ -------------
| -2| 0| 2| | 0| 0| 0|
------------ -------------
| -1| 0| 1| | 1| 2| 1|
------------ -------------
-- 1クロック前のBRAMの出力と現在の値の1クロック前の値を保持
process(clk) begin
if clk'event and clk='1' then
if reset='1' then
bram_data_1d <= (others => '0');
y_data_1d <= (others => '0');
else
if r_w='1' then
y_data_1d <= cam_ydata_2d;
bram_data_1d <= bram_data;
end if;
end if;
end if;
end process;
diff_cal_val <= "011"*(cam_ydata_2d) - ("000"&bram_data_1d) - ("000"&bram_data) - ("000"&y_data_1d);
-- マトリクスの絶対値
process(diff_cal_val) begin
if diff_cal_val(10)='1' then -- 負の値
abs_diff_cal_val <= not(diff_cal_val-1);
else -- 正の数
abs_diff_cal_val <= diff_cal_val;
end if;
end process;
ydata_out <= x"FF" when (abs_diff_cal_val(10) or abs_diff_cal_val(9) or abs_diff_cal_val(8))='1' else abs_diff_cal_val(7 downto 0);
最初に注意。この記事では水平ラインの最初を0ラインと記述しています。その他の記事では最初の水平ラインを1ラインと記述しているものがあるのでご注意ください。
-- 1クロック前のBRAMの出力と現在の値の1クロック前の値を保持
process(clk) begin
if clk'event and clk='1' then
if reset='1' then
bram_data_1d <= (others => '0');
y_data_1d <= (others => '0');
else
if r_w='1' then
y_data_1d <= cam_ydata_2d;
bram_data_1d <= bram_data;
end if;
end if;
end if;
end process;
-- 縦横斜めピクセルの引き算の絶対値
process(cam_ydata_2d, bram_data) begin -- 縦
if unsigned(cam_ydata_2d) >= unsigned(bram_data) then
vertical_comp_val <= unsigned(cam_ydata_2d) - unsigned(bram_data);
else
vertical_comp_val <= unsigned(bram_data) - unsigned(cam_ydata_2d);
end if;
end process;
process(cam_ydata_2d, y_data_1d) begin -- 横
if unsigned(cam_ydata_2d) >= unsigned(y_data_1d) then
horizontal_comp_val <= unsigned(cam_ydata_2d) - unsigned(y_data_1d);
else
horizontal_comp_val <= unsigned(y_data_1d) - unsigned(cam_ydata_2d);
end if;
end process;
process(cam_ydata_2d, bram_data_1d) begin
if unsigned(cam_ydata_2d) >= unsigned(bram_data_1d) then
skew_comp_val <= unsigned(cam_ydata_2d) - unsigned(bram_data_1d);
else
skew_comp_val <= unsigned(bram_data_1d) - unsigned(cam_ydata_2d);
end if;
end process;
-- 比較器 (縦横斜めのYデータを比較してエッジを検出する)
process(h_valid_flag, v_valid_flag, vertical_comp_val, horizontal_comp_val, skew_comp_val) begin
if h_valid_flag='0' and v_valid_flag='0' then -- hとvのvalid_flag が0の時は比較しない
ydata_out <= '0' & cam_ydata_2d(7 downto 1);
elsif h_valid_flag='1' and v_valid_flag='0' then -- 最初の水平ラインの時は水平方向だけ比較する
if horizontal_comp_val>=Edge_Threshold_Def then
ydata_out <= CONV_STD_LOGIC_VECTOR(Edge_Value_Def, 8) or ('0' & cam_ydata_2d(7 downto 1));
else
ydata_out <= '0' & cam_ydata_2d(7 downto 1);
end if;
elsif h_valid_flag='1' and v_valid_flag='1' then -- 比較
if vertical_comp_val>=Edge_Threshold_Def or horizontal_comp_val>=Edge_Threshold_Def or skew_comp_val>=Edge_Threshold_Def then -- 縦横斜めどれかがスレッショルドを超えていたらEdge_Value_Defをセット
ydata_out <= CONV_STD_LOGIC_VECTOR(Edge_Value_Def, 8) or ('0' & cam_ydata_2d(7 downto 1));
else
ydata_out <= '0' & cam_ydata_2d(7 downto 1);
end if;
else
ydata_out <= '0' & cam_ydata_2d(7 downto 1);
end if;
end process;
ウッドデッキパーツ表
防腐処理 2X4X8F 55本 床板用 計 (4,850(970*5)mm / 93mm = 52.15本)55(52.15)本*520円 = 27,560円
防腐処理 2X4X8F 10本 床桟用 5,200円
計 防腐処理 2X4X8F 65本 32,760円
斜めの分
防腐処理 2X4X8F 5本 床板用 (970mm / 93mm = 10.43本)半分なので5本でOK
総計 防腐処理 2X4X8F 70本 36,400円
-- 1つ前のYデータと現在のYデータを比較してエッジを検出する
process(h_valid_flag, alu_out, cam_ydata_2d) begin
if h_valid_flag='0' then -- 1つ前のYデータがない
ydata_out <= '0' & cam_ydata_2d(7 downto 1);
elsif h_valid_flag='1' then
if alu_out >= Edge_Threshold_Def then
ydata_out <= CONV_STD_LOGIC_VECTOR(Edge_Value_Def, 8) or ('0' & cam_ydata_2d(7 downto 1));
else
ydata_out <= '0' & cam_ydata_2d(7 downto 1);
end if;
else
ydata_out <= '0' & cam_ydata_2d(7 downto 1);
end if;
end process;
-- CAMERA_CONTROLLER
-- カメラデータを書き込むためのSRAMのアドレスを出力
-- 将来的にはI2Cコントローラを付けて、CMOSカメラの設定を変更することも考えている
library IEEE;
use IEEE.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
entity Camera_Controller is
port(
clk : in std_logic;
reset : in std_logic;
cam_href_2d : in std_logic; -- CMOSカメラからのHREFのラッチ出力
cam_href_3d : in std_logic; -- CMOSカメラからのHREFのラッチ出力(3クロック遅延)
r_w : in std_logic; -- Read / Write
master_sync : in std_logic; -- 同期信号
cam_ydata_2d : in std_logic_vector(7 downto 0); -- CMOSカメラからの輝度データ
ydata_out : out std_logic_vector(7 downto 0); -- 比較した値
mem_addr : out std_logic_vector(17 downto 0) -- CMOSカメラのデータを書き込むSRAMのアドレス
);
end Camera_Controller;
architecture RTL of Camera_Controller is
constant Edge_Threshold_Def : integer := 64;
constant Edge_Value_Def : integer := 128;
signal mem_a : unsigned(17 downto 0);
signal sub_count : std_logic_vector(1 downto 0);
type COMPARE_H_STATE is (no_data_h, comparing_h);
signal cs_chs : COMPARE_H_STATE;
signal h_valid_flag : std_logic;
signal alu_out : unsigned(7 downto 0);
signal ydata_1d : std_logic_vector(7 downto 0);
begin
-- 4クロックにアドレスが1つ進むので、4つ数えるカウンタを用意する。
process(clk) begin
if clk'event and clk='1' then
if reset='1' or master_sync='1' then
sub_count <= (others => '0');
else
if cam_href_2d='1' then
sub_count <= sub_count + 1;
end if;
end if;
end if;
end process;
-- SRAMのアドレス生成、4クロックに一回+1する
process(clk) begin
if clk'event and clk='1' then
if reset='1' or master_sync='1' then
mem_a <= (others => '0');
-- mem_a <= "000000000100000000";
else
if cam_href_2d='1' and sub_count="11" then
mem_a <= mem_a + 1;
end if;
end if;
end if;
end process;
mem_addr <= std_logic_vector(mem_a);
-- 水平方向の2つのデータが比較可能ということを表すステートマシン、cam_href_2dが1になった最初のデータは比較するデータがないので比較できない
process(clk) begin
if clk'event and clk='1' then
if reset='1' then
cs_chs <= no_data_h;
h_valid_flag <= '0';
else
case cs_chs is
when no_data_h =>
if cam_href_3d='1' then -- 最初の1つは排除
cs_chs <= comparing_h;
h_valid_flag <= '1';
else
cs_chs <= no_data_h;
end if;
when comparing_h =>
if cam_href_2d='0' then
cs_chs <= no_data_h;
h_valid_flag <= '0';
else
cs_chs <= comparing_h;
end if;
end case;
end if;
end if;
end process;
-- 1つ前のYデータを覚える
process(clk) begin
if clk'event and clk='1' then
if reset='1' then
ydata_1d <= (others => '0');
elsif r_w='1' then
ydata_1d <= cam_ydata_2d;
end if;
end if;
end process;
-- cam_ydata_2d - ydata_1dの絶対値を取る
process(cam_ydata_2d, ydata_1d) begin
if unsigned(cam_ydata_2d) >= unsigned(ydata_1d) then
alu_out <= unsigned(cam_ydata_2d) - unsigned(ydata_1d);
else
alu_out <= unsigned(ydata_1d) - unsigned(cam_ydata_2d);
end if;
end process;
-- 1つ前のYデータと現在のYデータを比較してエッジを検出する
process(h_valid_flag, alu_out) begin
if h_valid_flag='0' then -- 1つ前のYデータがないので、値は0
ydata_out <= (others => '0');
elsif h_valid_flag='1' then
if alu_out >= Edge_Threshold_Def then
ydata_out <= CONV_STD_LOGIC_VECTOR(Edge_Value_Def, 8);
else
ydata_out <= (others => '0');
end if;
else
ydata_out <= (others => '0');
end if;
end process;
end RTL;
--CamDisplay Contoroller with SRAM(トップモジュール)
-- トップモジュールから全部作ることにする。
-- CMOSカメラから出てくるビデオ出力はUYVYとする
-- VSYNCは正論理、HREFも正論理
-- clk(48MHz)はそのまま使用して、PCLKをDCMで受けて使用する。
-- IOBにマップされるロジックはこのトップモジュールにインスタンシエーションする。
-- synchronizerでは_1dのデータを使用し、その他のモジュールでは_2dのデータを使用する
-- 全体のタイミングは_2dを基準とする
library IEEE;
use IEEE.std_logic_1164.all;
use ieee.numeric_std.all;
-- pragma translate_off
library UNISIM;
use UNISIM.VComponents.all;
-- pragma translate_on
entity CamDispCntrl_SRAM is
port (
clk : in std_logic; -- 水晶発振器からの48MHzクロック
cam_vsync : in std_logic; -- CMOSカメラからのVSYNC
cam_href : in std_logic; -- CMOSカメラからのHREF
cam_pclk : in std_logic; -- CMOSカメラからのpclk
cam_ydata : in std_logic_vector(7 downto 0); -- CMOSカメラからのYデータ
cam_sio_c : out std_logic; -- CMOSカメラのI2Cクロック
-- cam_sio_d : inout std_logic; -- CMOSカメラのI2Cデータ
cam_sio_d : out std_logic; -- CMOSカメラのI2Cデータ
cam_clk : out std_logic; -- CMOSカメラのクロック
cam_reset : out std_logic; -- CMOSカメラのリセット(Hでリセット)
dac_red : out std_logic_vector(7 downto 0); -- DACへのRED出力
dac_green : out std_logic_vector(7 downto 0); -- DACへのGREEN出力
dac_blue : out std_logic_vector(7 downto 0); -- DACへのBLUE出力
n_dac_blank : out std_logic; -- DACへのアクティブローBLANK
dac_clk : out std_logic; -- DACクロック(24MHz)
vga_vsync : out std_logic; -- VGAのVSYNC
vga_hsync : out std_logic; -- VGAのHSYNC
mem_data : inout std_logic_vector(15 downto 0); -- SRAMのmemory data
n_mem_we : out std_logic; -- SRAMのmemory write enable
n_mem_rd : out std_logic; -- SRAMのmemory read enable
n_mem_cs0 : out std_logic; -- SRAMのchip select 0
n_mem_cs1 : out std_logic; -- SRAMのchip select 1
n_mem_cs2 : out std_logic; -- SRAMのchip select 2
n_mem_cs3 : out std_logic; -- SRAMのchip select 3
n_mem_lowerB : out std_logic; -- SRAMのmemory lower byte enable
n_mem_upperB : out std_logic; -- SRAMのmemory upper byte enable
mem_addr : out std_logic_vector(17 downto 0) -- SRAMのmemory address
);
end CamDispCntrl_SRAM;
architecture RTL of CamDispCntrl_SRAM is
component DCM_module_24MHz
port(
clk48MHz_in : in std_logic;
clk48_out : out std_logic;
cam_clk_out : out std_logic;
pclk_in : in std_logic;
mclk_out : out std_logic;
cam_clk_locked : out std_logic;
mclk_locked : out std_logic
);
end component;
component ODDR2
generic(
DDR_ALIGNMENT : string := "NONE";
INIT : bit := '0';
SRTYPE : string := "SYNC"
);
port(
Q : out std_ulogic;
C0 : in std_ulogic;
C1 : in std_ulogic;
CE : in std_ulogic := 'H';
D0 : in std_ulogic;
D1 : in std_ulogic;
R : in std_ulogic := 'L';
S : in std_ulogic := 'L'
);
end component;
component VGA_Display_Controller
port(
clk : in std_logic;
reset : in std_logic;
master_sync : in std_logic; -- 表示タイミングの同期信号
pixel_y_data : in std_logic_vector(15 downto 0); -- Yのデータ、下のdata_enableが1の時に有効
data_enable : in std_logic;
h_count_out : out unsigned(9 downto 0); -- 水平カウンタのカウント出力
v_count_out : out unsigned(9 downto 0); -- 垂直カウンタのカウント出力
red_out : out std_logic_vector(7 downto 0); -- VGA出力
green_out : out std_logic_vector(7 downto 0); -- VGA出力
blue_out : out std_logic_vector(7 downto 0); -- VGA出力
blank_out : out std_logic; -- BLANK出力
h_syncx_out : out std_logic; -- 水平同期出力
v_syncx_out : out std_logic; -- 垂直同期出力
mem_addr : out std_logic_vector(18 downto 0) -- SRAMのアドレス、バイト単位
);
end component;
component synchronizer
port(
clk : in std_logic;
reset : in std_logic;
cam_vsync_1d : in std_logic;
cam_href_1d : in std_logic;
master_sync : out std_logic;
r_w : out std_logic
);
end component;
component SRAM_Controller
port(
clk : in std_logic;
clk48 : in std_logic;
reset : in std_logic;
r_w : in std_logic; -- Read or Write
cam_href_3d : in std_logic; -- cam_href の3クロック遅れ、各モジュールで2クロック遅れの信号を使っているので、それよりも1クロック遅れている信号をweのイネーブルとして使用する。これはUYVYとデータが来るので、サンプルするのに1クロック遅れるから。
master_sync : in std_logic;
cam_mem_addr : in std_logic_vector(17 downto 0); -- CMOSカメラの書き込み用のアドレス
cam_ydata_in : in std_logic_vector(7 downto 0); -- CMOSカメラのデータ
vga_mem_addr : in std_logic_vector(18 downto 1); -- VGAコントローラー用読み出し用アドレス
mem_data_out : out std_logic_vector(15 downto 0); -- SRAMのデータ出力。CMOSカメラのデータを2つ集めたもの。
mem_data_oe : out std_logic; -- SRAMのmemory data出力のOutput Enable
n_mem_we : out std_logic; -- SRAMのWE
n_mem_cs0 : out std_logic; -- SRAMのchip select 0
n_mem_cs1 : out std_logic; -- SRAMのchip select 1
n_mem_cs2 : out std_logic; -- SRAMのchip select 2
n_mem_cs3 : out std_logic; -- SRAMのchip select 3
n_mem_lowerB : out std_logic; -- SRAMのmemory lower byte enable
n_mem_upperB : out std_logic; -- SRAMのmemory upper byte enable
mem_addr : out std_logic_vector(17 downto 0) -- SRAMのmemory address
);
end component;
component Camera_Controller
port(
clk : in std_logic;
reset : in std_logic;
cam_href_2d : in std_logic; -- CMOSカメラからのHREFのラッチ出力
cam_href_3d : in std_logic; -- CMOSカメラからのHREFのラッチ出力(3クロック遅延)
r_w : in std_logic; -- Read / Write
master_sync : in std_logic; -- 同期信号
cam_ydata_2d : in std_logic_vector(7 downto 0); -- CMOSカメラからの輝度データ
ydata_out : out std_logic_vector(7 downto 0); -- 比較した値
mem_addr : out std_logic_vector(17 downto 0) -- CMOSカメラのデータを書き込むSRAMのアドレス
);
end component;
component IOBUF
port(
O : out std_logic;
IO : inout std_logic;
I : in std_logic;
T : in std_logic
);
end component;
signal mclk : std_logic;
signal reset : std_logic;
signal mclk_locked : std_logic;
signal master_sync : std_logic;
signal r_w : std_logic;
signal cam_href_1d, cam_vsync_1d : std_logic;
signal cam_href_3d : std_logic;
signal cam_href_2d, cam_vsync_2d : std_logic;
signal cam_ydata_1d, cam_ydata_2d : std_logic_vector(7 downto 0);
signal w_r : std_logic;
signal vga_blank : std_logic;
signal vga_mem_addr : std_logic_vector(17 downto 0);
signal vga_mem_addr_19 : std_logic_vector(18 downto 0);
signal cam_mem_addr : std_logic_vector(17 downto 0);
signal clk48 : std_logic;
signal mem_data_out : std_logic_vector(15 downto 0); -- SRAMのデータ出力。CMOSカメラのデータを2つ集めたもの。
signal mem_data_oe : std_logic; -- SRAMのmemory data出力のOutput Enable
signal n_mem_data_oe : std_logic;
signal vga_ydata : std_logic_vector(15 downto 0);
signal input_mem_data : std_logic_vector(15 downto 0);
signal cam_clk_node, cam_clk_locked : std_logic;
signal n_cam_clk_node, cam_clk_reset : std_logic;
signal n_mclk : std_logic;
signal ydata_YUV : std_logic_vector(7 downto 0);
begin
cam_sio_c <= '1';
cam_sio_d <= 'Z';
cam_reset <= '0'; -- OV7640のRESETはアクティブハイ
DCM_module_24MHz_inst : DCM_module_24MHz port map(
clk48MHz_in => clk,
clk48_out => clk48,
cam_clk_out => cam_clk_node,
pclk_in => cam_pclk,
mclk_out => mclk,
cam_clk_locked => cam_clk_locked,
mclk_locked => mclk_locked
);
reset <= not mclk_locked;
-- CMOSカメラ用クロックの生成
n_cam_clk_node <= not cam_clk_node;
cam_clk_reset <= not cam_clk_locked;
ODDR2_for_cam_clk : ODDR2 generic map(
SRTYPE => "ASYNC"
) port map(
Q => cam_clk,
C0 => cam_clk_node,
C1 => n_cam_clk_node,
CE => '1',
D0 => '1',
D1 => '0',
R => cam_clk_reset,
S => '0'
);
-- DAC用クロックの生成
n_mclk <= not mclk;
ODDR2_for_dac_clk : ODDR2 generic map(
SRTYPE => "ASYNC"
) port map(
Q => dac_clk,
C0 => mclk,
C1 => n_mclk,
CE => '1',
D0 => '1',
D1 => '0',
R => reset,
S => '0'
);
-- CMOSカメラからの入力は一度IOBのFFを通す
process(mclk) begin
if mclk'event and mclk='1' then
if reset='1' then
cam_vsync_1d <= '0';
cam_href_1d <= '0';
cam_ydata_1d <= (others => '0');
cam_vsync_2d <= '0';
cam_href_2d <= '0';
cam_ydata_2d <= (others => '0');
cam_href_3d <= '0';
else
cam_vsync_1d <= cam_vsync;
cam_href_1d <= cam_href;
cam_ydata_1d <= cam_ydata;
cam_vsync_2d <= cam_vsync_1d;
cam_href_2d <= cam_href_1d;
cam_ydata_2d <= cam_ydata_1d;
cam_href_3d <= cam_href_2d;
end if;
end if;
end process;
-- CMOSカメラの書き込みアドレスの生成
synchronizer_inst : synchronizer port map(
clk => mclk,
reset => reset,
cam_vsync_1d => cam_vsync_1d,
cam_href_1d => cam_href_1d,
master_sync => master_sync,
r_w => r_w
);
-- mem_dataの入力FF
process(mclk) begin
if mclk'event and mclk='1' then
if reset='1' then
vga_ydata <= (others => '0');
else
vga_ydata <= input_mem_data;
end if;
end if;
end process;
w_r <= not r_w;
VGA_Display_Controller_inst : VGA_Display_Controller port map(
clk => mclk,
reset => reset,
master_sync => master_sync,
pixel_y_data => vga_ydata,
data_enable => w_r,
h_count_out => open,
v_count_out => open,
red_out => dac_red,
green_out => dac_green,
blue_out => dac_blue,
blank_out => vga_blank,
h_syncx_out => vga_hsync,
v_syncx_out => vga_vsync,
mem_addr => vga_mem_addr_19
);
n_dac_blank <= not vga_blank;
Camera_Controller_inst : Camera_Controller port map(
clk => mclk,
reset => reset,
cam_href_2d => cam_href_2d,
cam_href_3d => cam_href_3d,
r_w => r_w,
master_sync => master_sync,
cam_ydata_2d => cam_ydata_2d,
ydata_out => ydata_YUV,
mem_addr => cam_mem_addr
);
vga_mem_addr <= vga_mem_addr_19(18 downto 1);
SRAM_Controller_inst : SRAM_Controller port map(
clk => mclk,
clk48 => clk48,
reset => reset,
r_w => r_w,
cam_href_3d => cam_href_3d,
master_sync => master_sync,
cam_mem_addr => cam_mem_addr,
cam_ydata_in => ydata_YUV,
vga_mem_addr => vga_mem_addr,
mem_data_out => mem_data_out,
mem_data_oe => mem_data_oe,
n_mem_we => n_mem_we,
n_mem_cs0 => n_mem_cs0,
n_mem_cs1 => n_mem_cs1,
n_mem_cs2 => n_mem_cs2,
n_mem_cs3 => n_mem_cs3,
n_mem_lowerB => n_mem_lowerB,
n_mem_upperB => n_mem_upperB,
mem_addr => mem_addr
);
n_mem_data_oe <= not mem_data_oe;
MEM_DATA_GEN : for i in 15 downto 0 generate
IOBUF_inst : IOBUF port map(
O => input_mem_data(i),
IO => mem_data(i),
I => mem_data_out(i),
T => n_mem_data_oe
);
end generate MEM_DATA_GEN;
n_mem_rd <= not r_w;
end RTL;
-- ydata の出力
process(reset, pclock) begin -- Yデータ
if reset='1' then
y_data <= "00000001";
elsif pclock'event and pclock='1' then
if h_count<H_ACTIVE_VIDEO and h_count(0)='1' then -- 水平の表示区間で2クロックに1回シフト
if y_data=128 then
y_data <= "00000001";
else
y_data <= y_data(6 downto 0) & '0';
end if;
elsif h_count=0 and v_count=0 then -- 1フレーム描画の最初にリセット
y_data <= "00000001";
end if;
end if;
end process;
日 | 月 | 火 | 水 | 木 | 金 | 土 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | - | - | - | - | - |