Forum: FPGA, VHDL & Co. Anfängerfrage: Übertragung starten


von M. P. (warranty)


Lesenswert?

Hi Leute,
bin noch ein VHDL Anfänger und habe -wie ihr euch wohl denken könnt- 
eine Frage.

Und zwar bastel ich gerade am Code um Seriell Daten vom FPGA zum PC zu 
senden. Also ein UART über RS-232 Schnittstelle. Das ganze hab ich in 
einen process gepackt dieser hat in seiner sensivity list den clock (50 
Mhz) und einen Reset. Der process ist wie ein Zustandsautomat aufgebaut 
und funktioniert im soweit auch ganz anständig. Die Bits werden jeweils 
für 2600 durchläufe gehalten, also eine Bitrate von 19200.

Nun will ich aber nur senden wenn ein neues Byte zum senden ankommt, und 
dann auch nur einmal. Das heißt nur wenn tx_start high wird. In die 
sensivity list kann ichs ja nicht reinpacken. Und nur mit der if 
Überprüfung kommt mir das ganze nicht sehr elegant vor.

Hat jemand einen Tipp wie man das elegant und sauber bewerkstelligt?
1
uart: process(clk, clr)
2
begin 
3
4
if clr = '1' then 
5
  (...)
6
elsif (clk'event and clk = '1') then 
7
  case UART_Status is 
8
    when idle =>  -- Es wird gewartet bis tx_start high wird
9
      if (tx_start = '1') then
10
        tx_data <= data;
11
        UART_Status <= start;
12
      else
13
        UART_Status <= idle;
14
      end if;
15
      
16
    when start => -- Startbit senden
17
    (...)
18
    when hold => -- Hält das Datenbit für eine bestimmte Zeit 
19
    (...)  
20
    when next => -- nächstes Datenbit
21
    (...)  
22
    when parity => -- Parity bit senden
23
    (...)
24
    when stop => -- Stop Bit senden
25
    (...)
26
  end case; 
27
end if; 
28
end process uart;

Schonmal im Voraus Danke für alle konstruktiven Antworten.
Marc

von Falk B. (falk)


Lesenswert?

@  Marc P. (warranty)

>und funktioniert im soweit auch ganz anständig. Die Bits werden jeweils
>für 2600 durchläufe gehalten, also eine Bitrate von 19200.

Hoffentlich mit clock enable, siehe Taktung FPGA/CPLD

>sensivity list kann ichs ja nicht reinpacken. Und nur mit der if
>Überprüfung kommt mir das ganze nicht sehr elegant vor.

Warum? Genau so macht man das.

MfG
Falk

von M. P. (warranty)


Lesenswert?

Falk Brunner schrieb:
>>und funktioniert im soweit auch ganz anständig. Die Bits werden jeweils
>>für 2600 durchläufe gehalten, also eine Bitrate von 19200.
>
> Hoffentlich mit clock enable, siehe Taktung FPGA/CPLD

Naja die 50 Mhz sind Systemtakt!. Sorry aber ich hab mich glaub nicht 
deutlich genug ausgedrückt. Diser process wird mit 50 Mhz getrieben. Die 
zählschleifen für das halten der bits befinden sich in den jeweiligen 
case anweisungen. Ich glaube du meinst, dass ich einen eigenen dafür 
habe, oder?

Falk Brunner schrieb:
>>sensivity list kann ichs ja nicht reinpacken. Und nur mit der if
>>Überprüfung kommt mir das ganze nicht sehr elegant vor.
>
> Warum? Genau so macht man das.

Naja also sollte ich mir in einer Variable merken ob das letzte bit 
schon gesendet wurde, und erst wieder die data einlesen bzw. die 
variable rücksetzen wenn tx_start low geworden ist, zb. so:
1
uart: process(clk, clr)
2
variable x: boolean:= false;
3
begin 
4
5
if clr = '1' then 
6
  (...)
7
elsif (clk'event and clk = '1') then 
8
  case UART_Status is 
9
    when idle =>  -- Es wird gewartet bis tx_start high wird
10
      if (tx_start = '1') then
11
        if not x then  -- wenn x true, dann wurde das byte schon ausgegeben
12
        UART_Status <= start;
13
        end if;
14
      else
15
        x := false;
16
        tx_data <= data;
17
        UART_Status <= idle;
18
      end if;
19
      
20
    when start => -- Startbit senden, counter löschen, Parity Bit berechnen
21
      x := true;
(...)
(...)

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


Lesenswert?

Marc P. schrieb:
> Naja also sollte ich mir in einer Variable merken ob das letzte bit
> schon gesendet wurde, und erst wieder die data einlesen bzw. die
> variable rücksetzen wenn tx_start low geworden ist, zb. so:
So ein Handshake wäre auch meine bevorzugte Methode, aber die 
Implementierung ist viel einfacher:
1
uart: process(clk, clr)
2
begin 
3
4
if clr = '1' then 
5
  (...)
6
elsif (clk'event and clk = '1') then 
7
  case UART_Status is 
8
    when idle =>  -- Es wird gewartet bis tx_start high wird
9
      if (tx_start = '1') then
10
        tx_data <= data;
11
        UART_Status <= start;  --<<<< das brauchst du nicht wenn sich UART_Status sowieso nicht ändert....
12
      else
13
        UART_Status <= idle;
14
      end if;
15
      
16
    when start => -- Startbit senden
17
    (...)
18
    when hold => -- Hält das Datenbit für eine bestimmte Zeit 
19
    (...)  
20
    when next => -- nächstes Datenbit
21
    (...)  
22
    when parity => -- Parity bit senden
23
    (...)
24
    when stop => -- Stop Bit senden
25
    (...)
26
    when check_start =>
27
      if (tx_start = '0') then --<<<< warten, bis tx_start wieder inaktiv
28
        UART_Status <= idle;
29
      end if;
30
  end case; 
31
end if; 
32
end process uart;

BTW:
Du hast eine recht aufwendige Implementierung über eine FSM. Lade doch 
einfach den kompletten Frame incl. Start,Daten und Stopbit in ein 
Schieberegister und takte das Bit für Bit raus. So etwa: 
http://www.lothar-miller.de/s9y/categories/42-RS232

Das mit dem (vermutlich) asynchronen clr ist unschön und 
wahrscheinlich unnötig...

von René D. (Firma: www.dossmatik.de) (dose)


Angehängte Dateien:

Lesenswert?

Ich habe einen Transmitter mit einer State Machine, die wiederum einen 
Multiplexer füttert und so die Bitreihenfolge erzeugt wird. Diese 
Implementierung ist entspechend deiner Anfrage.

8N1 bedeutet:
8 Datenbit
No Parity
1 Stoppbit

Wenn du unbedingt ein Paritybit brauchst, dann hänge der State machine 
einen Zustand hinten dran.


Ich sehe gerade.
Der Vergleich   "if tick_counter=tick then" ist vom Typ her nicht ganz 
in Ordnung. Es hatte bei mir funktioniert. Sauberer wäre beide Operanden 
vom gleichem Typ.

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


Lesenswert?

@ René D.
1
entity Uart_8N1_TX is
2
 --50MHz/115200=434
3
 --for other system clock cycle or baudrate
4
 --tick is  to adapted
5
generic (tick: integer :=434);
6
:

Lass doch den Synthesizer rechnen:
1
entity Uart_8N1_TX is
2
generic (tick: integer := 50000000/115200 ); -- clock frequency / baudrate 
3
:

von René D. (Firma: www.dossmatik.de) (dose)


Lesenswert?

Lass doch den Synthesizer rechnen:

Ja das ist noch besser.


Noch besser wäre
generic( baudrate: integer:=115200;
         clk_freq: integer:=50E6);

und damit rechnen.


Wie kritisch findest du den Vergleich mit den Typen integer und 
unsigned?



Man braucht eine Sammlung von primitiven Elementen. Dafür müsste es eine 
IEEE library geben. So erfindet jeder das Rad neu.

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.