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) │
└────────────────────────┘ └─────────────────────┘| Wert | Bedeutung |
|---|---|
| „Driver is not yet configured“ — Initialzustand nach Power-On oder Reset. |
| „Driver is configured“ — |
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 │
└───────────────────────────────────────┘| Literal | Bedeutung |
|---|---|
| Transceiver wird deaktiviert. |
| Transceiver wird aktiviert — laut SWS u. a. auch die Kennzeichnung eines passiven Wake-ups. |
| Transceiver aktiv, zusätzlich aktive Wake-up-Anforderung. |
Es gibt kein |
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, ...) bereitDie Reihenfolge EthTrcv vor Eth vor EthIf ist kein Zufall. |
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_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ückgabewert | Bedeutung |
|---|---|
| Moduswechsel wurde angestoßen (nicht zwingend bereits abgeschlossen — Auto-Negotiation braucht Zeit). |
| Moduswechsel nicht möglich, z. B. weil sich der Transceiver noch in |
|
EthTrcv_GetLinkState — Link-Status abfragen
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:
| Strategie | Funktionsweise | Trade-off |
|---|---|---|
Polling |
| 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 | 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:
| Kategorie | Beispiel | Reporting-Mechanismus |
|---|---|---|
Entwicklungsfehler | NULL-Pointer als Konfiguration, ungültiger | DET ( |
Laufzeit-/Produktionsfehler | PHY antwortet nicht mehr auf MDIO, Link bricht unerwartet ab, PHY-Übertemperatur (falls unterstützt) | DEM ( |
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. |
Codebeispiel — Init- und Link-Check-Ablauf
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, ¤tMode);
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 |
Serie
| Teil | Thema | Status |
|---|---|---|
1 | Fertig | |
2 | API & Initialisierungssequenz | Dieser Post |
3 | Folgt | |
4 | Folgt |
Zusammenfassung
| Thema | Kernaussage für Software-Entwickler |
|---|---|
Zustandsmaschine |
|
Init-Reihenfolge | EcuM ruft |
| Kein |
| Setzt nur den Übertragungspfad frei, garantiert keinen physikalischen Link |
| Polling oder Interrupt-gestützt; Serienprojekte kombinieren häufig beides |
Fehlerbehandlung | Entwicklungsfehler → DET (meist deaktiviert im Produktivbuild); Laufzeitfehler → DEM mit Debounce vor dem DTC |
Weiter in der EthTrcv-Serie: EthTrcv Teil 3 — ARXML-Konfiguration in der Praxis