Dualhead MCB Frame Buffer

From Hamsterworks Wiki!

Jump to: navigation, search

This FPGA Project was completed April 2013.

Dualhead mcb framebuffer.jpg

Building on my MCB Frame Buffer and dvid_test projects this adds DVI-D output, allowing the signal to display the same image on both a analogue VGA and DVI-D/HDMI monitor at the same time. I'm using the Pipistrello development board and the LogicStart Megawing for the anlogue output.

The sharp-eyed will notice that the Red and Green channels are swaped in the photo above. As soon as I work out which is correct I'll fix it!

Contents

Source files

Rather than posting all the source on this page, here is a ZIP archive of everything other than the MIG-generated files for the MCB.

File:Dualhead mcb frame buffer.zip

I am not able to include the MCB code as it I don't have ownership of the generated code, but here is how to do it.

Generating the mem32 memory interface

Generate the "mem32" component using the Xilinx Memory Interface Generator, as per the instructions and screenshots in MCB Frame Buffer.

Once generated, remove the IP core from the design, and then find and add the following source files into your project

  • All the VHD files from ipcore_dir\mem32\user_design\rtl
  • mem32.ucf from ipcoredir\mem32\user_design\par

Customising the MCB clocking

The default clocking generated by the Memory Interface Generator is

ADV_PLL Port Signal Speed Phase Use
CLKOUT0 clk_2x_0 100MHz 0 Memory Clock
CLKOUT1 clk_2x_180 100MHz 180 Memory Clock, inverted
CLKOUT2 clk0_bufg_in 33MHz 0 User Clock
CLKOUT3 mcb_drp_clk_bufg_in 75MHz 0 Memory calibration clock
CLKOUT4 clk1_bufg_in, N/A 0 Not used
CLKOUT5 clk2_bufg_in N/A 0 Not used

This needs to be modified to generate the following:

ADV_PLL Port Signal Speed Phase Use
CLKOUT0 clk_2x_0 150MHz 0 Memory clock
CLKOUT1 clk_2x_180 150MHz 180 Memory clock, inverted
CLKOUT2 clk0_bufg_in 75MHz 0 Pixel clock
CLKOUT3 mcb_drp_clk_bufg_in 75MHz 0 Memory calibration clock
CLKOUT4 clk1_bufg_in, 375MHz 0 DVI-D DDR bit clock
CLKOUT5 clk2_bufg_in 375MHz 0 DVI-D DDR bit clock, inverted

If done correctly in simulation the clocks should look like this:

Mcb clocking.jpg

Changes for mem32.vhd

I'm sorry but the bold attribute doesn't show up too well on code - most of these code blocks are two line to be added between the top and bottom lines.

Add c3_clk1 and c3_clk1 to the mem32 entity statements:

  c3_clk0                                 : out std_logic;
  c3_clk1                                 : out std_logic;
  c3_clk2                                 : out std_logic;
  c3_rst0                                 : out std_logic;

Add C_CLKOUT4_DIVIDE and C_CLKOUT5_DIVIDE to the component generic list for "memc3_infrastructure":

     C_CLKOUT3_DIVIDE     : integer;
     C_CLKOUT4_DIVIDE     : integer;
     C_CLKOUT5_DIVIDE     : integer;
     C_CLKFBOUT_MULT      : integer;


Add clk1 and clk2 to the component port list for "memc3_infrastructure":

     clk0                                   : out   std_logic;
     clk1                                   : out   std_logic;
     clk2                                   : out   std_logic;
     rst0                                   : out   std_logic;

Add C3_CLKOUT4_DIVIDE and C3_CLKOUT4_DIVIDE in the constants, and then set the constants as follows:

  constant C3_CLKOUT0_DIVIDE       : integer := 5;  -- 150 MHz
  constant C3_CLKOUT1_DIVIDE       : integer := 5;  -- 150 MHz
  constant C3_CLKOUT2_DIVIDE       : integer := 10; --  75 MHz
  constant C3_CLKOUT3_DIVIDE       : integer := 10; --  75 MHz
  constant C3_CLKOUT4_DIVIDE       : integer := 2;  -- 375 MHz 
  constant C3_CLKOUT5_DIVIDE       : integer := 2;  -- 375 MHz
  constant C3_CLKFBOUT_MULT        : integer := 15; -- 750 MHz

In the declaration of memc3_infrastructure_inst add the generic mappings:

  C_CLKOUT3_DIVIDE                  => C3_CLKOUT3_DIVIDE,
  C_CLKOUT4_DIVIDE                  => C3_CLKOUT4_DIVIDE,
  C_CLKOUT5_DIVIDE                  => C3_CLKOUT5_DIVIDE,
  C_CLKFBOUT_MULT                   => C3_CLKFBOUT_MULT,

Add clk1 and clk2 to the ports of memc3_infrastructure_inst

  clk0                            => c3_clk0,
  clk1                            => c3_clk1,
  clk2                            => c3_clk2,
  rst0                            => c3_rst0,

Changes for memc3_infrastructure.vhd

Add the generics for C_CLKOUT4_DIVIDE and C_CLKOUT5_DIVIDE to the memc3_infrastructure entity. Don't worry about the default assignment:

   C_CLKOUT3_DIVIDE   : integer := 8;
   C_CLKOUT4_DIVIDE   : integer := 8;
   C_CLKOUT5_DIVIDE   : integer := 8;
   C_CLKFBOUT_MULT   : integer := 12;

Add the 'clk1' and 'clk2' ports:

   clk0            : out std_logic;
   clk1            : out std_logic;
   clk2            : out std_logic;
   rst0            : out std_logic;

Add the following signals so we can buffer the clk1 and clk2 clocks:

 signal   clk0_bufg_in        : std_logic;
 signal   clk1_bufg           : std_logic;
 signal   clk1_bufg_in        : std_logic;
 signal   clk2_bufg           : std_logic;
 signal   clk2_bufg_in        : std_logic;
 signal   mcb_drp_clk_bufg_in : std_logic;

Add the two assignment statements to connect clk1_bufg and clk2_bufg to the output pins;

 clk0     <= clk0_bufg;
 clk1     <= clk1_bufg;
 clk2     <= clk2_bufg;
 pll_lock <= bufpll_mcb_locked;

Set the generic assignments for the u_pll_adv instance:

        CLKOUT3_DIVIDE     => C_CLKOUT3_DIVIDE,
        CLKOUT4_DIVIDE     => C_CLKOUT4_DIVIDE,
        CLKOUT5_DIVIDE     => C_CLKOUT5_DIVIDE,
        CLKOUT0_PHASE      => 0.000,

Most important! Set the CLKOUT5_PHASE generic for u_pll_adv to 180 degrees:

        CLKOUT4_PHASE      => 0.000,
        CLKOUT5_PHASE      => 180.000,
        CLKOUT0_DUTY_CYCLE => 0.500,

Add the signal mapping for u_pll_adv's CLKOUT4 and CLKOUT5 output:

          CLKOUT3          => mcb_drp_clk_bufg_in,
          CLKOUT4          => clk1_bufg_in,
          CLKOUT5          => clk2_bufg_in,
          DO               => open,

And after U_BUFG_CLK0 add two new global buffers. Sorry about the inconsistent instance name, but U_BUFG_CLK1 is already taken:

   U_BUFG_CLK4 : BUFG port map ( O => clk1_bufg, I => clk1_bufg_in);
   U_BUFG_CLK5 : BUFG port map ( O => clk2_bufg, I => clk2_bufg_in);

In mem32.ucf

The following constraints need to be commented out, as the nets that the reference are optimized out of the design:

# NET "memc?_wrapper_inst/memc?_mcb_raw_wrapper_inst/selfrefresh_mcb_mode" TIG;
# NET "c?_pll_lock" TIG;

Just before those two lines, add the full path to the memory controller ("inst_mem_wrapper/u_mem32/") to the instance name:

INST "inst_mem_wrapper/u_mem32/memc?_wrapper_inst/memc?_mcb_raw_wrapper_inst/gen_term_calib.mcb_soft_calibration_top_inst/mcb_soft_calibration_inst/DONE_SOFTANDHARD_CAL*" TIG;

Comment out the following two constraints, as the are derived:

 # NET "memc3_infrastructure_inst/sys_clk_ibufg" TNM_NET = "SYS_CLK3";
 # TIMESPEC "TS_SYS_CLK3" = PERIOD "SYS_CLK3"  20  ns HIGH 50 %;

Comment out the following lines, as they are not connected externally:

# NET  "c3_sys_clk"                                  IOSTANDARD = LVCMOS25;
# NET  "c3_sys_rst_i"                                IOSTANDARD = LVCMOS18;

And finally comment out these two constraints, which are also not connected externally:

# NET  "c3_sys_clk"                                LOC = "R10" ;
# NET  "c3_sys_rst_i"                              LOC = "M8" ;

There! Done.

Personal tools