Written by
Niels Moseley
on
on
Gowin FPGA embedded SDRAM
Introduction
There aren’t many resources on the web that show how to interface to the GOWIN SDRAM controller, especially in VHDL. Make sure the GOWIN SDRAM controller name is ‘SDRAM_controller’. Here is the VHDL example:
-- Top level SDRAM test code for Gowin
-- Version Description
-- 0.1: initial version
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.SDRAM_controller;
entity tec0117_top is
port
(
clk12M : in std_logic;
userbutton : in std_logic;
leds : out std_logic_vector(7 downto 0);
serial_out : out std_logic;
serial_in : in std_logic;
serial_cts_n : in std_logic;
-- sdram IO
O_sdram_clk : out std_logic;
O_sdram_cs_n : out std_logic;
O_sdram_cke : out std_logic;
O_sdram_cas_n : out std_logic;
O_sdram_ras_n : out std_logic;
O_sdram_wen_n : out std_logic;
O_sdram_dqm : out std_logic_vector(1 downto 0);
O_sdram_ba : out std_logic_vector(1 downto 0);
IO_sdram_dq : inout std_logic_vector(15 downto 0);
O_sdram_addr : out std_logic_vector(11 downto 0)
);
end;
architecture rtl of tec0117_top is
signal sdram_in_data : std_logic_vector(15 downto 0);
signal sdram_out_data : std_logic_vector(15 downto 0);
signal sdram_init_done : std_logic;
signal sdram_busy_n : std_logic;
signal sdram_rd_valid : std_logic;
signal sdram_wrd_ack : std_logic;
signal reset_n : std_logic;
signal counter : unsigned(20 downto 0); -- event counter
signal rw_stb : std_logic;
signal counter2: unsigned(7 downto 0); -- memory data counter
type state_t is (S_wait_for_init, S_idle, S_write, S_wait_wr_ack, S_wait, S_read, S_wait2);
signal state : state_t := S_idle;
signal wr_n : std_logic := '1';
signal rd_n : std_logic := '1';
begin
reset_n <= userbutton;
serial_out <= '1';
u_sdram: entity work.SDRAM_controller(beh)
port map
(
O_sdram_clk => O_sdram_clk,
O_sdram_cke => O_sdram_cke,
O_sdram_cs_n => O_sdram_cs_n,
O_sdram_cas_n => O_sdram_cas_n,
O_sdram_ras_n => O_sdram_ras_n,
O_sdram_wen_n => O_sdram_wen_n,
O_sdram_dqm => O_sdram_dqm,
O_sdram_addr => O_sdram_addr,
O_sdram_ba => O_sdram_ba,
IO_sdram_dq => IO_sdram_dq,
I_sdrc_rst_n => userbutton,
I_sdrc_clk => clk12M,
I_sdram_clk => not clk12M,
I_sdrc_selfrefresh => '0',
I_sdrc_power_down => '0',
I_sdrc_wr_n => wr_n,
I_sdrc_rd_n => rd_n,
I_sdrc_addr => (others => '0'),
I_sdrc_data_len => (others => '0'), -- one word
I_sdrc_dqm => "00",
I_sdrc_data => sdram_in_data,
O_sdrc_data => sdram_out_data,
O_sdrc_init_done => sdram_init_done,
O_sdrc_busy_n => sdram_busy_n,
O_sdrc_rd_valid => sdram_rd_valid,
O_sdrc_wrd_ack => sdram_wrd_ack
);
proc_pulser: process(clk12M)
begin
if rising_edge(clk12M) then
if (reset_n = '0') then
counter <= (others => '0');
rw_stb <= '0';
else
rw_stb <= '0';
counter <= counter + 1;
if (counter = 0) then
rw_stb <= '1';
end if;
end if;
end if;
end process proc_pulser;
proc_rw: process(clk12M)
begin
if rising_edge(clk12M) then
if (reset_n = '0') then
counter2 <= (others => '0');
state <= S_wait_for_init;
else
case state is
when S_wait_for_init =>
if (sdram_init_done = '1') then
state <= S_idle;
end if;
when S_idle =>
if (rw_stb = '1') then
state <= S_write;
end if;
when S_write =>
sdram_in_data <= std_logic_vector(counter2 & counter2);
wr_n <= '0';
counter2 <= counter2 + 1;
state <= S_wait_wr_ack;
when S_wait_wr_ack =>
wr_n <= '1';
if (sdram_busy_n = '0') then
state <= S_wait;
end if;
when S_wait =>
if (sdram_busy_n = '1') then
rd_n <= '0';
state <= S_read;
end if;
when S_read =>
rd_n <= '1';
if (sdram_rd_valid = '1') then
leds <= sdram_out_data(7 downto 0);
state <= S_wait2;
end if;
when S_wait2 =>
if (sdram_busy_n = '1') then
state <= S_idle;
end if;
end case;
end if;
end if;
end process proc_rw;
end rtl;
The .cst file:
// Board: Trenz Electronics TEC0117
IO_LOC "clk12M" 35;
IO_PORT "clk12M" IO_TYPE=LVTTL33 PULL_MODE=UP;
IO_LOC "userbutton" 77;
IO_PORT "userbutton" IO_TYPE=LVTTL33 PULL_MODE=UP;
/*
FT2232H-56Q BDBUS pins:
BDBUS0 pin 16 TXD (out from FT2232)
BDBUS1 pin 15 RXD (in)
BDBUS2 pin 14 RTS_n (out)
BDBUS3 pin 13 CTS_n (in)
BDBUS4 pin 11 DTR_n (out)
*/
// naming w.r.t the CPU
IO_LOC "serial_out" 15;
IO_PORT "serial_out" IO_TYPE=LVTTL33;
IO_LOC "serial_in" 16;
IO_PORT "serial_in" IO_TYPE=LVTTL33;
IO_LOC "serial_cts_n" 14;
IO_PORT "serial_cts_n" IO_TYPE=LVTTL33;
IO_LOC "leds[0]" 86;
IO_PORT "leds[0]" IO_TYPE=LVTTL33;
IO_LOC "leds[1]" 85;
IO_PORT "leds[1]" IO_TYPE=LVTTL33;
IO_LOC "leds[2]" 84;
IO_PORT "leds[2]" IO_TYPE=LVTTL33;
IO_LOC "leds[3]" 83;
IO_PORT "leds[3]" IO_TYPE=LVTTL33;
IO_LOC "leds[4]" 82;
IO_PORT "leds[4]" IO_TYPE=LVTTL33;
IO_LOC "leds[5]" 81;
IO_PORT "leds[5]" IO_TYPE=LVTTL33;
IO_LOC "leds[6]" 80;
IO_PORT "leds[6]" IO_TYPE=LVTTL33;
IO_LOC "leds[7]" 79;
IO_PORT "leds[7]" IO_TYPE=LVTTL33;