Serielle Schnittstelle auf fpga implementieren (verilog)

Ich weiß nicht, ob das hierher gehört oder Stackoverflow. Ich nehme hier an, dass Verilog zwar wie Software aussieht, aber tatsächlich Hardwareverbindungen beschreibt?

Ich habe ein Spartan-3AN-Evaluierungsboard und versuche, eine einfache RS232-Port-Schnittstelle darauf zu implementieren, die ich nicht zum Laufen bringen kann. Ich bin ein erfahrener Softwareentwickler, aber neu bei Verilog und digitalem Design. Ich möchte vom Blinken einer einzelnen LED zum nächsten Schritt übergehen.

Ich habe versucht, es so zu implementieren - 1) Generieren Sie einen Taktimpuls "serclock" mit der Baudrate, also zu Beginn jedes Bits. 2) Implementieren Sie eine Zustandsmaschine, die, sobald ihr gesagt wird, dass sie mit der richtigen Geschwindigkeit durch die Zustände gehen soll. 3) Implementieren Sie eine Suche, um das richtige Datenbit abhängig von dem Zustand auszugeben, in dem sich 2) befindet.

Wenn es einen besseren Weg gibt, wäre ich für jede Hilfe dankbar. Ich würde jedoch erwarten, dass dies funktioniert, aber ich bekomme überhaupt nichts. Kann jemand etwas Dummes erkennen, das ich getan habe? Ich würde mich über jeden Rat freuen.

// Serial port demo program
// 
// Assumptions: 50Mhz clock rate

module SerDemo(input clk, output ser);


// Start signal tells it to start sending bits
reg start;

//The bits of data to send
reg [7:0] data;

/////////////////////////////////////////////////////////////////////////////
// Serial port clock generator
// Generate a 9600 baud clock signal for the serial port by dividing the
// 50Mhz clock by 5208

reg [14:0] clockdiv;

// Count from 0..5207 then reset back to zero
always @(posedge clk) 
begin
    if (clockdiv == 5207) 
        clockdiv <= 0;
    else
        clockdiv <= clockdiv + 1;
end

// The serclock is a short pulse each time we are reset
wire serclock = (clockdiv == 0);

/////////////////////////////////////////////////////////////////////////////
// Serial port state machine
// Only start the state machine when "start" is set. Only advance to the
// next state when serclock is set.

reg [3:0] state;

always @(posedge clk)
begin
   case (state)
        4'b0000: if (start) state <= 4'b0001;
        4'b0001: if (serclock) state <= 4'b0010;    // Start bit
        4'b0010: if (serclock) state <= 4'b0011;    // Bit 0
        4'b0011: if (serclock) state <= 4'b0100;    // Bit 1
        4'b0100: if (serclock) state <= 4'b0101;    // Bit 2
        4'b0101: if (serclock) state <= 4'b0110;    // Bit 3
        4'b0110: if (serclock) state <= 4'b0111;    // Bit 4
        4'b0111: if (serclock) state <= 4'b1000;    // Bit 5
        4'b1000: if (serclock) state <= 4'b1001;    // Bit 6
         4'b1001: if (serclock) state <= 4'b1010;   // Bit 7
        4'b1010: if (serclock) state <= 4'b0000;    // Stop bit
        default: state <= 4'b0000;                  // Undefined, skip to stop
    endcase
end


///////////////////////////////////////////////////////////////////////////////
// Serial port data
// Ensure that the serial port has the correct data on it in each state

reg outbit;

always @(posedge clk)
begin
    case (state)
         4'b0000: outbit <= 1;              // idle
         4'b0001: outbit <= 0;              // Start bit
         4'b0010: outbit <= data[0];        // Bit 0
         4'b0011: outbit <= data[1];        // Bit 1
         4'b0100: outbit <= data[2];        // Bit 2
         4'b0101: outbit <= data[3];        // Bit 3
         4'b0110: outbit <= data[4];        // Bit 4
         4'b0111: outbit <= data[5];        // Bit 5
         4'b1000: outbit <= data[6];        // Bit 6
         4'b1001: outbit <= data[7];        // Bit 7
         4'b1010: outbit <= 0;          // Stop bit
         default: outbit <= 1;          // Bad state output idle
    endcase
end

// Output register to pin
assign ser = outbit;

///////////////////////////////////////////////////////////////////////////////
// Test by outputting a letter 'd'

always @(posedge clk)
begin
    data = 100;
     start = 1;
end

endmodule
Oh, ich habe nicht gesagt, was das Problem ist. Das Problem ist, dass ich überhaupt nichts auf der Ausgabe der seriellen Schnittstelle bekomme. Ich würde einen Strom von Buchstaben 'd' erwarten (ASCII-Code 100)
Ich habe gerade ähnlichen Code auf fpga4fun.com/SerialInterface.html gefunden , der funktioniert, wenn ich ihn versuche. Ich wüsste aber trotzdem gerne, was mit mir los ist
Ich spreche kein Verilog, aber mir ist aufgefallen, dass Ihr Stopbit null ist, was 1 sein sollte. Lesen Sie den Port auf einem Oszilloskop oder auf einem UART? Im letzteren Fall erhalten Sie möglicherweise kein Zeichen, wenn es das Stoppbit nicht sieht.
Oh nein ein Tippfehler. Das war alles. Ich habe mir diesen Code 100 Mal angesehen und es nicht bemerkt. Danke, es funktioniert jetzt einwandfrei. Können Sie das als Antwort angeben, dann kann ich es akzeptieren?
Nicht im Zusammenhang mit Ihrer Frage, aber synthetisierbares Verilog hängt stark von der Befolgung von Konventionen ab und nicht nur von den strengen Regeln der Sprache. Ihr Code ist mit ziemlicher Sicherheit funktionsfähig, könnte aber eine Überprüfung durch erfahrene Designer gebrauchen. Der erste Vorschlag, den ich machen würde, ist, dass Sie bei der Generierung outbitein Schieberegister anstelle eines Mux verwenden könnten, um die Ressourcennutzung zu reduzieren.
Zweitens, wo Sie generieren state, wenn Sie den Test für serclockaußerhalb der case-Anweisung verschieben, generieren Sie eine ordnungsgemäße Gated Clock und halten auch Ihre startErkennung mit serclock synchronisiert. So wie es ist, können Sie ein Runt-Startbit generieren.
Wenn Sie eine weitere Frage stellen, in der Sie nach einer allgemeinen Codeüberprüfung fragen, erhalten Sie möglicherweise einige weitere nützliche Vorschläge.
Danke für die Vorschläge. Gute Idee. Ich verwende diesen Code nicht mehr, aber ich habe ein anderes Verilog, das funktioniert, aber möglicherweise nicht ideal ist, das ich in den nächsten ein oder zwei Wochen zur Überprüfung veröffentlichen könnte. Ich denke, es wäre auch eine gute Frage für Leute, die lernen möchten, was gute Praxis ist, und mir helfen möchten.
Außerdem ist mir gerade klar geworden, dass ich aktivierte Uhren hätte sagen sollen , nicht geschlossene Uhren. Gated Clocks sind in FPGAs im Allgemeinen eine schlechte Praxis, aber die richtige Verwendung des Clock-Enable-Eingangs der Flip-Flops spart Ressourcen und verbessert das Timing.
Ich bin mir auch nicht sicher, warum diese Frage auf der Titelseite auftauchte, ich wusste nicht, dass sie mehr als ein Jahr alt war, als ich kommentierte.
Ich war ein wenig überrascht, eine Benachrichtigung über Kommentare zu erhalten, aber es ist immer noch gültig, Ratschläge zu einer alten Frage hinzuzufügen, da der Zweck dieser Website darin besteht, durchsuchbare Fragen zu erstellen und Personen direkt zu antworten.

Antworten (2)

Ich spreche kein Verilog, aber mir ist aufgefallen, dass Ihr Stopbit null ist, was 1 sein sollte. Lesen Sie den Port auf einem Oszilloskop oder auf einem UART? Im letzteren Fall erhalten Sie möglicherweise kein Zeichen, wenn es das Stoppbit nicht sieht.

Sie haben das System nicht auf einen bekannten Zustand zurückgesetzt .

Das heißt, ich nehme an, dass Sie dies tun, um Verilog zu lernen? Ansonsten gibt es viele frei verfügbare Kerne, die Sie im Internet finden können, die dies tun. :)

Als Beispiel:

// Count from 0..5207 then reset back to zero
always @(posedge clk) 
begin
  if (rst) begin
    clockdiv <= 0;
  end else begin
    if (clockdiv == 5207) 
        clockdiv <= 0;
    else
        clockdiv <= clockdiv + 1;
  end
end
Ja unbedingt das ist verilog zu lernen. Es schien ein nettes, überschaubares kleines Projekt zu sein, um einige Grundlagen zu lernen.
Ich werde einen Reset hinzufügen. Ich dachte, dass die Uhr sowieso früh genug umlaufen würde, so dass dies nur dazu führen würde, dass das erste Bit um ein paar ms verzögert wird. Nicht das, was ich für echte Projekte tun würde, aber eine vernünftige Abkürzung beim Lernen. Liege ich falsch?
Sie können nicht davon ausgehen, dass die Register bei 0 beginnen. Daher ist es zwingend erforderlich, dass alle Register beim Start auf einen bekannten Zustand zurückgesetzt werden. In Ihrem Fall sind sowohl state als auch clockdiv beim Start undefiniert. Das Erhöhen eines undefinierten Werts ist also immer noch undefiniert usw.
Ich dachte mir, dass es einen Wert zwischen 0..8191 haben würde, also würde es schließlich bei Null landen und anfangen zu arbeiten. Punkt genommen, ich werde sicher sein, dass das Zurücksetzen in Zukunft richtig gehandhabt wird.
Auf einem FPGA ist ein Reset möglicherweise nicht unbedingt erforderlich. Bei Spartan-3 weiß ich es nicht genau, aber bei anderen Xilinx-Architekturen ist der Anfangszustand der Register in der Konfiguration definiert. Für eine maximale Übertragbarkeit (zu verschiedenen Architekturen oder einem ASIC) sollten HDL-Beschreibungen normalerweise immer noch zurückgesetzt werden, aber ein Zurücksetzen ist nicht erforderlich.
Während es in Ordnung ist, bestimmte Signale undefiniert zu lassen, wenn sie keine illegalen Werte annehmen können, gehört es im Allgemeinen zum guten Ton, einen Mechanismus bereitzustellen, um alle Flops auf einen bekannten Zustand zurückzusetzen. Sie werden froh sein, dass Sie es getan haben, sobald es an der Zeit ist, Dinge zu debuggen. Allerdings ist die Zustandsvariable einer endlichen Zustandsmaschine definitiv nicht eines dieser Signale, die undefiniert bleiben können - niemals. Sie müssen von einem bekannten Zustand ausgehen.