Forum: FPGA, VHDL & Co. cpld SRAM Interface in VHDL


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von befro (Gast)


Lesenswert?

Hallo an Alle,

für mein kleines CPLD-Projekt brauche ich ein Interface für ein SRAM 
128K*8Bit.

Das Interface hat einen internen Adresscounter, der über ein Clock 
Leitung sowei Reset gesteuert wird. Auserdem gibt es eine Leitung, die 
bestimmt, ob vom Ram gelesen oder ins Ram geschrieben werden soll. Das 
Interface soll einen Dateneingang und einen Datenausgang haben ( also 
nicht Tri-State ).

Hier mein erster Entwurf, vielleicht kann mir jemand sagen, ob es so 
gehen könnte:
1
entity RamInterface is
2
    Port ( 
3
        -- RAM SIGNALS
4
        ramAddress : out  STD_LOGIC_VECTOR (16 downto 0);
5
        ramData : inout  STD_LOGIC_VECTOR (7 downto 0);
6
        ramNWE : out  STD_LOGIC;
7
        ramNOE : out  STD_LOGIC;
8
        
9
        -- Interface Signals
10
        dataOut : out  STD_LOGIC_VECTOR (7 downto 0);
11
        dataIn : in  STD_LOGIC_VECTOR (7 downto 0);
12
        clk : in  STD_LOGIC;
13
        clkNextValue : in  STD_LOGIC;
14
        ReadOrNSample : in  STD_LOGIC;
15
        Reset : in STD_LOGIC);  
16
end RamInterface;
17
18
architecture Behavioral of RamInterface is
19
signal ramAddressCounter: STD_LOGIC_VECTOR (16 downto 0 );
20
21
begin
22
EinProzessModell: process(clk,clkNextValue,readOrNSample,ramAddressCounter, dataIn)
23
begin
24
  if rising_edge(clkNextValue) then
25
    if Reset = '0' then
26
      ramAddressCounter <= ramAddressCounter+1;
27
    else
28
      ramAddressCounter <= ( others => '0' );
29
    end if;
30
  end if;  
31
  
32
  if readOrNSample = '1' then -- Daten vom Ram lesen
33
    ramData <= ( others => 'Z' ); -- CPLD Interface hochohmig
34
    ramNOE <= '0'; -- Ram Ausgang einschalten 
35
    ramNWE <= '1'; -- Ram write disable
36
    dataOut <= ramData ; -- Daten vom Ram auf Interface output
37
  else -- Daten in Ram schreiben
38
    ramNOE <= '1'; -- Ram Ausgang ausschalten 
39
    ramNWE <= '0'; -- Ram write enable
40
    ramData <= dataIn; -- Daten vom Interface  ins RAM schreiben
41
  end if;
42
end process EinProzessModell;
43
44
ramAddress <= ramAddressCounter;
45
46
end Behavioral;

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Das mit dem Einprozessmodell hast du offenbar extrem weit gefasst :-/

Es ist nicht "State of the Art", einen getakteten und einen 
kombinatorischen Teil zusammen in einen Prozess zu packen. Du wirst 
daran später sicher noch deine Freude haben. Nur mal angenommen, du 
änderst irgendwann was, machst die Änderungen wieder raus und bekommst 
sowas:
1
EinProzessModell: process(clkNextValue)
2
begin
3
  if rising_edge(clkNextValue) then
4
    if Reset = '0' then
5
      ramAddressCounter <= ramAddressCounter+1;
6
    else
7
      ramAddressCounter <= ( others => '0' );
8
  end if;  
9
  
10
  if readOrNSample = '1' then -- Daten vom Ram lesen
11
    ramData <= ( others => 'Z' ); -- CPLD Interface hochohmig
12
    ramNOE <= '0'; -- Ram Ausgang einschalten 
13
    ramNWE <= '1'; -- Ram write disable
14
    dataOut <= ramData ; -- Daten vom Ram auf Interface output
15
  else -- Daten in Ram schreiben
16
    ramNOE <= '1'; -- Ram Ausgang ausschalten 
17
    ramNWE <= '0'; -- Ram write enable
18
    ramData <= dataIn; -- Daten vom Interface  ins RAM schreiben
19
    end if;
20
  end if;
21
end process EinProzessModell;
Na, siehst du den Fehler auf Anhieb?

Das Ein-, Zwei- usw. Modell gilt ugs. nur für State-Machines, nicht für 
allgemeine Beschreibungen ;-)

Schreibs besser so:
1
-- Adresszähler
2
process(clk,clkNextValue,readOrNSample,ramAddressCounter, dataIn)
3
begin
4
  if rising_edge(clkNextValue) then
5
    if Reset = '0' then
6
      ramAddressCounter <= ramAddressCounter+1;
7
    else
8
      ramAddressCounter <= ( others => '0' );
9
    end if;  
10
  end if;  
11
end process;
12
13
-- Kombinatorik
14
process(readOrNSample, dataIn)
15
begin
16
  if readOrNSample = '1' then -- Daten vom Ram lesen
17
    ramData <= ( others => 'Z' ); -- CPLD Interface hochohmig
18
    ramNOE <= '0'; -- Ram Ausgang einschalten 
19
    ramNWE <= '1'; -- Ram write disable
20
    dataOut <= ramData ; -- Daten vom Ram auf Interface output
21
  else -- Daten in Ram schreiben
22
    ramNOE <= '1'; -- Ram Ausgang ausschalten 
23
    ramNWE <= '0'; -- Ram write enable
24
    ramData <= dataIn; -- Daten vom Interface  ins RAM schreiben
25
  end if;
26
end process;

BTW:
Du solltest das Datenblatt deines SRAMs mal genau anschauen, ob du nach 
einem Schreibzugriff sofort wieder lesen darfst. Da gibt es durchaus 
Einschränkungen  :-o

von befro (Gast)


Lesenswert?

>Na, siehst du den Fehler auf Anhieb?
Ich vermute Du meinst die Empfindlichkeitsliste?

>Du solltest das Datenblatt deines SRAMs mal genau anschauen, ob du nach
>einem Schreibzugriff sofort wieder lesen darfst.

Ein wenig problematisch ist meine Implementierung wahrscheinlich schon. 
Bei den SRAMs wird das Schreiben normalerweise über ein low/high Flanke 
am WE (write enable pin, bei mir ramNWE ) gesteuert. Die Adressen und 
Daten müssen eine bestimmte Zeit vorher schon anliegen. Ich habe den WE 
pin quasi fix auf den Wert ReadOrNSample geklemnnt, der für das lesen 
von n-Samples auf 0 gelegt wird. Meine Hoffnung ist, dass durch das 
Weiterschalten der Adresse die Daten auch schon so übernommen werden. 
Zugegebenermaßen etwas murksig, aber ich dachte mir, so kann ich eine 
State-Machine für das korrekte toggeln der Signale sparen. Vor allen 
Dingen, weil das lesen der N-Samples mit vollem Systemtakt erfolgen 
soll.
Ein weiteres Problem, bei dem ich mir noch nicht so sicher bin, ist, ob 
die Datenübertragung vom VHDL-Speicherinterface zur Restlogik 
zuverlässig funktioniert, oder ob man dafür noch zusätzliche Ein und 
Ausgangslatches einbauen sollte.

von Klaus F. (kfalser)


Lesenswert?

Auch das Output Enable des FPGA's wirkt nicht sofort, sondern mit einer 
gewissen Verzögerung, die größer ist, als die Laufzeit eines "normalen" 
Pins.
DataIn erscheint deshalb am Pin später als z.B. ramNWE.

Das mußt Du auch beim Hochohmig schalten berücksichtigen.
Wenn ramNWE zurück auf high geht, und das SRAM wieder die Ausgänge 
aktiviert, aber das FPGA noch nicht hochohmig ist, kommt es zu 
Konflikten auf dem Bus.

von befro (Gast)


Lesenswert?

>Auch das Output Enable des FPGA's wirkt nicht sofort, sondern mit einer
>gewissen Verzögerung, die größer ist, als die Laufzeit eines "normalen"
>Pins.

Deshalb hier eine neue Version des SRAM-Interfaces. Hier habe ich 
versucht, das Timing von WE und OE so hinzuschieben, dass kein 
Buskonflickt auftritt. Vom Timing her scheint das Ganze jetzt 
einigermaßen zu stimmen, aber irgendwie klappt es nicht den Datenport 
des CPLDs laut Simulation hochohmig zu schalten ( ramData = "ZZZZZZZZ" 
). Habt Ihr eine Idee, woran es liegen könnte?
1
entity RamInterface is
2
    Port ( 
3
        -- RAM SIGNALS
4
        ramAddress : out  STD_LOGIC_VECTOR (16 downto 0);
5
        ramData : inout  STD_LOGIC_VECTOR (7 downto 0):="ZZZZZZZZ";
6
        ramNWE : out  STD_LOGIC;
7
        ramNOE : out  STD_LOGIC;
8
        
9
        -- Interface Signals
10
        dataOut : out  STD_LOGIC_VECTOR (7 downto 0);
11
        dataIn : in  STD_LOGIC_VECTOR (7 downto 0);
12
        clk : in  STD_LOGIC;
13
        clkNextValue : in  STD_LOGIC;
14
        ReadOrNSample : in  STD_LOGIC;
15
        Reset : in STD_LOGIC);  
16
end RamInterface;
17
18
architecture Behavioral of RamInterface is
19
signal ramAddressCounter: STD_LOGIC_VECTOR (16 downto 0 ):="00000000000000000";
20
signal rns_delayed: STD_LOGIC:='1';
21
signal ramDataOutEnable: STD_LOGIC:='0'; --disable output buffer
22
23
begin
24
EinProzessModell: process(clk,clkNextValue,readOrNSample,ramAddressCounter, dataIn)
25
begin
26
  
27
  if rising_edge(clkNextValue) then
28
    if Reset = '0' then
29
      ramAddressCounter <= ramAddressCounter+1;
30
    else
31
      ramAddressCounter <= ( others => '0' );
32
    end if;  
33
    rns_delayed <= readOrNSample; -- verzögertes read/write Umschaltsignal
34
  end if;  
35
  
36
  if readOrNSample = '1' then -- Daten vom Ram lesen
37
    ramData <= ( others => 'Z' ); -- CPLD Interface hochohmig
38
    ramNWE <= '1'; -- Ram write disable
39
    dataOut <= ramData ; -- Daten vom Ram auf Interface output
40
  
41
  else -- Daten ins Ram schreiben
42
    ramNWE <= clkNextValue or clk;
43
    if ramDataOutEnable ='1' then
44
      ramData <= dataIn; -- Daten vom Interface  ins RAM schreiben
45
    --else ramData <= (others => 'Z');
46
    end if;
47
  end if;
48
end process EinProzessModell;
49
50
ramDataOutEnable <= not (rns_delayed or readOrNSample );
51
ramNOE <= not (rns_delayed and readOrNSample );
52
53
ramAddress <= ramAddressCounter;
54
55
end Behavioral;

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.