Hallo, Ich will über einen UART im FPGA mit dem PC kommunizieren, um den FPGA steuern zu können. Ich habe dazu nun erst mal ein kleines Testdesign gebastelt(siehe Anhang). Es soll nach dem Senden von „Start“ alle 3 Sekunden(momentan mit Vollgas) „Hallo“ senden, bis man „Stop“ schickt. Auf meinem Xilinx-FPGA läuft das auch ausgezeichnet. Allerdings läuft genau dieses Design nicht auf meinem Altera-Board. Der Receiver scheint zu funktionieren, der Transmitter nicht. Über herausgeführte Pins habe ich herausgefunden, dass der Transmitter nicht bereit zu sein scheint. Kann mir jemand ein paar Tips geben, woran so was liegen könnte? Wäre jemand so nett und würde das Ding schnell auf sein Altera bzw. Xilinx Board ziehen und berichten, ob es geht? 9600 Baud keine Parität 8 Datenbits 1 Stopbit Eingangstakt sollte 40MHz sein. Sonst muss der Clockteiler im Sender und Empfänger Modul dementsprechend umgestellt werden. Danke schon im Voraus. Daniel
Schau mal auf http://www.fpga4fun.com , da ist ein UART beschrieben der sicher auf Altera läuft. Ob der auch mit einem Xilinx FPGA funktioniert, weiss ich allerdings nicht. Gruss Andi
Hallo, es wuerde mich sehr interessieren, wieso die Hardwarebeschreibung auf einem Xilinx FPGA funktioniert und auf einem Altera FPGA nicht. Ich dachte immer das waere der besondere Vorteil von FPGA's, solange man nicht Herstellerspezifische Hardware benutzt. Eine Hardwarebeschreibung sollte immer gleich funktionieren oder irre ich mich? Gruß, Dirk
Seltsam. Ich hätte auch immer gedacht dass ein VHDL-Code auf allen FPGAs gleich funktioniert. Ich würde es gerne testen. Habe aber auch nur ein Spartan-Board.
Hallo Daniel Ich habe es eben auf einem Cyclone EP1C12F324I7 ausprobiert. Mit einer Taktrate von 40 MHz hat es nicht funktioniert!! Nachdem ich in den Quellcode geschaut hatte, habe ich es mit 50MHz ausprobiert und er spuckte "alloallo" aus. "Start" und "Stop" funktionieren auch. Dein Zustandsautomat hängst sich nach dem Reset auf. Hast du auch darauf geachtet, das unterschiedliche Boards mit unterschiedlicher Logik arbeiten. Die Taster kann entweder Low- oder High- Aktiv sein. MfG Holger
Hast du ALLE signale mit im reset? Du hast einen Zähler, der nicht auf " >= ", sondern nur auf " = " abfragt. Ich mache an solchen Stellen gerne den Vergleich auf >=. (if cnt >= 5012 then cnt <= 0; else ....... ..... end if;) Falls er im reset auf größeren Werten als 5012 landet, kann man den Zähler auf diese Weise wieder definiert zurückbringen. Wenn man nur auf " = " abfragt zählt er evtl. munter weiter (je nachdem was im else-Zweig steht).
Hi,
vielen Dank erst mal an alle für die Antworten.
Vorneweg:
Die UART-Module stammen nicht von mir, sondern hier aus dem Forum.
@Andi:
Thx. Ich schau mir den mal an.
@Dirk:
Das ist richtig, dass eine Hardware-Beschreibung immer gehen sollte,
egal welcher Hersteller.
Aber hier scheint ein Problem vorzuliegen, da genau das gleiche Design
auf Xilinx läuft und auf Altera nicht.
@Homer: Könntest Du es bitte auf dem Spartan-Board testen? THX.
@high_speed:
Thx fürs Testen.
Erst mal scheint es ja dann nicht an Xilinx/Altera zu liegen, sondern
vllt. Am Takt. Vllt. Ist es die größere Abweichung...Bei 50MHz sind es
ca. 0,6Hz und bei 40MHz sind es 0,8Hz Abweichung von 9600Hz. Kann ich
mir aber nicht vorstellen.
>>Dein Zustandsautomat hängst sich nach dem Reset auf.
Welchen meinst Du? Der in uart_hello.vhd oder im Sender bzw. Empfänger
Modul?
Dass es nach einem Reset(mit Taster) nicht mehr geht hab ich gemerkt.
Muss aber an den Modulen liegen, da in uart_hello.vhd gar kein Reset
verwendet wird.
Auf Taster Low/High Aktiv habe ich geachtet.
@Rainer:
Das könnte die Ursache sein, dass nach einem Reset mit dem Taster gar
nix mehr geht... Ich werds probieren.
Daniel
Ich mache an solchen Stellen gerne den Vergleich auf >=. (if cnt >= 5012 then cnt <= 0; else ....... ..... end if;) Das ist aber im Regelfall nicht besonders effizient und kann ziemliche Gattergräber geben. Gruss Axel
Hallo Daniel Auf dem Xilinx-Board hast du wahrscheinlich ein wenig Glück gehabt. 40MHz und 50MHz sind aber schon ein extremer Unterschied. Der Taktteiler für den UART hat den Wert von 5208, das ergibt bei 40MHz eine Bitrate von 7680 bit/s, bei 50MHz sind es 9600 bit/s .
1 | if count_clk = 5208 then |
2 | count_clk <= 0; |
Der Fehler im Reset liegt im Transmitter:
1 | ..
|
2 | signal tx_ready_int : std_logic := '1'; -- initalized to 1 for tx_ready = 1 on start |
3 | ..
|
4 | begin
|
5 | -------------------------------------
|
6 | -- load tx_ready with rx_ready_int --
|
7 | -----------------------------------
|
8 | tx_ready <= tx_ready_int; |
9 | ..
|
Ich habe es jetzt umgeschrieben auf:
1 | library ieee; |
2 | use ieee.std_logic_1164.all; |
3 | use ieee.std_logic_unsigned.all; |
4 | |
5 | entity transmitter is |
6 | generic ( |
7 | CLK_div_bit : natural := 5208 -- clock = 50 MHz |
8 | );
|
9 | port ( |
10 | CLK : in std_logic; -- clock |
11 | nReset : in std_logic; -- asynch reset |
12 | Tx : out std_logic; -- transmitter output |
13 | Tx_Data : in std_logic_vector(7 downto 0); -- data input |
14 | data_ready : in std_logic := '1'; -- control signal data ready |
15 | tx_ready : out std_logic -- transmitter ready for new data |
16 | );
|
17 | end transmitter; |
18 | |
19 | |
20 | architecture behavior of transmitter is |
21 | |
22 | signal sending : boolean; -- sending mode |
23 | signal sent : boolean; -- sent mode |
24 | signal count_CLK : std_logic_vector(12 downto 0); --natural range 0 to 4167; -- clock counter for clock divider |
25 | signal count_bit : natural range 0 to 10; -- bit counter |
26 | signal enable : std_logic; -- clock enable for sending mode |
27 | signal data_register : std_logic_vector(7 downto 0); -- for storage of data input to send |
28 | |
29 | begin
|
30 | |
31 | --------------------------------------------------
|
32 | -- clock divider for baudrate generation --
|
33 | -- sensitive to clock, asynch reset by received --
|
34 | -- receiving mode: generate clock enable --
|
35 | -- for wished baudrate --
|
36 | --------------------------------------------------
|
37 | |
38 | clock_divider : process (CLK, sent) is |
39 | begin
|
40 | if sent then |
41 | count_CLK <= (others => '0'); |
42 | elsif CLK'event and CLK = '1' then |
43 | if sending then |
44 | enable <= '0'; |
45 | if count_CLK = CLK_div_bit then |
46 | count_CLK <= (others => '0'); |
47 | elsif count_CLK = 0 then |
48 | enable <= '1'; |
49 | count_CLK <= count_CLK + 1; |
50 | else
|
51 | count_CLK <= count_CLK + 1; |
52 | end if; |
53 | end if; |
54 | end if; |
55 | end process clock_divider; |
56 | |
57 | -----------------------------------------------------------
|
58 | -- data storage of input data --
|
59 | -- sensitive to clock, asynch reset by reset --
|
60 | -- storage data in internal register when data_ready = 1
|
61 | -----------------------------------------------------------
|
62 | |
63 | data_storage : process (CLK, nReset, sent) is |
64 | begin
|
65 | if nReset = '0' or sent then |
66 | data_register <= (others => '0'); |
67 | sending <= false; |
68 | elsif CLK'event and CLK = '1' then |
69 | if data_ready = '1' then |
70 | if not sending then |
71 | data_register <= Tx_Data; |
72 | sending <= true; |
73 | end if; |
74 | end if; |
75 | end if; |
76 | end process data_storage; |
77 | |
78 | -------------------------------------------------------
|
79 | -- send storaged data --
|
80 | -- sensitive to clock, asynch reset by reset --
|
81 | -- load tx with content of data register from 0 to 9 --
|
82 | -- when sending complete : ready for new data --
|
83 | -------------------------------------------------------
|
84 | |
85 | data_send : process (CLK, nReset) is |
86 | begin
|
87 | if nReset = '0' then |
88 | Tx <= '1'; |
89 | count_bit <= 0; |
90 | tx_ready <= '1'; |
91 | elsif CLK'event and CLK = '1' then |
92 | sent <= false; |
93 | if enable = '1' then |
94 | tx_ready <= '0'; |
95 | Tx <= '1'; |
96 | |
97 | case count_bit is |
98 | when 0 => |
99 | Tx <= '0'; |
100 | count_bit <= count_bit + 1; |
101 | |
102 | when 9 => |
103 | Tx <= '1'; |
104 | count_bit <= count_bit + 1; |
105 | |
106 | when 10 => |
107 | Tx <= '1'; |
108 | count_bit <= 0; |
109 | sent <= true; |
110 | tx_ready <= '1'; |
111 | |
112 | when others => count_bit <= count_bit + 1; |
113 | Tx <= data_register(count_bit - 1); |
114 | |
115 | end case; |
116 | |
117 | end if; |
118 | end if; |
119 | end process data_send; |
120 | |
121 | end architecture behavior; |
MfG Holger
Hi, >Auf dem Xilinx-Board hast du wahrscheinlich ein wenig Glück gehabt. >40MHz und 50MHz sind aber schon ein extremer Unterschied. >Der Taktteiler für den UART hat den Wert von 5208, das ergibt bei 40MHz >eine Bitrate von 7680 bit/s, bei 50MHz sind es 9600 bit/s . Warum Glück? Denkst Du, ich habe den Clockteiler nicht eingestellt?? Das habe ich. Bei 50MHz auf 5208, bei 40MHz auf 4167. Da der Teiler eigentlich Nachkommastellen hat gibt das Abweichungen von 0,6Hz bzw. 0,8Hz. Thx für den Code. Ich probiers mal damit. Daniel
Wenn ich mich nicht täusche, dürfte der Code von mir stammen. Was hat denn da für ein Fehler am Reset vorgelegen? Ich kann ihn in dem Post nicht erkennen... Achso, bei mir hat die UART gefunzt, auf einem V2-250 und einem S2-300E. T.M.
Der Fehler am Reset war, dass nach dem Betätigen des Testers nix mehr gesendet wurde. D.h. der Transmitter war nicht mehr "ready"(da der Reset nur auf Deine Module geführt wurde). Ich bin der Sache aber nicht näher nachgegangen, da das ja nicht das Hauptproblem ist. THX übrigens für das Einstellen des UARTs ins Forum. Daniel
Im Anhang habe ich mal eine neue Version angehängt, es muss aber noch einiges verbessert werden. Es sind noch nicht alle Signale im Reset. Daniel in deiner Version hatten die Tasten noch nicht richtig funktioniert, weil das Eingangsregister nicht gelöscht wurden. Das mit dem Glück bezog sich aber nicht unbedingt auf die Taktrate. Manchmal hat man auch nur Glück, das die Signale nach der Initialisierung den richtigen Zustand aufweisen. Wo hast du überhaupt den Taktteiler verändert? Wenn ich das im Code Lese, befürchte ich, dass du nur den Wertebereich verändert hast.
1 | signal count_clk : natural range 0 to 4167; |
2 | ..
|
3 | > if count_clk = 5208 then |
4 | > count_clk <= 0; |
T.M. das war nicht direkt ein Fehler in deinem UART, sondern es liegt am Zusammenspiel der Zustandsautomaten. Daniels Automat wartet auf eine steigende Flanke von Tx_ready (umbenannt), welche nach dem Reset nicht mehr kommt und schon hat sich der Automat weggehängt. MfG Holger
Hi, vielen Dank für Deine Mühe. Den Taktteiler habe ich selbstverständlich hier geändert: if count_clk = 5208 then count_clk <= 0; Der Bereich wurde auch angepasst. Leider kommt bei dieser Version bei mir nur ab und zu mal was: llllllllllllllllllll HHHHHHHHHHHHHHHHH oooooooooooooo Irgendwie so was halt. Die LED reagiert auch nicht auf das Senden von „Start“. Takt und Pins stimmen. Am Design hab ich nix geändert außer dass der Reset-Taster jetzt high-aktiv ist. Was auch lustig ist: Auf dem Xilinx-Board (Spartan3 Starter Kit) fängt bei Deinem Design plötzlich das obere linke Feld der 7-Segment-Anzeige an zu spinnen. Beim Reset is es aus, beim Drücken auf den Senden-Knopf is es an. Ich habe die Pins mehrmals überprüft: Kein einziger Pin der 7-Seg. Anzeige kommt im UCF-File vor. Ich bin mir zu 100% sicher. Keine Ahnung, was da abgeht. Hab mein UCF-File mal angehängt. Wäre jemand, der ein Xilinx Spartan3 Starter Kit hat mal so nett und würde das Design von high_speed „Uart_neu.zip“ mal mit meinem constraint-File auf dem Board ausprobieren(7-Seg. Anzeigen so lassen, wie sie sind). Senden-Taster: BTN2 Send_enable-LED: LD7 Reset: BTN3 Transmit_out: LD0 Daniel
Hallo Daniel, ich bin jetzt kein Xilinx/ISE-Spezialist, aber in deinem Toplevel hast du ein paar Ports, die in deinem UCF nicht auftauchen. Was macht da ISE? Bei Altera/Quartus werden unplatzierte Pins dann halt irgendwo platziert. Das könnte dann das flackern der 7-Seg.Anzeige erklären. G Rainer
Hallo robodriver Ich habe im Anhang mal ein Bild von der Top-level entity angehängt. Die Taster sind bei mir low aktiv, die LEDs high aktiv. Der Takt vom Oszillator sind 32MHz. Nach der PLL habe ich dann die 50MHz. MfG Holger
@Rainer Die Pins, die nicht auftauchen hab ich extra draußen gelassen, weil ich sie vorerst nicht brauche. Was ISE da macht weiß ich nicht. Ich gehe davon aus, dass die gar nicht herausgeführt werden. Wenn doch, bitte belehrt mich. Ich weise mal alle Pins zu und schau, obs immer noch flackert. @high_speed Hmm...ich weiß auch net was da los ist. Mein Takt kommt direkt ausm 50MHz Quarzoszi. LEDs und Taster high_aktiv. Hab ich geändert.... Daniel
Hi, also: wie schon beschrieben läuft uart_neu nicht auf meinem Xilinx Board. Vorhin hab ich es auf dem Altera Board getestet: Läuft per Knopfdruck, jedoch wird nicht auf die Eingabe von „Start“ oder „Stop“ reagiert. Ich kann mir das nicht erklären. Hab alles mehrmals überprüft.... Daniel
@daniel_r ich belehre dich dann mal : lasse KEINE pins undefiniert (im ucf). xilinx legt die pinne irgendwohin. wenn du pech hast und zufällig einen pin erwischst der (über einen chip z.b.) auf gnd oder vcc liegt kanns knallen. festgestellt hab ich das selbst mal (ohne das es geknallt hat) das mir ein von mir erzeugtes vga-signal auf einmal nicht mehr funktionierte. habe eine halbe stunde gebraucht um festzustellen das ich das ucf-file nicht in meinem design hatte (nachdem ich das projekt neu aufgesetzt hatte). nach dem hinzufügen des ucf-files klappte alles wie gehabt. also : keine pins undefiniert lassen. ich finde es persönlich auch ziemlich bedenklich das man da noch nichtmal eine warnung (eine fehlermeldung wäre besser) bekommt. gerade bei großen designs macht es denke ich sinn. hingegen verstehe ich nicht, das der fitter (bei xilinx) meckert wenn man einen definierten (im ucf) pin nicht verwendet. dann meckert der als wenns kein morgen mehr gibt .... schon merkwürdig, aber vielleicht ist das ein fall für "inverse logik" :-) gruß rene
@high_speed ich habe mein altes Altera-Board rausgepackt und dein Code mal draufgeladen. Es tut bei mir nicht. Auch die LED geht nicht an, wenn ich Start eintippe. Ich habe es mit 50MHZ probiert(mit PLL aus 25MHz).
Hallo Daniel Was für ein Terminalprogramm benutzt du? Ich benutze RealTerm (jetzt 1.99.0.34). http://realterm.sourceforge.net Wie wird der Takt erzeugt? (Oszillator- und PLL- Daten) Was für EVA-Boards sind es? Schaltplan? Mein Design geht von einem Eingangstakt von 50MHz aus. Für andere Taktraten muss man
1 | generic ( |
2 | CLK_div_bit : natural := 5208; -- clock = 50 MHz |
3 | CLK_div_start : natural := 2604 -- clock = 50 Mhz |
4 | );
|
in uart_hello ändern. CLK_div_start hat ca. den halben Wert von CLK_div_bit. Die Steuerbefehle sind "Start" und "Stop" mit großem 'S'. Die Eingangssignale des VHDL-Design: CLK: rising edge nReset: low aktiv Rx: high aktiv Knopf: high aktiv Die Ausgangssignale des VHDL-Design: Tx: high aktiv led: high aktiv data_ctrl: high aktiv clock_out: high aktiv tx_ready_out: high aktiv transmit_out: high aktiv signal test_signal : std_logic_vector(1 downto 0); -- Taktteilung Senden Ist erstmal ein Hilfssignal, es soll eine Pause generieren, bis Tx_ready auf '0' geht, so dass das nächste Zeichen erst bei der nächsten '1' in den Sendepuffer des UART geschrieben wird, ansonsten wird bei der nächsten steigenden Flanke von CLK schon das nächste Zeichen in den Puffer geschrieben. In deiner Originalversion wurde nach dem Start: "Halloalloalloallo".. ausgegeben. Das karm dadurch zustande, das das 'H' anders behandelt wurde als der Rest. MfG Holger
Hallo Holger, ich benutze momentan das Windows-Terminal. Der Takt wird bei beiden Boards über einen Quarzoszillator(50 MHz bei dem Xilinx Board und 40 MHz beim Altera Board) erzeugt. Ich benutze keine PLL. Das Xilinx Board ist ein Spartan3 Starter Kit, das Altera Board gehört der Firma, in der mein Vater arbeitet. Ich darf den Schaltplan deswegen leider nicht posten. Aber ich kann versichern, dass die Hardware OK ist. Das Design, welches auf dem Prom ist benutzt auch die RS232 und funktioniert. Die Generics hab ich selbstverständlich dem Takt angepasst(mehrmals überprüft). Befehle werden mit großem "S" gesendet. Daniel
@ TheMason Das is ja echt wissenswert, dass unbenutzte Pins einfach irgendwo hin gemappt werden. Danke für die Info. Werde zukünftig alle Pins zuweisen. Daniel
Hallo Daniel
> .. ich benutze momentan das Windows-Terminal
Ich habe es eben auch mal mit HyperTerminal ausprobiert und es
funktioniert
genauso gut. Besorge dir trotzdem mal ein anderes Terminal, das
HyperTerminal ist nicht gerade benutzerfreundlich.
Die PLL habe ich jetzt mal rausgenommen und takte direkt mit 32 MHz.
Im Anhang hänge im mal das aktuelle Projekt als Quartus II Archiv an.
MfG
Holger
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.