This post builds on EthTrcv Part 1 — Basics & Classification. That post covered the role of EthTrcv in the AUTOSAR Ethernet architecture. This one goes deeper: how does EthTrcv actually get from UNINIT to a state where frames flow — and which API calls make that happen?

Anyone who has debugged an Ethernet link bring-up knows the pattern: EthTrcv_Init gets called, everything looks plausible, and the link still doesn’t come up. Narrowing down cases like that requires knowing which state should be reached when — and which function is responsible for it.

The EthTrcv State Machine

Many developers conflate two concepts that the AUTOSAR specification deliberately keeps apart: the driver’s initialization status and the transceiver’s requested operating mode. That distinction is actually the more interesting part of the story — the two live in different types with different purposes, and not knowing the split makes it easy to chase the wrong identifier while debugging.

Initialization status: EthTrcv_StateType

EthTrcv_StateType (SWS_EthTrcv_00101) explicitly does not model an operating state, according to the spec — it is plain "status supervision used for Development Error Detection", meant for debugging, with exactly two values:

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

ETHTRCV_STATE_UNINIT (0x00)

"Driver is not yet configured" — initial state after power-on or reset.

ETHTRCV_STATE_INIT (0x01)

"Driver is configured" — EthTrcv_Init has completed successfully (SWS_EthTrcv_00030).

That’s the whole enum — there is no ACTIVE, DOWN, or SLEEP value. The UNINIT → INIT transition happens exactly once per power cycle and, per the SWS, must not be repeated without first returning to UNINIT (e.g. via a reset). Calling EthTrcv_Init a second time during normal operation is a configuration error and most implementations flag it via a DET report, provided EthTrcvDevErrorDetect is enabled.

Operating mode: Eth_ModeType

What most people mean by "active" or "down" is not a state of the EthTrcv driver in the strict sense at all — it is the transceiver’s requested mode, set via EthTrcv_SetTransceiverMode(TrcvIdx, TrcvMode). TrcvMode is of type Eth_ModeType, the same type used by the Eth module (defined in Eth_GeneralTypes.h, not as an EthTrcv-specific type). There are three literals:

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   │
                                        └───────────────────────────────────────┘
LiteralMeaning

ETH_MODE_DOWN

Transceiver is disabled.

ETH_MODE_ACTIVE

Transceiver is enabled — per the SWS, this also covers a passive wake-up.

ETH_MODE_ACTIVE_WITH_WAKEUP_REQUEST

Transceiver active plus an active wake-up request. Per SWS_EthTrcv_00049, EthTrcv_GetTransceiverMode always reports this mode back as ETH_MODE_ACTIVE — the difference isn’t visible from the outside.

There is no EthTrcv_ModeType and no ETHTRCV_MODE_ACTIVE/ETHTRCV_MODE_DOWN literals — these names circulate occasionally but do not exist in the SWS. The real type is Eth_ModeType, deliberately shared with the Eth module: both modules talk about the same thing ("which transmission mode is requested"), and AUTOSAR avoids maintaining two parallel, redundant types for that. Namespace-wise — and conceptually — the operating mode has nothing to do with EthTrcv_StateType: a transceiver can very well be INIT while ETH_MODE_DOWN is the currently requested mode.

The Initialization Sequence in Detail

EthTrcv does not initialize itself. The call comes from outside — specifically from the init callback that the EcuM invokes as part of post-build loop initialization. The order in which this happens is not arbitrary; it is dictated by dependencies between the modules.

EcuM_Init()
  │
  ├─► EcuM_AL_DriverInitZero()      ── basic drivers (Port, Dio, ...)
  │
  └─► EcuM_AL_DriverInitOne()       ── EthTrcv, Eth, EthIf, CanIf, ...
        │
        ├─► EthTrcv_Init(EthTrcv_ConfigType* config)
        │     └─ PHY hardware reset, MDIO baseline configuration,
        │        register programming per ARXML
        │
        ├─► Eth_Init(Eth_ConfigType* config)
        │     └─ configure MAC controller, set up DMA descriptors
        │
        └─► EthIf_Init(EthIf_ConfigType* config)
              └─ logically links EthTrcv and Eth instances,
                 provides the unified API for upper layers (TcpIp, ...)

The order EthTrcv before Eth before EthIf is not a coincidence. EthIf_Init internally iterates over all configured EthTrcv and Eth instances and links them via the mappings stored in the ARXML (EthIfCtrlIdxEthTrcvIdx). If EthTrcv_Init has not completed by this point, that linkage either fails or EthIf ends up working with a PHY whose state is still UNINIT.

Inside EthTrcv_Init itself, the following steps typically run:

1. Validate configuration pointer (NULL check, DET if enabled)
2. Set internal state variables to defaults
3. Trigger PHY hardware reset (RST_N pin or soft reset via MDIO)
4. Wait for PHY boot time (vendor-specific, see datasheet)
5. Read PHY identification (PHY ID register via MDIO) and check against configuration
6. Program static PHY registers per ARXML configuration
   (auto-negotiation advertisement, interface mode, delays, ...)
7. Internal state: UNINIT → INIT
8. Return E_OK (or E_NOT_OK on failure, state remains UNINIT)

Step 5 — the PHY ID check — is easy to overlook in practice, but it is one of the cheapest error detectors available: if the PHY ID read via MDIO does not match the expected one, you are looking at an assembly error, an MDIO address problem, or a power-sequencing fault — long before you’d otherwise end up debugging the link itself.

Key API Functions

EthTrcv_Init — Pass Configuration, Reset the PHY

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

EthTrcv_Init receives a pointer to the generated configuration structure — in the post-build case, this pointer comes directly from the ARXML code generator; in the pre-compile case it is usually NULL_PTR and configuration is referenced through compiled constants. Per the SWS the function has no return value; errors go through DEM instead: per SWS_EthTrcv_00040, if the access check to the transceiver fails, the function reports the production error ETHTRCV_E_ACCESS, not via a Std_ReturnType.

This is exactly where a lot of integrations trip up: anyone expecting EthTrcv_Init to return a Std_ReturnType like many other BSW functions ends up checking a return value that does not exist, and misses DET/DEM reports as the actual error channel.

EthTrcv_SetTransceiverMode — Activate or Shut Down the Transceiver

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

Controls the transition between ETH_MODE_DOWN, ETH_MODE_ACTIVE, and ETH_MODE_ACTIVE_WITH_WAKEUP_REQUEST. TrcvIdx addresses the specific transceiver instance (relevant for multi-PHY configurations). Return values:

Return valueMeaning

E_OK

Mode change was triggered (not necessarily completed yet — auto-negotiation takes time).

E_NOT_OK

Mode change not possible, e.g. because the transceiver is still in UNINIT or the PHY is not responding.

EthTrcv_SetTransceiverMode(ETH_MODE_ACTIVE) merely enables the transmission path — it does not guarantee a link. Whether an actual physical connection comes up depends on the link partner, the cable, and auto-negotiation. Sending frames immediately after this call without checking the link state risks frames being silently dropped.

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

Returns ETHTRCV_LINK_STATE_ACTIVE or ETHTRCV_LINK_STATE_DOWN via the output parameter. There are two fundamental strategies for determining the link state:

StrategyHow it worksTrade-off

Polling

EthIf/upper layer calls EthTrcv_GetLinkState cyclically (typically every 10–100 ms from a task context).

Simple, deterministic, but detection latency for a link change equals the polling interval.

Interrupt-driven

PHY signals link changes via a dedicated interrupt pin; the ISR sets a flag evaluated in task context, which triggers EthTrcv_GetLinkState promptly.

Low latency, but requires an extra hardware pin and ISR handling; not every PHY supports it.

Many production projects combine both approaches: an interrupt for fast reaction to link loss (safety-relevant, e.g. on backbone connections), plus polling as a fallback in case the interrupt path misses an event for some reason.

EthTrcv_GetTransceiverMode — Query the Current Mode

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

The counterpart to EthTrcv_SetTransceiverMode — reads back the most recently set (not necessarily the physically already-reached) mode. Useful for diagnostics and for upper layers that want to check whether a mode change is even necessary before calling SetTransceiverMode again.

Error Handling

EthTrcv distinguishes between two error categories that are handled differently:

CategoryExampleReporting mechanism

Development error

NULL pointer as configuration, invalid TrcvIdx, API call before Init

DET (Det_ReportError), only active when EthTrcvDevErrorDetect == STD_ON; usually disabled in production builds

Runtime / production error

PHY stops responding on MDIO, link drops unexpectedly, PHY over-temperature (if supported)

DEM (Dem_SetEventStatus / Dem_ReportErrorStatus), stays active in production builds

A typical DEM-relevant failure case is a PHY failure during operation: a previously successfully initialized PHY suddenly stops responding to MDIO accesses — for example due to a power glitch, an ESD event, or a hardware defect.

Cyclic task
   │
   ├─► EthTrcv_GetLinkState() → E_NOT_OK (MDIO timeout)
   │
   ├─► Increment internal retry counter
   │
   ├─► Threshold exceeded?
   │      │
   │      ├─ No  → keep polling
   │      │
   │      └─ Yes → Dem_SetEventStatus(ETHTRCV_E_ACCESS, DEM_EVENT_STATUS_FAILED)
   │              → diagnostic event set, DTC potentially maturing
   │              → EthIf notified of link loss via callback
   │
   └─► EthTrcv_GetLinkState() back to E_OK?
          └─ Yes → Dem_SetEventStatus(..., DEM_EVENT_STATUS_PASSED)

A single failed MDIO access is not by itself grounds for a DEM event — MDIO bus glitches caused by EMC can happen occasionally. Common implementations use debounce counters (several consecutive failed attempts) before setting a DTC, to avoid flickering diagnostic entries.

The following example shows a realistic, simplified flow for how an application task monitors link state and reacts to loss after EcuM has already run the init sequence.

#define ETHTRCV_IDX_MAIN        0u
#define LINK_LOSS_THRESHOLD     5u

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

/* Called cyclically from a 10ms task, after EcuM has already
 * run the init sequence (EthTrcv_Init -> Eth_Init -> EthIf_Init). */
void EthLink_MainFunction(void)
{
    Std_ReturnType retVal;
    EthTrcv_LinkStateType linkState;

    /* Activate the transceiver if not already done */
    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);
        /* Return value deliberately not treated as fatal here --
         * activation will be retried next cycle if it failed. */
    }

    /* Query link state */
    retVal = EthTrcv_GetLinkState(ETHTRCV_IDX_MAIN, &linkState);

    if (retVal != E_OK)
    {
        /* MDIO access failed - PHY possibly unreachable */
        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);
            /* Application-side reaction to link-up, e.g. notify
             * the TcpIp stack via an EthIf callback. */
        }
    }
    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);
        }
    }
}

This example is deliberately simplified — in a production application this logic usually lives inside EthIf or a dedicated state-manager module, not application-level code. It does, however, illustrate the basic flow: guard mode changes, poll link state, debounce before DEM reporting.

Series

PartTopicStatus

1

Basics & Classification

Done

2

API & Initialization Sequence

This post

3

ARXML Configuration in Practice

Coming up

4

WakeUp Handling & Diagnostics

Coming up

Summary

TopicKey takeaway for software developers

State machine

ETHTRCV_STATE_UNINIT → ETHTRCV_STATE_INIT (EthTrcv_StateType) is a plain DET status value with only two states; the operating mode (ETH_MODE_DOWN/ETH_MODE_ACTIVE/ETH_MODE_ACTIVE_WITH_WAKEUP_REQUEST, type Eth_ModeType) is independent of it and set via EthTrcv_SetTransceiverMode

Init order

EcuM calls EthTrcv_Init before Eth_Init and before EthIf_InitEthIf links both via ARXML mappings

EthTrcv_Init

No Std_ReturnType — errors go through DET/DEM, not the return value

EthTrcv_SetTransceiverMode

Only enables the transmission path, does not guarantee a physical link

EthTrcv_GetLinkState

Polling or interrupt-driven; production projects often combine both

Error handling

Development errors → DET (usually disabled in production builds); runtime errors → DEM with debounce before the DTC