Forum: FPGA, VHDL & Co. UART schickt keine Zeichen


von Tim V. (nrgyzer)


Lesenswert?

Hallo zusammen,

ich entwickle schon seit einigen Jahren Software. Was 
FPGA-Programmierung angeht bin ich aber ein ziemlicher Neuling. Was ich 
habe ist ein Spartan 6 (konkret: xc6slx150). Nachdem ich nun ein paar 
LEDs zum blinken gebracht habe, möchte ich nun eine UART realisieren. 
Nachdem ich schon einige Foren und Tutorials durchforstet habe, komme 
ich einfach nicht weiter. Ich habe folgendes Constraint-File:
1
##############################################################
2
# Clock Pins
3
##############################################################
4
5
NET "clk" LOC = J1 | IOSTANDARD = LVCMOS33;
6
7
##############################################################
8
# TxD/RxD Pins
9
##############################################################
10
NET "ser" LOC = B1 | IOSTANDARD = LVCMOS33;
11
12
##############################################################
13
# Clock Domains
14
##############################################################
15
16
NET "uartclk" TNM_NET = "uartclk";
17
TIMESPEC "TS_clk" = PERIOD "uartclk" 50 MHZ HIGH 50%;

Meine uart (nur tx-Seite) sieht wie folgt aus (weitestgehend von 
http://electronics.stackexchange.com/questions/13718/implement-serial-port-on-fpga-verilog 
übernommen):
1
// Serial port demo program
2
// 
3
// Assumptions: 50Mhz clock rate
4
5
module SerDemo(input uartclk, output ser);
6
7
// Start signal tells it to start sending bits
8
reg start;
9
10
//The bits of data to send
11
reg [7:0] data;
12
13
/////////////////////////////////////////////////////////////////////////////
14
// Serial port clock generator
15
// Generate a 9600 baud clock signal for the serial port by dividing the
16
// 50Mhz clock by 5208
17
18
reg [14:0] clockdiv;
19
20
// Count from 0..5207 then reset back to zero
21
always @(posedge uartclk) 
22
begin
23
    if (clockdiv == 5207) 
24
        clockdiv <= 0;
25
    else
26
        clockdiv <= clockdiv + 1;
27
end
28
29
// The serclock is a short pulse each time we are reset
30
wire serclock = (clockdiv == 0);
31
32
/////////////////////////////////////////////////////////////////////////////
33
// Serial port state machine
34
// Only start the state machine when "start" is set. Only advance to the
35
// next state when serclock is set.
36
37
reg [3:0] state;
38
39
always @(posedge uartclk)
40
begin
41
   case (state)
42
        4'b0000: if (start) state <= 4'b0001;
43
        4'b0001: if (serclock) state <= 4'b0010;    // Start bit
44
        4'b0010: if (serclock) state <= 4'b0011;    // Bit 0
45
        4'b0011: if (serclock) state <= 4'b0100;    // Bit 1
46
        4'b0100: if (serclock) state <= 4'b0101;    // Bit 2
47
        4'b0101: if (serclock) state <= 4'b0110;    // Bit 3
48
        4'b0110: if (serclock) state <= 4'b0111;    // Bit 4
49
        4'b0111: if (serclock) state <= 4'b1000;    // Bit 5
50
        4'b1000: if (serclock) state <= 4'b1001;    // Bit 6
51
        4'b1001: if (serclock) state <= 4'b1010;    // Bit 7
52
        4'b1010: if (serclock) state <= 4'b0000;    // Stop bit
53
        default: state <= 4'b0000;                  // Undefined, skip to stop
54
    endcase
55
end
56
57
58
///////////////////////////////////////////////////////////////////////////////
59
// Serial port data
60
// Ensure that the serial port has the correct data on it in each state
61
62
reg outbit;
63
64
always @(posedge uartclk)
65
begin
66
    case (state)
67
         4'b0000: outbit <= 1;              // idle
68
         4'b0001: outbit <= 0;              // Start bit
69
         4'b0010: outbit <= data[0];        // Bit 0
70
         4'b0011: outbit <= data[1];        // Bit 1
71
         4'b0100: outbit <= data[2];        // Bit 2
72
         4'b0101: outbit <= data[3];        // Bit 3
73
         4'b0110: outbit <= data[4];        // Bit 4
74
         4'b0111: outbit <= data[5];        // Bit 5
75
         4'b1000: outbit <= data[6];        // Bit 6
76
         4'b1001: outbit <= data[7];        // Bit 7
77
         4'b1010: outbit <= 1;          // Stop bit
78
         default: outbit <= 1;          // Bad state output idle
79
    endcase
80
end
81
82
// Output register to pin
83
assign ser = outbit;
84
85
///////////////////////////////////////////////////////////////////////////////
86
// Test by outputting a letter 'T'
87
88
always @(posedge uartclk)
89
begin
90
     data = 84; // ASCII 85 = T
91
     start = 1;
92
end
93
94
endmodule

Die UART soll ständig das Zeichen "T" zum Rechner schicken. Wenn ich den 
Clock-Pin (J1 - 100MHz) für die UART-Clock (uartclk) verwende und meinen 
Counter (die 5207) entsprechend anpasse, empfange ich immer das Zeichen 
"T". Wenn ich allerdings den Code oben verwende und nicht die 100MHz 
nehmen möchte, die bei J1 anliegen, sondern nur 50MHz, läuft scheinbar 
überhaupt nichts. Ich empfange nichts und die TxD-LED auf dem Board 
zeigt auch nichts an. Es scheint so, als sendet der FPGA schlichtweg 
nichts. Was mache ich falsch? Muss ich bei meinem TIMESPEC für die 
uartclk noch irgendwas angeben oder...?!?

von Falk B. (falk)


Lesenswert?

@ Tim V. (nrgyzer)

>ich einfach nicht weiter. Ich habe folgendes Constraint-File:

Pinzuweisung und Definition des Taktes.

>Die UART soll ständig das Zeichen "T" zum Rechner schicken.

Nicht so gut und sinnvoll. Denn der braucht auch mal ne Pause zum 
synchronisieren, wenigstens einmal am Anfang. Aber das wird, mehr oder 
weniger zufällig, schon klappen.

> Wenn ich den
>Clock-Pin (J1 - 100MHz) für die UART-Clock (uartclk) verwende und meinen
>Counter (die 5207) entsprechend anpasse, empfange ich immer das Zeichen
>"T".

Ist doch super.

> Wenn ich allerdings den Code oben verwende und nicht die 100MHz
>nehmen möchte, die bei J1 anliegen, sondern nur 50MHz, läuft scheinbar
>überhaupt nichts. Ich empfange nichts und die TxD-LED auf dem Board
>zeigt auch nichts an. Es scheint so, als sendet der FPGA schlichtweg
>nichts. Was mache ich falsch?

Liegen die 50 MHz auch wirklich an? Hast du den Teiler angepasst?

> Muss ich bei meinem TIMESPEC für die
>uartclk noch irgendwas angeben oder...?!?

Nein, das ist nur für den Synthesizer eine Timingvorgabe, damit er 
prüfen kann, ob deine Logik 50 MHz schafft. Ob du dann wirklich 50 MHz 
anlegst oder nicht, ist dein Bier.

von Tim V. (nrgyzer)


Lesenswert?

Vielen Dank für deine Antwort, Falk!

1] Was meinst du mit "Pinzuweisung und Definition des Taktes."? Die 
nicht verwendeten Pins sind floatend.

2] Was müsste ich denn einbauen, damit der sich synchronisieren kann? 
Müsste ich noch einen Reset-State beim Zähler mit einbauen, so wie es 
auf 
http://electronics.stackexchange.com/questions/13718/implement-serial-port-on-fpga-verilog 
beschrieben ist?

3] Ja, finde ich auch :). Zumindest klappt schonmal bei 100MHz.

4] Welchen Teiler meinst du konkret? Die 5207 bzw. 5208 sollten für 50 
MHz und 9600 Baud reichen. Oder meinst du noch etwas anderes? Oder 
meinst du Clock Domain Crossing 
(http://www.fpga4fun.com/CrossClockDomain.html)?

5] Achso, okay. Ich dachte durch das TIMESPEC-Constraint erhalte ich 
irgendwie eine 50 MHz-Clock, auf die ich mich in meinem Verilog-Modul 
beziehen kann...

von Falk B. (falk)


Lesenswert?

@Tim V. (nrgyzer)

>1] Was meinst du mit "Pinzuweisung und Definition des Taktes."? Die
>nicht verwendeten Pins sind floatend.

Ist OK. Das war nur ein allgemeiner Kommentar.

>2] Was müsste ich denn einbauen, damit der sich synchronisieren kann?

Eine Sendepause.

>Müsste ich noch einen Reset-State beim Zähler mit einbauen, so wie es
>auf
>http://electronics.stackexchange.com/questions/137...
>beschrieben ist?

Das ist eine Möglichkeit.

>4] Welchen Teiler meinst du konkret? Die 5207 bzw. 5208 sollten für 50
>MHz und 9600 Baud reichen.

Nach Adam Ries schon. Aber wenn du den Teiler vorher verdoppelt hast 
(wegen dem 100 MHz Takt), musst du ihn dann wieder auf die 5207 zurück 
stellen.

> Oder meinst du noch etwas anderes? Oder
>meinst du Clock Domain Crossing
>(http://www.fpga4fun.com/CrossClockDomain.html)?

Nein.

>5] Achso, okay. Ich dachte durch das TIMESPEC-Constraint erhalte ich
>irgendwie eine 50 MHz-Clock, auf die ich mich in meinem Verilog-Modul
>beziehen kann...

Nein. Das ist nur die Anweisung an den Compiler, das Timing zu prüfen.
Das ist KEIN per Software einstellbarer Oszillator!

von Tim V. (nrgyzer)


Lesenswert?

Also an dem Pin J1 liegen ja die 100 MHz an. Was müsste ich tun, damit 
ich daraus 50 MHz machen kann? Müsste ich dann einen anderen 
Oszillator-Pin verwenden oder wie kann ich die 100 MHz an dem J1-Pin 
verwenden um meine UART mit 50 MHz zu clocken?

von P. K. (pek)


Lesenswert?

Du speist die 100 MHz in den DLL/PLL-Block (oder wie immer die 
Taktaufbereitung in Deinem FPGA bezeichnet wird) und halbierst ihn auf 
50 MHz.
Das geht ziemlich einfach mit dem CoreGenerator. Den generierten Core 
musst Du dann lediglich noch instanziieren (plus ein propagate clocks in 
den Timing-Constraints).

von Tim V. (nrgyzer)


Lesenswert?

Danke pek für die Hinweise. Ich weiß zwar noch nicht genau wie das 
umgesetzt wird. Jetzt habe ich aber zumindest einen prinzipiellen 
Anhaltspunkt, wonach ich suchen muss etc... :)

von P. K. (pek)


Lesenswert?

Das hier beschreibt den Einbau prinzipiell:
https://embeddedmicro.com/tutorials/mojo/using-core-generator

Was Du in Deinem Fall brauchst, findest Du im IP-Katalog unter:
FPGA Feature and Design > Clocking > Clocking Wizard

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.