Forum: FPGA, VHDL & Co. VHDL UART mehrere Vectoren empfangen und einordnen


von Neuling (Gast)


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';

von bitwurschtler (Gast)


Lesenswert?

Neuling schrieb:
> Anbei befindet sich ein Ansatz für den Empfang einzelner Bytes, den ich
> derzeit nutze.


Ja, bspw. mit einer Ansteuerung eines Embedded RAM-Blocks:
https://danstrother.com/2010/09/11/inferring-rams-in-fpgas/#vhdl

von JB (Gast)


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...

von Professor FPGA (Gast)


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

von JB (Gast)


Lesenswert?

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

what schleife? :D

Ein Zähler + Schieberegister ist das Mittel der Wahl.

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


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.

von Neuling (Gast)


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.

von JB (Gast)


Lesenswert?

>Wenn zB für 20 ms nichts gekommen ist,
>dann ist das nächste Byte das erste der 16 Bytes.

find ich besser.

von JB (Gast)


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

von Neuling (Gast)


Lesenswert?

Mhhh auf die Gefahr mir zu blamieren,
wie genau sieht das in VHDL denn aus?

Ich hab mir ein paar Beispiele dazu angesehen, werde aber noch nicht 
ganz schlau daraus..

Vielen Dank soweit :)

von Gustl B. (-gb-)


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.

: Bearbeitet durch User
von Neuling (Gast)


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

von Duke Scarring (Gast)


Lesenswert?

Neuling schrieb:
> Wie kann ich das verhindern?
Durch umkopieren der Daten ins nächste Register...

von Neuling (Gast)


Lesenswert?

Wie genau kann so etwas denn umgesetzt werden?
Ich bin davon ausgegangen, dass die Wertigkeit der zuvor angekommenen 
Bits durch eine solche Implementierung beibehalten werden würde.

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


Lesenswert?

Neuling schrieb:
> Wie kann ich das verhindern?
Du darfst diese Schieberei natürlich nicht jeden Takt machen, sondern 
nur einmalig jeweils dann, wenn ein neues Byte empfangen wurde.

von Neuling (Gast)


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

von Gustl B. (-gb-)


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.

von Duke Scarring (Gast)


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

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.