VHDL UART mehrere Vectoren empfangen und einordnen

Gast #4875443
Lesenswert?

Hallo!

Ich empfange über die RS232 Schnittstelle 16 Bytes, die ich in einen 128 
Bit großen Vektor einordnen will.
Ich stelle mir das alles ungefähr wie folgt vor:

Speicher(7 downto 0) <= Byte1
(...)
Speicher(127 downto 120) <= Byte16

Ich hab bereits mehrere Ansätze versucht, konnte die gewünschte 
Funktionalität jedoch nicht erreichen.

Anbei befindet sich ein Ansatz für den Empfang einzelner Bytes, den ich 
derzeit nutze.
Hat jemand eine Idee, wie man das am besten realisieren kann?

Vielen lieben Dank!

Liebe Grüße


--RS232: Empfang
process begin
  wait until rising_edge(CLK);
  rxd_sr <= rxd_sr(rxd_sr'left-1 downto 0) & RXD;
  if (rxbitcnt<9) then    -- Empfang läuft
    if(rxcnt<(Quarz_Taktfrequenz/Baudrate)-1) then
      rxcnt    <= rxcnt+1;
    else
      rxcnt    <= 0;
      rxbitcnt <= rxbitcnt+1;
      rxsr     <= rxd_sr(rxd_sr'left-1) & rxsr(rxsr'left downto 1); -- 
rechts schieben, weil LSB first
    end if;
  else -- warten auf Startbit
    if (rxd_sr(3 downto 2) = "10") then
      rxcnt    <= ((Quarz_Taktfrequenz/Baudrate)-1)/2;
      rxbitcnt <= 0;
    end if;
  end if;
end process;
RX_Data <= rxsr;  --RX_DATA müsste in den Vektor eingeordnet werden.
RX_Busy <= '1' when (rxbitcnt<9) else '0';
Gast #4875458
Lesenswert?

Na wo ist das Problem?

Du brauchst einen weiteren Zähler, ich würde einen 20er nehmen und vor 
jedem senden der 16 Bytes ein Preambel senden (z.B. "AAAA"). Dann 
synchronisierst du gleich. Wie ein Zähler funzt siehst du ja im RS232 
Code...
Gast #4875460
Lesenswert?

Also Entweder du schiebst jetzt die Daten in ein Schieberegister, so wie 
du das schon mit den empfangen Bits machst.
RX_Data <= RX_Data(RX_Data'left-8 downto 0) & rxsr;

oder halt mit einem Datenarray

TYPE RX_Type is array (0 to 15) of STD_LOGIC_VECTOR(7 downto 0);
Signal RX_Data : RX_Type (others => (others => '0');

und dann mit ner schleife halt das Array durchgehen, bis du alle Bytes 
empfangen hast.

So in etwa würde ich das zumindest machen ;D
Moderator (Firma: Titel) Persönliche Seite #4875466
Lesenswert?

Neuling schrieb:
> Hat jemand eine Idee, wie man das am besten realisieren kann?
Du machst eine übergeordnete FSM, die den Index mitzählt und dann einen 
Multiplexer entsprechend ansteuert.

Und dann solltest du dir noch Gedanken machen,  was passiert, wenn du 
mal 1 Zeichen "verlierst". Für diese 16 Bytes solltest du also noch ein 
Protokoll einführen, das dir das erste Byte zeigt. Am einfachsten könnte 
das über ein Timeout geschehen. Wenn zB für 20 ms nichts gekommen ist, 
dann ist das nächste Byte das erste der 16 Bytes.
Gast #4875500
Lesenswert?

Erstmal danke für die zahlreichen Ideen :).

Ich weiß auch nicht wieso, allerdings sitze ich bereits schon länger an 
diesen Problem ...

Bezüglich der Idee mit dem Array:
Was für eine Schleife würde man denn da genau nehmen?
Ich bin noch relativ neu und etwas unerfahren :D
Aber das dürfte doch so in etwa aussehen oder?

for i in 0 to 16 loop
(...)

Mit einem Schieberegister hab ich selber noch keine Erfahrung ^^.
Wie bereits erwähnt ist das noch ein Beispielcode an dem ich mich 
orientiere.
Gast #4875504
Lesenswert?

>Mit einem Schieberegister hab ich selber noch keine Erfahrung ^^.

Ist ganz simpel, wir nehmen das oben angesprochene Array und einen 
Zeiger und schon haben wir ein Schieberegister. Der Zeiger zeigt dabei 
immer auf ein Element und kann durch ein äußeres Signal um eins erhöht 
und zurückgesetzt werden.

Gruß J
#4875534
Lesenswert?

JB schrieb:
>>Mit einem Schieberegister hab ich selber noch keine Erfahrung ^^.
>
> Ist ganz simpel, wir nehmen das oben angesprochene Array und einen
> Zeiger und schon haben wir ein Schieberegister. Der Zeiger zeigt dabei
> immer auf ein Element und kann durch ein äußeres Signal um eins erhöht
> und zurückgesetzt werden.
>
> Gruß J

Nein, das ist gerade kein Schieberegister sondern ein RAM.

Ein Schieberegister ist sowas:
1
signal sr: std_logic_vector(127 downto 0):=(others => '0');
2
signal uart_data: std_logic_vector(7 downto 0):=(others => '0');
3

4
begin
5

6
process begin
7
   wait until rising_edge(CLK);
8
   sr <= sr(119 downto 0) & uart_data;
9
end process;

Im Beispiel wird in jedem Takt von rechts etwas reingeschoben und sr(127 
downto 120) fällt links raus.
Gast #4876462
Lesenswert?

So ich habe versucht mich mal etwas schlau zu lesen und habe nun habe 
nun den folgenden Ansatz hinbekommen:


--Schieberegister
Generic( weite: natural := 128; --Registerbreite
         schw:  natural :=8     --Schiebeweite
        );

(...)

--Schieberegister
SYN_SHIFT: process (CLK)
begin
  if CLK='1' and CLK'event then
    --Links schieben
    YINT <= YINT(weite-1-schw downto 0) & RX_Data;
  end if;
end process SYN_SHIFT;
speicher <= YINT;

Wenn ich nun die 16 Bytes empfange, einsortiere und daraufhin den Inhalt 
des gefüllten Vektors erneut verschicke, so entspricht der Inhalt des 
Vektors bloß dem letzten Byte.

Empfangene Bytes:
(Byte 1), (Byte 2), (...), (Byte n)
Verschickte Bytes:
(Byte n), (Byte n), (...), (Byte n)

Kann mir jemand erklären wo mein Fehler liegt?
So wie ich das sehe wird der Inhalt zwar nach links verschoben, jedoch 
aber auch von dem neusten angekommenen Byte sofort wieder überschrieben.
Wie kann ich das verhindern?

Ich wäre wie immer für jede Idee oder Ansatz sehr dankbar.

Liebe Grüße
Gast #4876553
Lesenswert?

Vielen Dank soweit für die Ansätze :)
Ich habe das nun wie folgt implementiert...

SYN_SHIFT: process(RXBuff)
begin
  if clk='1' and clk'event then

RXBuff ist ein std_logic Signal, dass bei einem neuen Byte auf ein High 
gesetzt wird.

Nach ein paar Testläufen muss ich leider feststellen, dass sich an den 
Messungen nichts geändert hat.
Der Prozess sollte doch nun aber bloß dann ausgeführt werden, sofern das 
Signal ausschlägt?
Habe ich da etwas falsch gemacht?

Liebe Grüße
#4876597
Lesenswert?

Du brauchst ein Signal nennen wir es "neues_byte" das wenn ein neues 
Byte empfangen wurde für genau einen Takt auf '1' gesetzt wird und sonst 
'0' ist.

Dann kannst Du das von weiter oben so erweitern:
1
signal sr: std_logic_vector(127 downto 0):=(others => '0');
2
signal uart_data: std_logic_vector(7 downto 0):=(others => '0');
3
signal RX_Busy_buffer: std_logic:='0';
4
signal neues_byte: std_logic:='0';
5

6

7
begin
8

9
process begin
10
   wait until rising_edge(CLK);
11
   neues_byte <= '0';
12
   RX_Busy_buffer <= RX_Busy;
13
   if RX_Busy_buffer = '1' and RX_Busy = '0' then
14
      neues_byte <= '1';
15
   end if;
16
end process;
17

18
process begin -- Das ist Dein Schieberegister
19
   wait until rising_edge(CLK);
20
   if neues_byte = '1' then
21
      sr <= sr(119 downto 0) & uart_data;
22
   end if;
23
end process;

Das kann man natürlich noch deutlich kompakter schreiben, aber so ist es 
hoffentlich verständlich. Wenn also Dein RX_Busy von '1' nach '0' geht 
wird neues_byte für einen Takt lang '1' und das ist die Bedingung damit 
das Schieberegister geschoben wird.
Gast #4876818
Lesenswert?

Neuling schrieb:

> Der Prozess sollte doch nun aber bloß dann ausgeführt werden, sofern das
> Signal ausschlägt?
> Habe ich da etwas falsch gemacht?
Ja :-)

> SYN_SHIFT: process(RXBuff)
> begin
>   if clk='1' and clk'event the
Die Sensitiviy-Liste ist nur für den Simulator relevant.
Der Synthesizer ignoriert sie.

Wenn Simulation, Synthese und Verhalten übereinstimmen sollen, muß das 
so geschrieben werden:
1
  SYN_SHIFT: process(clk)
2
  begin
3
    if clk='1' and clk'event then
4
      if RXBuff = '1' then
5
        ...
6
      end if;
7
    end if;
8
  end process;

Oder kürzer (identisch, aber m.E. lesbarer) so:
1
  SYN_SHIFT: process
2
  begin
3
    wait until rising_edge( clk);
4
    if RXBuff = '1' then
5
      ...
6
    end if;
7
  end process;

Duke

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren