Forum: FPGA, VHDL & Co. [VHDL] Variable UART-Baudrate


von AD (Gast)


Lesenswert?

Hallo Leute,

Folgende Eckdaten zu meinem Problem:

FPGA: Lattice iCE40 HX1K
Systemtakt: 100.5 MHz (spuckt der PLL-Generator so "unrund" aus)

Ich möchte ein UART-Modul, dass mit verschiedenen µCs mit verschiedenen 
Baudraten kommuniziert, können auch nicht die gängigen sein.

Aus diesem Grund will ich anhand eines Sync-Bytes (0x55 oder 0xAA) vom 
µC die Zeit messen, die ein Bit des Inputs anliegt, um bei den 
darauffolgenden Datenbits zu wissen, wann der Wert gültig ist. Das Ganze 
hab ich mit einer Statemachine umgesetzt.

Kommt eine fallende Flanke am Eingang, starte ich einen Zähler und 
stoppe ihn bei einer steigenden Flanke. Das Ganze mach ich 4mal (bzw. 
5mal bei 0xAA), dann ist meine UART-Message (8 Datenbits,1 Stopbit) zu 
Ende und ich weise den gemessenen Wert einer Variable zu. Das klappt 
auch alles wunderbar in der Simulation, nur in der Praxis hauts nicht 
ganz hin, hier der relevante Code dazu:
1
  IF rising_edge(clk) THEN     
2
           
3
     rx_detect <= rx_detect(rx_detect'left-1 DOWNTO 0) & uart_rx;
4
5
     CASE uart_rx_mode IS
6
 
7
     WHEN uart_rx_sync =>
8
           
9
         CASE uart_sync_state IS
10
         
11
         WHEN uart_sync_idle =>
12
         
13
             IF (rx_detect(3 DOWNTO 2) = "10") THEN
14
                 uart_sync_state <= start_counter;
15
             END IF;          
16
          
17
         WHEN start_counter =>             
18
           
19
             IF (rx_detect(3 DOWNTO 2) = "01") THEN        
20
                 uart_sync_state <= stop_counter;
21
             END IF;
22
         
23
             counter_rx <= counter_rx + 1;
24
          
25
         WHEN stop_counter =>
26
        
27
              temp <= counter_rx;
28
              cnt_value <= cnt_value + counter_rx;
29
              cnt_iteration <= cnt_iteration + 1;
30
              uart_sync_state <= reset_counter;
31
        
32
         WHEN reset_counter =>
33
        
34
              counter_rx <= 0;  
35
                          
36
              IF cnt_iteration = 4 THEN                     
37
                 uart_sync_state <= sync_values;
38
              ELSE
39
                 uart_sync_state <= uart_sync_idle;
40
              END IF;              
41
42
         WHEN sync_values =>  
43
           
44
              bit_time <= temp;                  
45
              uart_sync_state <= sync_finished;
46
        
47
         WHEN sync_finished =>        
48
         
49
              cnt_iteration <= 0;
50
              cnt_value <= 0;
51
              counter_rx <= 0;
52
              temp <= 0;
53
              uart_rx_mode <= uart_rx_normal; 
54
              uart_sync_state <= uart_sync_idle;
55
        
56
         END CASE;

Alle Werte (bit_time,temp,counter_rx,..) sind Signale vom Typ Integer.

Wenn ich die Zuweisung bit_time <= temp; auskommentiere, und bit_time 
mit einem festen Wert für eine bestimmte Baudrate initialisiere, 
funktioniert alles super, allerdings ist dann eben die Baudrate nicht 
variabel...

Auch meine Clock bricht mit dieser Zuweisung ein, mit der Zeile:
(Hier sogar noch über 100MHz, oft aber auch darunter)

                     Clock Summary
=====================================================================
Number of clocks: 3
Clock: I1.uart_pll_inst/PLLOUTCORE | Frequency: 107.23 MHz | Target: 
100.50 MHz
Clock: I1.uart_pll_inst/PLLOUTGLOBAL | Frequency: N/A | Target: 100.50 
MHz
Clock: my_clk | Frequency: N/A | Target: 12.00 MHz

Ohne:

                     Clock Summary
=====================================================================
Number of clocks: 3
Clock: I1.uart_pll_inst/PLLOUTCORE | Frequency: 147.30 MHz | Target: 
100.50 MHz
Clock: I1.uart_pll_inst/PLLOUTGLOBAL | Frequency: N/A | Target: 100.50 
MHz
Clock: my_clk | Frequency: N/A | Target: 12.00 MHz

Aufgrund der Clock Summarys hab ich nur die Vermutung dass durch die 
Zuweisung ein kritischer/zu langer Pfad entsteht, bin mir da aber nicht 
sicher (-> noch FPGA-Anfänger)

Seht ihr sonst Fehler, bzw kann man das überhaupt so machen? Gibts 
Alternativen?

Leider etwas langer Post geworden, trotzdem danke für jede Hilfe!

MfG
Andreas

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


Lesenswert?

AD schrieb:
> Alle Werte (bit_time,temp,counter_rx,..) sind Signale vom Typ Integer.
Hoffentlich eingeschränkte Integer (so mit "range 0 to xxx")...

> Wenn ich die Zuweisung bit_time <= temp; auskommentiere
Das Problem liegt nicht an dieser Stelle, denn diese Zuweisung kann 
problemlos mit maximaler Taktfrequenz gemacht werden. Es leigt eher 
dort, wo bit_time wieder verwendet wird...

von AD (Gast)


Lesenswert?

yo sind beschränkt;

ich verwende die Variable dann in den Sende/Empfangs-Statemachines; dort 
zählt einfach ein counter bis zu diesem Wert hoch.

Ich weiss derzeit auch noch nicht ob "gültige" Werte gemessen werden um 
das UART-Timing einzuhalten, kann ich wrsl erst morgen testen. Aufgrund 
der clock summarys ist mir nur aufgefallen, dass da was nicht stimmen 
kann.

Irgendwelche Ideen?

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


Lesenswert?

AD schrieb:
> ich verwende die Variable
Welche Variable denn?
AD schrieb:
> bit_time <= temp;
Das ist ein Signal, und Variablen sind in VHDL ganz was anderes als 
Signale! Ich möchte fast behaupten, dass ein VHDL Anfänger das erste 
viertel Jahr ohne eine einzige Variable auskommt. Siehe dazu in aller 
Ausführlichkeit den Beitrag "Variable vs Signal"

AD schrieb:
> Auch meine Clock bricht mit dieser Zuweisung ein, mit der Zeile:
> (Hier sogar noch über 100MHz, oft aber auch darunter)
Was verlangst du denn? Welche Constraints hast du auf den Takt 
gesetzt? Welchen Takt hast du tatsächlich im Design?

von pks (Gast)


Lesenswert?

Lothar Miller schrieb:
> Ich möchte fast behaupten, dass ein VHDL Anfänger das erste
> viertel Jahr ohne eine einzige Variable auskommt.

Ich möchte fast behaupten, dass man generell ohne auskommt :-)

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


Lesenswert?

pks schrieb:
> Ich möchte fast behaupten, dass man generell ohne auskommt :-)
Manchmal sind sie schon unglaublich praktisch. In Funktionen sind sie 
z.B. ganz gut aufgehoben. Oder für kleine Teilaufgaben wie dort: 
http://www.lothar-miller.de/s9y/categories/24-Rechnen

Wo sie aber überhaupt nichts zu suchen haben sind FSM und getaktete 
Zähler.

von AD (Gast)


Lesenswert?

Sorry hab mich falsch ausgedrückt. Ich verwende nur Signale, keine 
Variablen.

Systemclock ist 100 MHz, die durch eine PLL erzeugt werden.
(schon nachgemessen, passt)

Die Clock direkt ist wrsl nicht das Problem, da ich sie auch messe, wenn 
ich die Zeile nicht auskommentiere, Frequency gibt mir ja nur an, was 
die maximal mögliche Taktrate wäre.

Nur der Unterschied mit dieser Zeile von 40 MHz machte mich stutzig und 
auf den Fehler aufmerksam.

Wie gesagt, das bit_time Signal verwende ich dann nur als obere Schranke 
für meinen Zähler in der Sende/Empfangs-StateMachine; wenn ich diese 
Schranke vorher fest initialisiere, funktioniert alles. Wenn ich 
dynamisch messe und dann zuweise, klappts nicht.

Bin gerade dabei die gemessen Bitzeiten(also der bit_time Wert) zu 
überprüfen, vllt liegt hier der Fehler. Aber eig sollten bei 100MHz auch 
Abweichungen von ein paar Takten nicht soviel ausmachen, die UART ist ja 
minimal fehlertolerant.

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


Lesenswert?

AD schrieb:
> Nur der Unterschied mit dieser Zeile von 40 MHz machte mich stutzig und
> auf den Fehler aufmerksam.
Welcher Fehler? 107MHz ist doch auch noch mehr als die geforderten 
100MHz. "Fertig!" sagt sich da die Toolchain, wenn sie mehr als 100MHz 
erreicht hat...

> Wenn ich dynamisch messe und dann zuweise, klappts nicht.
Dann liegt der Fehler in der Messung. Welchen Wert bekommst du denn da 
für temp raus?

: Bearbeitet durch Moderator
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.