Heim Der Blog Blog Details

Wie implementiert man UART, SPI oder I2C in einem FPGA?

August 07 2025
Ampheo

Anfrage

Globaler Lieferant elektronischer Komponenten AMPHEO PTY LTD: Umfangreiches Inventar für One-Stop-Shopping. Einfache Anfragen, schnelle, individuelle Lösungen und Angebote.

SCHNELLE ANFRAGE
ZUR RFQ-LISTE HINZUFÜGEN
Die Implementierung von UART, SPI oder I2C in einem FPGA erfordert das Entwerfen oder Verwenden bestehender Verilog/VHDL-Module, die diese Kommunikationsprotokolle handhaben.

Die Implementierung von UART, SPI oder I2C in einem FPGA erfordert das Entwerfen oder Verwenden bestehender Verilog/VHDL-Module, die diese Kommunikationsprotokolle handhaben. Nachfolgend sind die wichtigsten Schritte und Überlegungen für jedes Protokoll aufgeführt.

Wie implementiert man UART, SPI oder I2C in einem FPGA?


1. UART (Universal Asynchronous Receiver-Transmitter)

UART ist ein einfaches serielles Protokoll mit TX (Senden) und RX (Empfangen) und konfigurierbarer Baudrate.

Implementierungsschritte

Sender (UART_TX)

  1. Baudraten-Generator:

    • Erzeugt ein Taktsignal mit der gewünschten Baudrate (z. B. 9600, 115200 Baud).

    • Beispiel für 100 MHz FPGA-Takt und 115200 Baud:

      verilog
       
      localparam CLK_FREQ = 100_000_000;
      localparam BAUD_RATE = 115200;
      localparam BAUD_COUNT = CLK_FREQ / BAUD_RATE;
  2. Zustandsautomat für TX:

    • Leerlauf → Startbit (0) → 8 Datenbits → Stoppbit (1).

    • Datenbits nacheinander ausgeben.

Empfänger (UART_RX)

  1. Oversampling (optional, aber empfohlen):

    • Abtasten der RX-Leitung mit 16x Baudrate für Rauschimmunität (z. B. Erkennung des Startbits durch mehrere Abtastwerte).

  2. Zustandsautomat für RX:

    • Warten auf Startbit → 8 Datenbits einlesen → Stoppbit prüfen.

Beispiel für ein UART-Modul (Verilog)

verilog
 
module uart_tx (
    input clk, input [7:0] data, input tx_start,
    output reg tx, output reg tx_done
);
    reg [3:0] bit_counter = 0;
    reg [15:0] baud_counter = 0;
    reg [9:0] shift_reg = 10'b1_11111111_0; // Stopp + Daten + Start
    
    always @(posedge clk) begin
        if (tx_start) shift_reg <= {1'b1, data, 1'b0}; // Daten laden
        if (baud_counter == BAUD_COUNT-1) begin
            tx <= shift_reg[0];
            shift_reg <= {1'b1, shift_reg[9:1]}; // Rechts schieben
            bit_counter <= bit_counter + 1;
            if (bit_counter == 9) tx_done <= 1;
        end
    end
endmodule

2. SPI (Serial Peripheral Interface)

SPI ist ein synchrones, vollduplex-Protokoll mit SCLK (Takt), MOSI (Master Out Slave In), MISO (Master In Slave Out) und CS (Chip Select).

Implementierungsschritte

SPI-Master

  1. SCLK erzeugen (einstellbare Frequenz, CPOL, CPHA).

  2. Daten über MOSI senden und über MISO empfangen (getaktet).

  3. CS (Chip Select) steuern (aktiv-low für Slave-Auswahl).

SPI-Slave

  1. MOSI bei SCLK-Flanken einlesen (abhängig von CPHA/CPOL).

  2. MISO steuern, wenn CS aktiv ist.

Beispiel für SPI-Master (Verilog)

verilog
 
module spi_master (
    input clk, input [7:0] data, input start,
    output reg sclk, mosi, cs, output reg [7:0] miso_data
);
    reg [2:0] bit_counter = 0;
    reg [7:0] shift_reg;
    
    always @(posedge clk) begin
        if (start) begin
            cs <= 0;
            shift_reg <= data;
            bit_counter <= 0;
        end
        if (!cs) begin
            sclk <= ~sclk; // Takt toggeln
            if (sclk) begin // Bei steigender Flanke
                mosi <= shift_reg[7];
                shift_reg <= {shift_reg[6:0], miso}; // MISO einlesen
                bit_counter <= bit_counter + 1;
                if (bit_counter == 7) cs <= 1; // Fertig
            end
        end
    end
endmodule

3. I2C (Inter-Integrated Circuit)

I2C ist ein Zwei-Draht-Protokoll (SDA, SCL) mit Multi-Master- und Multi-Slave-Fähigkeit und 7/10-Bit-Adressierung.

Implementierungsschritte

I2C-Master

  1. SCL (Takt) erzeugen (~100 kHz im Standardmodus, ~400 kHz im Fast Mode).

  2. I2C-Zustandsautomat:

    • Startbedingung (SDA fällt, während SCL hoch ist).

    • 7-Bit-Adresse + R/W-Bit senden.

    • Auf ACK warten (SDA wird vom Slave auf Low gezogen).

    • Datenbytes senden/empfangen.

    • Stoppbedingung (SDA steigt, während SCL hoch ist).

I2C-Slave

  1. Startbedingung erkennen (SDA/SCL überwachen).

  2. Adressabgleich prüfen (ACK senden, wenn übereinstimmend).

  3. Daten lesen/schreiben basierend auf R/W-Bit.

Beispiel für I2C-Master (Verilog)

verilog
 
module i2c_master (
    input clk, input [6:0] addr, input [7:0] data, input start,
    inout sda, output scl
);
    reg sda_out, scl_out;
    reg [3:0] state = 0;
    
    assign sda = (sda_out) ? 1'bz : 1'b0; // Open-Drain
    assign scl = (scl_out) ? 1'bz : 1'b0;
    
    always @(posedge clk) begin
        case (state)
            0: if (start) begin // Startbedingung
                sda_out <= 0; state <= 1;
            end
            1: begin // Adresse + R/W senden
                scl_out <= 1; sda_out <= addr[6]; // MSB zuerst
                state <= 2;
            end
            // ... (ACK-Prüfung, Datenübertragung, Stoppbedingung)
        endcase
    end
endmodule

Vergleichstabelle

Protokoll Geschwindigkeit Leitungen Komplexität Anwendungsfall
UART Langsam (bis ~4 Mbps) 2 (TX, RX) Einfach Debugging, PC-Kommunikation
SPI Schnell (bis 100+ MHz) 4 (SCLK, MOSI, MISO, CS) Mittel Hochgeschwindigkeitssensoren, Flash-Speicher
I2C Langsam (~100-400 kHz) 2 (SDA, SCL) Komplex (Multi-Master) Niedriggeschwindigkeitssensoren, EEPROM

Wichtige Tipps

  • Verwenden Sie FIFOs zur Datenpufferung bei UART/SPI/I2C.

  • Implementieren Sie Clock Domain Crossing (CDC), wenn verschiedene Taktdomänen verwendet werden.

  • Nutzen Sie FPGA-Hersteller-IP-Cores (Xilinx AXI UART, Intel SPI Controller) für schnelle Integration.

  • Simulieren Sie mit Tools wie ModelSim/GTKWave vor der Implementierung.

Ampheo