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';
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
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...
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
>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.
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.
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.
>Wenn zB für 20 ms nichts gekommen ist, >dann ist das nächste Byte das erste der 16 Bytes. find ich besser.
>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
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 :)
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
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
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.
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.
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
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.