Forum: FPGA, VHDL & Co. Fehler beim Auslesen aus Dual Port RAM


von Michael (Gast)


Lesenswert?

Hallo Forum,

ich versuche gerade einen UART auf meine DE2-115 Board zu 
implementieren. Receiver und Transmitter laufen. Daten kann ich senden 
und auch empfangen.
Ich möchte in meinem Design einen Dual Port Ram einsetzen um das 
folgende Verarbeiten unabhänig vom empfangen zu halten. Das heißt wenn 
Daten empfangen werden, werden diese direkt in den RAM geschrieben. Der 
Process sieht dafür folgender Maßen aus:
1
 ram:process(sig_reset, clk_50MHz)
2
variable sig_addr_counter_temp : integer range 0 to 127:= 0;
3
variable sig_addr_counter : std_logic_vector(6 downto 0):=(others => '0');
4
begin
5
if (sig_reset = '0') then
6
   sig_addr_counter := "0000000";
7
   sig_web <= '0';
8
   sig_enb <= '0';
9
   sig_wea <= '0';
10
   sig_ena <= '0';
11
elsif (clk_50MHz'event and clk_50MHz = '1') then
12
   -- in RAM schreiben
13
   pre_write <= sig_irq;  
14
   if (sig_irq = '1' and pre_write = '0') then                
15
      sig_addrb <= sig_addr_counter;
16
      sig_web <= '1';
17
      sig_enb <= '1';
18
      sig_dib <= sig_data_rxd;
19
      sig_data_in_fifo <= '1';
20
      if (sig_addr_counter <= "1111110") then
21
      sig_addr_counter_temp := sig_addr_counter_temp + 1;
22
         sig_addr_counter := std_logic_vector(to_unsigned(sig_addr_counter_temp,7));
23
      end if;
24
   else
25
      sig_web <= '0';
26
      sig_enb <= '0';
27
   end if;
28
   -- aus RAM auslesen 
29
   pre_read <= rs232_fifo_addr_en_s;
30
   if (rs232_fifo_addr_en_s = '1' and pre_read = '0') then
31
      sig_addra <= rs232_fifo_addr_s(6 downto 0);
32
      sig_wea <= '0';
33
      sig_ena <= '1';
34
   else
35
      sig_wea <= '0';
36
      sig_ena <= '0';
37
   end if;
38
   --Überlauf und wenn Daten komplett ausgelesen, dann Adresse zurück
39
   if (rs232_fifo_addr_en_s = '1' and (rs232_fifo_addr_s(6 downto 0) = "1111111" or (rs232_fifo_addr_s(6 downto 0) = std_logic_vector(to_unsigned(sig_addr_counter_temp-1,7))))) then 
40
    sig_data_in_fifo       <= '0';
41
    sig_addr_counter_temp  := 0;
42
      sig_addr_counter       := "0000000";
43
   end if;
44
   rs232_data_rxd_valid_s   <= sig_ena;
45
  rs232_data_cnt_s       <= sig_addr_counter;
46
end if;
47
end process;

Im ersten Teil wird in den RAM geschrieben auf die entsprechende Adresse 
(sig_addr_counter). Bei weiteren empfangenen Daten wird immer wieder 
erhöht bis das ende des RAMs erreicht ist. Dann fängt der von vorne an. 
Bereits vorhandene Daten werden gelöscht. (ist gewollt) Im folgenden 
Teil wird ausgelesen von der übergebenen Adresse.
Hierfür habe ich in einem weiteren Process eine Statemachine 
geschrieben, womit die Signallaufzeiten,(verfügbarkeit) berücksichtigt 
werden sollen.
1
receive_process:process (clk_50MHz, nReset)
2
begin
3
if (nReset = '0') then
4
state_rxd  <= START;
5
elsif (clk_50MHz'event and clk_50MHz = '1') then                
6
    case state_rxd is                      
7
      
8
      when START =>      
9
        if (rs232_fifo_addr_en_s = '1' ) then
10
          rs232_fifo_addr_en_s <= '0';
11
        else
12
          state_rxd         <= READ_POSSIBLE;              
13
        end if; 
14
      
15
      when READ_POSSIBLE =>
16
        if (sig_data_in_fifo = '1') then
17
          rs232_fifo_addr_en_s <= '1';
18
          rs232_fifo_addr_s   <= std_logic_vector(to_unsigned(data_in_fifo_cnt,7));  
19
          state_rxd     <= FINISHED_READ;  
20
        else
21
          state_rxd    <=  state_rxd;
22
        end if;       
23
      
24
      when FINISHED_READ =>
25
        read_step         <= read_step - 1;
26
        if (read_step = 0) then
27
          read_step      <= 1;
28
          memory_global    <= sig_doa;        
29
          state_rxd       <= CHECK_STATE; 
30
        end if;   
31
        
32
      when CHECK_STATE =>
33
        if (rs232_fifo_addr_s <= rs232_data_cnt_s) then
34
          data_in_fifo_cnt     <= data_in_fifo_cnt + 1;
35
        else
36
          data_in_fifo_cnt     <= 0;
37
        end if; 
38
        state_rxd         <= START;  
39
    end case; 
40
end process;

das Signal sig_doa ist der Ausgang vom RAM und der Wert von der 
abgefragten Adresse soll in das Signal memory_global abgelegt werden. 
Der Process ist so ausgelegt, das dies solange gemacht wird bis der FiFo 
leer ist. Das funktioniert auch alles, allerdings wird mir immer eine 
Null zurück gegeben. Und da liegt mein Problem. Irgendwas mit der 
Berechnung und der Parallelität mit Signalen und dem FPGA habe ich 
wahrscheinlich übersehen. Hat jemand eventuell eine Idee was ich noch 
anders machen kann oder noch ergänzen.
zur vollständigkeit hier noch der RAM. da bin ich mir aber sicher, das 
dieser funktioniert.

Vielen Dank, Gruß Michael
1
architecture arch_rs232ram of rs232ram is
2
3
type ram_type is array (0 to 127) of std_logic_vector(7 downto 0); 
4
shared variable RAM : ram_type :=
5
  ( 
6
   X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00",  -- 0
7
   X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00",  -- 1
8
   X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00",  -- 2
9
   X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00",  -- 3
10
   X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00",  -- 4
11
   X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00",  -- 5
12
   X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00",  -- 6
13
   X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00",  -- 7
14
   X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00",  -- 8
15
   X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00",  -- 9
16
   X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00",  -- 10
17
   X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00",  -- 11
18
   X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00",  -- 12
19
   X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00",  -- 13
20
   X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00",  -- 14
21
   X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00"   -- 15
22
   ); 
23
24
begin
25
26
process (clka)
27
begin
28
  if rising_edge(clka) then                                   --output
29
    if ena = '1' then
30
      if wea = '1' then
31
        RAM(to_integer(unsigned(addra))) := dina;
32
      end if;
33
      douta <= RAM(to_integer(unsigned(addra)));
34
    end if;
35
  end if;
36
end process;
37
38
process (clkb)
39
begin
40
  if rising_edge(clkb) then                                   --input
41
    if enb = '1' then
42
      if web = '1' then
43
        RAM(to_integer(unsigned(addrb))) := dinb;
44
      end if;
45
      doutb <= RAM(to_integer(unsigned(addrb)));
46
    end if;
47
  end if;
48
end process;
49
50
end arch_rs232ram;

: Bearbeitet durch Moderator
von Duke Scarring (Gast)


Lesenswert?

Michael schrieb:
> Das funktioniert auch alles, allerdings wird mir immer eine
> Null zurück gegeben. Und da liegt mein Problem. Irgendwas mit der
> Berechnung und der Parallelität mit Signalen und dem FPGA habe ich
> wahrscheinlich übersehen.
Warum machst Du keine Simulation?

Duke

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


Lesenswert?

Michael schrieb:
> Der Process sieht dafür folgender Maßen aus:
Verwende doch bitte die [ vhdl ] und [ /vhdl ] Tags um deinen Code
(ohne die Leerzeichen in den eckigen Klammern).

> shared variable
Wofür brauchst du sowas?

> da bin ich mir aber sicher, das dieser funktioniert.
Du hast das RAM also simuliert und nachvollzogen, dass es das macht, was 
du willst?

BTW: du brauchst für diese Aufgabe mit 99,999% Wahrscheinlichkeit kein 
DPRAM. Denn die SIO ist so unglaublich viel langsamer als deine 
Taktfrequenz, dass du locker ein stinknormales RAM lesen und schreiben 
kannst...

von J. S. (engineer) Benutzerseite


Lesenswert?

Ein DP-RAM wird hier nicht nur nicht benötigt, sondern ist auch noch 
kontraproduktiv. Wenn es asynchron beschrieben wird, dann liegt ein 
elend langer Schreibvorgang an, während dem nichts (vernüftiges) gelesen 
werden kann und folglich nicht darf. Wenn man es aber synchron 
beschreibt, um einen kurzen Schreibvorgang im Massstab des Systemtaktes 
zu haben, muss man die IOs zwangsläufig einsynchronisieren, landet 
indirekt bei der konventionellen Lösung und kann wie schon angedeutet, 
das DPRAM direkt weglassen.

Was hier gebraucht wird, ist bestenfalls ein FIFO.

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.