Sie sind auf Seite 1von 58

Assignment: OV7670 camera on De-10

kit

Group 8: Đặng Thanh Tùng- 1751111


Nguyễn Trương Minh Tâm-1751083
Assignment: OV7670 camera on De-10 kit

The objective of this project is to design a simple digital camera system in order to
illustrate some of the main concepts related to digital design with VHDL and
FPGAs, image and video formats, CMOS cameras, basic image processing
algorithms (black and white filters, edge detection, etc.) embedded programming
of microcontrollers, and others. This camera is not something that you will be able
to compete with against today's sophisticated commercial cameras, but it provides
a learning exercise and a platform for you to potentially try out new ideas and
enhancements.
Procedure:
First, take a look at the camera pins and assign them to the De-10 board:

Open quartus II, choose Pin Planner

Assign the pins correspondingly:


Here, we simply build a preliminary design where we simply connect the OV7670
camera module to the FPGA, retrieve video frames from the camera module, store
temporarily each image frame's data inside the FPGA, and use that data to drive a
VGA monitor connected to the board. We'll complicate this design in follow-up
implementations. Note that each implementation is a stand alone design by itself.

This initial implementation is a cleaned up version and ported to the DE2-115


board of the project

Code for it:


library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity ov7670_registers is
Port ( clk : in STD_LOGIC;
resend : in STD_LOGIC;
advance : in STD_LOGIC;
command : out std_logic_vector(15 downto 0);
finished : out STD_LOGIC);
end ov7670_registers;

architecture Behavioral of ov7670_registers is

signal sreg : std_logic_vector(15 downto 0);


signal address : std_logic_vector(7 downto 0) := (others => '0');

begin

command <= sreg;


with sreg select finished <= '1' when x"FFFF", '0' when others;

process(clk)
begin
if rising_edge(clk) then

if resend = '1' then


address <= (others => '0');
elsif advance = '1' then
address <= std_logic_vector(unsigned(address)+1);
end if;

case address is
when x"00" => sreg <= x"1280"; -- COM7 Reset
when x"01" => sreg <= x"1280"; -- COM7 Reset
when x"02" => sreg <= x"1204"; -- COM7 Size & RGB output
when x"03" => sreg <= x"1100"; -- CLKRC Prescaler - Fin/(1+1)
when x"04" => sreg <= x"0C00"; -- COM3 Lots of stuff, enable scaling, all others off
when x"05" => sreg <= x"3E00"; -- COM14 PCLK scaling off

when x"06" => sreg <= x"8C00"; -- RGB444 Set RGB format
when x"07" => sreg <= x"0400"; -- COM1 no CCIR601
when x"08" => sreg <= x"4010"; -- COM15 Full 0-255 output, RGB 565
when x"09" => sreg <= x"3a04"; -- TSLB Set UV ordering, do not auto-reset window
when x"0A" => sreg <= x"1438"; -- COM9 - AGC Celling
when x"0B" => sreg <= x"4f40"; --x"4fb3"; -- MTX1 - colour conversion matrix
when x"0C" => sreg <= x"5034"; --x"50b3"; -- MTX2 - colour conversion matrix
when x"0D" => sreg <= x"510C"; --x"5100"; -- MTX3 - colour conversion matrix
when x"0E" => sreg <= x"5217"; --x"523d"; -- MTX4 - colour conversion matrix
when x"0F" => sreg <= x"5329"; --x"53a7"; -- MTX5 - colour conversion matrix
when x"10" => sreg <= x"5440"; --x"54e4"; -- MTX6 - colour conversion matrix
when x"11" => sreg <= x"581e"; --x"589e"; -- MTXS - Matrix sign and auto contrast
when x"12" => sreg <= x"3dc0"; -- COM13 - Turn on GAMMA and UV Auto adjust
when x"13" => sreg <= x"1100"; -- CLKRC Prescaler - Fin/(1+1)

when x"14" => sreg <= x"1711"; -- HSTART HREF start (high 8 bits)
when x"15" => sreg <= x"1861"; -- HSTOP HREF stop (high 8 bits)
when x"16" => sreg <= x"32A4"; -- HREF Edge offset and low 3 bits of HSTART
and HSTOP
when x"17" => sreg <= x"1903"; -- VSTART VSYNC start (high 8 bits)
when x"18" => sreg <= x"1A7b"; -- VSTOP VSYNC stop (high 8 bits)
when x"19" => sreg <= x"030a"; -- VREF VSYNC low two bits

when x"1A" => sreg <= x"0e61"; -- COM5(0x0E) 0x61


when x"1B" => sreg <= x"0f4b"; -- COM6(0x0F) 0x4B

when x"1C" => sreg <= x"1602"; --


when x"1D" => sreg <= x"1e37"; -- MVFP (0x1E) 0x07 -- FLIP AND MIRROR
IMAGE 0x3x

when x"1E" => sreg <= x"2102";


when x"1F" => sreg <= x"2291";

when x"20" => sreg <= x"2907";


when x"21" => sreg <= x"330b";

when x"22" => sreg <= x"350b";


when x"23" => sreg <= x"371d";

when x"24" => sreg <= x"3871";


when x"25" => sreg <= x"392a";

when x"26" => sreg <= x"3c78"; -- COM12 (0x3C) 0x78


when x"27" => sreg <= x"4d40";

when x"28" => sreg <= x"4e20";


when x"29" => sreg <= x"6900"; -- GFIX (0x69) 0x00

when x"2A" => sreg <= x"6b4a";


when x"2B" => sreg <= x"7410";
when x"2C" => sreg <= x"8d4f";
when x"2D" => sreg <= x"8e00";

when x"2E" => sreg <= x"8f00";


when x"2F" => sreg <= x"9000";

when x"30" => sreg <= x"9100";


when x"31" => sreg <= x"9600";

when x"32" => sreg <= x"9a00";


when x"33" => sreg <= x"b084";

when x"34" => sreg <= x"b10c";


when x"35" => sreg <= x"b20e";

when x"36" => sreg <= x"b382";


when x"37" => sreg <= x"b80a";

when others => sreg <= x"ffff";


end case;
end if;
end process;
end Behavioral;

This code is used to set the register of the camera, each pixel will have a corresponding value
and the register will save a value to COMMAND

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity i2c_sender is
Port ( clk : in STD_LOGIC;
siod : inout STD_LOGIC;
sioc : out STD_LOGIC;
taken : out STD_LOGIC;
send : in STD_LOGIC;
id : in STD_LOGIC_VECTOR (7 downto 0);
reg : in STD_LOGIC_VECTOR (7 downto 0);
value : in STD_LOGIC_VECTOR (7 downto 0));
end i2c_sender;

architecture Behavioral of i2c_sender is

signal divider : unsigned (7 downto 0) := "00000001"; -- this value gives a 254 cycle
pause before the initial frame is sent
signal busy_sr : std_logic_vector(31 downto 0) := (others => '0');
signal data_sr : std_logic_vector(31 downto 0) := (others => '1');

begin

process(busy_sr, data_sr(31))
begin
if busy_sr(11 downto 10) = "10" or
busy_sr(20 downto 19) = "10" or
busy_sr(29 downto 28) = "10" then
siod <= 'Z';
else
siod <= data_sr(31);
end if;
end process;

process(clk)
begin
if rising_edge(clk) then
taken <= '0';
if busy_sr(31) = '0' then
SIOC <= '1';
if send = '1' then
if divider = "00000000" then
data_sr <= "100" & id & '0' & reg & '0' & value & '0' & "01";
busy_sr <= "111" & "111111111" & "111111111" & "111111111" & "11";
taken <= '1';
else
divider <= divider+1; -- this only happens on powerup
end if;
end if;
else

case busy_sr(32-1 downto 32-3) & busy_sr(2 downto 0) is


when "111"&"111" => -- start seq #1
case divider(7 downto 6) is
when "00" => SIOC <= '1';
when "01" => SIOC <= '1';
when "10" => SIOC <= '1';
when others => SIOC <= '1';
end case;
when "111"&"110" => -- start seq #2
case divider(7 downto 6) is
when "00" => SIOC <= '1';
when "01" => SIOC <= '1';
when "10" => SIOC <= '1';
when others => SIOC <= '1';
end case;
when "111"&"100" => -- start seq #3
case divider(7 downto 6) is
when "00" => SIOC <= '0';
when "01" => SIOC <= '0';
when "10" => SIOC <= '0';
when others => SIOC <= '0';
end case;
when "110"&"000" => -- end seq #1
case divider(7 downto 6) is
when "00" => SIOC <= '0';
when "01" => SIOC <= '1';
when "10" => SIOC <= '1';
when others => SIOC <= '1';
end case;
when "100"&"000" => -- end seq #2
case divider(7 downto 6) is
when "00" => SIOC <= '1';
when "01" => SIOC <= '1';
when "10" => SIOC <= '1';
when others => SIOC <= '1';
end case;
when "000"&"000" => -- Idle
case divider(7 downto 6) is
when "00" => SIOC <= '1';
when "01" => SIOC <= '1';
when "10" => SIOC <= '1';
when others => SIOC <= '1';
end case;
when others =>
case divider(7 downto 6) is
when "00" => SIOC <= '0';
when "01" => SIOC <= '1';
when "10" => SIOC <= '1';
when others => SIOC <= '0';
end case;
end case;

if divider = "11111111" then


busy_sr <= busy_sr(32-2 downto 0) & '0';
data_sr <= data_sr(32-2 downto 0) & '1';
divider <= (others => '0');
else
divider <= divider+1;
end if;
end if;
end if;
end process;
end Behavioral;

This code take the value of COMMAND to the SIOC signal of the camera

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity VGA is
Port (
CLK25 : in STD_LOGIC; -- 25 MHz input clock
clkout : out STD_LOGIC; -- Output clock to the ADV7123 and TFT display

Hsync,Vsync : out STD_LOGIC; -- output the two synchronization signals for the VGA
display
Nblank : out STD_LOGIC; -- control signal for ADV7123 D / A converter
activeArea : out STD_LOGIC;
Nsync : out STD_LOGIC -- synchronization signals and control of the TFT screen
);
end VGA;

architecture Behavioral of VGA is

signal Hcnt:STD_LOGIC_VECTOR(9 downto 0):="0000000000"; -- for counting columns


signal Vcnt:STD_LOGIC_VECTOR(9 downto 0):="1000001000"; -- for counting lines
signal video:STD_LOGIC;
constant HM: integer :=799; --the maximum size considered 800 (horizontal)
constant HD: integer :=640; --the size of the screen (horizontal)
constant HF: integer :=16; --front porch
constant HB: integer :=48; --back porch
constant HR: integer :=96; --sync time
constant VM: integer :=524; --the maximum size considered 525 (vertical)
constant VD: integer :=480; --the size of the screen (vertical)
constant VF: integer :=10; --front porch
constant VB: integer :=33; --back porch
constant VR: integer :=2; --retrace
begin

--initialization of a counter from 0 to 799 (800 pixels per line):


--at each clock edge increments the column counter
--ie from 0 to 799.
process(CLK25)
begin
if (CLK25'event and CLK25='1') then
if (Hcnt = HM) then -- 799
Hcnt <= "0000000000";
if (Vcnt= VM) then -- 524
Vcnt <= "0000000000";
activeArea <= '1';
else
if vCnt < 240-1 then
activeArea <= '1';
end if;
Vcnt <= Vcnt+1;
end if;
else
if hcnt = 320-1 then
activeArea <= '0';
end if;
Hcnt <= Hcnt + 1;
end if;
end if;
end process;
-- generation of horizontal sync signal Hsync:
process(CLK25)
begin
if (CLK25'event and CLK25='1') then
if (Hcnt >= (HD+HF) and Hcnt <= (HD+HF+HR-1)) then -- Hcnt >= 656 and Hcnt <=
751
Hsync <= '0';
else
Hsync <= '1';
end if;
end if;
end process;

-- generation of the vertical sync signal Vsync:


process(CLK25)
begin
if (CLK25'event and CLK25='1') then
if (Vcnt >= (VD+VF) and Vcnt <= (VD+VF+VR-1)) then ---Vcnt >= 490 and vcnt<=
491
Vsync <= '0';
else
Vsync <= '1';
end if;
end if;
end process;

-- Blank and Nsync to order the ADV7123 converter:


Nsync <= '1';
video <= '1' when (Hcnt < HD) and (Vcnt < VD) -- it is to use the complete 640x480
resolution
else '0';
Nblank <= video;
clkout <= CLK25;

end Behavioral;

Set up a 640x480 resolution screen, or VGA with horizontal and vertical pixel

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity digital_cam_impl1 is
Port ( clk_50 : in STD_LOGIC;
btn_resend : in STD_LOGIC;
led_config_finished : out STD_LOGIC;

vga_hsync : out STD_LOGIC;


vga_vsync : out STD_LOGIC;
vga_r : out STD_LOGIC_vector(7 downto 0);
vga_g : out STD_LOGIC_vector(7 downto 0);
vga_b : out STD_LOGIC_vector(7 downto 0);
vga_blank_N : out STD_LOGIC;
vga_sync_N : out STD_LOGIC;
vga_CLK : out STD_LOGIC;

ov7670_pclk : in STD_LOGIC;
ov7670_xclk : out STD_LOGIC;
ov7670_vsync : in STD_LOGIC;
ov7670_href : in STD_LOGIC;
ov7670_data : in STD_LOGIC_vector(7 downto 0);
ov7670_sioc : out STD_LOGIC;
ov7670_siod : inout STD_LOGIC;
ov7670_pwdn : out STD_LOGIC;
ov7670_reset : out STD_LOGIC
);
end digital_cam_impl1;

architecture my_structural of digital_cam_impl1 is

COMPONENT VGA
PORT(
CLK25 : IN std_logic;
Hsync : OUT std_logic;
Vsync : OUT std_logic;
Nblank : OUT std_logic;
clkout : OUT std_logic;
activeArea : OUT std_logic;
Nsync : OUT std_logic
);
END COMPONENT;

COMPONENT ov7670_controller
PORT(
clk : IN std_logic;
resend : IN std_logic;
siod : INOUT std_logic;
config_finished : OUT std_logic;
sioc : OUT std_logic;
reset : OUT std_logic;
pwdn : OUT std_logic;
xclk : OUT std_logic
);
END COMPONENT;

COMPONENT frame_buffer
PORT(
data : IN std_logic_vector(11 downto 0);
rdaddress : IN std_logic_vector(16 downto 0);
rdclock : IN std_logic;
wraddress : IN std_logic_vector(16 downto 0);
wrclock : IN std_logic;
wren : IN std_logic;
q : OUT std_logic_vector(11 downto 0)
);
END COMPONENT;

COMPONENT ov7670_capture
PORT(
pclk : IN std_logic;
vsync : IN std_logic;
href : IN std_logic;
d : IN std_logic_vector(7 downto 0);
addr : OUT std_logic_vector(16 downto 0);
dout : OUT std_logic_vector(11 downto 0);
we : OUT std_logic
);
END COMPONENT;

COMPONENT RGB
PORT(
Din : IN std_logic_vector(11 downto 0);
Nblank : IN std_logic;
R : OUT std_logic_vector(7 downto 0);
G : OUT std_logic_vector(7 downto 0);
B : OUT std_logic_vector(7 downto 0)
);
END COMPONENT;

-- DE2-115 board has an Altera Cyclone V E, which has ALTPLL's'


COMPONENT my_altpll
PORT (
inclk0 : IN STD_LOGIC := '0';
c0 : OUT STD_LOGIC ;
c1 : OUT STD_LOGIC
);
END COMPONENT;

COMPONENT Address_Generator
PORT(
CLK25 : IN std_logic;
enable : IN std_logic;
vsync : in STD_LOGIC;
address : OUT std_logic_vector(16 downto 0)
);
END COMPONENT;
signal clk_50_camera : std_logic;
signal clk_25_vga : std_logic;
signal wren : std_logic;
signal resend : std_logic;
signal nBlank : std_logic;
signal vSync : std_logic;

signal wraddress : std_logic_vector(16 downto 0);


signal wrdata : std_logic_vector(11 downto 0);
signal rdaddress : std_logic_vector(16 downto 0);
signal rddata : std_logic_vector(11 downto 0);
signal red,green,blue : std_logic_vector(7 downto 0);
signal activeArea : std_logic;

begin

vga_r <= red(7 downto 0);


vga_g <= green(7 downto 0);
vga_b <= blue(7 downto 0);

Inst_vga_pll: my_altpll PORT MAP(


inclk0 => clk_50,
c0 => clk_50_camera,
c1 => clk_25_vga
);
-- take the inverted push button because KEY0 on DE2-115 board generates
-- a signal 111000111; with 1 with not pressed and 0 when pressed/pushed;
resend <= not btn_resend;
vga_vsync <= vsync;
vga_blank_N <= nBlank;

Inst_VGA: VGA PORT MAP(


CLK25 => clk_25_vga,
clkout => vga_CLK,
Hsync => vga_hsync,
Vsync => vsync,
Nblank => nBlank,
Nsync => vga_sync_N,
activeArea => activeArea
);

Inst_ov7670_controller: ov7670_controller PORT MAP(


clk => clk_50_camera,
resend => resend,
config_finished => led_config_finished,
sioc => ov7670_sioc,
siod => ov7670_siod,
reset => ov7670_reset,
pwdn => ov7670_pwdn,
xclk => ov7670_xclk
);

Inst_ov7670_capture: ov7670_capture PORT MAP(


pclk => ov7670_pclk,
vsync => ov7670_vsync,
href => ov7670_href,
d => ov7670_data,
addr => wraddress,
dout => wrdata,
we => wren
);

Inst_frame_buffer: frame_buffer PORT MAP(


rdaddress => rdaddress,
rdclock => clk_25_vga,
q => rddata,
wrclock => ov7670_pclk,
wraddress => wraddress(16 downto 0),
data => wrdata,
wren => wren
);

Inst_RGB: RGB PORT MAP(


Din => rddata,
Nblank => activeArea,
R => red,
G => green,
B => blue
);

Inst_Address_Generator: Address_Generator PORT MAP(


CLK25 => clk_25_vga,
enable => activeArea,
vsync => vsync,
address => rdaddress
);

end my_structural;

this design basically connects a CMOS camera (OV7670 module) to DE2-115 board; video
frames are picked up from camera, buffered on the FPGA (using embedded RAM), and
displayed on the VGA monitor, which is also connected to the board; clock signals generated
inside FPGA using ALTPLL's that take as input the board's 50MHz signal from on-board
oscillator.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity RGB is
Port (
Din : in STD_LOGIC_VECTOR (11 downto 0); -- gray level of 8-bit pixels
Nblank : in STD_LOGIC; -- signal indicates the display area, outside the
display area
-- the three colors take 0
R,G,B : out STD_LOGIC_VECTOR (7 downto 0) -- the three colors on 10 bits
);
end RGB;

architecture Behavioral of RGB is


begin
R <= Din(11 downto 8) & Din(11 downto 8) when Nblank='1' else "00000000";
G <= Din(7 downto 4) & Din(7 downto 4) when Nblank='1' else "00000000";
B <= Din(3 downto 0) & Din(3 downto 0) when Nblank='1' else "00000000";
end Behavioral;

Now input the color to the pixel with the correct Din and Nblank

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity ov7670_controller is
Port ( clk : in STD_LOGIC;
resend : in STD_LOGIC;
config_finished : out std_logic;
sioc : out STD_LOGIC;
siod : inout STD_LOGIC;
reset : out STD_LOGIC;
pwdn : out STD_LOGIC;
xclk : out STD_LOGIC
);
end ov7670_controller;

architecture Behavioral of ov7670_controller is

COMPONENT ov7670_registers
PORT(
clk : IN std_logic;
advance : IN std_logic;
resend : in STD_LOGIC;
command : OUT std_logic_vector(15 downto 0);
finished : OUT std_logic
);
END COMPONENT;

COMPONENT i2c_sender
PORT(
clk : IN std_logic;
send : IN std_logic;
taken : out std_logic;
id : IN std_logic_vector(7 downto 0);
reg : IN std_logic_vector(7 downto 0);
value : IN std_logic_vector(7 downto 0);
siod : INOUT std_logic;
sioc : OUT std_logic
);
END COMPONENT;

signal sys_clk : std_logic := '0';


signal command : std_logic_vector(15 downto 0);
signal finished : std_logic := '0';
signal taken : std_logic := '0';
signal send : std_logic;
-- device write ID; see datasheet of camera module;
constant camera_address : std_logic_vector(7 downto 0) := x"42";

begin

config_finished <= finished;


send <= not finished;

Inst_i2c_sender: i2c_sender PORT MAP(


clk => clk,
taken => taken,
siod => siod,
sioc => sioc,
send => send,
id => camera_address,
reg => command(15 downto 8),
value => command(7 downto 0)
);
reset <= '1'; -- Normal mode
pwdn <= '0'; -- Power device up
xclk <= sys_clk;

Inst_ov7670_registers: ov7670_registers PORT MAP(


clk => clk,
advance => taken,
command => command,
finished => finished,
resend => resend
);
process(clk)
begin
if rising_edge(clk) then
sys_clk <= not sys_clk;
end if;
end process;
end Behavioral;

Controll the OV760 camera - transferes registers to the camera over an I2C like bus, with
clk , taken, siod, send , sioc , id , reg , value,…. Signals

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity ov7670_capture is
Port ( pclk : in STD_LOGIC;
vsync : in STD_LOGIC;
href : in STD_LOGIC;
d : in STD_LOGIC_VECTOR (7 downto 0);
addr : out STD_LOGIC_VECTOR (16 downto 0);
dout : out STD_LOGIC_VECTOR (11 downto 0);
we : out STD_LOGIC);
end ov7670_capture;

architecture Behavioral of ov7670_capture is

signal d_latch : std_logic_vector(15 downto 0) := (others => '0');


signal address : STD_LOGIC_VECTOR(16 downto 0) := (others => '0');
signal line : std_logic_vector(1 downto 0) := (others => '0');
signal href_last : std_logic_vector(6 downto 0) := (others => '0');
signal we_reg : std_logic := '0';
signal href_hold : std_logic := '0';
signal latched_vsync : STD_LOGIC := '0';
signal latched_href : STD_LOGIC := '0';
signal latched_d : STD_LOGIC_VECTOR (7 downto 0) := (others => '0');
begin

addr <= address;


we <= we_reg;
dout <= d_latch(15 downto 12) & d_latch(10 downto 7) & d_latch(4 downto 1);

capture_process: process(pclk)
begin
if rising_edge(pclk) then

if we_reg = '1' then


address <= std_logic_vector(unsigned(address)+1);
end if;

-- This is a bit tricky href starts a pixel transfer that takes 3 cycles
-- Input | state after clock tick
-- href | wr_hold d_latch dout we address address_next
-- cycle -1 x | xx xxxxxxxxxxxxxxxx xxxxxxxxxxxx x xxxx xxxx
-- cycle 0 1 | x1 xxxxxxxxRRRRRGGG xxxxxxxxxxxx x xxxx addr
-- cycle 1 0 | 10 RRRRRGGGGGGBBBBB xxxxxxxxxxxx x addr addr
-- cycle 2 x | 0x GGGBBBBBxxxxxxxx RRRRGGGGBBBB 1 addr addr+1

-- detect the rising edge on href - the start of the scan line
if href_hold = '0' and latched_href = '1' then
case line is
when "00" => line <= "01";
when "01" => line <= "10";
when "10" => line <= "11";
when others => line <= "00";
end case;
end if;
href_hold <= latched_href;

-- capturing the data from the camera, 12-bit RGB


if latched_href = '1' then
d_latch <= d_latch( 7 downto 0) & latched_d;
end if;
we_reg <= '0';

-- Is a new screen about to start (i.e. we have to restart capturing


if latched_vsync = '1' then
address <= (others => '0');
href_last <= (others => '0');
line <= (others => '0');
else
-- If not, set the write enable whenever we need to capture a pixel
if href_last(2) = '1' then
if line(1) = '1' then
we_reg <= '1';
end if;
href_last <= (others => '0');
else
href_last <= href_last(href_last'high-1 downto 0) & latched_href;
end if;
end if;
end if; -- if rising_edge(pclk) then
if falling_edge(pclk) then
latched_d <= d;
latched_href <= href;
latched_vsync <= vsync;
end if; -- if falling_edge(pclk) then

end process;

end Behavioral;

Use the “line” command to control the frequency of captured image on the camera-4 cycles.
The data will be stored in RAM

LIBRARY ieee;
USE ieee.std_logic_1164.all;

ENTITY frame_buffer IS
PORT
(
data : IN STD_LOGIC_VECTOR (11 DOWNTO 0);
rdaddress : IN STD_LOGIC_VECTOR (16 DOWNTO 0);
rdclock : IN STD_LOGIC;
wraddress : IN STD_LOGIC_VECTOR (16 DOWNTO 0);
wrclock : IN STD_LOGIC;
wren : IN STD_LOGIC;
q : OUT STD_LOGIC_VECTOR (11 DOWNTO 0)
);
END frame_buffer;

ARCHITECTURE SYN OF frame_buffer IS


COMPONENT my_frame_buffer_15to0 IS
PORT
(
data : IN STD_LOGIC_VECTOR (11 DOWNTO 0);
rdaddress : IN STD_LOGIC_VECTOR (15 DOWNTO 0);
rdclock : IN STD_LOGIC ;
wraddress : IN STD_LOGIC_VECTOR (15 DOWNTO 0);
wrclock : IN STD_LOGIC := '1';
wren : IN STD_LOGIC := '0';
q : OUT STD_LOGIC_VECTOR (11 DOWNTO 0)
);
END COMPONENT;

-- read signals
signal q_top : STD_LOGIC_VECTOR (11 DOWNTO 0);
signal q_bottom : STD_LOGIC_VECTOR (11 DOWNTO 0);
-- write signals
signal wren_top : STD_LOGIC;
signal wren_bottom : STD_LOGIC;

BEGIN

Inst_buffer_top : my_frame_buffer_15to0
PORT MAP (
data => data(11 downto 0),
rdaddress => rdaddress(15 downto 0),
rdclock => rdclock,
wraddress => wraddress(15 downto 0),
wrclock => wrclock,
wren => wren_top,
q => q_top
);
Inst_buffer_bottom : my_frame_buffer_15to0
PORT MAP (
data => data(11 downto 0),
rdaddress => rdaddress(15 downto 0),
rdclock => rdclock,
wraddress => wraddress(15 downto 0),
wrclock => wrclock,
wren => wren_bottom,
q => q_bottom
);

process (wraddress(16), wren)


begin
case wraddress(16) is
when '0' =>
wren_top <= wren; wren_bottom <= '0';
when '1' =>
wren_top <= '0'; wren_bottom <= wren;
when others =>
wren_top <= '0'; wren_bottom <= '0';
end case;
end process;

process (rdaddress(16), q_top, q_bottom)


begin
case rdaddress(16) is
when '0' =>
q <= q_top;
when '1' =>
q <= q_bottom;
when others =>
q <= "000000000000";
end case;
end process;

END SYN;

This code is used to create a buffer to store pixels data for a frame of 320x240 pixels, data for
each pixel is 12 bits

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity Address_Generator is
Port (
CLK25,enable : in STD_LOGIC;
vsync : in STD_LOGIC;
address : out STD_LOGIC_VECTOR (16 downto 0)
);
end Address_Generator;

architecture Behavioral of Address_Generator is

signal val: STD_LOGIC_VECTOR(address'range):= (others => '0');


begin

address <= val; e

process(CLK25)
begin
if rising_edge(CLK25) then

if (enable='1') then

if (val < 320*240) then


val <= val + 1 ;
end if;
end if;

if vsync = '0' then


val <= (others => '0');
end if;

end if;
end process;
end Behavioral;

Finally, generate the address for the 320*240 frame

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use ieee.std_logic_unsigned.all;
entity sdram_rw is
Port (
-- connections to sdram controller;
clk_i : in STD_LOGIC; -- 25 MHz
rst_i : in STD_LOGIC;
addr_i : out STD_LOGIC_vector(24 downto 0);
dat_i : out STD_LOGIC_vector(31 downto 0);
dat_o : in STD_LOGIC_vector(31 downto 0);
we_i : out STD_LOGIC;
ack_o : in STD_LOGIC;
stb_i : out STD_LOGIC;
cyc_i : out STD_LOGIC;
-- connections to frame buffer 2 for which we need to
-- generate addresses and pass image data from SDRAM;
addr_buf2 : OUT STD_LOGIC_VECTOR (16 downto 0);
dout_buf2 : OUT std_logic_vector(11 downto 0);
we_buf2 : OUT std_logic;
-- connections from frame buffer 1 from where we
-- take snapshot; we of buf 1 is controlled by ov7670_capture
-- here we only read from buffer 1;
addr_buf1 : OUT STD_LOGIC_VECTOR (16 downto 0);
din_buf1 : IN std_logic_vector(11 downto 0);
-- rw controls
take_snapshot : in STD_LOGIC; -- store to SDRAM;
display_snapshot : in STD_LOGIC; -- read/fetch from SDRAM;
led_done : out STD_LOGIC
);
end sdram_rw;
architecture my_behavioral of sdram_rw is

constant START_WRITE_ST : std_logic_vector(3 downto 0) := "0000";


constant WRITE_ST : std_logic_vector(3 downto 0) := "0001";
constant WAIT_WRITE_ACK_ST : std_logic_vector(3 downto 0) := "0010";
constant READ_ST : std_logic_vector(3 downto 0) := "0011";
constant WAIT_READ_ACK_ST : std_logic_vector(3 downto 0) := "0100";
constant WRITE_WAIT_ST : std_logic_vector(3 downto 0) := "0101";
constant START_READ_ST : std_logic_vector(3 downto 0) := "0110";
constant READ_WAIT_ST : std_logic_vector(3 downto 0) := "0111";
constant DONE_ST : std_logic_vector(3 downto 0) := "1000";
constant IDLE_ST : std_logic_vector(3 downto 0) := "1001";

-- we need to read 320x240 = 76800 words; we use 1 word in SDRAM per pixel
-- even though right now pixel data is only 12 bits of useful info;
-- this is just in case we'll use 24 bits per pixel in the future;
constant NUM_PIXELS : std_logic_vector(16 downto 0) :=
std_logic_vector(to_unsigned(76799, 17));

-- signal that storing or fetching one frame is done;


signal led_done_r: std_logic := '0';

-- coming from buffer 1, for storage of snapshot into SDRAM;


signal addr_buf1_r : STD_LOGIC_VECTOR(16 downto 0) := (others => '0');
signal din_buf1_r : std_logic_vector(11 downto 0);
-- going to buffer 2, for display;
signal addr_buf2_r : STD_LOGIC_VECTOR(16 downto 0) := (others => '0');
signal dout_buf2_r : std_logic_vector(11 downto 0) := (others => '0');
signal we_buf2_r : std_logic := '0';

-- redundant counter; keeps track of num of pixels written/read from sdram;


signal rw_cntr: std_logic_vector(16 downto 0) := (others => '0');
-- state of the FSM that implements the read or write steps;
signal state: std_logic_vector(3 downto 0) := IDLE_ST;

-- address bus to sdram_controller;


signal addr_i_r: std_logic_vector(24 downto 0) := (others => '0');
signal dat_i_r: std_logic_vector(31 downto 0);
signal dat_o_r: std_logic_vector(31 downto 0);
signal we_i_r: std_logic := '0';
signal stb_i_r: std_logic := '0';
signal cyc_i_r: std_logic := '0';

begin

dat_o_r <= dat_o;


addr_i <= addr_i_r;
dat_i <= dat_i_r; -- should not be really necessary;
stb_i <= stb_i_r;
cyc_i <= cyc_i_r;
we_i <= we_i_r;

-- writes into sdram: buffer 1 --> sdram;


addr_buf1 <= addr_buf1_r; -- needed because I increment addr_buf1_r;
din_buf1_r <= din_buf1;

-- read backs: sdram --> buffer 2;


addr_buf2 <= addr_buf2_r;
dout_buf2 <= dout_buf2_r;
we_buf2 <= we_buf2_r;
led_done <= led_done_r;

process (clk_i)
begin
if rising_edge (clk_i) then
if (rst_i = '1') then
state <= IDLE_ST;
led_done_r <= '0';
we_buf2_r <= '0';
elsif (take_snapshot = '1' and state = IDLE_ST) then
state <= START_WRITE_ST;
led_done_r <= '0';
we_buf2_r <= '0';
addr_buf1_r <= (others => '0');
elsif (display_snapshot = '1' and state = IDLE_ST) then
state <= START_READ_ST;
led_done_r <= '0';
we_buf2_r <= '1';
addr_buf2_r <= (others => '0');

else
case state is

-- part 1: sequence of states related to writes;


-- state START_WRITE_ST is visited once only for each frame;
when START_WRITE_ST =>
state <= WRITE_ST;
addr_i_r <= (others => '0');
rw_cntr <= (others => '0');
we_i_r <= '1'; -- stays like that during writes;
addr_buf1_r <= (others => '0');

-- each pixel data writing into sdram goes tru the sequence of 3 states:
-- WRITE_ST --> WAIT_WRITE_ACK_ST --> WRITE_WAIT_ST
when WRITE_ST =>
state <= WAIT_WRITE_ACK_ST;
stb_i_r <= '1';
cyc_i_r <= '1';
we_i_r <= '1';
-- now, this is a bit tricky: pick up data coming from buffer 1 here;
-- data should be stable already, because I changed the address in the previous
-- cycle inside state WRITE_WAIT_ST, but on falling edge of clk_i, from within
-- a different process;
--dat_i_r <= ("00000000000000000000" & "000000001111"); -- blue debug;
dat_i_r <= ("00000000000000000000" & din_buf1_r); -- pass this to be written to
sdram;
-- increment address for buf1; very important to do this here instead of
-- in WRITE_WAIT_ST state; otherwise, we get a pixel lag that will shift the image
-- to the right;
addr_buf1_r <= addr_buf1_r + 1;

when WAIT_WRITE_ACK_ST =>


if (ack_o = '1') then
state <= WRITE_WAIT_ST;
stb_i_r <= '0';
cyc_i_r <= '0';
end if;

when WRITE_WAIT_ST =>


if (rw_cntr < NUM_PIXELS) then
state <= WRITE_ST;
rw_cntr <= rw_cntr + 1; -- keep track of how many times we write into sdram;
addr_i_r <= addr_i_r + 2; -- increment address for sdram controller;
else
state <= DONE_ST;
end if;

-- part 2: states below related to read backs;


-- state START_READ_ST is visited once only for each frame;
when START_READ_ST =>
addr_i_r <= "0000000000000000000000000"; -- (others => '0');
rw_cntr <= (others => '0');
we_i_r <= '0'; -- stays like that during read backs;
addr_buf2_r <= (others => '0');
dout_buf2_r <= "110000000011"; -- Yellow;
we_buf2_r <= '1';
state <= READ_ST;

-- each pixel data reading process goes tru the sequence of 3 states:
-- READ_ST --> WAIT_READ_ACK_ST --> READ_WAIT_ST
-- which means three clock periods of 25 MHz; note that sdram
-- controller operates with clk_100 that is much faster;
when READ_ST => -- tell sdram_controller we want to read from addr_i_r
stb_i_r <= '1';
cyc_i_r <= '1';
we_i_r <= '0';
state <= WAIT_READ_ACK_ST;

when WAIT_READ_ACK_ST => -- wait for controller which should assert ack_o
-- here we "stall" in this state until ack_o is asserted;
if (ack_o = '1') then
stb_i_r <= '0';
cyc_i_r <= '0';
--dout_buf2_r <= "110000000011"; -- pink debug;
dout_buf2_r <= dat_o_r(11 downto 0); -- what comes from sdram_controller is sent
to buffer 2;
state <= READ_WAIT_ST;
end if;

when READ_WAIT_ST => -- terminate or go for next pixel;


if (rw_cntr < NUM_PIXELS) then
-- rw_cntr keeps track of how many times we read from sdram; we could
-- use addr_buf2_r instead; but keep it this way in case later we'll
-- need to increment addr_buf2_r by 2 or 4;
rw_cntr <= rw_cntr + 1;
addr_i_r <= addr_i_r + 2; -- increment address for sdram controller;
addr_buf2_r <= addr_buf2_r + 1; -- increment address for buf2;
state <= READ_ST;
else
state <= DONE_ST;
end if;

-- when arrived to this state, a whole frame was written or read and we should
-- stay here and not repeat the process of writing or reading a frame
-- unless the whole thing is reset, which places us again in IDLE_ST state;
when DONE_ST =>
state <= DONE_ST; -- this ways we read or write all pixels only once;
led_done_r <= '1'; -- notify user it's success; will be used for self reset too at
top_level;
when others =>
state <= IDLE_ST;
led_done_r <= '0';

end case;
end if;
end if;
end process;

end my_behavioral;

used here to write into sdram the frame from frame buffer 1, also, used to read from sdram
and place the frame into frame buffer 2, the led done is asserted to signal that all pixels have
been written or read;

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use ieee.std_logic_unsigned.all;

entity sdram_controller is
Port (
clk_i: in STD_LOGIC; -- clk_100
dram_clk_i: in STD_LOGIC; -- clk_100_3ns
rst_i: in STD_LOGIC;
dll_locked: in STD_LOGIC;
-- all ddr signals
dram_addr: out STD_LOGIC_vector(12 downto 0);
dram_bank: out STD_LOGIC_vector(1 downto 0);
dram_cas_n: out STD_LOGIC;
dram_cke: out STD_LOGIC;
dram_clk: out STD_LOGIC;
dram_cs_n: out STD_LOGIC;
dram_dq: inout STD_LOGIC_vector(15 downto 0);
dram_ldqm: out STD_LOGIC;
dram_udqm: out STD_LOGIC;
dram_ras_n: out STD_LOGIC;
dram_we_n: out STD_LOGIC;
-- wishbone bus
addr_i: in STD_LOGIC_vector(24 downto 0);
dat_i: in STD_LOGIC_vector(31 downto 0);
dat_o: out STD_LOGIC_vector(31 downto 0);
we_i: in STD_LOGIC;
ack_o: out STD_LOGIC;
stb_i: in STD_LOGIC;
cyc_i: in STD_LOGIC
);
end sdram_controller;

architecture my_behavioral of sdram_controller is

-- row width 13
-- column width 10
-- bank width 2
-- user address is specified as {bank,row,column}

-- now, look at page 24 of datasheet of SDRAM chips;


-- we see address[2:0] is the Burst Length (BL), which we'll set here as 2; so, address[2:0]
must be "001"
-- also, address[3] is Burst Type; we set it to Sequential; so, address[3] must be '0';
-- also, address[6:4] is CAS Latency, which we set to 3 here; so, address[6:4] must be
"011";
-- MODE_REGISTER is defined as: BA1 BA0 A12 A11 A10 A9 A8 A7 A6 A5 A4 A3 A2
A1 A0
-- with BA1 BA0 A12 A11 A10 being reserved;
-- so we use A2 A1 A0 = "001" to BL=2; A3 = '0'; A6 A5 A4 = "011" to CAS=3
-- Note: I am defining MODE_REGISTER with just 13 bits instead of 15 bits; discard BA1
BA0;
constant MODE_REGISTER : std_logic_vector(12 downto 0) := "0000000110001";

constant INIT_IDLE : std_logic_vector(2 downto 0) := "000";


constant INIT_WAIT_200us : std_logic_vector(2 downto 0) := "001";
constant INIT_INIT_PRE : std_logic_vector(2 downto 0) := "010";
constant INIT_WAIT_PRE : std_logic_vector(2 downto 0) := "011";
constant INIT_MODE_REG : std_logic_vector(2 downto 0) := "100";
constant INIT_WAIT_MODE_REG : std_logic_vector(2 downto 0) := "101";
constant INIT_DONE_ST : std_logic_vector(2 downto 0) := "110";

constant IDLE_ST : std_logic_vector(3 downto 0) := "0000";


constant REFRESH_ST : std_logic_vector(3 downto 0) := "0001";
constant REFRESH_WAIT_ST : std_logic_vector(3 downto 0) := "0010";
constant ACT_ST : std_logic_vector(3 downto 0) := "0011";
constant WAIT_ACT_ST : std_logic_vector(3 downto 0) := "0100";
constant WRITE0_ST : std_logic_vector(3 downto 0) := "0101";
constant WRITE1_ST : std_logic_vector(3 downto 0) := "0110";
constant WRITE_PRE_ST : std_logic_vector(3 downto 0) := "0111";
constant READ0_ST : std_logic_vector(3 downto 0) := "1000";
constant READ1_ST : std_logic_vector(3 downto 0) := "1001";
constant READ2_ST : std_logic_vector(3 downto 0) := "1010";
constant READ3_ST : std_logic_vector(3 downto 0) := "1011";
constant READ4_ST : std_logic_vector(3 downto 0) := "1100";
constant READ_PRE_ST : std_logic_vector(3 downto 0) := "1101";
constant PRE_ST : std_logic_vector(3 downto 0) := "1110";
constant WAIT_PRE_ST : std_logic_vector(3 downto 0) := "1111";

-- if 100 MHz, then, period is T_CLK = 10 ns


-- 7 cycles == time to wait after refresh 70ns
-- also time to wait between two ACT commands; I'll make it 100ns though;
constant TRC_CNTR_VALUE : std_logic_vector(3 downto 0) :=
std_logic_vector(to_unsigned(10, 4));
-- need 8192=2^13 refreshes for every 64_000_000 ns
-- (every 64ms, see page 7 of datasheet of ISSI SDRAM chips on DE2-115)
-- so the # of cycles between refreshes is 64000000 / 8192 / 10 = 781.25; I'll make 780
though;
constant RFSH_INT_CNTR_VALUE : std_logic_vector(24 downto 0) :=
std_logic_vector(to_unsigned(780, 25));
-- ras to cas delay 20 ns; that's about 2 T_CLK
-- will also be used for tRP and tRSC
constant TRCD_CNTR_VALUE : std_logic_vector(2 downto 0) :=
std_logic_vector(to_unsigned(2, 3));
-- TODO: datasheet of SDRAM chips (page 20) says that
-- A 100us delay is required prior to issuing any command other than a COMMAND
INHIBIT or a NOP.
-- 20000 cycles to make up 200 us instead of 100 us
constant WAIT_200us_CNTR_VALUE : std_logic_vector(15 downto 0) :=
std_logic_vector(to_unsigned(20000, 16));

signal address_r: std_logic_vector(24 downto 0);

signal dram_addr_r: std_logic_vector(12 downto 0);


signal dram_bank_r: std_logic_vector(1 downto 0);
signal dram_dq_r: std_logic_vector(15 downto 0);
signal dram_cas_n_r: std_logic;
signal dram_ras_n_r: std_logic;
signal dram_we_n_r: std_logic;

signal dat_o_r: std_logic_vector(31 downto 0) := (others => '0');


signal ack_o_r: std_logic := '0';
signal dat_i_r: std_logic_vector(31 downto 0);
signal we_i_r: std_logic := '0';
signal stb_i_r: std_logic;
signal oe_r: std_logic := '0';

signal current_state: std_logic_vector(3 downto 0) := IDLE_ST;


signal next_state: std_logic_vector(3 downto 0) := IDLE_ST;
signal current_init_state: std_logic_vector(2 downto 0) := INIT_IDLE;
signal next_init_state: std_logic_vector(2 downto 0) := INIT_IDLE;

signal init_done: std_logic := '0';


signal init_pre_cntr: std_logic_vector(3 downto 0) := (others => '0');
signal trc_cntr: std_logic_vector(3 downto 0) := (others => '0');
signal rfsh_int_cntr: std_logic_vector(24 downto 0) := (others => '0');
signal trcd_cntr: std_logic_vector(2 downto 0) := (others => '0');
signal wait_200us_cntr: std_logic_vector(15 downto 0) := (others => '0');
signal do_refresh: std_logic;

begin
dram_addr <= dram_addr_r;
dram_bank <= dram_bank_r;
dram_cas_n <= dram_cas_n_r;
dram_ras_n <= dram_ras_n_r;
dram_we_n <= dram_we_n_r;
dram_dq <= dram_dq_r when oe_r = '1' else (others => 'Z');

dat_o <= dat_o_r;


ack_o <= ack_o_r;

dram_cke <= '1'; -- dll_locked


dram_cs_n <= not dll_locked; -- chip select is always on in normal op
dram_clk <= dram_clk_i;
dram_ldqm <= '0'; -- don't do byte masking
dram_udqm <= '0'; -- don't do byte masking

process (clk_i)
begin
if rising_edge (clk_i) then
if (stb_i_r = '1' and current_state = ACT_ST) then
stb_i_r <= '0';
elsif (stb_i = '1' and cyc_i = '1') then
address_r <= addr_i;
dat_i_r <= dat_i;
we_i_r <= we_i; -- pick whatever value we_i has;
stb_i_r <= stb_i;
end if;
end if;
end process;

process (clk_i, rst_i)


begin
if rising_edge (clk_i) then
if (rst_i = '1') then
wait_200us_cntr <= (others => '0');
elsif (current_init_state = INIT_IDLE) then
wait_200us_cntr <= WAIT_200us_CNTR_VALUE;
else
wait_200us_cntr <= wait_200us_cntr - 1;
end if;
end if;
end process;

-- control the interval between refreshes


process (clk_i, rst_i)
begin
if rising_edge (clk_i) then
if (rst_i = '1') then
rfsh_int_cntr <= (others => '0'); -- immediately initiate new refresh on reset
elsif (current_state = REFRESH_WAIT_ST) then
do_refresh <= '0';
rfsh_int_cntr <= RFSH_INT_CNTR_VALUE;
elsif (rfsh_int_cntr = "0000000000000000000000000") then
do_refresh <= '1';
else
rfsh_int_cntr <= rfsh_int_cntr - 1;
end if;
end if;
end process;

process (clk_i, rst_i)


begin
if rising_edge (clk_i) then
if (rst_i = '1') then
trc_cntr <= "0000";
elsif (current_state = PRE_ST or current_state = REFRESH_ST) then
trc_cntr <= TRC_CNTR_VALUE;
else
trc_cntr <= trc_cntr - 1;
end if;
end if;
end process;

-- counter to control the activate


process (clk_i, rst_i)
begin
if rising_edge (clk_i) then
if (rst_i = '1') then
trcd_cntr <= "000";
elsif (current_state = ACT_ST or current_init_state = INIT_INIT_PRE
or current_init_state = INIT_MODE_REG) then
trcd_cntr <= TRCD_CNTR_VALUE;
else
trcd_cntr <= trcd_cntr - 1;
end if;
end if;
end process;

process (clk_i, rst_i)


begin
if rising_edge (clk_i) then
if (rst_i = '1') then
init_pre_cntr <= "0000";
elsif (current_init_state = INIT_INIT_PRE) then
init_pre_cntr <= init_pre_cntr + 1;
end if;
end if;
end process;

process (clk_i)
begin
if rising_edge (clk_i) then
if (current_init_state = INIT_DONE_ST) then
init_done <= '1';
end if;
end if;
end process;

-- state change
process (clk_i, rst_i)
begin
if rising_edge (clk_i) then
if (rst_i = '1') then
current_init_state <= INIT_IDLE;
else
current_init_state <= next_init_state;
end if;
end if;
end process;

process (clk_i, rst_i)


begin
if rising_edge (clk_i) then
if (rst_i = '1') then
current_state <= IDLE_ST;
else
current_state <= next_state;
end if;
end if;
end process;

-- initialization is fairly easy on this chip: wait 200us then issue


-- 8 precharges before setting the mode register
process (current_init_state)
begin
case current_init_state is
when INIT_IDLE =>
if (init_done = '0') then
next_init_state <= INIT_WAIT_200us;
else
next_init_state <= INIT_IDLE;
end if;

when INIT_WAIT_200us =>


if (wait_200us_cntr = "0000000000000000") then
next_init_state <= INIT_INIT_PRE;
else
next_init_state <= INIT_WAIT_200us;
end if;

when INIT_INIT_PRE =>


next_init_state <= INIT_WAIT_PRE;

when INIT_WAIT_PRE =>


if (trcd_cntr = "000") then -- this is tRP
if (init_pre_cntr = "1000") then
next_init_state <= INIT_MODE_REG;
else
next_init_state <= INIT_INIT_PRE;
end if;
else
next_init_state <= INIT_WAIT_PRE;
end if;

when INIT_MODE_REG =>


next_init_state <= INIT_WAIT_MODE_REG;

when INIT_WAIT_MODE_REG =>


if (trcd_cntr = "000") then -- tRSC
next_init_state <= INIT_DONE_ST;
else
next_init_state <= INIT_WAIT_MODE_REG;
end if;

when INIT_DONE_ST =>


next_init_state <= INIT_IDLE;

when others =>


next_init_state <= INIT_IDLE;
end case;
end process;

-- this is the main controller logic:


process (current_state)
begin
case current_state is
when IDLE_ST =>
if (init_done = '0') then
next_state <= IDLE_ST;
elsif (do_refresh = '1') then
next_state <= REFRESH_ST;
elsif (stb_i_r = '1') then
next_state <= ACT_ST;
else
next_state <= IDLE_ST;
end if;

when REFRESH_ST =>


next_state <= REFRESH_WAIT_ST;

when REFRESH_WAIT_ST =>


if (trc_cntr = "0000") then
next_state <= IDLE_ST;
else
next_state <= REFRESH_WAIT_ST;
end if;

when ACT_ST =>


next_state <= WAIT_ACT_ST;

when WAIT_ACT_ST =>


if (trcd_cntr = "000") then
if (we_i_r = '1') then
next_state <= WRITE0_ST;
else
next_state <= READ0_ST;
end if;
else
next_state <= WAIT_ACT_ST;
end if;

when WRITE0_ST =>


next_state <= WRITE1_ST;

when WRITE1_ST =>


next_state <= WRITE_PRE_ST;

when WRITE_PRE_ST =>


next_state <= PRE_ST;

when READ0_ST =>


next_state <= READ1_ST;

when READ1_ST =>


next_state <= READ2_ST;

when READ2_ST =>


next_state <= READ3_ST;

when READ3_ST =>


next_state <= READ4_ST;

when READ4_ST =>


next_state <= READ_PRE_ST;

when READ_PRE_ST =>


next_state <= PRE_ST;

when PRE_ST =>


next_state <= WAIT_PRE_ST;

when WAIT_PRE_ST =>


-- if the next command was not another row activate in the same bank
-- we could wait tRCD only; for simplicity but at the detriment of
-- efficiency we always wait tRC
if (trc_cntr = "0000") then
next_state <= IDLE_ST;
else
next_state <= WAIT_PRE_ST;
end if;

when others =>


next_state <= IDLE_ST;
end case;
end process;

-- ack_o signal
process (clk_i)
begin
if rising_edge (clk_i) then
if (current_state = READ_PRE_ST or current_state = WRITE_PRE_ST) then
ack_o_r <= '1';
elsif (current_state = WAIT_PRE_ST) then
ack_o_r <= '0';
end if;
end if;
end process;

-- data
process (clk_i, rst_i)
begin
if rising_edge (clk_i) then
if (rst_i = '1') then
dat_o_r <= (others => '0');
dram_dq_r <= (others => '0');
oe_r <= '0';
elsif (current_state = WRITE0_ST) then
dram_dq_r <= dat_i_r(31 downto 16);
oe_r <= '1';
elsif (current_state = WRITE1_ST) then
dram_dq_r <= dat_i_r(15 downto 0);
oe_r <= '1';
elsif (current_state = READ4_ST) then
-- we should actually be reading this on READ3, but
-- because of delay the data comes a cycle later...
dat_o_r(31 downto 16) <= dram_dq;
dram_dq_r <= (others => 'Z');
oe_r <= '0';
elsif (current_state = READ_PRE_ST) then
dat_o_r(15 downto 0) <= dram_dq;
dram_dq_r <= (others => 'Z');
oe_r <= '0';
else
dram_dq_r <= (others => 'Z');
oe_r <= '0';
end if;
end if;
end process;

-- address
process (clk_i)
begin
if rising_edge (clk_i) then
if (current_init_state = INIT_MODE_REG) then
dram_addr_r <= MODE_REGISTER;
elsif (current_init_state = INIT_INIT_PRE) then
-- from page 6 of datasheet of SDRAM chips on DE2-115 board:
-- A10 is sampled during a PRECHARGE command to
-- determine if all banks are to be precharged (A10 HIGH)
-- or bank selected by BA0, BA1 (LOW).
dram_addr_r <= "0010000000000"; -- A[10] = '1' to precharge all
elsif (current_state = ACT_ST) then
dram_addr_r <= address_r(22 downto 10);
dram_bank_r <= address_r(24 downto 23);
elsif (current_state = WRITE0_ST or current_state = READ0_ST) then
-- enter column with bit A10 set to 1 indicating auto precharge;
dram_addr_r <= "001" & address_r(9 downto 0);
dram_bank_r <= address_r(24 downto 23);
else
dram_addr_r <= (others => '0');
dram_bank_r <= "00";
end if;
end if;
end process;

-- commands
process (clk_i)
begin
if rising_edge (clk_i) then
if (current_init_state = INIT_INIT_PRE
or current_init_state = INIT_MODE_REG
or current_state = REFRESH_ST
or current_state = ACT_ST) then
dram_ras_n_r <= '0';
else
dram_ras_n_r <= '1';
end if;

if (current_state = READ0_ST
or current_state = WRITE0_ST
or current_state = REFRESH_ST
or current_init_state = INIT_MODE_REG) then
dram_cas_n_r <= '0';
else
dram_cas_n_r <= '1';
end if;

if (current_init_state = INIT_INIT_PRE
or current_state = WRITE0_ST
or current_init_state = INIT_MODE_REG) then
dram_we_n_r <= '0';
else
dram_we_n_r <= '1';
end if;
end if;
end process;

end my_behavioral;

this is the most important code: DRAM. Generate a DRAM to save the data temporarily

Compile the project and finish the work.


References:

http://www.dejazzer.com/eigenpi/digital_camera/digital_camera.html

Das könnte Ihnen auch gefallen