Altera_Forum
Honored Contributor
13 years agoSDRAM Framebuffer with two asynchronous clocks
Hi,
I want to build up a universal display tester using the DE2-115 Board. First of all I've tried to use the altera video IP, but this was quite complex, so I decided to build all blocks on my own. The two main components are a configurable video signal generator and a 'smart' fifo which is connected to a sdram of the avalon bus. The signal generator has a pixel clock (rd_clk) and needs to get new data synchronously to this clock. The fifo has to ensure that the signal generator gets his data without any interrupts – except the 'invisible area' of the display. It consists of an altera megafunction dual clock fifo, a avalon interface to the sdram controller and a logic which requests bursts to keep the fifo filled (see the attached code). The logic has to count the pixel\address as well. After the last pixel it resets the address and starts with the first pixel. The logic runs at 100Mhz. So far, so good. I've tested this system with 640x480 at 25MHz, 800x600 at 50MHz and 1024x768 at 65MHz. I derive the pixel clock from the main clk(100Mhz) using a pll. When I use frequencies like 25,50,65 Mhz then everything works perfectly. My Problem is, when I use frequencies like 24.94MHz or 33.6MHz (so that they are completely asynchronous to the main clk) then the fifo component fails. The signal generator still works, but it doesn't get any data at all. Has anybody an idea why this happens? I'm a vhdl beginner, so please excuse my amateur code:)! Thanks in advance!
LIBRARY ieee;
USE ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;
entity fifo is
port
(
-- Fifo Interface
signal clk_rd : in std_logic;
signal read_enable : in std_logic;
signal data_out : out std_logic_vector(31 downto 0);
signal full : out std_logic;
signal empty : out std_logic;
signal base_address : in std_logic_vector(31 downto 0);
-- Avalon Interface
signal reset : in std_logic := '0';
signal clk : in std_logic := '0';
signal address : out std_logic_vector(31 downto 0):= (others => '0');
signal read : out std_logic := '1';
signal readdatavalid : in std_logic := '0';
signal readdata : in std_logic_vector(31 downto 0) := (others => '0');
signal waitrequest : in std_logic := '1';
signal burstcount : out std_logic_vector(7 downto 0) := "00000000";
-- Debug Interface
signal debug_in : in std_logic_vector(63 downto 0);
signal debug_out : out std_logic_vector(63 downto 0)
);
end entity;
architecture fifo_a of fifo is
constant buffer_size : integer := 30000;
constant total_pixels: integer := 1024 * 768;
subtype counter is integer range 0 to 65535;
signal cnt_wr : std_logic_vector(14 downto 0) := (others => '0');
signal cnt_rd : std_logic_vector(14 downto 0) := (others => '0');
type t_state is
(
s_reset,
s_idle,
s_wait,
s_request_burst,
s_finish
);
signal read_state : t_state := s_reset;
component fifotest IS
PORT
(
aclr : IN STD_LOGIC := '0';
data : IN STD_LOGIC_VECTOR (31 DOWNTO 0);
rdclk : IN STD_LOGIC ;
rdreq : IN STD_LOGIC ;
wrclk : IN STD_LOGIC ;
wrreq : IN STD_LOGIC ;
q : OUT STD_LOGIC_VECTOR (31 DOWNTO 0);
rdempty : OUT STD_LOGIC ;
rdusedw : OUT STD_LOGIC_VECTOR (14 DOWNTO 0);
wrfull : OUT STD_LOGIC ;
wrusedw : OUT STD_LOGIC_VECTOR (14 DOWNTO 0)
);
END component fifotest;
begin
c0: fifotest
port map
(
aclr => debug_in(0), --last visible Pixel clears
data => readdata,
wrclk => clk,
wrfull => debug_out(9),
wrusedw => cnt_wr,
wrreq => readdatavalid,
rdclk => clk_rd,
rdreq => read_enable,
q => data_out,
rdempty => debug_out(8),
rdusedw => cnt_rd
);
p0: process( clk, reset, waitrequest, readdata, readdatavalid )
variable pixels_left : integer := 0;
variable addr_cnt : integer := 0;
variable need_burst : std_logic := '0';
variable burst_length : counter := 0;
variable addr_offset : counter := 0;
variable read_cnt : counter := 0;
begin
if ( reset = '1' ) then
pixels_left := 0;
read_cnt := 0;
addr_cnt := 0;
read_state <= s_idle;
elsif ( clk'event and clk = '1' ) then -- Auf steigende Flanke triggern
-- liegen gültige Daten an...?
if readdatavalid = '1' then --> ... dann wurden diese gerade eingelesen (unten)
read_cnt := read_cnt - 1; --> Anzahl der ausstehenden Daten verringern.
end if;
case read_state is
when s_idle =>
if debug_in(0) = '1' then
read_state <= s_wait;
read_cnt := 0;
end if;
when s_wait =>
-- Werte initialisieren
burst_length := 0;
addr_offset := 0;
burstcount <= "00000000";
need_burst := '1';
if pixels_left >= 128 then
burst_length := 128;
addr_offset := 512;
burstcount <= "10000000"; -- 128
elsif pixels_left >= 64 then
burst_length := 64;
addr_offset := 256;
burstcount <= "01000000"; -- 64
elsif pixels_left >= 32 then
burst_length := 32;
addr_offset := 128;
burstcount <= "00100000"; -- 32
elsif pixels_left >= 16 then
burst_length := 16;
addr_offset := 64;
burstcount <= "00010000"; -- 16
elsif pixels_left >= 8 then
burst_length := 8;
addr_offset := 32;
burstcount <= "00001000"; -- 8
elsif pixels_left >= 4 then
burst_length := 4;
addr_offset := 16;
burstcount <= "00000100"; -- 4
elsif pixels_left >= 2 then
burst_length := 2;
addr_offset := 8;
burstcount <= "00000010"; -- 2
elsif pixels_left = 1 then
burst_length := 1;
addr_offset := 4;
burstcount <= "00000001"; -- 1
elsif pixels_left = 0 then
need_burst := '0';
addr_cnt := conv_integer(base_address);
pixels_left := total_pixels;
end if;
if ( need_burst = '1' ) then
if ( (cnt_wr + read_cnt) <= (buffer_size - burst_length) ) then -- Ist noch Platz im Puffer?
-- Ja
addr_cnt := addr_cnt + addr_offset; -- Adresse erhöhen
pixels_left := pixels_left - burst_length; -- Anzahl der verbleibenden Pixel verringern
read_state <= s_request_burst; -- Nächsten Burst anfordern ...
read_cnt := read_cnt + burst_length; -- ... und Anzahl der ausstehenden Daten erhöhen
else -- Nein
read_state <= s_wait; -- Hier warten
end if;
else
read_state <= s_finish;
end if;
when s_request_burst =>
if waitrequest /= '1' then -- Müssen wir warten?
-- Nein: Somit wurde gerade ein Burst angefordert!
read_state <= s_wait; -- Hier warten
else
read_state <= s_request_burst;
end if;
when s_finish =>
if read_cnt = 0 then
read_state <= s_idle;
else
read_state <= s_finish;
end if;
when others =>
--read_state <= s_reset;
end case;
-- Avalon-Interface aktualisieren
address <= conv_std_logic_vector(addr_cnt,32);
end if;
end process p0;
read <= '1' when read_state = s_request_burst else '0';
end architecture;