Access to SDRAM on Altera Cyclone dev kit - compactflash controller

F

fanf

Hello,

(I'm a beginner in vhdl programmation, so excuse me if my questions seem
trivial.)

I have to create a VHDL design witch runs on altera's cyclone FPGA. To
do that, I use your microtronix dev board, but not the SOPC builder
components.
The goal of the design is to create a data storage box, a kind of hard
disk where the disk is replaced by some SDRAM and a Compact Flash Card.

Does somebody know where I could find doc about this topic ? I mean, doc
about making a controller for a Compact Flash Card (it should have be
done yet),
managing read/write between flash card/sdram/controller of the
datastorage in an efficient way, etc.

I also want to be able to read/write in SDRAM and for that, I use the
Altera's SDRAM controller found here :
http://www.altera.com/products/ip/iup/memory/m-alt-sdr-sdram.html
I create a state machine to interface the SDRAM's controller and the
others part of the design. This state machine manages sdram
initialisation, and read/write queries.
All simulations work fine, but when I load my code on the board, it does
not work.
I thought it was a problem with the use of onboard clocks, but it seems
that there is something else : an other design which only made two write
statement and then alternatively read each one works fine.
I really don't know what might be the source of the problem, so what are
the things I have to check ? Are there frequently done mistakes in using
this SDRAM controller ? (I join my broken code and the working one)

I also want to split my big state machine in several parts which are
semantically consistant : one for the init, an other for reading
queries, etc. And I don't know how to
handle this problem. What is 'the right way' to do this in vhdl ?

Many thanks


--------------------------------------------------------------------------------
Working design
--------------------------------------------------------------------------------
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;

ENTITY sdramInit IS
GENERIC (
NOP_TIME : integer := 2;
CONSTANT C_NOP : std_logic_vector (2 DOWNTO 0) := "000";
CONSTANT C_PRECHARGE : std_logic_vector (2 DOWNTO 0) := "100";
CONSTANT C_REFRESH : std_logic_vector (2 DOWNTO 0) := "011";
CONSTANT C_LOAD_MODE : std_logic_vector (2 DOWNTO 0) := "101";
CONSTANT C_LOAD_REG1 : std_logic_vector (2 DOWNTO 0) := "110";
CONSTANT C_LOAD_REG2 : std_logic_vector (2 DOWNTO 0) := "111"
);
PORT (
clk : IN std_logic;
data_to_mp : IN std_logic_vector (31 DOWNTO 0);
rst_1 : IN std_logic;
ack_to_mp : IN std_logic;
data_to_sd : OUT std_logic_vector (31 DOWNTO 0);
cmd_to_sd : OUT std_logic_vector (2 DOWNTO 0);
adresse_to_sd : OUT std_logic_vector (22 DOWNTO 0);
dm_to_sd : OUT std_logic_vector (3 DOWNTO 0);
data_to_7seg : OUT std_logic_vector (6 DOWNTO 0);
led1 : OUT std_logic;
led2 : OUT std_logic);

END sdramInit;


ARCHITECTURE archi OF sdramInit IS
TYPE TYPE_STATE IS (reset,
nop,
precharge, prechargeNop,
loadmode, loadmodeNop,
load_reg2, load_reg2Nop,
load_reg1, load_reg1Nop,
refresh1,
refresh2,
ecriture,
ecriture2,
lecture,
lecture2,
fin,
wait1,
wait2,
wait0,
fetch1,
fetch2,
nopn,
nopn1,
nopn2,
nopn3);
SIGNAL etat : TYPE_STATE;
SIGNAL counter : integer RANGE 0 TO 255;
signal nccounter : integer range 0 to 100000000;

BEGIN -- archi

PROCESS (clk, rst_1)
BEGIN -- PROCESS
IF rst_1 = '0' THEN -- asynchronous reset (active low)
etat <= reset;
cmd_to_sd <= C_NOP;
adresse_to_sd <= "00000000000000000000000";
data_to_sd <= "00000000000000000000000000000000";
dm_to_sd <= "1100";
counter <= 0;
led1 <= '0';
led2 <= '0';
nccounter <= 0;
ELSIF clk'event AND clk = '1' THEN -- rising clock edge

CASE etat IS
WHEN reset => etat <= nop;
counter <= 0;
WHEN nop => cmd_to_sd <= C_NOP;
IF counter = NOP_TIME THEN
etat <= precharge;
counter <= 0;
ELSE
etat <= nop;
counter <= counter + 1;
END IF;
WHEN precharge => IF ack_to_mp = '1' THEN
etat <= prechargeNop;
ELSE
cmd_to_sd <= C_PRECHARGE;
etat <= precharge;
END IF;
WHEN prechargeNop => cmd_to_sd <= C_NOP;
etat <= loadmode;
WHEN loadmode => IF ack_to_mp = '1' THEN
etat <= loadmodeNop;
ELSE
cmd_to_sd <= C_LOAD_MODE;
adresse_to_sd <= "00000000000001000010000";
-- a10 : reserved = 0
-- a9 : Write Burst = 1 (single location access)
-- a8-7 : Op mode 00
-- a6-4 : CAS latency : 001 ( 1 )
-- a3 : BT 0 ( sequential )
-- a2-0 : busrt length 000 ( 1 )
etat <= loadmode;
END IF;
WHEN loadmodeNop => cmd_to_sd <= C_NOP;
etat <= load_reg2;
WHEN load_reg2 => IF ack_to_mp = '1' THEN
etat <= load_reg1;
ELSE
cmd_to_sd <= C_LOAD_REG2;
-- adresse_to_sd <= "00000000000011000011010"; -- 1562 c'est pour
100 MHz
adresse_to_sd <= "00000000000001000000000"; -- 521 c'est pour 33
MHz

etat <= load_reg2;
END IF;
-- WHEN load_reg2Nop => cmd_to_sd <= C_NOP;
-- etat <= load_reg1;
WHEN load_reg1 => IF ack_to_mp = '1' THEN
etat <= refresh1;
ELSE
cmd_to_sd <= C_LOAD_REG1;
-- adresse_to_sd <= "00000000000001001101101"; -- old value
adresse_to_sd <= "00000000000001000101001";
-- a12-9 : burst lenght : 0001
-- a8 : sdram controller mode : 0 (normal)
-- a7-4 : refresh command duration in clocks ???? t rrd = 14 ns
/ 30 ns
-- a3-2 : ras to cas in number of clocks ??? trcd = 20 ns / 30
ns ? -- bizarrement, marche bcp mieux avec une valeur de 2
-- a1-0 : cas latency : 1
etat <= load_reg1;
END IF;
-- WHEN load_reg1Nop => cmd_to_sd <= C_NOP;
-- etat <= refresh1;
WHEN refresh1 => IF ack_to_mp = '1' THEN
cmd_to_sd <= C_NOP;
etat <= refresh2;
ELSE
cmd_to_sd <= C_REFRESH;
etat <= refresh1;
END IF;
WHEN refresh2 => IF ack_to_mp = '1' THEN
cmd_to_sd <= C_NOP;
etat <= nopn;
ELSE
cmd_to_sd <= C_REFRESH;
etat <= refresh2;
END IF;
when nopn => cmd_to_sd <="000";
etat <= nopn1;

when nopn1 => cmd_to_sd <="000";
etat <= nopn2;
when nopn2 => cmd_to_sd <="000";
etat <= nopn3;
when nopn3 => cmd_to_sd <="000";
etat <= ecriture;

WHEN ecriture => cmd_to_sd <= "010";
data_to_sd <= "00000000000000000000000011111001";
adresse_to_sd <= "00000000000000000000000";
IF ack_to_mp = '1' THEN
etat <= wait0;
ELSE
etat <= ecriture;
END IF;
WHEN wait0 => cmd_to_sd <= "000";


if nccounter<9 then
nccounter <= nccounter +1;
etat <= wait0;
else
nccounter <= 0;
etat <= ecriture2;
end if;
WHEN ecriture2 => cmd_to_sd <= "010";
data_to_sd <= "00000000000000000000000000001111";
adresse_to_sd <= "00000000000000000000001";
IF ack_to_mp = '1' THEN
etat <= wait2;
ELSE
etat <= ecriture2;
END IF;
WHEN lecture => cmd_to_sd <= "001";
led1 <= '1';
led2 <= '0';
adresse_to_sd <= "00000000000000000000000";
IF ack_to_mp = '1' THEN

etat <= fetch1;
ELSE
etat <= lecture;
END IF;

WHEN fetch1 =>cmd_to_sd <= "000";
-- wait RCD + CL + 2 = 1 + 20 ns + 2clk = 3 clk
if nccounter<2 then
nccounter <= nccounter +1;
etat <= fetch1;
else
data_to_7seg <= data_to_mp (6 DOWNTO 0);
nccounter <= 0;
etat <= wait1;
end if;


WHEN wait1 =>
if nccounter<4000000 then
nccounter <= nccounter +1;
etat <= wait1;
else
nccounter <= 0;

etat <= lecture2;
end if;

WHEN lecture2 => cmd_to_sd <= "001";
led1 <= '0';
led2 <= '1';
adresse_to_sd <= "00000000000000000000001";
IF ack_to_mp = '1' THEN
-- data_to_7seg <= data_to_mp (6 DOWNTO 0);
etat <= fetch2;
ELSE
etat <= lecture2;
END IF;
WHEN fetch2 =>cmd_to_sd <= "000";
-- wait RCD + CL + 2 = 1 + 20 ns + 2clk = 3 clk
if nccounter<2 then
nccounter <= nccounter +1;
etat <= fetch2;
else
data_to_7seg <= data_to_mp (6 DOWNTO 0);
nccounter <= 0;
etat <= wait2;
end if;

WHEN wait2 =>
cmd_to_sd <= "000";
if nccounter<4000000 then
nccounter <= nccounter +1;
etat <= wait2;
else
nccounter <= 0;
etat <= lecture;
end if;

WHEN fin => etat <= fin;
WHEN OTHERS => NULL;
END CASE;
END IF;
END PROCESS;

END archi;

---------------------------------------------------------------------------------
My design
---------------------------------------------------------------------------------

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;


-- Module SdramInterface

-- Fonctionnal description :
-- this module is an interface between the sdram controller and others
parts
-- of the design (say "ext").
-- Its goal is to manage sdram initialisation and read/write queries.
-- It implements a state machine with 4 main states :
-- - initialisation of the SDRAM,
-- - wait for a command,
-- - write on SDRAM and
-- - read on SDRAM

ENTITY sdramInterface is
GENERIC (

-- command to the SDRAM controller
CONSTANT C_NOP : std_logic_vector (2 DOWNTO 0) := "000";
CONSTANT C_init_precharge : std_logic_vector (2 DOWNTO 0) := "100";
CONSTANT C_REFRESH : std_logic_vector (2 DOWNTO 0) := "011";
CONSTANT C_init_load_mode : std_logic_vector (2 DOWNTO 0) := "101";
CONSTANT C_init_load_reg1 : std_logic_vector (2 DOWNTO 0) := "110";
CONSTANT C_init_load_reg2 : std_logic_vector (2 DOWNTO 0) := "111";
constant C_WRITEA : std_logic_vector (2 DOWNTO 0) := "010";
constant C_READEA : std_logic_vector (2 DOWNTO 0) := "001";

-- commands from/to ext
constant READ_OK : std_logic_vector (1 DOWNTO 0) := "01";
constant READ_MODE : std_logic_vector (1 DOWNTO 0) := "01";
constant WRITE_OK : std_logic_vector (1 DOWNTO 0) := "10";
constant WRITE_MODE : std_logic_vector (1 DOWNTO 0) := "10";

-- Parameter of the sdram
constant ASIZE : integer := 23; -- adress size
constant DSIZE : integer := 32; -- data size
constant DSIZE_sur_8 : integer := 4; -- data mask size
constant BL : integer := 1; --burst lengh
constant TL_W : integer := 1; --latence time on a write command
constant TL_R : integer := 4; --latence time on a read command

-- conf of sdram chip (load_mode command)
-- a10 : reserved : 0
-- a9 : Write Burst : 0
-- a8-7 : op mode : 00
-- a6-4 : CAS latency : 001 ( 1 )
-- a3 : BT : 0 ( sequential )
-- a2-0 : busrt length : 000 ( 1 )
constant CONF_init_load_mode : std_logic_vector (22 downto 0) :=
"00000000000000000010000";

-- Config of REG1 : altera controller parameter
-- a12-9 : burst lenght : 0001
-- a8 : sdram controller mode : 0 (normal)
-- a7-4 : refresh command duration in clocks : t(rrd)/clock period =
14 ns / 30.5 ns = 1 (??)
-- a3-2 : ras to cas (rcd) in number of clocks : t(rcd)/clock period
= 20 ns / 30.5 ns (? idem, 1 ?)
-- a1-0 : cas latency : 01
constant CONF_REG1 : std_logic_vector (22 downto 0) :=
"00000000000001000101001";


-- Config de REG2 : period beetwin refresh
-- value is obtained by the calcul 15.625us/T, where T is clock period
(in micro second)
-- constant CONF_REG2 : std_logic_vector (ASIZE-1 downto 0) :=
"00000000000011000011010" -- 1562 when clock= 100 MHz, T = 0.01 us
constant CONF_REG2 : std_logic_vector (22 downto 0) :=
"00000000000001000000000" -- 512 when clock= 32.768 MHz, T = .0305us

);

PORT (
-- NOTATION :
-- what is transfered to ext is prefixed by _ext_
-- what is transfered to the controller is prefixed by _cont_
clk : IN std_logic;
rst_n : IN std_logic;
-- to/from extr
i_ext_donnees : IN std_logic_vector (DSIZE-1 DOWNTO 0); --data from
ext (data to write on SDRAM)
i_ext_masqueEcriture : std_logic_vector (DSIZE_sur_8 - 1 downto 0);
--data mask
i_ext_adresse : in std_logic_vector (ASIZE-1 downto 0); --adress
i_ext_demande_rw : in std_logic_vector (1 downto 0); --ext queries
o_ext_donnees : OUT std_logic_vector (DSIZE-1 DOWNTO 0); --data to
ext (data read from SDRAM)
o_ext_sdram_ready : OUT std_logic; --wait for read/write
o_ext_rw_ok : out std_logic_vector (1 downto 0); -- ack read/write
o_ext_erreur : out std_logic; --error
-- to/from the controller
i_cont_donnees : IN std_logic_vector (DSIZE-1 DOWNTO 0); -- data
from the controller (data read on SDRAM)
i_cont_accuseCommande : IN std_logic; -- command to controller ack
o_cont_donnees : OUT std_logic_vector (DSIZE-1 DOWNTO 0); -- data
to the controller (data to write on SDRAM)
o_cont_commande : OUT std_logic_vector (2 DOWNTO 0); -- command to
the controller
o_cont_adresse : OUT std_logic_vector (ASIZE-1 DOWNTO 0); -- adress
o_cont_masqueEcriture : OUT std_logic_vector (DSIZE_sur_8 - 1
DOWNTO 0) -- mask

);

end sdramInterface;

--/////////////////////////////////////////////////////////////////////////////////////////////////////////////--


ARCHITECTURE archi OF sdramInterface is

type type_etatProcessPrincipal is (
etat_reset, etat_erreur,
-- init states
init_attente_stab,
init_precharge, init_prechargeNop,
init_load_mode, init_load_modeNop,
init_load_reg1, init_load_reg2,
init_refresh1, init_refresh2,
init_2nop,
-- wait command state
etat_attente_instruction,
-- read states
ecriture_init,
ecriture_attente_latence,
ecriture_boucle_donnees,
-- write states
lecture_init,
lecture_attente_latence,
lecture_boucle_donnees
);
signal etat_suivant : type_etatProcessPrincipal;

signal compteur_ecriture : integer range 0 to TL_W; -- write latence
counter
signal compteur_lecture : integer range 0 to TL_R; --read latence counter
signal compteur_bl : integer range 0 to BL; -- burst lenght counter
signal i : integer range 0 to 3000; -- init counter

-- register
signal reg_o_ext_donnees : std_logic_vector (DSIZE-1 downto 0);
signal reg_o_cont_donnees : std_logic_vector (DSIZE-1 downto 0);
signal reg_o_cont_masqueecriture : std_logic_vector (3 downto 0);
signal reg_o_cont_adresse : std_logic_vector (ASIZE-1 downto 0);

BEGIN -- archi

process (clk, rst_n)

variable num_ecriture : std_logic;

begin
if rst_n = '0' then -- asynchronous reset, active low
etat_suivant <= init_attente_stab;
compteur_ecriture <= 0;
compteur_lecture <= 0;
compteur_bl <= 0;
i <= 0;
--to/from cont
o_cont_commande <= C_NOP;
reg_o_cont_adresse <= (others => '0');
reg_o_cont_donnees <= (others => '0');
reg_o_cont_masqueEcriture <= (others => '0');
--to/from ext
reg_o_ext_donnees <= (others => '0');
o_ext_rw_ok <= "00";
elsif clk'event and clk = '1' then

case etat_suivant is

--*******************************************************************************************

-- State to manage the micron SDRAM chip and altera controller
--
-- o_cont_adresse is the bus to pass the config parameter
--*******************************************************************************************


when init_attente_stab =>
o_cont_commande <= C_NOP;
if i < 3000 then --wait 100 us, ie 30*100 clk
o_cont_commande <= C_NOP;
i <= i + 1;
etat_suivant <= init_attente_stab;
else
etat_suivant <= init_precharge;
end if;

when init_precharge =>
if i_cont_accuseCommande = '1' then
o_cont_commande <= C_NOP;
etat_suivant <= init_prechargeNop;
else
o_cont_commande <= C_init_precharge;
etat_suivant <= init_precharge;
end if;

when init_prechargeNop =>
o_cont_commande <= C_NOP;
etat_suivant <= init_load_mode;

when init_load_mode =>
if i_cont_accuseCommande = '1' then
o_cont_commande <= C_NOP;
etat_suivant <= init_load_modeNop;
else
o_cont_commande <= C_init_load_mode;
reg_o_cont_adresse <= CONF_init_load_mode;
etat_suivant <= init_load_mode;
end if;

when init_load_modeNop =>
o_cont_commande <= C_NOP;
etat_suivant <= init_load_reg2;

when init_load_reg2 =>
if i_cont_accuseCommande = '1' then
o_cont_commande <= C_NOP;
etat_suivant <= init_load_reg1;
else
o_cont_commande <= C_init_load_reg2;
reg_o_cont_adresse <= CONF_REG2;
etat_suivant <= init_load_reg2;
end if;

when init_load_reg1 =>
if i_cont_accuseCommande = '1' then
o_cont_commande <= C_NOP;
etat_suivant <= init_refresh1;
else
o_cont_commande <= C_init_load_reg1;
reg_o_cont_adresse <= CONF_REG1;
etat_suivant <= init_load_reg1;
end if;

when init_refresh1 =>
if i_cont_accuseCommande = '1' then
o_cont_commande <= C_NOP;
etat_suivant <= init_refresh2;
else
o_cont_commande <= C_REFRESH;
etat_suivant <= init_refresh1;
end if;

when init_refresh2 =>
if i_cont_accuseCommande = '1' then
o_cont_commande <= C_NOP;
etat_suivant <= init_2nop;
i <= 0;
else
o_cont_commande <= C_REFRESH;
etat_suivant <= init_refresh2;
end if;

when init_2nop =>
o_cont_commande <= C_NOP;
if i < 2 then
i <= i + 1;
etat_suivant <= init_2nop;
else
i <= 0;
etat_suivant <= etat_attente_instruction;
end if;

--*******************************************************************************

-- wait state : nothing is done until a read or write command is done
by ext.
--*******************************************************************************


when etat_attente_instruction =>
o_cont_commande <= C_NOP;
reg_o_cont_adresse <= (others => 'X');
reg_o_cont_donnees <= (others => 'X');
reg_o_cont_masqueEcriture <= (others => 'X');
o_ext_rw_ok <= "00";

-- is there a new demand ?
case i_ext_demande_rw is
when READ_MODE =>
etat_suivant <= lecture_init;
when WRITE_MODE =>
etat_suivant <= ecriture_init;
when others =>
etat_suivant <= etat_attente_instruction;
end case;

--******************************************************************************************

-- states of a burst write
--******************************************************************************************


when ecriture_init =>
compteur_ecriture <= 0;
o_cont_commande <= C_WRITEA;
o_ext_rw_ok <= "00";

--register data
reg_o_cont_adresse <= i_ext_adresse;
reg_o_cont_donnees <= i_ext_donnees;
reg_i_ext_masque <= i_ext_masque;

if i_cont_accuseCommande = '1' then
o_cont_commande <= C_NOP;
etat_suivant <= ecriture_attente_latence;
else
etat_suivant <= ecriture_init;
end if;

-- wait for the write-latency
when ecriture_attente_latence =>
o_cont_commande <= C_NOP;

if compteur_ecriture < (TL_W - 1) then
compteur_ecriture <= compteur_ecriture + 1;
o_ext_rw_ok <= "00"; --not in burst loop
etat_suivant <= ecriture_attente_latence;
else
compteur_ecriture <= 0;
etat_suivant <= ecriture_boucle_donnees;
o_ext_rw_ok <= WRITE_OK;
compteur_bl <= 1; --first burst data is wrote
end if;

-- next words of the burst message, one word per clock tick
when ecriture_boucle_donnees =>
o_cont_commande <= C_NOP;
if compteur_bl < BL then
o_ext_rw_ok <= WRITE_OK;
etat_suivant <= ecriture_boucle_donnees;
compteur_bl <= compteur_bl + 1;
else --and of burst
o_ext_rw_ok <= "00";
etat_suivant <= etat_attente_instruction;
end if;
--- end of write burst states ---

--******************************************************************************************

-- state of a read burst
--******************************************************************************************


when lecture_init =>
compteur_lecture <= 0;
o_ext_rw_ok <= "00";
reg_o_cont_adresse <= i_ext_adresse;
o_cont_commande <= C_READEA;

if i_cont_accuseCommande = '1' then --now, only TL_R ticks remain.
o_cont_commande <= C_NOP;
compteur_lecture <= 0;
etat_suivant <= lecture_attente_latence;
else
etat_suivant <= lecture_init;
end if;

-- wait for the right number of ticks
when lecture_attente_latence =>
o_cont_commande <= C_NOP;
if compteur_lecture < (TL_R-1) then
compteur_lecture <= compteur_lecture + 1;
etat_suivant <= lecture_attente_latence;
o_ext_rw_ok <= "00";
else
reg_o_ext_donnees <= i_cont_donnees;
etat_suivant <= lecture_boucle_donnees;
o_ext_rw_ok <= READ_OK;
compteur_bl <= 1; --number 0 of the burst done
end if;

-- next words of the burst, one per clock tick.
when lecture_boucle_donnees =>
if compteur_bl < BL then
reg_o_ext_donnees <= i_cont_donnees;
o_ext_rw_ok <= READ_OK;
compteur_bl <= compteur_bl + 1;
etat_suivant <= lecture_boucle_donnees;
else
o_ext_rw_ok <= READ_OK;
etat_suivant <= etat_attente_instruction;
end if;
--- end of read burst states ---

when etat_erreur => etat_suivant <= etat_erreur;
when others => etat_suivant <= etat_erreur;

end case; --end of state machine
end if;
end process;

--***********************************************************************************

-- others parallel instructions
--***********************************************************************************


--error and ready signal to ext
o_ext_sdram_ready <= '1' when etat_suivant = etat_attente_instruction
else '0';
o_ext_erreur <= '0' when etat_suivant = etat_erreur else '1';


--registered outputs
o_cont_adresse <= reg_o_cont_adresse;
o_cont_donnees <= reg_o_cont_donnees;
o_cont_masqueEcriture <= reg_o_cont_masqueEcriture;

o_ext_donnees <= reg_o_ext_donnees;

end archi;
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,011
Latest member
AjaUqq1950

Latest Threads

Top