Dieser Post baut auf EthTrcv Teil 1 — Grundlagen & Einordnung auf. Dort ging es um die Rolle von EthTrcv in der AUTOSAR-Ethernet-Architektur. Hier geht es tiefer: Wie kommt EthTrcv von UNINIT bis in den Zustand, in dem tatsächlich Frames fließen — und welche API-Aufrufe stecken dahinter?

Wer schon einmal einen Ethernet-Link-Bringup debuggt hat, kennt das Muster: EthTrcv_Init wird aufgerufen, alles sieht plausibel aus, aber der Link kommt nicht. Um solche Fälle einzugrenzen, muss man wissen, welcher Zustand wann erreicht werden sollte — und welche Funktion dafür verantwortlich ist.

Die EthTrcv-Zustandsmaschine

EthTrcv vermischt in der Wahrnehmung vieler Entwickler zwei Konzepte, die die AUTOSAR-Spezifikation bewusst voneinander getrennt hält: den Initialisierungsstatus des Treibers und den angeforderten Betriebsmodus des Transceivers. Das ist tatsächlich der interessantere Teil der Geschichte — beide leben in unterschiedlichen Typen mit unterschiedlichem Zweck, und wer die Trennung nicht kennt, sucht beim Debuggen leicht am falschen Identifier.

Initialisierungsstatus: EthTrcv_StateType

EthTrcv_StateType (SWS_EthTrcv_00101) modelliert laut Spezifikation ausdrücklich keinen Betriebszustand, sondern ist reine „Status supervision used for Development Error Detection“ — zum Debuggen gedacht, mit genau zwei Werten:

                    EthTrcv_Init()
        ┌────────────────────────┐ ──────────────────► ┌─────────────────────┐
        │ ETHTRCV_STATE_UNINIT    │                      │ ETHTRCV_STATE_INIT  │
        │ (0x00)                  │                      │ (0x01)              │
        └────────────────────────┘                      └─────────────────────┘
WertBedeutung

ETHTRCV_STATE_UNINIT (0x00)

„Driver is not yet configured“ — Initialzustand nach Power-On oder Reset.

ETHTRCV_STATE_INIT (0x01)

„Driver is configured“ — EthTrcv_Init wurde erfolgreich durchlaufen (SWS_EthTrcv_00030).

Mehr Werte gibt es nicht — insbesondere kein ACTIVE, DOWN oder SLEEP. Der Übergang UNINIT → INIT ist einmalig pro Power-Zyklus und darf laut SWS nicht erneut durchlaufen werden, ohne dass vorher wieder UNINIT erreicht wurde (z. B. durch einen Reset). Ein zweiter EthTrcv_Init-Aufruf im laufenden Betrieb ist ein Konfigurationsfehler und wird von den meisten Implementierungen mit DET-Reports quittiert, sofern EthTrcvDevErrorDetect aktiviert ist.

Betriebsmodus: Eth_ModeType

Was die meisten mit „aktiv“ oder „down“ meinen, ist gar kein Zustand des EthTrcv-Treibers im engeren Sinn, sondern der angeforderte Modus des Transceivers — gesetzt über EthTrcv_SetTransceiverMode(TrcvIdx, TrcvMode). TrcvMode ist vom Typ Eth_ModeType, demselben Typ, den auch das Eth-Modul verwendet (definiert in Eth_GeneralTypes.h, nicht als eigener EthTrcv-Typ). Es gibt drei Literale:

EthTrcv_SetTransceiverMode(TrcvIdx, TrcvMode)     // TrcvMode : Eth_ModeType

     ┌──────────────────┐   ETH_MODE_ACTIVE    ┌────────────────────┐
     │  ETH_MODE_DOWN    │ ────────────────────►│  ETH_MODE_ACTIVE   │
     └──────────────────┘ ◄────────────────────└──────────┬─────────┘
                             ETH_MODE_DOWN                 │ ETH_MODE_ACTIVE_WITH_WAKEUP_REQUEST
                                                            ▼
                                        ┌───────────────────────────────────────┐
                                        │  ETH_MODE_ACTIVE_WITH_WAKEUP_REQUEST   │
                                        └───────────────────────────────────────┘
LiteralBedeutung

ETH_MODE_DOWN

Transceiver wird deaktiviert.

ETH_MODE_ACTIVE

Transceiver wird aktiviert — laut SWS u. a. auch die Kennzeichnung eines passiven Wake-ups.

ETH_MODE_ACTIVE_WITH_WAKEUP_REQUEST

Transceiver aktiv, zusätzlich aktive Wake-up-Anforderung. EthTrcv_GetTransceiverMode liefert diesen Modus laut SWS_EthTrcv_00049 aber immer als ETH_MODE_ACTIVE zurück — nach außen ist der Unterschied also nicht sichtbar.

Es gibt kein EthTrcv_ModeType und keine Literale ETHTRCV_MODE_ACTIVE/ETHTRCV_MODE_DOWN — solche Namen kursieren gelegentlich, existieren aber nicht in der SWS. Der reale Typ heißt Eth_ModeType und wird bewusst mit dem Eth-Modul geteilt: Beide Module sprechen über denselben Kanal („welcher Übertragungsmodus ist angefordert“), und AUTOSAR vermeidet es, dafür zwei parallele, redundante Typen zu pflegen. Namensraum-technisch — und konzeptionell — hat der Betriebsmodus nichts mit EthTrcv_StateType zu tun: Ein Transceiver kann durchaus INIT sein und gleichzeitig ETH_MODE_DOWN angefordert haben.

Initialisierungssequenz im Detail

EthTrcv initialisiert sich nicht selbst. Der Aufruf kommt von außen — konkret aus dem Init-Callback, das der EcuM im Rahmen der Post-Build-Loop-Initialisierung aufruft. Die Reihenfolge ist dabei nicht beliebig, sondern durch Abhängigkeiten zwischen den Modulen vorgegeben.

EcuM_Init()
  │
  ├─► EcuM_AL_DriverInitZero()      ── Basis-Treiber (Port, Dio, ...)
  │
  └─► EcuM_AL_DriverInitOne()       ── EthTrcv, Eth, EthIf, CanIf, ...
        │
        ├─► EthTrcv_Init(EthTrcv_ConfigType* config)
        │     └─ PHY-Hardware-Reset, MDIO-Grundkonfiguration,
        │        Register-Programmierung laut ARXML
        │
        ├─► Eth_Init(Eth_ConfigType* config)
        │     └─ MAC-Controller konfigurieren, DMA-Deskriptoren aufsetzen
        │
        └─► EthIf_Init(EthIf_ConfigType* config)
              └─ Verbindet EthTrcv- und Eth-Instanzen logisch,
                 stellt die einheitliche API für obere Schichten (TcpIp, ...) bereit

Die Reihenfolge EthTrcv vor Eth vor EthIf ist kein Zufall. EthIf_Init iteriert intern über alle konfigurierten EthTrcv- und Eth-Instanzen und verknüpft sie über die im ARXML hinterlegten Zuordnungen (EthIfCtrlIdxEthTrcvIdx). Ist EthTrcv_Init zu diesem Zeitpunkt noch nicht durchlaufen, schlägt diese Verknüpfung fehl oder EthIf arbeitet mit einem PHY, dessen Zustand noch UNINIT ist.

Innerhalb von EthTrcv_Init selbst laufen typischerweise folgende Schritte ab:

1. Konfigurationszeiger validieren (NULL-Check, DET falls aktiviert)
2. Interne Zustandsvariablen auf Default setzen
3. PHY-Hardware-Reset auslösen (RST_N-Pin oder Soft-Reset via MDIO)
4. Warten auf PHY-Bootzeit (herstellerspezifisch, siehe Datenblatt)
5. PHY-Identifikation lesen (PHY-ID-Register über MDIO) und gegen Konfiguration prüfen
6. Statische PHY-Register gemäß ARXML-Konfiguration programmieren
   (Auto-Negotiation-Advertisement, Interface-Modus, Delays, ...)
7. Interner Zustand: UNINIT → INIT
8. Rückgabe E_OK (oder E_NOT_OK bei Fehler, Zustand bleibt UNINIT)

Schritt 5 — die PHY-ID-Prüfung — wird in der Praxis gerne übersehen, ist aber der günstigste Fehler-Detektor den man haben kann: Stimmt die per MDIO gelesene PHY-ID nicht mit der erwarteten überein, liegt entweder ein Bestückungsfehler, ein MDIO-Adressproblem oder ein Power-Sequencing-Fehler vor — lange bevor man beim Link-Debugging landet.

Die wichtigsten API-Funktionen

EthTrcv_Init — Konfiguration übergeben, PHY zurücksetzen

FUNC(void, ETHTRCV_CODE) EthTrcv_Init(
    P2CONST(EthTrcv_ConfigType, AUTOMATIC, ETHTRCV_APPL_CONST) CfgPtr
);

EthTrcv_Init erhält einen Zeiger auf die generierte Konfigurationsstruktur — im Post-Build-Fall kommt dieser Zeiger direkt vom ARXML-Codegenerator, im Pre-Compile-Fall ist er meist NULL_PTR und die Konfiguration wird über kompilierte Konstanten referenziert. Die Funktion hat laut SWS keinen Rückgabewert; Fehler laufen stattdessen über DEM: Schlägt laut SWS_EthTrcv_00040 der Zugriffs-Check auf den Transceiver fehl, meldet die Funktion den Produktionsfehler ETHTRCV_E_ACCESS, nicht über einen Std_ReturnType.

Genau das ist ein häufiger Stolperstein bei der Integration: Wer erwartet, dass EthTrcv_Init wie viele andere BSW-Funktionen einen Std_ReturnType liefert, prüft den — nicht existenten — Rückgabewert und übersieht DET-/DEM-Reports als eigentlichen Fehlerkanal.

EthTrcv_SetTransceiverMode — Transceiver aktivieren oder abschalten

FUNC(Std_ReturnType, ETHTRCV_CODE) EthTrcv_SetTransceiverMode(
    uint8 TrcvIdx,
    Eth_ModeType TrcvMode
);

Steuert den Übergang zwischen ETH_MODE_DOWN, ETH_MODE_ACTIVE und ETH_MODE_ACTIVE_WITH_WAKEUP_REQUEST. TrcvIdx adressiert die konkrete Transceiver-Instanz (relevant bei Multi-PHY-Konfigurationen). Rückgabewerte:

RückgabewertBedeutung

E_OK

Moduswechsel wurde angestoßen (nicht zwingend bereits abgeschlossen — Auto-Negotiation braucht Zeit).

E_NOT_OK

Moduswechsel nicht möglich, z. B. weil sich der Transceiver noch in UNINIT befindet oder der PHY nicht antwortet.

EthTrcv_SetTransceiverMode(ETH_MODE_ACTIVE) setzt lediglich den Übertragungspfad frei — es garantiert keinen Link. Ob tatsächlich eine physikalische Verbindung zustande kommt, hängt von der Gegenstelle, dem Kabel und der Auto-Negotiation ab. Wer nach diesem Aufruf sofort Frames versendet, ohne den Link-Zustand zu prüfen, riskiert stillschweigend verworfene Frames.

FUNC(Std_ReturnType, ETHTRCV_CODE) EthTrcv_GetLinkState(
    uint8 TrcvIdx,
    P2VAR(EthTrcv_LinkStateType, AUTOMATIC, ETHTRCV_APPL_DATA) LinkStatePtr
);

Liefert ETHTRCV_LINK_STATE_ACTIVE oder ETHTRCV_LINK_STATE_DOWN über den Ausgabeparameter. Es gibt zwei grundsätzliche Strategien, wie der Link-Zustand ermittelt wird:

StrategieFunktionsweiseTrade-off

Polling

EthIf/obere Schicht ruft EthTrcv_GetLinkState zyklisch auf (typisch alle 10–100 ms aus einem Task-Kontext).

Einfach, deterministisch, aber Latenz bis zur Erkennung eines Link-Wechsels = Polling-Intervall.

Interrupt-gestützt

PHY signalisiert Link-Änderungen über einen dedizierten Interrupt-Pin; ISR setzt ein Flag, das im Task-Kontext ausgewertet wird und EthTrcv_GetLinkState zeitnah triggert.

Geringe Latenz, aber zusätzlicher Hardware-Pin und ISR-Handling nötig; nicht jeder PHY unterstützt das.

Viele Serien-Projekte kombinieren beide Ansätze: Interrupt für die schnelle Reaktion auf Link-Verlust (sicherheitsrelevant, z. B. bei Backbone-Verbindungen), zusätzliches Polling als Fallback, falls der Interrupt-Pfad aus irgendeinem Grund einen Event verpasst.

EthTrcv_GetTransceiverMode — aktuellen Modus abfragen

FUNC(Std_ReturnType, ETHTRCV_CODE) EthTrcv_GetTransceiverMode(
    uint8 TrcvIdx,
    P2VAR(Eth_ModeType, AUTOMATIC, ETHTRCV_APPL_DATA) TrcvModePtr
);

Das Gegenstück zu EthTrcv_SetTransceiverMode — liest den zuletzt gesetzten (nicht zwingend den physikalisch bereits erreichten) Modus zurück. Nützlich für Diagnose und für obere Schichten, die vor einem erneuten SetTransceiverMode-Aufruf prüfen wollen, ob überhaupt ein Wechsel nötig ist.

Fehlerbehandlung

EthTrcv unterscheidet zwischen zwei Fehlerkategorien, die unterschiedlich behandelt werden:

KategorieBeispielReporting-Mechanismus

Entwicklungsfehler

NULL-Pointer als Konfiguration, ungültiger TrcvIdx, API-Aufruf vor Init

DET (Det_ReportError), nur aktiv wenn EthTrcvDevErrorDetect == STD_ON; im Produktivbuild i. d. R. deaktiviert

Laufzeit-/Produktionsfehler

PHY antwortet nicht mehr auf MDIO, Link bricht unerwartet ab, PHY-Übertemperatur (falls unterstützt)

DEM (Dem_SetEventStatus / Dem_ReportErrorStatus), bleibt auch im Produktivbuild aktiv

Ein typischer DEM-relevanter Fehlerfall ist der PHY-Ausfall während des Betriebs: Ein zuvor erfolgreich initialisierter PHY antwortet plötzlich nicht mehr auf MDIO-Zugriffe — etwa durch einen Power-Glitch, ESD-Ereignis oder einen Hardware-Defekt.

Zyklischer Task
   │
   ├─► EthTrcv_GetLinkState() → E_NOT_OK (MDIO-Timeout)
   │
   ├─► Interner Retry-Zähler erhöhen
   │
   ├─► Schwellwert überschritten?
   │      │
   │      ├─ Nein → weiter pollen
   │      │
   │      └─ Ja → Dem_SetEventStatus(ETHTRCV_E_ACCESS, DEM_EVENT_STATUS_FAILED)
   │              → Diagnose-Event gesetzt, DTC ggf. reifend
   │              → EthIf wird über Callback über Link-Verlust informiert
   │
   └─► EthTrcv_GetLinkState() wieder E_OK?
          └─ Ja → Dem_SetEventStatus(..., DEM_EVENT_STATUS_PASSED)

Ein einzelner fehlgeschlagener MDIO-Zugriff ist noch kein Grund für einen DEM-Event — MDIO-Bus- Störungen durch EMV können vereinzelt auftreten. Praxisübliche Implementierungen verwenden Debounce-Zähler (mehrere aufeinanderfolgende Fehlversuche) bevor ein DTC gesetzt wird, um Flackern in der Diagnose zu vermeiden.

Das folgende Beispiel zeigt einen realistischen, vereinfachten Ablauf, wie ein Applikations- Task nach dem EcuM-Bringup den Link-Zustand überwacht und auf Verlust reagiert.

#define ETHTRCV_IDX_MAIN        0u
#define LINK_LOSS_THRESHOLD     5u

static uint8 linkLossCounter = 0u;
static boolean linkWasUp = FALSE;

/* Wird zyklisch aus einem 10ms-Task aufgerufen, nachdem EcuM
 * die Init-Sequenz (EthTrcv_Init -> Eth_Init -> EthIf_Init)
 * bereits durchlaufen hat. */
void EthLink_MainFunction(void)
{
    Std_ReturnType retVal;
    EthTrcv_LinkStateType linkState;

    /* Transceiver aktivieren, falls noch nicht geschehen */
    Eth_ModeType currentMode;
    retVal = EthTrcv_GetTransceiverMode(ETHTRCV_IDX_MAIN, &currentMode);

    if ((retVal == E_OK) && (currentMode != ETH_MODE_ACTIVE))
    {
        (void)EthTrcv_SetTransceiverMode(ETHTRCV_IDX_MAIN, ETH_MODE_ACTIVE);
        /* Rueckgabewert hier bewusst nicht fatal behandelt --
         * Aktivierung wird im naechsten Zyklus erneut versucht,
         * falls sie fehlschlaegt. */
    }

    /* Link-Zustand abfragen */
    retVal = EthTrcv_GetLinkState(ETHTRCV_IDX_MAIN, &linkState);

    if (retVal != E_OK)
    {
        /* MDIO-Zugriff fehlgeschlagen - PHY evtl. nicht erreichbar */
        if (linkLossCounter < LINK_LOSS_THRESHOLD)
        {
            linkLossCounter++;
        }
    }
    else if (linkState == ETHTRCV_LINK_STATE_ACTIVE)
    {
        linkLossCounter = 0u;

        if (!linkWasUp)
        {
            linkWasUp = TRUE;
            Dem_SetEventStatus(ETHTRCV_E_ACCESS, DEM_EVENT_STATUS_PASSED);
            /* Applikationsseitige Reaktion auf Link-Up, z.B.
             * TcpIp-Stack ueber EthIf-Callback informieren. */
        }
    }
    else /* ETHTRCV_LINK_STATE_DOWN */
    {
        if (linkLossCounter < LINK_LOSS_THRESHOLD)
        {
            linkLossCounter++;
        }
    }

    if (linkLossCounter >= LINK_LOSS_THRESHOLD)
    {
        if (linkWasUp)
        {
            linkWasUp = FALSE;
            Dem_SetEventStatus(ETHTRCV_E_ACCESS, DEM_EVENT_STATUS_FAILED);
        }
    }
}

Das Beispiel ist bewusst vereinfacht — in einer Serienapplikation läuft diese Logik meist innerhalb von EthIf bzw. eines State-Manager-Moduls, nicht in applikationsnahem Code. Es zeigt aber den grundlegenden Ablauf: Moduswechsel absichern, Link-Zustand pollen, Debounce vor DEM-Reporting.

Serie

TeilThemaStatus

1

Grundlagen & Einordnung

Fertig

2

API & Initialisierungssequenz

Dieser Post

3

ARXML-Konfiguration in der Praxis

Folgt

4

WakeUp-Handling & Diagnose

Folgt

Zusammenfassung

ThemaKernaussage für Software-Entwickler

Zustandsmaschine

ETHTRCV_STATE_UNINIT → ETHTRCV_STATE_INIT (EthTrcv_StateType) ist eine reine DET-Statusgröße mit nur zwei Werten; der Betriebsmodus (ETH_MODE_DOWN/ETH_MODE_ACTIVE/ETH_MODE_ACTIVE_WITH_WAKEUP_REQUEST, Typ Eth_ModeType) ist davon unabhängig und wird über EthTrcv_SetTransceiverMode gesetzt

Init-Reihenfolge

EcuM ruft EthTrcv_Init vor Eth_Init und vor EthIf_Init auf — EthIf verknüpft beide über ARXML-Zuordnungen

EthTrcv_Init

Kein Std_ReturnType — Fehler laufen über DET/DEM, nicht über den Rückgabewert

EthTrcv_SetTransceiverMode

Setzt nur den Übertragungspfad frei, garantiert keinen physikalischen Link

EthTrcv_GetLinkState

Polling oder Interrupt-gestützt; Serienprojekte kombinieren häufig beides

Fehlerbehandlung

Entwicklungsfehler → DET (meist deaktiviert im Produktivbuild); Laufzeitfehler → DEM mit Debounce vor dem DTC